Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deletion of managed SOA record-sets fails on terraform destroy #12827

Assignees
Labels
bug forward/review In review; remove label to forward service/cloud-dns

Comments

@rtokarek-fastly
Copy link

rtokarek-fastly commented Oct 18, 2022

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request.
  • Please do not leave +1 or me too comments, they generate extra noise for issue followers and do not help prioritize the request.
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment.
  • If an issue is assigned to the modular-magician user, it is either in the process of being autogenerated, or is planned to be autogenerated soon. If an issue is assigned to a user, that user is claiming responsibility for the issue. If an issue is assigned to hashibot, a community member has claimed the issue already.

Terraform Version

Terraform v1.2.8
on darwin_amd64
+ provider registry.terraform.io/hashicorp/google v4.41.0

Affected Resource(s)

  • google_dns_record_set
    type = "SOA"

Terraform Configuration Files

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "= 4.41"
    }
  }
}

resource "google_dns_managed_zone" "tfprovidergooglebug-com" {
  project    = var.project_id
  name       = "tfprovidergooglebug-com"
  dns_name   = "tfprovidergooglebug.com."
  visibility = "public"
}

resource "google_dns_record_set" "tfprovidergooglebug-soa" {
  project      = var.project_id
  managed_zone = "tfprovidergooglebug-com"
  name         = "tfprovidergooglebug.com."
  type         = "SOA"
  ttl          = "21600"
  rrdatas      = ["ns-cloud-d1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 259200 120"]
}

Debug Output

terraform apply output is not applicable. That succeeds just fine. The trouble is terraform destroy. The debug output is uninteresting, but can be provided if somebody really wants.

Expected Behavior

Because the SOA record is fundamental to the zone, a destroy or delete operation should fake deletion – the same as for root-level NS records. The SOA gets deleted when the zone resource is deleted, but because we're managing the SOA record content, we run into a problem when destroying. Terraform wants to delete the managed SOA record before deleting the zone. The google cloud DNS apis properly deny deletion, but the underlying terraform go code shouldn't even try. It's not appropriate in this case.

Actual Behavior

google_dns_record_set.tfprovidergooglebug-soa: Destroying... [id=projects/<project_id>/managedZones/tfprovidergooglebug-com/rrsets/tfprovidergooglebug.com./SOA]
google_dns_managed_zone.tfprovidergooglebug-com: Destroying... [id=projects/<project_id>/managedZones/tfprovidergooglebug-com]
google_dns_managed_zone.tfprovidergooglebug-com: Destruction complete after 1s
╷
│ Error: Error when reading or editing google_dns_record_set: googleapi: Error 400: The resource record set 'entity.change.deletions[0]' is invalid because a zone must contain exactly one resource record set of type 'SOA' at the apex., invalidZoneApex
│ 
│ 

The problem is here:

// NS records must always have a value, so we short-circuit delete
// this allows terraform delete to work, but may have unexpected
// side-effects when deleting just that record set.
// Unfortunately, you can set NS records on subdomains, and those
// CAN and MUST be deleted, so we need to retrieve the managed zone,
// check if what we're looking at is a subdomain, and only not delete
// if it's not actually a subdomain
if d.Get("type").(string) == "NS" {
mz, err := config.NewDnsClient(userAgent).ManagedZones.Get(project, zone).Do()
if err != nil {
return fmt.Errorf("Error retrieving managed zone %q from %q: %s", zone, project, err)
}
domain := mz.DnsName
if domain == d.Get("name").(string) {
log.Println("[DEBUG] NS records can't be deleted due to API restrictions, so they're being left in place. See https://www.terraform.io/docs/providers/google/r/dns_record_set.html for more information.")
return nil
}
}

The simple solution is to add to the check for NS record type to also check for SOA if d.Get("type").(string) == "NS" || d.Get("type").(string) == "SOA" {

A PR that does this, updates the comment, and updates debug log is forthcoming.

Steps to Reproduce

  1. Pick a project you have permissions to create a DNS zone resource in, and set a variable project_id to that.
  2. create a .tf file with the config from above.
  3. terraform init
  4. terraform apply
  5. terraform destroy

Observe the error on step 5.

@rtokarek-fastly
Copy link
Author

A PR is here:

#12828

@rtokarek-fastly
Copy link
Author

rtokarek-fastly added a commit to rtokarek-fastly/magic-modules that referenced this issue Oct 19, 2022
When trying to delete record-sets that are managed by terraform, some record types can't be deleted by DNS and API restrictions.

(It doesn't make sense to delete the Start Of Authority (SOA) or root-level NS records by themselves as they're fundamental to the zone construct – their value can be changed, but they must exist for the zone itself to exist.)

The code previously only pretended deletes for root-level NS records. This change adds SOA to that behavior so that terraform delete/destroy can function properly when SOA is managed.

See issue hashicorp/terraform-provider-google#12827
@rtokarek-fastly
Copy link
Author

PR GoogleCloudPlatform/magic-modules#6724 for GoogleCloudPlatform/magic-modules is up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment