diff --git a/.changelog/5191.txt b/.changelog/5191.txt new file mode 100644 index 0000000000..fb33860a98 --- /dev/null +++ b/.changelog/5191.txt @@ -0,0 +1,6 @@ +```release-note:bug +dns: fixed an issue in `google_dns_record_set` where creating the resource would result in an 409 error +``` +```release-note:bug +dns: fixed an issue in `google_dns_record_set` where `rrdatas` could not be updated +``` diff --git a/google-beta/provider.go b/google-beta/provider.go index 7e11762498..a4654f18a8 100644 --- a/google-beta/provider.go +++ b/google-beta/provider.go @@ -889,9 +889,9 @@ func Provider() *schema.Provider { return provider } -// Generated resources: 240 +// Generated resources: 239 // Generated IAM resources: 117 -// Total generated resources: 357 +// Total generated resources: 356 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1103,7 +1103,6 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_dialogflow_cx_environment": resourceDialogflowCXEnvironment(), "google_dns_managed_zone": resourceDNSManagedZone(), "google_dns_policy": resourceDNSPolicy(), - "google_dns_record_set": resourceDNSResourceDnsRecordSet(), "google_essential_contacts_contact": resourceEssentialContactsContact(), "google_filestore_instance": resourceFilestoreInstance(), "google_firebase_project": resourceFirebaseProject(), @@ -1291,6 +1290,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_dataflow_flex_template_job": resourceDataflowFlexTemplateJob(), "google_dataproc_cluster": resourceDataprocCluster(), "google_dataproc_job": resourceDataprocJob(), + "google_dns_record_set": resourceDnsRecordSet(), "google_endpoints_service": resourceEndpointsService(), "google_folder": resourceGoogleFolder(), "google_folder_organization_policy": resourceGoogleFolderOrganizationPolicy(), diff --git a/google-beta/resource_access_context_manager_access_level_condition.go b/google-beta/resource_access_context_manager_access_level_condition.go index 12b6c8540f..3b36c9588a 100644 --- a/google-beta/resource_access_context_manager_access_level_condition.go +++ b/google-beta/resource_access_context_manager_access_level_condition.go @@ -22,7 +22,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func resourceAccessContextManagerAccessLevelCondition() *schema.Resource { diff --git a/google-beta/resource_access_context_manager_service_perimeter_resource.go b/google-beta/resource_access_context_manager_service_perimeter_resource.go index ae40c0bdf8..abc1ed184f 100644 --- a/google-beta/resource_access_context_manager_service_perimeter_resource.go +++ b/google-beta/resource_access_context_manager_service_perimeter_resource.go @@ -21,7 +21,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) func resourceAccessContextManagerServicePerimeterResource() *schema.Resource { diff --git a/google-beta/resource_bigquery_dataset.go b/google-beta/resource_bigquery_dataset.go index 4b467d7ff8..4fb48010c0 100644 --- a/google-beta/resource_bigquery_dataset.go +++ b/google-beta/resource_bigquery_dataset.go @@ -23,7 +23,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) const datasetIdRegexp = `[0-9A-Za-z_]+` diff --git a/google-beta/resource_bigquery_dataset_access.go b/google-beta/resource_bigquery_dataset_access.go index 6f2fe3fce1..0725c4a9c4 100644 --- a/google-beta/resource_bigquery_dataset_access.go +++ b/google-beta/resource_bigquery_dataset_access.go @@ -22,7 +22,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) var bigqueryAccessRoleToPrimitiveMap = map[string]string{ diff --git a/google-beta/resource_bigquery_job.go b/google-beta/resource_bigquery_job.go index e23860ed89..a075981089 100644 --- a/google-beta/resource_bigquery_job.go +++ b/google-beta/resource_bigquery_job.go @@ -24,7 +24,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) var ( diff --git a/google-beta/resource_bigquery_routine.go b/google-beta/resource_bigquery_routine.go index 740b91a699..dda6333cae 100644 --- a/google-beta/resource_bigquery_routine.go +++ b/google-beta/resource_bigquery_routine.go @@ -25,7 +25,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func resourceBigQueryRoutine() *schema.Resource { diff --git a/google-beta/resource_bigtable_app_profile.go b/google-beta/resource_bigtable_app_profile.go index 7289e014de..cc552eab61 100644 --- a/google-beta/resource_bigtable_app_profile.go +++ b/google-beta/resource_bigtable_app_profile.go @@ -22,7 +22,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/bigtableadmin/v2" ) func resourceBigtableAppProfile() *schema.Resource { diff --git a/google-beta/resource_cloud_run_domain_mapping.go b/google-beta/resource_cloud_run_domain_mapping.go index 37526d8b63..58485a7941 100644 --- a/google-beta/resource_cloud_run_domain_mapping.go +++ b/google-beta/resource_cloud_run_domain_mapping.go @@ -24,7 +24,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) var domainMappingGoogleProvidedLabels = []string{ diff --git a/google-beta/resource_cloud_run_service.go b/google-beta/resource_cloud_run_service.go index d2da4408db..f9ad8d7415 100644 --- a/google-beta/resource_cloud_run_service.go +++ b/google-beta/resource_cloud_run_service.go @@ -25,7 +25,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) func revisionNameCustomizeDiff(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { diff --git a/google-beta/resource_composer_environment.go b/google-beta/resource_composer_environment.go index afbc68c233..aec69f3686 100644 --- a/google-beta/resource_composer_environment.go +++ b/google-beta/resource_composer_environment.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - composer "google.golang.org/api/composer/v1beta1" ) const ( diff --git a/google-beta/resource_compute_backend_service.go b/google-beta/resource_compute_backend_service.go index 3f191aabce..e91c631ec9 100644 --- a/google-beta/resource_compute_backend_service.go +++ b/google-beta/resource_compute_backend_service.go @@ -23,11 +23,8 @@ import ( "strconv" "time" - "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/compute/v1" - "google.golang.org/api/googleapi" ) // Whether the backend is a global or regional NEG diff --git a/google-beta/resource_compute_disk.go b/google-beta/resource_compute_disk.go index fbed6f77f9..87864fb2cc 100644 --- a/google-beta/resource_compute_disk.go +++ b/google-beta/resource_compute_disk.go @@ -25,7 +25,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) // Is the new disk size smaller than the old one? diff --git a/google-beta/resource_compute_instance_group_named_port.go b/google-beta/resource_compute_instance_group_named_port.go index cb820ccbb9..9f96246d84 100644 --- a/google-beta/resource_compute_instance_group_named_port.go +++ b/google-beta/resource_compute_instance_group_named_port.go @@ -22,7 +22,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) func resourceComputeInstanceGroupNamedPort() *schema.Resource { diff --git a/google-beta/resource_compute_network.go b/google-beta/resource_compute_network.go index 905252d433..edeb263732 100644 --- a/google-beta/resource_compute_network.go +++ b/google-beta/resource_compute_network.go @@ -23,7 +23,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func resourceComputeNetwork() *schema.Resource { diff --git a/google-beta/resource_compute_region_backend_service.go b/google-beta/resource_compute_region_backend_service.go index 19c8472ad8..1429292a11 100644 --- a/google-beta/resource_compute_region_backend_service.go +++ b/google-beta/resource_compute_region_backend_service.go @@ -24,7 +24,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) // Fields in "backends" that are not allowed for non-managed backend services diff --git a/google-beta/resource_compute_region_disk.go b/google-beta/resource_compute_region_disk.go index a70565efcc..e242bd700b 100644 --- a/google-beta/resource_compute_region_disk.go +++ b/google-beta/resource_compute_region_disk.go @@ -24,7 +24,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) func resourceComputeRegionDisk() *schema.Resource { diff --git a/google-beta/resource_compute_router_nat.go b/google-beta/resource_compute_router_nat.go index dca4d08a91..f4e0d8071b 100644 --- a/google-beta/resource_compute_router_nat.go +++ b/google-beta/resource_compute_router_nat.go @@ -25,7 +25,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func resourceNameSetFromSelfLinkSet(v interface{}) *schema.Set { diff --git a/google-beta/resource_compute_router_peer.go b/google-beta/resource_compute_router_peer.go index 1fb9539f99..13c70d1ef2 100644 --- a/google-beta/resource_compute_router_peer.go +++ b/google-beta/resource_compute_router_peer.go @@ -24,7 +24,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func resourceComputeRouterBgpPeer() *schema.Resource { diff --git a/google-beta/resource_compute_security_policy.go b/google-beta/resource_compute_security_policy.go index f842e34033..f6bc9bf2e5 100644 --- a/google-beta/resource_compute_security_policy.go +++ b/google-beta/resource_compute_security_policy.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - compute "google.golang.org/api/compute/v0.beta" ) func resourceComputeSecurityPolicy() *schema.Resource { diff --git a/google-beta/resource_compute_subnetwork.go b/google-beta/resource_compute_subnetwork.go index 543938bbe6..4ae5236f37 100644 --- a/google-beta/resource_compute_subnetwork.go +++ b/google-beta/resource_compute_subnetwork.go @@ -22,7 +22,6 @@ import ( "reflect" "time" - "github.com/apparentlymart/go-cidr/cidr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" diff --git a/google-beta/resource_data_loss_prevention_stored_info_type.go b/google-beta/resource_data_loss_prevention_stored_info_type.go index 8c8df234cd..40e64e9101 100644 --- a/google-beta/resource_data_loss_prevention_stored_info_type.go +++ b/google-beta/resource_data_loss_prevention_stored_info_type.go @@ -22,7 +22,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) func resourceDataLossPreventionStoredInfoType() *schema.Resource { diff --git a/google-beta/resource_dataproc_cluster.go b/google-beta/resource_dataproc_cluster.go index 5988c4d0f3..b409489d64 100644 --- a/google-beta/resource_dataproc_cluster.go +++ b/google-beta/resource_dataproc_cluster.go @@ -11,8 +11,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - - dataproc "google.golang.org/api/dataproc/v1beta2" ) var ( diff --git a/google-beta/resource_dataproc_cluster_test.go b/google-beta/resource_dataproc_cluster_test.go index 798461eee3..25e813b876 100644 --- a/google-beta/resource_dataproc_cluster_test.go +++ b/google-beta/resource_dataproc_cluster_test.go @@ -14,8 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "google.golang.org/api/googleapi" - - dataproc "google.golang.org/api/dataproc/v1beta2" ) func TestDataprocExtractInitTimeout(t *testing.T) { diff --git a/google-beta/resource_dns_managed_zone.go b/google-beta/resource_dns_managed_zone.go index c8d77fde7b..6cc1425d01 100644 --- a/google-beta/resource_dns_managed_zone.go +++ b/google-beta/resource_dns_managed_zone.go @@ -25,7 +25,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/dns/v1" ) func resourceDNSManagedZone() *schema.Resource { diff --git a/google-beta/resource_dns_record_set.go b/google-beta/resource_dns_record_set.go index e44fc746ad..40cfa4c1cd 100644 --- a/google-beta/resource_dns_record_set.go +++ b/google-beta/resource_dns_record_set.go @@ -1,30 +1,15 @@ -// ---------------------------------------------------------------------------- -// -// *** AUTO GENERATED CODE *** Type: MMv1 *** -// -// ---------------------------------------------------------------------------- -// -// This file is automatically generated by Magic Modules and manual -// changes will be clobbered when the file is regenerated. -// -// Please read more about how to change this file in -// .github/CONTRIBUTING.md. -// -// ---------------------------------------------------------------------------- - package google import ( "fmt" "log" - "net" - "reflect" - "strconv" + "strings" - "time" + + "net" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "google.golang.org/api/dns/v1" ) func rrdatasDnsDiffSuppress(k, old, new string, d *schema.ResourceData) bool { @@ -79,21 +64,14 @@ func rrdatasListDiffSuppress(oldList, newList []string, fun func(x string) strin return true } -func resourceDNSResourceDnsRecordSet() *schema.Resource { +func resourceDnsRecordSet() *schema.Resource { return &schema.Resource{ - Create: resourceDNSResourceDnsRecordSetCreate, - Read: resourceDNSResourceDnsRecordSetRead, - Update: resourceDNSResourceDnsRecordSetUpdate, - Delete: resourceDNSResourceDnsRecordSetDelete, - + Create: resourceDnsRecordSetCreate, + Read: resourceDnsRecordSetRead, + Delete: resourceDnsRecordSetDelete, + Update: resourceDnsRecordSetUpdate, Importer: &schema.ResourceImporter{ - State: resourceDNSResourceDnsRecordSetImport, - }, - - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(4 * time.Minute), - Update: schema.DefaultTimeout(4 * time.Minute), - Delete: schema.DefaultTimeout(4 * time.Minute), + State: resourceDnsRecordSetImportState, }, Schema: map[string]*schema.Schema{ @@ -102,265 +80,309 @@ func resourceDNSResourceDnsRecordSet() *schema.Resource { Required: true, ForceNew: true, DiffSuppressFunc: compareSelfLinkOrResourceName, - Description: `Identifies the managed zone addressed by this request.`, + Description: `The name of the zone in which this record set will reside.`, }, + "name": { Type: schema.TypeString, Required: true, ForceNew: true, - Description: `For example, www.example.com.`, - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"A", "AAAA", "CAA", "CNAME", "DNSKEY", "DS", "IPSECVPNKEY", "MX", "NAPTR", "NS", "PTR", "SOA", "SPF", "SRV", "SSHFP", "TLSA", "TXT"}, false), - Description: `One of valid DNS resource types. Possible values: ["A", "AAAA", "CAA", "CNAME", "DNSKEY", "DS", "IPSECVPNKEY", "MX", "NAPTR", "NS", "PTR", "SOA", "SPF", "SRV", "SSHFP", "TLSA", "TXT"]`, + Description: `The DNS name this record set will apply to.`, }, + "rrdatas": { - Type: schema.TypeList, - Optional: true, - ForceNew: true, - DiffSuppressFunc: rrdatasDnsDiffSuppress, - Description: `The string data for the records in this record set whose meaning depends on the DNS type. -For TXT record, if the string data contains spaces, add surrounding \" if you don't want your string to get -split on spaces. To specify a single record value longer than 255 characters such as a TXT record for -DKIM, add \"\" inside the Terraform configuration string (e.g. "first255characters\"\"morecharacters").`, + Type: schema.TypeList, + Required: true, Elem: &schema.Schema{ Type: schema.TypeString, }, + DiffSuppressFunc: rrdatasDnsDiffSuppress, + Description: `The string data for the records in this record set whose meaning depends on the DNS type. For TXT record, if the string data contains spaces, add surrounding \" if you don't want your string to get split on spaces. To specify a single record value longer than 255 characters such as a TXT record for DKIM, add \"\" inside the Terraform configuration string (e.g. "first255characters\"\"morecharacters").`, }, + "ttl": { - Type: schema.TypeInt, - Optional: true, - Description: `Number of seconds that this ResourceRecordSet can be cached by -resolvers.`, + Type: schema.TypeInt, + Optional: true, + Description: `The time-to-live of this record set (seconds).`, }, + + "type": { + Type: schema.TypeString, + Required: true, + Description: `The DNS record set type.`, + }, + "project": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: `The ID of the project in which the resource belongs. If it is not provided, the provider project is used.`, }, }, UseJSONNumber: true, } } -func resourceDNSResourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error { +func resourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) userAgent, err := generateUserAgentString(d, config.userAgent) if err != nil { return err } - obj := make(map[string]interface{}) - nameProp, err := expandDNSResourceDnsRecordSetName(d.Get("name"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { - obj["name"] = nameProp - } - typeProp, err := expandDNSResourceDnsRecordSetType(d.Get("type"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("type"); !isEmptyValue(reflect.ValueOf(typeProp)) && (ok || !reflect.DeepEqual(v, typeProp)) { - obj["type"] = typeProp - } - ttlProp, err := expandDNSResourceDnsRecordSetTtl(d.Get("ttl"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("ttl"); !isEmptyValue(reflect.ValueOf(ttlProp)) && (ok || !reflect.DeepEqual(v, ttlProp)) { - obj["ttl"] = ttlProp - } - rrdatasProp, err := expandDNSResourceDnsRecordSetRrdatas(d.Get("rrdatas"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("rrdatas"); !isEmptyValue(reflect.ValueOf(rrdatasProp)) && (ok || !reflect.DeepEqual(v, rrdatasProp)) { - obj["rrdatas"] = rrdatasProp - } - managed_zoneProp, err := expandDNSResourceDnsRecordSetManagedZone(d.Get("managed_zone"), d, config) + project, err := getProject(d, config) if err != nil { return err - } else if v, ok := d.GetOkExists("managed_zone"); !isEmptyValue(reflect.ValueOf(managed_zoneProp)) && (ok || !reflect.DeepEqual(v, managed_zoneProp)) { - obj["managed_zone"] = managed_zoneProp } - url, err := replaceVars(d, config, "{{DNSBasePath}}projects/{{project}}/managedZones/{{managed_zone}}/rrsets") - if err != nil { - return err - } + name := d.Get("name").(string) + zone := d.Get("managed_zone").(string) + rType := d.Get("type").(string) - log.Printf("[DEBUG] Creating new ResourceDnsRecordSet: %#v", obj) - billingProject := "" + // Build the change + chg := &dns.Change{ + Additions: []*dns.ResourceRecordSet{ + { + Name: name, + Type: rType, + Ttl: int64(d.Get("ttl").(int)), + Rrdatas: rrdata(d), + }, + }, + } - project, err := getProject(d, config) + // The terraform provider is authoritative, so what we do here is check if + // any records that we are trying to create already exist and make sure we + // delete them, before adding in the changes requested. Normally this would + // result in an AlreadyExistsError. + log.Printf("[DEBUG] DNS record list request for %q", zone) + res, err := config.NewDnsClient(userAgent).ResourceRecordSets.List(project, zone).Do() if err != nil { - return fmt.Errorf("Error fetching project for ResourceDnsRecordSet: %s", err) + return fmt.Errorf("Error retrieving record sets for %q: %s", zone, err) } - billingProject = project + var deletions []*dns.ResourceRecordSet - // err == nil indicates that the billing_project value was found - if bp, err := getBillingProject(d, config); err == nil { - billingProject = bp + for _, record := range res.Rrsets { + if record.Type != rType || record.Name != name { + continue + } + deletions = append(deletions, record) + } + if len(deletions) > 0 { + chg.Deletions = deletions } - res, err := sendRequestWithTimeout(config, "POST", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutCreate)) + log.Printf("[DEBUG] DNS Record create request: %#v", chg) + chg, err = config.NewDnsClient(userAgent).Changes.Create(project, zone, chg).Do() if err != nil { - return fmt.Errorf("Error creating ResourceDnsRecordSet: %s", err) + return fmt.Errorf("Error creating DNS RecordSet: %s", err) } - // Store the ID now - id, err := replaceVars(d, config, "projects/{{project}}/managedZones/{{managed_zone}}/rrsets/{{name}}/{{type}}") + d.SetId(fmt.Sprintf("projects/%s/managedZones/%s/rrsets/%s/%s", project, zone, name, rType)) + + w := &DnsChangeWaiter{ + Service: config.NewDnsClient(userAgent), + Change: chg, + Project: project, + ManagedZone: zone, + } + _, err = w.Conf().WaitForState() if err != nil { - return fmt.Errorf("Error constructing id: %s", err) + return fmt.Errorf("Error waiting for Google DNS change: %s", err) } - d.SetId(id) - log.Printf("[DEBUG] Finished creating ResourceDnsRecordSet %q: %#v", d.Id(), res) - - return resourceDNSResourceDnsRecordSetRead(d, meta) + return resourceDnsRecordSetRead(d, meta) } -func resourceDNSResourceDnsRecordSetRead(d *schema.ResourceData, meta interface{}) error { +func resourceDnsRecordSetRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) userAgent, err := generateUserAgentString(d, config.userAgent) if err != nil { return err } - url, err := replaceVars(d, config, "{{DNSBasePath}}projects/{{project}}/managedZones/{{managed_zone}}/rrsets/{{name}}/{{type}}") + project, err := getProject(d, config) if err != nil { return err } - billingProject := "" + zone := d.Get("managed_zone").(string) - project, err := getProject(d, config) - if err != nil { - return fmt.Errorf("Error fetching project for ResourceDnsRecordSet: %s", err) - } - billingProject = project - - // err == nil indicates that the billing_project value was found - if bp, err := getBillingProject(d, config); err == nil { - billingProject = bp - } + // name and type are effectively the 'key' + name := d.Get("name").(string) + dnsType := d.Get("type").(string) - res, err := sendRequest(config, "GET", billingProject, url, userAgent, nil) + var resp *dns.ResourceRecordSetsListResponse + err = retry(func() error { + var reqErr error + resp, reqErr = config.NewDnsClient(userAgent).ResourceRecordSets.List( + project, zone).Name(name).Type(dnsType).Do() + return reqErr + }) if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("DNSResourceDnsRecordSet %q", d.Id())) + return handleNotFoundError(err, d, fmt.Sprintf("DNS Record Set %q", d.Get("name").(string))) + } + if len(resp.Rrsets) == 0 { + // The resource doesn't exist anymore + d.SetId("") + return nil } - if err := d.Set("project", project); err != nil { - return fmt.Errorf("Error reading ResourceDnsRecordSet: %s", err) + if len(resp.Rrsets) > 1 { + return fmt.Errorf("Only expected 1 record set, got %d", len(resp.Rrsets)) } - if err := d.Set("name", flattenDNSResourceDnsRecordSetName(res["name"], d, config)); err != nil { - return fmt.Errorf("Error reading ResourceDnsRecordSet: %s", err) + if err := d.Set("type", resp.Rrsets[0].Type); err != nil { + return fmt.Errorf("Error setting type: %s", err) } - if err := d.Set("type", flattenDNSResourceDnsRecordSetType(res["type"], d, config)); err != nil { - return fmt.Errorf("Error reading ResourceDnsRecordSet: %s", err) + if err := d.Set("ttl", resp.Rrsets[0].Ttl); err != nil { + return fmt.Errorf("Error setting ttl: %s", err) } - if err := d.Set("ttl", flattenDNSResourceDnsRecordSetTtl(res["ttl"], d, config)); err != nil { - return fmt.Errorf("Error reading ResourceDnsRecordSet: %s", err) + if err := d.Set("rrdatas", resp.Rrsets[0].Rrdatas); err != nil { + return fmt.Errorf("Error setting rrdatas: %s", err) } - if err := d.Set("rrdatas", flattenDNSResourceDnsRecordSetRrdatas(res["rrdatas"], d, config)); err != nil { - return fmt.Errorf("Error reading ResourceDnsRecordSet: %s", err) + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error setting project: %s", err) } return nil } -func resourceDNSResourceDnsRecordSetUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) userAgent, err := generateUserAgentString(d, config.userAgent) if err != nil { return err } - billingProject := "" - project, err := getProject(d, config) if err != nil { - return fmt.Errorf("Error fetching project for ResourceDnsRecordSet: %s", err) + return err } - billingProject = project - obj := make(map[string]interface{}) - typeProp, err := expandDNSResourceDnsRecordSetType(d.Get("type"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("type"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, typeProp)) { - obj["type"] = typeProp + zone := d.Get("managed_zone").(string) + + // 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 + } } - ttlProp, err := expandDNSResourceDnsRecordSetTtl(d.Get("ttl"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("ttl"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, ttlProp)) { - obj["ttl"] = ttlProp + + // Build the change + chg := &dns.Change{ + Deletions: []*dns.ResourceRecordSet{ + { + Name: d.Get("name").(string), + Type: d.Get("type").(string), + Ttl: int64(d.Get("ttl").(int)), + Rrdatas: rrdata(d), + }, + }, } - url, err := replaceVars(d, config, "{{DNSBasePath}}projects/{{project}}/managedZones/{{managed_zone}}/rrsets/{{name}}/{{type}}") + log.Printf("[DEBUG] DNS Record delete request: %#v", chg) + chg, err = config.NewDnsClient(userAgent).Changes.Create(project, zone, chg).Do() if err != nil { - return err + return handleNotFoundError(err, d, "google_dns_record_set") } - log.Printf("[DEBUG] Updating ResourceDnsRecordSet %q: %#v", d.Id(), obj) - - // err == nil indicates that the billing_project value was found - if bp, err := getBillingProject(d, config); err == nil { - billingProject = bp + w := &DnsChangeWaiter{ + Service: config.NewDnsClient(userAgent), + Change: chg, + Project: project, + ManagedZone: zone, } - - res, err := sendRequestWithTimeout(config, "PATCH", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutUpdate)) - + _, err = w.Conf().WaitForState() if err != nil { - return fmt.Errorf("Error updating ResourceDnsRecordSet %q: %s", d.Id(), err) - } else { - log.Printf("[DEBUG] Finished updating ResourceDnsRecordSet %q: %#v", d.Id(), res) + return fmt.Errorf("Error waiting for Google DNS change: %s", err) } - return resourceDNSResourceDnsRecordSetRead(d, meta) + d.SetId("") + return nil } -func resourceDNSResourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error { +func resourceDnsRecordSetUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) userAgent, err := generateUserAgentString(d, config.userAgent) if err != nil { return err } - billingProject := "" - project, err := getProject(d, config) - if err != nil { - return fmt.Errorf("Error fetching project for ResourceDnsRecordSet: %s", err) - } - billingProject = project - - url, err := replaceVars(d, config, "{{DNSBasePath}}projects/{{project}}/managedZones/{{managed_zone}}/rrsets/{{name}}/{{type}}") if err != nil { return err } - var obj map[string]interface{} - log.Printf("[DEBUG] Deleting ResourceDnsRecordSet %q", d.Id()) + zone := d.Get("managed_zone").(string) + recordName := d.Get("name").(string) - // err == nil indicates that the billing_project value was found - if bp, err := getBillingProject(d, config); err == nil { - billingProject = bp + oldTtl, newTtl := d.GetChange("ttl") + oldType, newType := d.GetChange("type") + + oldCountRaw, _ := d.GetChange("rrdatas.#") + oldCount := oldCountRaw.(int) + + chg := &dns.Change{ + Deletions: []*dns.ResourceRecordSet{ + { + Name: recordName, + Type: oldType.(string), + Ttl: int64(oldTtl.(int)), + Rrdatas: make([]string, oldCount), + }, + }, + Additions: []*dns.ResourceRecordSet{ + { + Name: recordName, + Type: newType.(string), + Ttl: int64(newTtl.(int)), + Rrdatas: rrdata(d), + }, + }, } - res, err := sendRequestWithTimeout(config, "DELETE", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutDelete)) + for i := 0; i < oldCount; i++ { + rrKey := fmt.Sprintf("rrdatas.%d", i) + oldRR, _ := d.GetChange(rrKey) + chg.Deletions[0].Rrdatas[i] = oldRR.(string) + } + log.Printf("[DEBUG] DNS Record change request: %#v old: %#v new: %#v", chg, chg.Deletions[0], chg.Additions[0]) + chg, err = config.NewDnsClient(userAgent).Changes.Create(project, zone, chg).Do() if err != nil { - return handleNotFoundError(err, d, "ResourceDnsRecordSet") + return fmt.Errorf("Error changing DNS RecordSet: %s", err) } - log.Printf("[DEBUG] Finished deleting ResourceDnsRecordSet %q: %#v", d.Id(), res) - return nil + w := &DnsChangeWaiter{ + Service: config.NewDnsClient(userAgent), + Change: chg, + Project: project, + ManagedZone: zone, + } + if _, err = w.Conf().WaitForState(); err != nil { + return fmt.Errorf("Error waiting for Google DNS change: %s", err) + } + + d.SetId(fmt.Sprintf("projects/%s/managedZones/%s/rrsets/%s/%s", project, zone, recordName, newType)) + + return resourceDnsRecordSetRead(d, meta) } -func resourceDNSResourceDnsRecordSetImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { +func resourceDnsRecordSetImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { config := meta.(*Config) if err := parseImportId([]string{ "projects/(?P[^/]+)/managedZones/(?P[^/]+)/rrsets/(?P[^/]+)/(?P[^/]+)", @@ -380,55 +402,20 @@ func resourceDNSResourceDnsRecordSetImport(d *schema.ResourceData, meta interfac return []*schema.ResourceData{d}, nil } -func flattenDNSResourceDnsRecordSetName(v interface{}, d *schema.ResourceData, config *Config) interface{} { - return v -} - -func flattenDNSResourceDnsRecordSetType(v interface{}, d *schema.ResourceData, config *Config) interface{} { - return v -} - -func flattenDNSResourceDnsRecordSetTtl(v interface{}, d *schema.ResourceData, config *Config) interface{} { - // Handles the string fixed64 format - if strVal, ok := v.(string); ok { - if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { - return intVal - } - } - - // number values are represented as float64 - if floatVal, ok := v.(float64); ok { - intVal := int(floatVal) - return intVal +func rrdata( + d *schema.ResourceData, +) []string { + rrdatasCount := d.Get("rrdatas.#").(int) + data := make([]string, rrdatasCount) + for i := 0; i < rrdatasCount; i++ { + data[i] = d.Get(fmt.Sprintf("rrdatas.%d", i)).(string) } - - return v // let terraform core handle it otherwise -} - -func flattenDNSResourceDnsRecordSetRrdatas(v interface{}, d *schema.ResourceData, config *Config) interface{} { - return v -} - -func expandDNSResourceDnsRecordSetName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - return v, nil + return data } -func expandDNSResourceDnsRecordSetType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - return v, nil -} - -func expandDNSResourceDnsRecordSetTtl(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - return v, nil -} +func ipv6AddressDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { + oldIp := net.ParseIP(old) + newIp := net.ParseIP(new) -func expandDNSResourceDnsRecordSetRrdatas(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - return v, nil -} - -func expandDNSResourceDnsRecordSetManagedZone(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { - f, err := parseGlobalFieldValue("managedZones", v.(string), "project", d, config, true) - if err != nil { - return nil, fmt.Errorf("Invalid value for managed_zone: %s", err) - } - return f.RelativeLink(), nil + return oldIp.Equal(newIp) } diff --git a/google-beta/resource_dns_record_set_sweeper_test.go b/google-beta/resource_dns_record_set_sweeper_test.go deleted file mode 100644 index 6907f06579..0000000000 --- a/google-beta/resource_dns_record_set_sweeper_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// ---------------------------------------------------------------------------- -// -// *** AUTO GENERATED CODE *** Type: MMv1 *** -// -// ---------------------------------------------------------------------------- -// -// This file is automatically generated by Magic Modules and manual -// changes will be clobbered when the file is regenerated. -// -// Please read more about how to change this file in -// .github/CONTRIBUTING.md. -// -// ---------------------------------------------------------------------------- - -package google - -import ( - "context" - "log" - "strings" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func init() { - resource.AddTestSweepers("DNSResourceDnsRecordSet", &resource.Sweeper{ - Name: "DNSResourceDnsRecordSet", - F: testSweepDNSResourceDnsRecordSet, - }) -} - -// At the time of writing, the CI only passes us-central1 as the region -func testSweepDNSResourceDnsRecordSet(region string) error { - resourceName := "DNSResourceDnsRecordSet" - log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) - - config, err := sharedConfigForRegion(region) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) - return err - } - - err = config.LoadAndValidate(context.Background()) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) - return err - } - - t := &testing.T{} - billingId := getTestBillingAccountFromEnv(t) - - // Setup variables to replace in list template - d := &ResourceDataMock{ - FieldsInSchema: map[string]interface{}{ - "project": config.Project, - "region": region, - "location": region, - "zone": "-", - "billing_account": billingId, - }, - } - - listTemplate := strings.Split("https://dns.googleapis.com/dns/v1beta2/projects/{{project}}/managedZones/{{managed_zone}}/rrsets", "?")[0] - listUrl, err := replaceVars(d, config, listTemplate) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) - return nil - } - - res, err := sendRequest(config, "GET", config.Project, listUrl, config.userAgent, nil) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) - return nil - } - - resourceList, ok := res["resourceDnsRecordSets"] - if !ok { - log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") - return nil - } - - rl := resourceList.([]interface{}) - - log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) - // Keep count of items that aren't sweepable for logging. - nonPrefixCount := 0 - for _, ri := range rl { - obj := ri.(map[string]interface{}) - if obj["name"] == nil { - log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) - return nil - } - - name := GetResourceNameFromSelfLink(obj["name"].(string)) - // Skip resources that shouldn't be sweeped - if !isSweepableTestResource(name) { - nonPrefixCount++ - continue - } - - deleteTemplate := "https://dns.googleapis.com/dns/v1beta2/projects/{{project}}/managedZones/{{managed_zone}}/rrsets/{{name}}/{{type}}" - deleteUrl, err := replaceVars(d, config, deleteTemplate) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) - return nil - } - deleteUrl = deleteUrl + name - - // Don't wait on operations as we may have a lot to delete - _, err = sendRequest(config, "DELETE", config.Project, deleteUrl, config.userAgent, nil) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) - } else { - log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) - } - } - - if nonPrefixCount > 0 { - log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) - } - - return nil -} diff --git a/google-beta/resource_dns_record_set_test.go b/google-beta/resource_dns_record_set_test.go index 52679cfd50..7f5d96ee75 100644 --- a/google-beta/resource_dns_record_set_test.go +++ b/google-beta/resource_dns_record_set_test.go @@ -53,6 +53,7 @@ func TestIpv6AddressDiffSuppress(t *testing.T) { } } } + func TestAccDNSRecordSet_basic(t *testing.T) { t.Parallel() @@ -157,13 +158,14 @@ func TestAccDNSRecordSet_nestedNS(t *testing.T) { t.Parallel() zoneName := fmt.Sprintf("dnszone-test-ns-%s", randString(t, 10)) + recordSetName := fmt.Sprintf("\"nested.%s.hashicorptest.com.\"", zoneName) vcrTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckDnsRecordSetDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccDnsRecordSet_nestedNS(zoneName, 300), + Config: testAccDnsRecordSet_NS(zoneName, recordSetName, 300), }, { ResourceName: "google_dns_record_set.foobar", @@ -175,6 +177,29 @@ func TestAccDNSRecordSet_nestedNS(t *testing.T) { }) } +func TestAccDNSRecordSet_secondaryNS(t *testing.T) { + t.Parallel() + + zoneName := fmt.Sprintf("dnszone-test-ns-%s", randString(t, 10)) + recordSetName := "google_dns_managed_zone.parent-zone.dns_name" + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDnsRecordSetDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDnsRecordSet_NS(zoneName, recordSetName, 300), + }, + { + ResourceName: "google_dns_record_set.foobar", + ImportStateId: fmt.Sprintf("projects/%s/managedZones/%s/rrsets/%s.hashicorptest.com./NS", getTestProjectFromEnv(), zoneName, zoneName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccDNSRecordSet_quotedTXT(t *testing.T) { t.Parallel() @@ -271,7 +296,7 @@ resource "google_dns_record_set" "foobar" { `, zoneName, zoneName, zoneName, addr2, ttl) } -func testAccDnsRecordSet_nestedNS(name string, ttl int) string { +func testAccDnsRecordSet_NS(name string, recordSetName string, ttl int) string { return fmt.Sprintf(` resource "google_dns_managed_zone" "parent-zone" { name = "%s" @@ -281,12 +306,12 @@ resource "google_dns_managed_zone" "parent-zone" { resource "google_dns_record_set" "foobar" { managed_zone = google_dns_managed_zone.parent-zone.name - name = "nested.%s.hashicorptest.com." + name = %s type = "NS" rrdatas = ["ns.hashicorp.services.", "ns2.hashicorp.services."] ttl = %d } -`, name, name, name, ttl) +`, name, name, recordSetName, ttl) } func testAccDnsRecordSet_bigChange(zoneName string, ttl int) string { diff --git a/google-beta/resource_gke_hub_feature_membership_test.go b/google-beta/resource_gke_hub_feature_membership_test.go index 9e1f2ea64d..ca20f019e9 100644 --- a/google-beta/resource_gke_hub_feature_membership_test.go +++ b/google-beta/resource_gke_hub_feature_membership_test.go @@ -5,7 +5,6 @@ import ( "fmt" "testing" - "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" gkehub "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/gkehub/beta" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" diff --git a/google-beta/resource_monitoring_slo.go b/google-beta/resource_monitoring_slo.go index a3ba736c07..c22d32d9d8 100644 --- a/google-beta/resource_monitoring_slo.go +++ b/google-beta/resource_monitoring_slo.go @@ -23,7 +23,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func validateMonitoringSloGoal(v interface{}, k string) (warnings []string, errors []error) { diff --git a/google-beta/resource_pubsub_subscription.go b/google-beta/resource_pubsub_subscription.go index cc8ac003d2..0b376ac58b 100644 --- a/google-beta/resource_pubsub_subscription.go +++ b/google-beta/resource_pubsub_subscription.go @@ -24,7 +24,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) func comparePubsubSubscriptionExpirationPolicy(_, old, new string, _ *schema.ResourceData) bool { diff --git a/google-beta/resource_secret_manager_secret_version.go b/google-beta/resource_secret_manager_secret_version.go index 82d2939b9a..8ae6181063 100644 --- a/google-beta/resource_secret_manager_secret_version.go +++ b/google-beta/resource_secret_manager_secret_version.go @@ -24,7 +24,6 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "google.golang.org/api/googleapi" ) func resourceSecretManagerSecretVersionUpdate(d *schema.ResourceData, meta interface{}) error { diff --git a/google-beta/resource_sql_source_representation_instance.go b/google-beta/resource_sql_source_representation_instance.go index 8847d77c9f..9c0eb4a96f 100644 --- a/google-beta/resource_sql_source_representation_instance.go +++ b/google-beta/resource_sql_source_representation_instance.go @@ -24,7 +24,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func resourceSQLSourceRepresentationInstance() *schema.Resource { diff --git a/google-beta/resource_storage_hmac_key.go b/google-beta/resource_storage_hmac_key.go index a53de79a2d..41ce7b3189 100644 --- a/google-beta/resource_storage_hmac_key.go +++ b/google-beta/resource_storage_hmac_key.go @@ -22,7 +22,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "google.golang.org/api/googleapi" ) func resourceStorageHmacKey() *schema.Resource { diff --git a/website/docs/r/dns_record_set.html.markdown b/website/docs/r/dns_record_set.html.markdown index 1e093b7eeb..4d62df958c 100644 --- a/website/docs/r/dns_record_set.html.markdown +++ b/website/docs/r/dns_record_set.html.markdown @@ -1,122 +1,176 @@ --- -# ---------------------------------------------------------------------------- -# -# *** AUTO GENERATED CODE *** Type: MMv1 *** -# -# ---------------------------------------------------------------------------- -# -# This file is automatically generated by Magic Modules and manual -# changes will be clobbered when the file is regenerated. -# -# Please read more about how to change this file in -# .github/CONTRIBUTING.md. -# -# ---------------------------------------------------------------------------- subcategory: "Cloud DNS" layout: "google" page_title: "Google: google_dns_record_set" sidebar_current: "docs-google-dns-record-set" description: |- - A single DNS record that exists on a domain name (i. + Manages a set of DNS records within Google Cloud DNS. --- # google\_dns\_record\_set -A single DNS record that exists on a domain name (i.e. in a managed zone). -This record defines the information about the domain and where the -domain / subdomains direct to. +Manages a set of DNS records within Google Cloud DNS. For more information see [the official documentation](https://cloud.google.com/dns/records/) and +[API](https://cloud.google.com/dns/api/v1/resourceRecordSets). -The record will include the domain/subdomain name, a type (i.e. A, AAA, -CAA, MX, CNAME, NS, etc) +~> **Note:** The provider treats this resource as an authoritative record set. This means existing records (including the default records) for the given type will be overwritten when you create this resource in Terraform. In addition, the Google Cloud DNS API requires NS records to be present at all times, so Terraform will not actually remove NS records during destroy but will report that it did. +## Example Usage +### Binding a DNS name to the ephemeral IP of a new instance: -## Example Usage - Dns Record Set Basic +```hcl +resource "google_dns_record_set" "frontend" { + name = "frontend.${google_dns_managed_zone.prod.dns_name}" + type = "A" + ttl = 300 + managed_zone = google_dns_managed_zone.prod.name -```hcl -resource "google_dns_managed_zone" "parent-zone" { - provider = "google-beta" - name = "my-zone" - dns_name = "my-zone.hashicorptest.com." - description = "Test Description" + rrdatas = [google_compute_instance.frontend.network_interface[0].access_config[0].nat_ip] +} + +resource "google_compute_instance" "frontend" { + name = "frontend" + machine_type = "g1-small" + zone = "us-central1-b" + + boot_disk { + initialize_params { + image = "debian-cloud/debian-9" + } + } + + network_interface { + network = "default" + access_config { + } + } +} + +resource "google_dns_managed_zone" "prod" { + name = "prod-zone" + dns_name = "prod.mydomain.com." } +``` + +### Adding an A record -resource "google_dns_record_set" "resource-recordset" { - provider = "google-beta" - managed_zone = google_dns_managed_zone.parent-zone.name - name = "test-record.my-zone.hashicorptest.com." +```hcl +resource "google_dns_record_set" "a" { + name = "backend.${google_dns_managed_zone.prod.dns_name}" + managed_zone = google_dns_managed_zone.prod.name type = "A" - rrdatas = ["10.0.0.1", "10.1.0.1"] - ttl = 86400 + ttl = 300 + + rrdatas = ["8.8.8.8"] +} + +resource "google_dns_managed_zone" "prod" { + name = "prod-zone" + dns_name = "prod.mydomain.com." } ``` -## Argument Reference +### Adding an MX record -The following arguments are supported: +```hcl +resource "google_dns_record_set" "mx" { + name = google_dns_managed_zone.prod.dns_name + managed_zone = google_dns_managed_zone.prod.name + type = "MX" + ttl = 3600 + + rrdatas = [ + "1 aspmx.l.google.com.", + "5 alt1.aspmx.l.google.com.", + "5 alt2.aspmx.l.google.com.", + "10 alt3.aspmx.l.google.com.", + "10 alt4.aspmx.l.google.com.", + ] +} +resource "google_dns_managed_zone" "prod" { + name = "prod-zone" + dns_name = "prod.mydomain.com." +} +``` -* `name` - - (Required) - For example, www.example.com. +### Adding an SPF record -* `type` - - (Required) - One of valid DNS resource types. - Possible values are `A`, `AAAA`, `CAA`, `CNAME`, `DNSKEY`, `DS`, `IPSECVPNKEY`, `MX`, `NAPTR`, `NS`, `PTR`, `SOA`, `SPF`, `SRV`, `SSHFP`, `TLSA`, and `TXT`. +Quotes (`""`) must be added around your `rrdatas` for a SPF record. Otherwise `rrdatas` string gets split on spaces. -* `managed_zone` - - (Required) - Identifies the managed zone addressed by this request. +```hcl +resource "google_dns_record_set" "spf" { + name = "frontend.${google_dns_managed_zone.prod.dns_name}" + managed_zone = google_dns_managed_zone.prod.name + type = "TXT" + ttl = 300 + rrdatas = ["\"v=spf1 ip4:111.111.111.111 include:backoff.email-example.com -all\""] +} -- - - +resource "google_dns_managed_zone" "prod" { + name = "prod-zone" + dns_name = "prod.mydomain.com." +} +``` +### Adding a CNAME record -* `ttl` - - (Optional) - Number of seconds that this ResourceRecordSet can be cached by - resolvers. + The list of `rrdatas` should only contain a single string corresponding to the Canonical Name intended. -* `rrdatas` - - (Optional) - The string data for the records in this record set whose meaning depends on the DNS type. - For TXT record, if the string data contains spaces, add surrounding \" if you don't want your string to get - split on spaces. To specify a single record value longer than 255 characters such as a TXT record for - DKIM, add \"\" inside the Terraform configuration string (e.g. "first255characters\"\"morecharacters"). +```hcl +resource "google_dns_record_set" "cname" { + name = "frontend.${google_dns_managed_zone.prod.dns_name}" + managed_zone = google_dns_managed_zone.prod.name + type = "CNAME" + ttl = 300 + rrdatas = ["frontend.mydomain.com."] +} -* `project` - (Optional) The ID of the project in which the resource belongs. - If it is not provided, the provider project is used. +resource "google_dns_managed_zone" "prod" { + name = "prod-zone" + dns_name = "prod.mydomain.com." +} +``` +## Argument Reference -## Attributes Reference +The following arguments are supported: -In addition to the arguments listed above, the following computed attributes are exported: +* `managed_zone` - (Required) The name of the zone in which this record set will + reside. -* `id` - an identifier for the resource with format `projects/{{project}}/managedZones/{{managed_zone}}/rrsets/{{name}}/{{type}}` +* `name` - (Required) The DNS name this record set will apply to. +* `rrdatas` - (Required) The string data for the records in this record set + whose meaning depends on the DNS type. For TXT record, if the string data contains spaces, add surrounding `\"` if you don't want your string to get split on spaces. To specify a single record value longer than 255 characters such as a TXT record for DKIM, add `\" \"` inside the Terraform configuration string (e.g. `"first255characters\" \"morecharacters"`). -## Timeouts -This resource provides the following -[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: +* `type` - (Required) The DNS record set type. -- `create` - Default is 4 minutes. -- `update` - Default is 4 minutes. -- `delete` - Default is 4 minutes. +- - - -## Import +* `ttl` - (Optional) The time-to-live of this record set (seconds). + +* `project` - (Optional) The ID of the project in which the resource belongs. If it + is not provided, the provider project is used. + +## Attributes Reference +-In addition to the arguments listed above, the following computed attributes are +-exported: -ResourceDnsRecordSet can be imported using any of these accepted formats: +* `id` - an identifier for the resource with format `projects/{{project}}/managedZones/{{zone}}/rrsets/{{name}}/{{type}}` + +## Import + +DNS record sets can be imported using either of these accepted formats: ``` -$ terraform import google_dns_record_set.default projects/{{project}}/managedZones/{{managed_zone}}/rrsets/{{name}}/{{type}} -$ terraform import google_dns_record_set.default {{project}}/{{managed_zone}}/{{name}}/{{type}} -$ terraform import google_dns_record_set.default {{managed_zone}}/{{name}}/{{type}} +$ terraform import google_dns_record_set.frontend projects/{{project}}/managedZones/{{zone}}/rrsets/{{name}}/{{type}} +$ terraform import google_dns_record_set.frontend {{project}}/{{zone}}/{{name}}/{{type}} +$ terraform import google_dns_record_set.frontend {{zone}}/{{name}}/{{type}} ``` -## User Project Overrides - -This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override). +Note: The record name must include the trailing dot at the end. \ No newline at end of file