From 4a9c8c9458598b4396afadfc2eda40467d4f7902 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Mon, 30 Mar 2020 19:33:49 +0000 Subject: [PATCH] allow google_dns_managed_zone.dnssec_config to be updated (#3313) * allow update for dns_managed_zone * add some input trues back in * add some input trues back in Signed-off-by: Modular Magician --- .changelog/3313.txt | 3 + google-beta/resource_dns_managed_zone.go | 109 ++++++++---------- google-beta/resource_dns_managed_zone_test.go | 41 ++++++- website/docs/r/dns_managed_zone.html.markdown | 4 +- 4 files changed, 93 insertions(+), 64 deletions(-) create mode 100644 .changelog/3313.txt diff --git a/.changelog/3313.txt b/.changelog/3313.txt new file mode 100644 index 0000000000..6542b8a1fb --- /dev/null +++ b/.changelog/3313.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +dns: added ability to update `google_dns_managed_zone.dnssec_config` +``` diff --git a/google-beta/resource_dns_managed_zone.go b/google-beta/resource_dns_managed_zone.go index 2b27a6c9f8..c38ac191ed 100644 --- a/google-beta/resource_dns_managed_zone.go +++ b/google-beta/resource_dns_managed_zone.go @@ -67,7 +67,6 @@ Must be unique within the project.`, "dnssec_config": { Type: schema.TypeList, Optional: true, - ForceNew: true, Description: `DNSSEC configuration`, MaxItems: 1, Elem: &schema.Resource{ @@ -76,29 +75,26 @@ Must be unique within the project.`, Type: schema.TypeList, Computed: true, Optional: true, - ForceNew: true, Description: `Specifies parameters that will be used for generating initial DnsKeys for this ManagedZone. If you provide a spec for keySigning or zoneSigning, -you must also provide one for the other.`, +you must also provide one for the other. +default_key_specs can only be updated when the state is 'off'.`, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "algorithm": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"ecdsap256sha256", "ecdsap384sha384", "rsasha1", "rsasha256", "rsasha512", ""}, false), Description: `String mnemonic specifying the DNSSEC algorithm of this key`, }, "key_length": { Type: schema.TypeInt, Optional: true, - ForceNew: true, Description: `Length of the keys in bits`, }, "key_type": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"keySigning", "zoneSigning", ""}, false), Description: `Specifies whether this is a key signing key (KSK) or a zone signing key (ZSK). Key signing keys have the Secure Entry @@ -110,7 +106,6 @@ to sign all other types of resource record sets.`, "kind": { Type: schema.TypeString, Optional: true, - ForceNew: true, Description: `Identifies what kind of resource this is`, Default: "dns#dnsKeySpec", }, @@ -121,7 +116,6 @@ to sign all other types of resource record sets.`, "kind": { Type: schema.TypeString, Optional: true, - ForceNew: true, Description: `Identifies what kind of resource this is`, Default: "dns#managedZoneDnsSecConfig", AtLeastOneOf: []string{"dnssec_config.0.kind", "dnssec_config.0.non_existence", "dnssec_config.0.state", "dnssec_config.0.default_key_specs"}, @@ -130,15 +124,14 @@ to sign all other types of resource record sets.`, Type: schema.TypeString, Computed: true, Optional: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"nsec", "nsec3", ""}, false), - Description: `Specifies the mechanism used to provide authenticated denial-of-existence responses.`, + Description: `Specifies the mechanism used to provide authenticated denial-of-existence responses. +non_existence can only be updated when the state is 'off'.`, AtLeastOneOf: []string{"dnssec_config.0.kind", "dnssec_config.0.non_existence", "dnssec_config.0.state", "dnssec_config.0.default_key_specs"}, }, "state": { Type: schema.TypeString, Optional: true, - ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"off", "on", "transfer", ""}, false), Description: `Specifies whether DNSSEC is enabled, and what mode it is in`, AtLeastOneOf: []string{"dnssec_config.0.kind", "dnssec_config.0.non_existence", "dnssec_config.0.state", "dnssec_config.0.default_key_specs"}, @@ -473,60 +466,56 @@ func resourceDNSManagedZoneUpdate(d *schema.ResourceData, meta interface{}) erro return err } - d.Partial(true) - - if d.HasChange("description") || d.HasChange("labels") || d.HasChange("private_visibility_config") || d.HasChange("forwarding_config") || d.HasChange("peering_config") { - obj := make(map[string]interface{}) + obj := make(map[string]interface{}) + descriptionProp, err := expandDNSManagedZoneDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + dnssecConfigProp, err := expandDNSManagedZoneDnssecConfig(d.Get("dnssec_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("dnssec_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, dnssecConfigProp)) { + obj["dnssecConfig"] = dnssecConfigProp + } + labelsProp, err := expandDNSManagedZoneLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + privateVisibilityConfigProp, err := expandDNSManagedZonePrivateVisibilityConfig(d.Get("private_visibility_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("private_visibility_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, privateVisibilityConfigProp)) { + obj["privateVisibilityConfig"] = privateVisibilityConfigProp + } + forwardingConfigProp, err := expandDNSManagedZoneForwardingConfig(d.Get("forwarding_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("forwarding_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, forwardingConfigProp)) { + obj["forwardingConfig"] = forwardingConfigProp + } + peeringConfigProp, err := expandDNSManagedZonePeeringConfig(d.Get("peering_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("peering_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, peeringConfigProp)) { + obj["peeringConfig"] = peeringConfigProp + } - descriptionProp, err := expandDNSManagedZoneDescription(d.Get("description"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { - obj["description"] = descriptionProp - } - labelsProp, err := expandDNSManagedZoneLabels(d.Get("labels"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { - obj["labels"] = labelsProp - } - privateVisibilityConfigProp, err := expandDNSManagedZonePrivateVisibilityConfig(d.Get("private_visibility_config"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("private_visibility_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, privateVisibilityConfigProp)) { - obj["privateVisibilityConfig"] = privateVisibilityConfigProp - } - forwardingConfigProp, err := expandDNSManagedZoneForwardingConfig(d.Get("forwarding_config"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("forwarding_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, forwardingConfigProp)) { - obj["forwardingConfig"] = forwardingConfigProp - } - peeringConfigProp, err := expandDNSManagedZonePeeringConfig(d.Get("peering_config"), d, config) - if err != nil { - return err - } else if v, ok := d.GetOkExists("peering_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, peeringConfigProp)) { - obj["peeringConfig"] = peeringConfigProp - } + url, err := replaceVars(d, config, "{{DNSBasePath}}projects/{{project}}/managedZones/{{name}}") + if err != nil { + return err + } - url, err := replaceVars(d, config, "{{DNSBasePath}}projects/{{project}}/managedZones/{{name}}") - if err != nil { - return err - } - _, err = sendRequestWithTimeout(config, "PATCH", project, url, obj, d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf("Error updating ManagedZone %q: %s", d.Id(), err) - } + log.Printf("[DEBUG] Updating ManagedZone %q: %#v", d.Id(), obj) + _, err = sendRequestWithTimeout(config, "PATCH", project, url, obj, d.Timeout(schema.TimeoutUpdate)) - d.SetPartial("description") - d.SetPartial("labels") - d.SetPartial("private_visibility_config") - d.SetPartial("forwarding_config") - d.SetPartial("peering_config") + if err != nil { + return fmt.Errorf("Error updating ManagedZone %q: %s", d.Id(), err) } - d.Partial(false) - return resourceDNSManagedZoneRead(d, meta) } diff --git a/google-beta/resource_dns_managed_zone_test.go b/google-beta/resource_dns_managed_zone_test.go index 07b4b7c1ce..18f0c37e2a 100644 --- a/google-beta/resource_dns_managed_zone_test.go +++ b/google-beta/resource_dns_managed_zone_test.go @@ -68,7 +68,7 @@ func TestAccDNSManagedZone_privateUpdate(t *testing.T) { }) } -func TestAccDNSManagedZone_dnssec_on(t *testing.T) { +func TestAccDNSManagedZone_dnssec_update(t *testing.T) { t.Parallel() zoneSuffix := acctest.RandString(10) @@ -86,11 +86,19 @@ func TestAccDNSManagedZone_dnssec_on(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccDnsManagedZone_dnssec_off(zoneSuffix), + }, + { + ResourceName: "google_dns_managed_zone.foobar", + ImportState: true, + ImportStateVerify: true, + }, }, }) } -func TestAccDNSManagedZone_dnssec_off(t *testing.T) { +func TestAccDNSManagedZone_dnssec_empty(t *testing.T) { t.Parallel() zoneSuffix := acctest.RandString(10) @@ -101,7 +109,7 @@ func TestAccDNSManagedZone_dnssec_off(t *testing.T) { CheckDestroy: testAccCheckDNSManagedZoneDestroy, Steps: []resource.TestStep{ { - Config: testAccDnsManagedZone_dnssec_off(zoneSuffix), + Config: testAccDnsManagedZone_dnssec_empty(zoneSuffix), }, { ResourceName: "google_dns_managed_zone.foobar", @@ -197,6 +205,8 @@ resource "google_dns_managed_zone" "foobar" { key_length = "2048" key_type = "keySigning" } + + non_existence = "nsec" } } `, suffix, suffix) @@ -208,6 +218,31 @@ resource "google_dns_managed_zone" "foobar" { name = "mzone-test-%s" dns_name = "tf-acctest-%s.hashicorptest.com." + dnssec_config { + state = "off" + default_key_specs { + algorithm = "rsasha256" + key_length = "2048" + key_type = "zoneSigning" + } + default_key_specs { + algorithm = "rsasha256" + key_length = "2048" + key_type = "keySigning" + } + + non_existence = "nsec3" + } +} +`, suffix, suffix) +} + +func testAccDnsManagedZone_dnssec_empty(suffix string) string { + return fmt.Sprintf(` +resource "google_dns_managed_zone" "foobar" { + name = "mzone-test-%s" + dns_name = "tf-acctest-%s.hashicorptest.com." + dnssec_config { state = "off" } diff --git a/website/docs/r/dns_managed_zone.html.markdown b/website/docs/r/dns_managed_zone.html.markdown index afe1bcaea7..f2198f911d 100644 --- a/website/docs/r/dns_managed_zone.html.markdown +++ b/website/docs/r/dns_managed_zone.html.markdown @@ -261,6 +261,7 @@ The `dnssec_config` block supports: * `non_existence` - (Optional) Specifies the mechanism used to provide authenticated denial-of-existence responses. + non_existence can only be updated when the state is `off`. * `state` - (Optional) @@ -270,7 +271,8 @@ The `dnssec_config` block supports: (Optional) Specifies parameters that will be used for generating initial DnsKeys for this ManagedZone. If you provide a spec for keySigning or zoneSigning, - you must also provide one for the other. Structure is documented below. + you must also provide one for the other. + default_key_specs can only be updated when the state is `off`. Structure is documented below. The `default_key_specs` block supports: