From dfa74dfde90e3fa92efc808d755b71fd23d360c0 Mon Sep 17 00:00:00 2001 From: Roberto Jung Drebes Date: Fri, 15 Feb 2019 17:24:39 +0000 Subject: [PATCH] [Terraform] DNS beta private managed_zones Signed-off-by: Modular Magician --- google-beta/resource_dns_managed_zone.go | 316 +++++++++++++++++- ...esource_dns_managed_zone_generated_test.go | 2 +- google-beta/resource_dns_managed_zone_test.go | 72 ++++ website/docs/r/dns_managed_zone.html.markdown | 91 +++++ 4 files changed, 475 insertions(+), 6 deletions(-) diff --git a/google-beta/resource_dns_managed_zone.go b/google-beta/resource_dns_managed_zone.go index d92174901c..2cbf654871 100644 --- a/google-beta/resource_dns_managed_zone.go +++ b/google-beta/resource_dns_managed_zone.go @@ -15,12 +15,15 @@ package google import ( + "bytes" "fmt" "log" "reflect" "time" + "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" ) func resourceDnsManagedZone() *schema.Resource { @@ -56,11 +59,64 @@ func resourceDnsManagedZone() *schema.Resource { Optional: true, Default: "Managed by Terraform", }, + "forwarding_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "target_name_servers": { + Type: schema.TypeSet, + Optional: true, + Elem: dnsManagedZoneForwardingConfigTargetNameServersSchema(), + Set: func(v interface{}) int { + raw := v.(map[string]interface{}) + if address, ok := raw["ipv4_address"]; ok { + hashcode.String(address.(string)) + } + var buf bytes.Buffer + schema.SerializeResourceForHash(&buf, raw, dnsManagedZoneForwardingConfigTargetNameServersSchema()) + return hashcode.String(buf.String()) + }, + }, + }, + }, + }, "labels": { Type: schema.TypeMap, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "private_visibility_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "networks": { + Type: schema.TypeSet, + Optional: true, + Elem: dnsManagedZonePrivateVisibilityConfigNetworksSchema(), + Set: func(v interface{}) int { + raw := v.(map[string]interface{}) + if url, ok := raw["network_url"]; ok { + return selfLinkNameHash(url) + } + var buf bytes.Buffer + schema.SerializeResourceForHash(&buf, raw, dnsManagedZonePrivateVisibilityConfigNetworksSchema()) + return hashcode.String(buf.String()) + }, + }, + }, + }, + }, + "visibility": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"private", "public", ""}, false), + Default: "public", + }, "name_servers": { Type: schema.TypeList, Computed: true, @@ -78,6 +134,29 @@ func resourceDnsManagedZone() *schema.Resource { } } +func dnsManagedZonePrivateVisibilityConfigNetworksSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "network_url": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + }, + } +} + +func dnsManagedZoneForwardingConfigTargetNameServersSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ipv4_address": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + func resourceDnsManagedZoneCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -106,8 +185,26 @@ func resourceDnsManagedZoneCreate(d *schema.ResourceData, meta interface{}) erro } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { obj["labels"] = labelsProp } + visibilityProp, err := expandDnsManagedZoneVisibility(d.Get("visibility"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("visibility"); !isEmptyValue(reflect.ValueOf(visibilityProp)) && (ok || !reflect.DeepEqual(v, visibilityProp)) { + obj["visibility"] = visibilityProp + } + 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(privateVisibilityConfigProp)) && (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(forwardingConfigProp)) && (ok || !reflect.DeepEqual(v, forwardingConfigProp)) { + obj["forwardingConfig"] = forwardingConfigProp + } - url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1/projects/{{project}}/managedZones") + url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1beta2/projects/{{project}}/managedZones") if err != nil { return err } @@ -133,7 +230,7 @@ func resourceDnsManagedZoneCreate(d *schema.ResourceData, meta interface{}) erro func resourceDnsManagedZoneRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1/projects/{{project}}/managedZones/{{name}}") + url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1beta2/projects/{{project}}/managedZones/{{name}}") if err != nil { return err } @@ -166,6 +263,15 @@ func resourceDnsManagedZoneRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("labels", flattenDnsManagedZoneLabels(res["labels"], d)); err != nil { return fmt.Errorf("Error reading ManagedZone: %s", err) } + if err := d.Set("visibility", flattenDnsManagedZoneVisibility(res["visibility"], d)); err != nil { + return fmt.Errorf("Error reading ManagedZone: %s", err) + } + if err := d.Set("private_visibility_config", flattenDnsManagedZonePrivateVisibilityConfig(res["privateVisibilityConfig"], d)); err != nil { + return fmt.Errorf("Error reading ManagedZone: %s", err) + } + if err := d.Set("forwarding_config", flattenDnsManagedZoneForwardingConfig(res["forwardingConfig"], d)); err != nil { + return fmt.Errorf("Error reading ManagedZone: %s", err) + } return nil } @@ -175,7 +281,7 @@ func resourceDnsManagedZoneUpdate(d *schema.ResourceData, meta interface{}) erro d.Partial(true) - if d.HasChange("description") || d.HasChange("labels") { + if d.HasChange("description") || d.HasChange("labels") || d.HasChange("private_visibility_config") || d.HasChange("forwarding_config") { obj := make(map[string]interface{}) descriptionProp, err := expandDnsManagedZoneDescription(d.Get("description"), d, config) if err != nil { @@ -189,8 +295,20 @@ func resourceDnsManagedZoneUpdate(d *schema.ResourceData, meta interface{}) erro } 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 + } - url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1/projects/{{project}}/managedZones/{{name}}") + url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1beta2/projects/{{project}}/managedZones/{{name}}") if err != nil { return err } @@ -201,6 +319,8 @@ func resourceDnsManagedZoneUpdate(d *schema.ResourceData, meta interface{}) erro d.SetPartial("description") d.SetPartial("labels") + d.SetPartial("private_visibility_config") + d.SetPartial("forwarding_config") } d.Partial(false) @@ -211,7 +331,7 @@ func resourceDnsManagedZoneUpdate(d *schema.ResourceData, meta interface{}) erro func resourceDnsManagedZoneDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1/projects/{{project}}/managedZones/{{name}}") + url, err := replaceVars(d, config, "https://www.googleapis.com/dns/v1beta2/projects/{{project}}/managedZones/{{name}}") if err != nil { return err } @@ -263,6 +383,96 @@ func flattenDnsManagedZoneLabels(v interface{}, d *schema.ResourceData) interfac return v } +func flattenDnsManagedZoneVisibility(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenDnsManagedZonePrivateVisibilityConfig(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["networks"] = + flattenDnsManagedZonePrivateVisibilityConfigNetworks(original["networks"], d) + return []interface{}{transformed} +} +func flattenDnsManagedZonePrivateVisibilityConfigNetworks(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := schema.NewSet(func(v interface{}) int { + raw := v.(map[string]interface{}) + if url, ok := raw["network_url"]; ok { + return selfLinkNameHash(url) + } + var buf bytes.Buffer + schema.SerializeResourceForHash(&buf, raw, dnsManagedZonePrivateVisibilityConfigNetworksSchema()) + return hashcode.String(buf.String()) + }, []interface{}{}) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed.Add(map[string]interface{}{ + "network_url": flattenDnsManagedZonePrivateVisibilityConfigNetworksNetworkUrl(original["networkUrl"], d), + }) + } + return transformed +} +func flattenDnsManagedZonePrivateVisibilityConfigNetworksNetworkUrl(v interface{}, d *schema.ResourceData) interface{} { + return v +} + +func flattenDnsManagedZoneForwardingConfig(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["target_name_servers"] = + flattenDnsManagedZoneForwardingConfigTargetNameServers(original["targetNameServers"], d) + return []interface{}{transformed} +} +func flattenDnsManagedZoneForwardingConfigTargetNameServers(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := schema.NewSet(func(v interface{}) int { + raw := v.(map[string]interface{}) + if address, ok := raw["ipv4_address"]; ok { + hashcode.String(address.(string)) + } + var buf bytes.Buffer + schema.SerializeResourceForHash(&buf, raw, dnsManagedZoneForwardingConfigTargetNameServersSchema()) + return hashcode.String(buf.String()) + }, []interface{}{}) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed.Add(map[string]interface{}{ + "ipv4_address": flattenDnsManagedZoneForwardingConfigTargetNameServersIpv4Address(original["ipv4Address"], d), + }) + } + return transformed +} +func flattenDnsManagedZoneForwardingConfigTargetNameServersIpv4Address(v interface{}, d *schema.ResourceData) interface{} { + return v +} + func expandDnsManagedZoneDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { return v, nil } @@ -285,3 +495,99 @@ func expandDnsManagedZoneLabels(v interface{}, d *schema.ResourceData, config *C } return m, nil } + +func expandDnsManagedZoneVisibility(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDnsManagedZonePrivateVisibilityConfig(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedNetworks, err := expandDnsManagedZonePrivateVisibilityConfigNetworks(original["networks"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNetworks); val.IsValid() && !isEmptyValue(val) { + transformed["networks"] = transformedNetworks + } + + return transformed, nil +} + +func expandDnsManagedZonePrivateVisibilityConfigNetworks(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedNetworkUrl, err := expandDnsManagedZonePrivateVisibilityConfigNetworksNetworkUrl(original["network_url"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNetworkUrl); val.IsValid() && !isEmptyValue(val) { + transformed["networkUrl"] = transformedNetworkUrl + } + + req = append(req, transformed) + } + return req, nil +} + +func expandDnsManagedZonePrivateVisibilityConfigNetworksNetworkUrl(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandDnsManagedZoneForwardingConfig(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedTargetNameServers, err := expandDnsManagedZoneForwardingConfigTargetNameServers(original["target_name_servers"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTargetNameServers); val.IsValid() && !isEmptyValue(val) { + transformed["targetNameServers"] = transformedTargetNameServers + } + + return transformed, nil +} + +func expandDnsManagedZoneForwardingConfigTargetNameServers(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedIpv4Address, err := expandDnsManagedZoneForwardingConfigTargetNameServersIpv4Address(original["ipv4_address"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIpv4Address); val.IsValid() && !isEmptyValue(val) { + transformed["ipv4Address"] = transformedIpv4Address + } + + req = append(req, transformed) + } + return req, nil +} + +func expandDnsManagedZoneForwardingConfigTargetNameServersIpv4Address(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google-beta/resource_dns_managed_zone_generated_test.go b/google-beta/resource_dns_managed_zone_generated_test.go index 36c70d2204..f14fca80e1 100644 --- a/google-beta/resource_dns_managed_zone_generated_test.go +++ b/google-beta/resource_dns_managed_zone_generated_test.go @@ -76,7 +76,7 @@ func testAccCheckDnsManagedZoneDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - url, err := replaceVarsForTest(rs, "https://www.googleapis.com/dns/v1/projects/{{project}}/managedZones/{{name}}") + url, err := replaceVarsForTest(rs, "https://www.googleapis.com/dns/v1beta2/projects/{{project}}/managedZones/{{name}}") if err != nil { return err } diff --git a/google-beta/resource_dns_managed_zone_test.go b/google-beta/resource_dns_managed_zone_test.go index eeb1d7dc45..f826756a94 100644 --- a/google-beta/resource_dns_managed_zone_test.go +++ b/google-beta/resource_dns_managed_zone_test.go @@ -38,6 +38,36 @@ func TestAccDnsManagedZone_update(t *testing.T) { }) } +func TestAccDnsManagedZone_privateUpdate(t *testing.T) { + t.Parallel() + + zoneSuffix := acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDnsManagedZoneDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDnsManagedZone_privateUpdate(zoneSuffix, "network-1", "network-2", "172.16.1.10", "172.16.1.20"), + }, + { + ResourceName: "google_dns_managed_zone.private", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccDnsManagedZone_privateUpdate(zoneSuffix, "network-2", "network-3", "172.16.1.10", "192.168.1.1"), + }, + { + ResourceName: "google_dns_managed_zone.private", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccDnsManagedZone_basic(suffix, description string) string { return fmt.Sprintf(` resource "google_dns_managed_zone" "foobar" { @@ -50,6 +80,48 @@ resource "google_dns_managed_zone" "foobar" { }`, suffix, suffix, description) } +func testAccDnsManagedZone_privateUpdate(suffix, first_network, second_network, first_nameserver, second_nameserver string) string { + return fmt.Sprintf(` +resource "google_dns_managed_zone" "private" { + name = "private-zone-%s" + dns_name = "private.example.com." + description = "Example private DNS zone" + visibility = "private" + private_visibility_config { + networks { + network_url = "${google_compute_network.%s.self_link}" + } + networks { + network_url = "${google_compute_network.%s.self_link}" + } + } + + forwarding_config { + target_name_servers { + ipv4_address = "%s" + } + target_name_servers { + ipv4_address = "%s" + } + } +} + +resource "google_compute_network" "network-1" { + name = "network-1-%s" + auto_create_subnetworks = false +} + +resource "google_compute_network" "network-2" { + name = "network-2-%s" + auto_create_subnetworks = false +} + +resource "google_compute_network" "network-3" { + name = "network-3-%s" + auto_create_subnetworks = false +}`, suffix, first_network, second_network, first_nameserver, second_nameserver, suffix, suffix, suffix) +} + func TestDnsManagedZoneImport_parseImportId(t *testing.T) { zoneRegexes := []string{ "projects/(?P[^/]+)/managedZones/(?P[^/]+)", diff --git a/website/docs/r/dns_managed_zone.html.markdown b/website/docs/r/dns_managed_zone.html.markdown index 64932e6f75..56a8f239ba 100644 --- a/website/docs/r/dns_managed_zone.html.markdown +++ b/website/docs/r/dns_managed_zone.html.markdown @@ -55,6 +55,50 @@ resource "random_id" "rnd" { byte_length = 4 } ``` +## Example Usage - Dns Managed Zone Private + + +```hcl +resource "google_dns_managed_zone" "private-zone" { + name = "private-zone" + dns_name = "private.example.com." + description = "Example private DNS zone" + labels = { + foo = "bar" + } + + visibility = "private" + + private_visibility_config { + networks { + network_url = "${google_compute_network.network-1.self_link}" + } + networks { + network_url = "${google_compute_network.network-2.self_link}" + } + } + + forwarding_config { + target_name_servers { + ipv4_address = "172.16.1.10" + } + target_name_servers { + ipv4_address = "172.16.1.20" + } + } + +} + +resource "google_compute_network" "network-1" { + name = "network-1" + auto_create_subnetworks = false +} + +resource "google_compute_network" "network-2" { + name = "network-2" + auto_create_subnetworks = false +} +``` ## Argument Reference @@ -81,10 +125,57 @@ The following arguments are supported: * `labels` - (Optional) A set of key/value label pairs to assign to this ManagedZone. + +* `visibility` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + The zone's visibility: public zones are exposed to the Internet, + while private zones are visible only to Virtual Private Cloud resources. + Must be one of: `public`, `private`. + +* `private_visibility_config` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + For privately visible zones, the set of Virtual Private Cloud + resources that the zone is visible from. Structure is documented below. + +* `forwarding_config` - + (Optional, [Beta](https://terraform.io/docs/providers/google/provider_versions.html)) + The presence for this field indicates that outbound forwarding is enabled + for this zone. The value of this field contains the set of destinations + to forward to. Structure is documented below. * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. +The `private_visibility_config` block supports: + +* `networks` - + (Optional) + The list of VPC networks that can see this zone. Structure is documented below. + + +The `networks` block supports: + +* `network_url` - + (Optional) + The fully qualified URL of the VPC network to bind to. + This should be formatted like + `https://www.googleapis.com/compute/v1/projects/{project}/global/networks/{network}` + +The `forwarding_config` block supports: + +* `target_name_servers` - + (Optional) + List of target name servers to forward to. Cloud DNS will + select the best available name server if more than + one target is given. Structure is documented below. + + +The `target_name_servers` block supports: + +* `ipv4_address` - + (Optional) + IPv4 address of a target name server. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: