diff --git a/.changelog/6665.txt b/.changelog/6665.txt
new file mode 100644
index 00000000000..58c8a410f23
--- /dev/null
+++ b/.changelog/6665.txt
@@ -0,0 +1,9 @@
+```release-note:enhancement
+dns: added `primary_backup` to `routing_policy` block of `google_dns_record_set` resource
+```
+```release-note:enhancement
+dns: added `enable_geo_fencing` to `routing_policy` block of `google_dns_record_set` resource
+```
+```release-note:enhancement
+dns: added `health_checked_targets` to `wrr` and `geo` blocks of `google_dns_record_set` resource
+```
diff --git a/google/resource_dns_record_set.go b/google/resource_dns_record_set.go
index 0a0afa2eb83..83316047b1e 100644
--- a/google/resource_dns_record_set.go
+++ b/google/resource_dns_record_set.go
@@ -9,6 +9,7 @@ import (
"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"
)
@@ -126,36 +127,70 @@ func resourceDnsRecordSet() *schema.Resource {
},
"rrdatas": {
Type: schema.TypeList,
- Required: true,
+ Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
+ "health_checked_targets": {
+ Type: schema.TypeList,
+ Optional: true,
+ Description: "The list of targets to be health checked. Note that if DNSSEC is enabled for this zone, only one of `rrdatas` or `health_checked_targets` can be set.",
+ MaxItems: 1,
+ Elem: healthCheckedTargetSchema,
+ },
},
},
- ExactlyOneOf: []string{"routing_policy.0.wrr", "routing_policy.0.geo"},
+ ExactlyOneOf: []string{"routing_policy.0.wrr", "routing_policy.0.geo", "routing_policy.0.primary_backup"},
+ ConflictsWith: []string{"routing_policy.0.enable_geo_fencing"},
},
"geo": {
+ Type: schema.TypeList,
+ Optional: true,
+ Description: `The configuration for Geo location based routing policy.`,
+ Elem: geoPolicySchema,
+ ExactlyOneOf: []string{"routing_policy.0.wrr", "routing_policy.0.geo", "routing_policy.0.primary_backup"},
+ },
+ "enable_geo_fencing": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "Specifies whether to enable fencing for geo queries.",
+ ConflictsWith: []string{"routing_policy.0.wrr", "routing_policy.0.primary_backup"},
+ },
+ "primary_backup": {
Type: schema.TypeList,
Optional: true,
- Description: `The configuration for Geo location based routing policy.`,
+ Description: "The configuration for a primary-backup policy with global to regional failover. Queries are responded to with the global primary targets, but if none of the primary targets are healthy, then we fallback to a regional failover policy.",
+ MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
- "location": {
- Type: schema.TypeString,
+ "primary": {
+ Type: schema.TypeList,
Required: true,
- Description: `The location name defined in Google Cloud.`,
+ Description: "The list of global primary targets to be health checked.",
+ MaxItems: 1,
+ Elem: healthCheckedTargetSchema,
},
- "rrdatas": {
- Type: schema.TypeList,
- Required: true,
- Elem: &schema.Schema{
- Type: schema.TypeString,
- },
+ "backup_geo": {
+ Type: schema.TypeList,
+ Required: true,
+ Description: "The backup geo targets, which provide a regional failover policy for the otherwise global primary targets.",
+ Elem: geoPolicySchema,
+ },
+ "enable_geo_fencing_for_backups": {
+ Type: schema.TypeBool,
+ Optional: true,
+ Description: "Specifies whether to enable fencing for backup geo queries.",
+ },
+ "trickle_ratio": {
+ Type: schema.TypeFloat,
+ Optional: true,
+ Description: "Specifies the percentage of traffic to send to the backup targets even when the primary targets are healthy.",
},
},
},
- ExactlyOneOf: []string{"routing_policy.0.wrr", "routing_policy.0.geo"},
+ ExactlyOneOf: []string{"routing_policy.0.wrr", "routing_policy.0.geo", "routing_policy.0.primary_backup"},
+ ConflictsWith: []string{"routing_policy.0.enable_geo_fencing"},
},
},
},
@@ -186,6 +221,82 @@ func resourceDnsRecordSet() *schema.Resource {
}
}
+var geoPolicySchema *schema.Resource = &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "location": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: `The location name defined in Google Cloud.`,
+ },
+ "rrdatas": {
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ },
+ "health_checked_targets": {
+ Type: schema.TypeList,
+ Optional: true,
+ Description: "For A and AAAA types only. The list of targets to be health checked. These can be specified along with `rrdatas` within this item.",
+ MaxItems: 1,
+ Elem: healthCheckedTargetSchema,
+ },
+ },
+}
+
+var healthCheckedTargetSchema *schema.Resource = &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "internal_load_balancers": {
+ Type: schema.TypeList,
+ Required: true,
+ Description: "The list of internal load balancers to health check.",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "load_balancer_type": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: `The type of load balancer. This value is case-sensitive. Possible values: ["regionalL4ilb"]`,
+ ValidateFunc: validation.StringInSlice([]string{"regionalL4ilb"}, false),
+ },
+ "ip_address": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "The frontend IP address of the load balancer.",
+ },
+ "port": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "The configured port of the load balancer.",
+ },
+ "ip_protocol": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: `The configured IP protocol of the load balancer. This value is case-sensitive. Possible values: ["tcp", "udp"]`,
+ ValidateFunc: validation.StringInSlice([]string{"tcp", "udp"}, false),
+ },
+ "network_url": {
+ Type: schema.TypeString,
+ Required: true,
+ DiffSuppressFunc: compareSelfLinkOrResourceName,
+ Description: "The fully qualified url of the network in which the load balancer belongs. This should be formatted like `https://www.googleapis.com/compute/v1/projects/{project}/global/networks/{network}`.",
+ },
+ "project": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "The ID of the project in which the load balancer belongs.",
+ },
+ "region": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: "The region of the load balancer. Only needed for regional load balancers.",
+ },
+ },
+ },
+ },
+ },
+}
+
func resourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
userAgent, err := generateUserAgentString(d, config.userAgent)
@@ -208,10 +319,15 @@ func resourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error
Type: rType,
Ttl: int64(d.Get("ttl").(int)),
}
- if rrdatas := rrdata(d); len(rrdatas) > 0 {
+ if rrdatas := expandDnsRecordSetRrdata(d.Get("rrdatas").([]interface{})); len(rrdatas) > 0 {
rset.Rrdatas = rrdatas
}
- if rp := routingPolicy(d); rp != nil {
+
+ rp, err := expandDnsRecordSetRoutingPolicy(d.Get("routing_policy").([]interface{}), d, config)
+ if err != nil {
+ return err
+ }
+ if rp != nil {
rset.RoutingPolicy = rp
}
chg := &dns.Change{
@@ -356,6 +472,11 @@ func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error
}
}
+ routingPolicy, err := expandDnsRecordSetRoutingPolicy(d.Get("routing_policy").([]interface{}), d, config)
+ if err != nil {
+ return err
+ }
+
// Build the change
chg := &dns.Change{
Deletions: []*dns.ResourceRecordSet{
@@ -363,8 +484,8 @@ func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error
Name: d.Get("name").(string),
Type: d.Get("type").(string),
Ttl: int64(d.Get("ttl").(int)),
- Rrdatas: rrdata(d),
- RoutingPolicy: routingPolicy(d),
+ Rrdatas: expandDnsRecordSetRrdata(d.Get("rrdatas").([]interface{})),
+ RoutingPolicy: routingPolicy,
},
},
}
@@ -414,6 +535,16 @@ func resourceDnsRecordSetUpdate(d *schema.ResourceData, meta interface{}) error
oldRoutingPolicyRaw, _ := d.GetChange("routing_policy")
oldRoutingPolicyList := oldRoutingPolicyRaw.([]interface{})
+ oldRoutingPolicy, err := expandDnsRecordSetRoutingPolicy(oldRoutingPolicyList, d, config)
+ if err != nil {
+ return err
+ }
+
+ newRoutingPolicy, err := expandDnsRecordSetRoutingPolicy(d.Get("routing_policy").([]interface{}), d, config)
+ if err != nil {
+ return err
+ }
+
chg := &dns.Change{
Deletions: []*dns.ResourceRecordSet{
{
@@ -421,7 +552,7 @@ func resourceDnsRecordSetUpdate(d *schema.ResourceData, meta interface{}) error
Type: oldType.(string),
Ttl: int64(oldTtl.(int)),
Rrdatas: make([]string, oldCount),
- RoutingPolicy: convertRoutingPolicy(oldRoutingPolicyList),
+ RoutingPolicy: oldRoutingPolicy,
},
},
Additions: []*dns.ResourceRecordSet{
@@ -429,8 +560,8 @@ func resourceDnsRecordSetUpdate(d *schema.ResourceData, meta interface{}) error
Name: recordName,
Type: newType.(string),
Ttl: int64(newTtl.(int)),
- Rrdatas: rrdata(d),
- RoutingPolicy: routingPolicy(d),
+ Rrdatas: expandDnsRecordSetRrdata(d.Get("rrdatas").([]interface{})),
+ RoutingPolicy: newRoutingPolicy,
},
},
}
@@ -481,108 +612,192 @@ func resourceDnsRecordSetImportState(d *schema.ResourceData, meta interface{}) (
return []*schema.ResourceData{d}, nil
}
-func rrdata(d *schema.ResourceData) []string {
- if _, ok := d.GetOk("rrdatas"); !ok {
- return []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 data
+func expandDnsRecordSetRrdata(configured []interface{}) []string {
+ return convertStringArr(configured)
}
-func routingPolicy(d *schema.ResourceData) *dns.RRSetRoutingPolicy {
- rp, ok := d.GetOk("routing_policy")
- if !ok {
- return nil
+func expandDnsRecordSetRoutingPolicy(configured []interface{}, d TerraformResourceData, config *Config) (*dns.RRSetRoutingPolicy, error) {
+ if len(configured) == 0 || configured[0] == nil {
+ return nil, nil
}
- rps := rp.([]interface{})
- if len(rps) == 0 {
- return nil
- }
- return convertRoutingPolicy(rps)
-}
-// converconvertRoutingPolicy converts []interface{} type value to *dns.RRSetRoutingPolicy one if ps is valid data.
-func convertRoutingPolicy(ps []interface{}) *dns.RRSetRoutingPolicy {
- if len(ps) != 1 {
- return nil
- }
- p, ok := ps[0].(map[string]interface{})
- if !ok {
- return nil
- }
-
- wrrRawItems, _ := p["wrr"].([]interface{})
- geoRawItems, _ := p["geo"].([]interface{})
+ data := configured[0].(map[string]interface{})
+ wrrRawItems, _ := data["wrr"].([]interface{})
+ geoRawItems, _ := data["geo"].([]interface{})
+ rawPrimaryBackup, _ := data["primary_backup"].([]interface{})
if len(wrrRawItems) > 0 {
- wrrItems := make([]*dns.RRSetRoutingPolicyWrrPolicyWrrPolicyItem, len(wrrRawItems))
- for i, item := range wrrRawItems {
- wi, _ := item.(map[string]interface{})
- irrdatas := wi["rrdatas"].([]interface{})
- if len(irrdatas) == 0 {
- return nil
- }
- rrdatas := make([]string, len(irrdatas))
- for j, rrdata := range irrdatas {
- rrdatas[j], ok = rrdata.(string)
- if !ok {
- return nil
- }
- }
- weight, ok := wi["weight"].(float64)
- if !ok {
- return nil
- }
- wrrItems[i] = &dns.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{
- Weight: weight,
- Rrdatas: rrdatas,
- }
+ wrrItems, err := expandDnsRecordSetRoutingPolicyWrrItems(wrrRawItems, d, config)
+ if err != nil {
+ return nil, err
}
-
return &dns.RRSetRoutingPolicy{
Wrr: &dns.RRSetRoutingPolicyWrrPolicy{
Items: wrrItems,
},
- }
+ }, nil
}
if len(geoRawItems) > 0 {
- geoItems := make([]*dns.RRSetRoutingPolicyGeoPolicyGeoPolicyItem, len(geoRawItems))
- for i, item := range geoRawItems {
- gi, _ := item.(map[string]interface{})
- irrdatas := gi["rrdatas"].([]interface{})
- if len(irrdatas) == 0 {
- return nil
- }
- rrdatas := make([]string, len(irrdatas))
- for j, rrdata := range irrdatas {
- rrdatas[j], ok = rrdata.(string)
- if !ok {
- return nil
- }
- }
- location, ok := gi["location"].(string)
- if !ok {
- return nil
- }
- geoItems[i] = &dns.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{
- Location: location,
- Rrdatas: rrdatas,
- }
+ geoItems, err := expandDnsRecordSetRoutingPolicyGeoItems(geoRawItems, d, config)
+ if err != nil {
+ return nil, err
}
-
return &dns.RRSetRoutingPolicy{
Geo: &dns.RRSetRoutingPolicyGeoPolicy{
- Items: geoItems,
+ Items: geoItems,
+ EnableFencing: data["enable_geo_fencing"].(bool),
},
+ }, nil
+ }
+
+ if len(rawPrimaryBackup) > 0 {
+ primaryBackup, err := expandDnsRecordSetRoutingPolicyPrimaryBackup(rawPrimaryBackup, d, config)
+ if err != nil {
+ return nil, err
+ }
+ return &dns.RRSetRoutingPolicy{
+ PrimaryBackup: primaryBackup,
+ }, nil
+ }
+
+ return nil, nil // unreachable here if ps is valid data
+}
+
+func expandDnsRecordSetRoutingPolicyWrrItems(configured []interface{}, d TerraformResourceData, config *Config) ([]*dns.RRSetRoutingPolicyWrrPolicyWrrPolicyItem, error) {
+ items := make([]*dns.RRSetRoutingPolicyWrrPolicyWrrPolicyItem, 0, len(configured))
+ for _, raw := range configured {
+ item, err := expandDnsRecordSetRoutingPolicyWrrItem(raw, d, config)
+ if err != nil {
+ return nil, err
+ }
+ items = append(items, item)
+ }
+ return items, nil
+}
+
+func expandDnsRecordSetRoutingPolicyWrrItem(configured interface{}, d TerraformResourceData, config *Config) (*dns.RRSetRoutingPolicyWrrPolicyWrrPolicyItem, error) {
+ data := configured.(map[string]interface{})
+ healthCheckedTargets, err := expandDnsRecordSetHealthCheckedTargets(data["health_checked_targets"].([]interface{}), d, config)
+ if err != nil {
+ return nil, err
+ }
+ return &dns.RRSetRoutingPolicyWrrPolicyWrrPolicyItem{
+ Rrdatas: convertStringArr(data["rrdatas"].([]interface{})),
+ Weight: data["weight"].(float64),
+ HealthCheckedTargets: healthCheckedTargets,
+ }, nil
+}
+
+func expandDnsRecordSetRoutingPolicyGeoItems(configured []interface{}, d TerraformResourceData, config *Config) ([]*dns.RRSetRoutingPolicyGeoPolicyGeoPolicyItem, error) {
+ items := make([]*dns.RRSetRoutingPolicyGeoPolicyGeoPolicyItem, 0, len(configured))
+ for _, raw := range configured {
+ item, err := expandDnsRecordSetRoutingPolicyGeoItem(raw, d, config)
+ if err != nil {
+ return nil, err
+ }
+ items = append(items, item)
+ }
+ return items, nil
+}
+
+func expandDnsRecordSetRoutingPolicyGeoItem(configured interface{}, d TerraformResourceData, config *Config) (*dns.RRSetRoutingPolicyGeoPolicyGeoPolicyItem, error) {
+ data := configured.(map[string]interface{})
+ healthCheckedTargets, err := expandDnsRecordSetHealthCheckedTargets(data["health_checked_targets"].([]interface{}), d, config)
+ if err != nil {
+ return nil, err
+ }
+ return &dns.RRSetRoutingPolicyGeoPolicyGeoPolicyItem{
+ Rrdatas: convertStringArr(data["rrdatas"].([]interface{})),
+ Location: data["location"].(string),
+ HealthCheckedTargets: healthCheckedTargets,
+ }, nil
+}
+
+func expandDnsRecordSetHealthCheckedTargets(configured []interface{}, d TerraformResourceData, config *Config) (*dns.RRSetRoutingPolicyHealthCheckTargets, error) {
+ if len(configured) == 0 || configured[0] == nil {
+ return nil, nil
+ }
+
+ data := configured[0].(map[string]interface{})
+ internalLoadBalancers, err := expandDnsRecordSetHealthCheckedTargetsInternalLoadBalancers(data["internal_load_balancers"].([]interface{}), d, config)
+ if err != nil {
+ return nil, err
+ }
+ return &dns.RRSetRoutingPolicyHealthCheckTargets{
+ InternalLoadBalancers: internalLoadBalancers,
+ }, nil
+}
+
+func expandDnsRecordSetHealthCheckedTargetsInternalLoadBalancers(configured []interface{}, d TerraformResourceData, config *Config) ([]*dns.RRSetRoutingPolicyLoadBalancerTarget, error) {
+ ilbs := make([]*dns.RRSetRoutingPolicyLoadBalancerTarget, 0, len(configured))
+ for _, raw := range configured {
+ ilb, err := expandDnsRecordSetHealthCheckedTargetsInternalLoadBalancer(raw, d, config)
+ if err != nil {
+ return nil, err
}
+ ilbs = append(ilbs, ilb)
}
+ return ilbs, nil
+}
- return nil // unreachable here if ps is valid data
+func expandDnsRecordSetHealthCheckedTargetsInternalLoadBalancer(configured interface{}, d TerraformResourceData, config *Config) (*dns.RRSetRoutingPolicyLoadBalancerTarget, error) {
+ data := configured.(map[string]interface{})
+ networkUrl, err := expandDnsRecordSetHealthCheckedTargetsInternalLoadBalancerNetworkUrl(data["network_url"], d, config)
+ if err != nil {
+ return nil, err
+ }
+ return &dns.RRSetRoutingPolicyLoadBalancerTarget{
+ LoadBalancerType: data["load_balancer_type"].(string),
+ IpAddress: data["ip_address"].(string),
+ Port: data["port"].(string),
+ IpProtocol: data["ip_protocol"].(string),
+ NetworkUrl: networkUrl.(string),
+ Project: data["project"].(string),
+ Region: data["region"].(string),
+ }, nil
+}
+
+func expandDnsRecordSetHealthCheckedTargetsInternalLoadBalancerNetworkUrl(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
+ if v == nil || v.(string) == "" {
+ return "", nil
+ } else if strings.HasPrefix(v.(string), "https://") {
+ return v, nil
+ }
+ url, err := replaceVars(d, config, "{{ComputeBasePath}}"+v.(string))
+ if err != nil {
+ return "", err
+ }
+ return ConvertSelfLinkToV1(url), nil
+}
+
+func expandDnsRecordSetRoutingPolicyPrimaryBackup(configured []interface{}, d TerraformResourceData, config *Config) (*dns.RRSetRoutingPolicyPrimaryBackupPolicy, error) {
+ if len(configured) == 0 || configured[0] == nil {
+ return nil, nil
+ }
+
+ data := configured[0].(map[string]interface{})
+
+ geoRawItems, _ := data["backup_geo"].([]interface{})
+
+ primaryTargets, err := expandDnsRecordSetHealthCheckedTargets(data["primary"].([]interface{}), d, config)
+ if err != nil {
+ return nil, err
+ }
+
+ items, err := expandDnsRecordSetRoutingPolicyGeoItems(geoRawItems, d, config)
+ if err != nil {
+ return nil, err
+ }
+
+ return &dns.RRSetRoutingPolicyPrimaryBackupPolicy{
+ PrimaryTargets: primaryTargets,
+ TrickleTraffic: data["trickle_ratio"].(float64),
+ BackupGeoTargets: &dns.RRSetRoutingPolicyGeoPolicy{
+ Items: items,
+ EnableFencing: data["enable_geo_fencing_for_backups"].(bool),
+ },
+ }, nil
}
func flattenDnsRecordSetRoutingPolicy(policy *dns.RRSetRoutingPolicy) []interface{} {
@@ -596,6 +811,10 @@ func flattenDnsRecordSetRoutingPolicy(policy *dns.RRSetRoutingPolicy) []interfac
}
if policy.Geo != nil {
p["geo"] = flattenDnsRecordSetRoutingPolicyGEO(policy.Geo)
+ p["enable_geo_fencing"] = policy.Geo.EnableFencing
+ }
+ if policy.PrimaryBackup != nil {
+ p["primary_backup"] = flattenDnsRecordSetRoutingPolicyPrimaryBackup(policy.PrimaryBackup)
}
return append(ps, p)
}
@@ -606,6 +825,7 @@ func flattenDnsRecordSetRoutingPolicyWRR(wrr *dns.RRSetRoutingPolicyWrrPolicy) [
ri := make(map[string]interface{})
ri["weight"] = item.Weight
ri["rrdatas"] = item.Rrdatas
+ ri["health_checked_targets"] = flattenDnsRecordSetHealthCheckedTargets(item.HealthCheckedTargets)
ris = append(ris, ri)
}
return ris
@@ -617,11 +837,56 @@ func flattenDnsRecordSetRoutingPolicyGEO(geo *dns.RRSetRoutingPolicyGeoPolicy) [
ri := make(map[string]interface{})
ri["location"] = item.Location
ri["rrdatas"] = item.Rrdatas
+ ri["health_checked_targets"] = flattenDnsRecordSetHealthCheckedTargets(item.HealthCheckedTargets)
ris = append(ris, ri)
}
return ris
}
+func flattenDnsRecordSetHealthCheckedTargets(targets *dns.RRSetRoutingPolicyHealthCheckTargets) []map[string]interface{} {
+ if targets == nil {
+ return nil
+ }
+
+ data := map[string]interface{}{
+ "internal_load_balancers": flattenDnsRecordSetInternalLoadBalancers(targets.InternalLoadBalancers),
+ }
+
+ return []map[string]interface{}{data}
+}
+
+func flattenDnsRecordSetInternalLoadBalancers(ilbs []*dns.RRSetRoutingPolicyLoadBalancerTarget) []map[string]interface{} {
+ ilbsSchema := make([]map[string]interface{}, 0, len(ilbs))
+ for _, ilb := range ilbs {
+ data := map[string]interface{}{
+ "load_balancer_type": ilb.LoadBalancerType,
+ "ip_address": ilb.IpAddress,
+ "port": ilb.Port,
+ "ip_protocol": ilb.IpProtocol,
+ "network_url": ilb.NetworkUrl,
+ "project": ilb.Project,
+ "region": ilb.Region,
+ }
+ ilbsSchema = append(ilbsSchema, data)
+ }
+ return ilbsSchema
+}
+
+func flattenDnsRecordSetRoutingPolicyPrimaryBackup(primaryBackup *dns.RRSetRoutingPolicyPrimaryBackupPolicy) []map[string]interface{} {
+ if primaryBackup == nil {
+ return nil
+ }
+
+ data := map[string]interface{}{
+ "primary": flattenDnsRecordSetHealthCheckedTargets(primaryBackup.PrimaryTargets),
+ "trickle_ratio": primaryBackup.TrickleTraffic,
+ "backup_geo": flattenDnsRecordSetRoutingPolicyGEO(primaryBackup.BackupGeoTargets),
+ "enable_geo_fencing_for_backups": primaryBackup.BackupGeoTargets.EnableFencing,
+ }
+
+ return []map[string]interface{}{data}
+}
+
func validateRecordNameTrailingDot(v interface{}, k string) (warnings []string, errors []error) {
value := v.(string)
len_value := len(value)
diff --git a/google/resource_dns_record_set_test.go b/google/resource_dns_record_set_test.go
index 66f670a7027..28d3b18ee94 100644
--- a/google/resource_dns_record_set_test.go
+++ b/google/resource_dns_record_set_test.go
@@ -263,6 +263,9 @@ func TestAccDNSRecordSet_uppercaseMX(t *testing.T) {
func TestAccDNSRecordSet_routingPolicy(t *testing.T) {
t.Parallel()
+ networkName := fmt.Sprintf("tf-test-network-%s", randString(t, 10))
+ backendName := fmt.Sprintf("tf-test-backend-%s", randString(t, 10))
+ forwardingRuleName := fmt.Sprintf("tf-test-forwarding-rule-%s", randString(t, 10))
zoneName := fmt.Sprintf("dnszone-test-%s", randString(t, 10))
vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
@@ -270,7 +273,7 @@ func TestAccDNSRecordSet_routingPolicy(t *testing.T) {
CheckDestroy: testAccCheckDnsRecordSetDestroyProducer(t),
Steps: []resource.TestStep{
{
- Config: testAccDnsRecordSet_routingPolicyWRR(zoneName, "127.0.0.10", 300, 0.1),
+ Config: testAccDnsRecordSet_routingPolicyWRR(networkName, backendName, forwardingRuleName, zoneName, 300),
},
{
ResourceName: "google_dns_record_set.foobar",
@@ -279,7 +282,16 @@ func TestAccDNSRecordSet_routingPolicy(t *testing.T) {
ImportStateVerify: true,
},
{
- Config: testAccDnsRecordSet_routingPolicyGEO(zoneName, "127.0.0.10", 300, "us-central1"),
+ Config: testAccDnsRecordSet_routingPolicyGEO(networkName, backendName, forwardingRuleName, zoneName, 300),
+ },
+ {
+ ResourceName: "google_dns_record_set.foobar",
+ ImportStateId: fmt.Sprintf("%s/%s/test-record.%s.hashicorptest.com./A", getTestProjectFromEnv(), zoneName, zoneName),
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccDnsRecordSet_routingPolicyPrimaryBackup(networkName, backendName, forwardingRuleName, zoneName, 300),
},
{
ResourceName: "google_dns_record_set.foobar",
@@ -294,6 +306,9 @@ func TestAccDNSRecordSet_routingPolicy(t *testing.T) {
func TestAccDNSRecordSet_changeRouting(t *testing.T) {
t.Parallel()
+ networkName := fmt.Sprintf("tf-test-network-%s", randString(t, 10))
+ backendName := fmt.Sprintf("tf-test-backend-%s", randString(t, 10))
+ forwardingRuleName := fmt.Sprintf("tf-test-forwarding-rule-%s", randString(t, 10))
zoneName := fmt.Sprintf("dnszone-test-%s", randString(t, 10))
vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
@@ -310,7 +325,7 @@ func TestAccDNSRecordSet_changeRouting(t *testing.T) {
ImportStateVerify: true,
},
{
- Config: testAccDnsRecordSet_routingPolicyGEO(zoneName, "127.0.0.10", 300, "us-central1"),
+ Config: testAccDnsRecordSet_routingPolicyGEO(networkName, backendName, forwardingRuleName, zoneName, 300),
},
{
ResourceName: "google_dns_record_set.foobar",
@@ -475,8 +490,27 @@ resource "google_dns_record_set" "foobar" {
`, name, name, name, ttl)
}
-func testAccDnsRecordSet_routingPolicyWRR(zoneName, addr2 string, ttl int, weight float64) string {
+func testAccDnsRecordSet_routingPolicyWRR(networkName, backendName, forwardingRuleName, zoneName string, ttl int) string {
return fmt.Sprintf(`
+resource "google_compute_network" "default" {
+ name = "%s"
+}
+
+resource "google_compute_region_backend_service" "backend" {
+ name = "%s"
+ region = "us-central1"
+}
+
+resource "google_compute_forwarding_rule" "default" {
+ name = "%s"
+ region = "us-central1"
+
+ load_balancing_scheme = "INTERNAL"
+ backend_service = google_compute_region_backend_service.backend.id
+ all_ports = true
+ network = google_compute_network.default.name
+}
+
resource "google_dns_managed_zone" "parent-zone" {
name = "%s"
dns_name = "%s.hashicorptest.com."
@@ -491,20 +525,56 @@ resource "google_dns_record_set" "foobar" {
routing_policy {
wrr {
- weight = 0.9
- rrdatas = ["127.0.0.1"]
+ weight = 0
+ rrdatas = ["1.2.3.4", "4.3.2.1"]
}
+
+ wrr {
+ weight = 0
+ rrdatas = ["2.3.4.5", "5.4.3.2"]
+ }
+
wrr {
- weight = %g
- rrdatas = ["%s"]
+ weight = 1.0
+
+ health_checked_targets {
+ internal_load_balancers {
+ load_balancer_type = "regionalL4ilb"
+ ip_address = google_compute_forwarding_rule.default.ip_address
+ port = "80"
+ ip_protocol = "tcp"
+ network_url = google_compute_network.default.id
+ project = google_compute_forwarding_rule.default.project
+ region = google_compute_forwarding_rule.default.region
+ }
+ }
}
}
}
-`, zoneName, zoneName, zoneName, ttl, weight, addr2)
+`, networkName, backendName, forwardingRuleName, zoneName, zoneName, zoneName, ttl)
}
-func testAccDnsRecordSet_routingPolicyGEO(zoneName, addr2 string, ttl int, location string) string {
+func testAccDnsRecordSet_routingPolicyGEO(networkName, backendName, forwardingRuleName, zoneName string, ttl int) string {
return fmt.Sprintf(`
+resource "google_compute_network" "default" {
+ name = "%s"
+}
+
+resource "google_compute_region_backend_service" "backend" {
+ name = "%s"
+ region = "us-central1"
+}
+
+resource "google_compute_forwarding_rule" "default" {
+ name = "%s"
+ region = "us-central1"
+
+ load_balancing_scheme = "INTERNAL"
+ backend_service = google_compute_region_backend_service.backend.id
+ all_ports = true
+ network = google_compute_network.default.name
+}
+
resource "google_dns_managed_zone" "parent-zone" {
name = "%s"
dns_name = "%s.hashicorptest.com."
@@ -518,17 +588,101 @@ resource "google_dns_record_set" "foobar" {
ttl = %d
routing_policy {
+ enable_geo_fencing = true
+
+ geo {
+ location = "us-east4"
+ rrdatas = ["1.2.3.4", "4.3.2.1"]
+ }
+
geo {
location = "asia-east1"
- rrdatas = ["127.0.0.1"]
+ rrdatas = ["2.3.4.5", "5.4.3.2"]
}
+
geo {
- location = "%s"
- rrdatas = ["%s"]
+ location = "us-central1"
+
+ health_checked_targets {
+ internal_load_balancers {
+ load_balancer_type = "regionalL4ilb"
+ ip_address = google_compute_forwarding_rule.default.ip_address
+ port = "80"
+ ip_protocol = "tcp"
+ network_url = google_compute_network.default.id
+ project = google_compute_forwarding_rule.default.project
+ region = google_compute_forwarding_rule.default.region
+ }
+ }
+ }
+ }
+}
+`, networkName, backendName, forwardingRuleName, zoneName, zoneName, zoneName, ttl)
+}
+
+func testAccDnsRecordSet_routingPolicyPrimaryBackup(networkName, backendName, forwardingRuleName, zoneName string, ttl int) string {
+ return fmt.Sprintf(`
+resource "google_compute_network" "default" {
+ name = "%s"
+}
+
+resource "google_compute_region_backend_service" "backend" {
+ name = "%s"
+ region = "us-central1"
+}
+
+resource "google_compute_forwarding_rule" "default" {
+ name = "%s"
+ region = "us-central1"
+
+ load_balancing_scheme = "INTERNAL"
+ backend_service = google_compute_region_backend_service.backend.id
+ all_ports = true
+ network = google_compute_network.default.name
+}
+
+resource "google_dns_managed_zone" "parent-zone" {
+ name = "%s"
+ dns_name = "%s.hashicorptest.com."
+ description = "Test Description"
+}
+
+resource "google_dns_record_set" "foobar" {
+ managed_zone = google_dns_managed_zone.parent-zone.name
+ name = "test-record.%s.hashicorptest.com."
+ type = "A"
+ ttl = %d
+
+ routing_policy {
+ primary_backup {
+ trickle_ratio = 0.1
+ enable_geo_fencing_for_backups = true
+
+ primary {
+ internal_load_balancers {
+ load_balancer_type = "regionalL4ilb"
+ ip_address = google_compute_forwarding_rule.default.ip_address
+ port = "80"
+ ip_protocol = "tcp"
+ network_url = google_compute_network.default.id
+ project = google_compute_forwarding_rule.default.project
+ region = google_compute_forwarding_rule.default.region
+ }
+ }
+
+ backup_geo {
+ location = "us-west1"
+ rrdatas = ["1.2.3.4"]
+ }
+
+ backup_geo {
+ location = "asia-east1"
+ rrdatas = ["5.6.7.8"]
+ }
}
}
}
-`, zoneName, zoneName, zoneName, ttl, location, addr2)
+`, networkName, backendName, forwardingRuleName, zoneName, zoneName, zoneName, ttl)
}
func testAccDnsRecordSet_interpolated(zoneName string) string {
diff --git a/website/docs/r/dns_record_set.html.markdown b/website/docs/r/dns_record_set.html.markdown
index bcc124ee33d..d6b2709c9fc 100644
--- a/website/docs/r/dns_record_set.html.markdown
+++ b/website/docs/r/dns_record_set.html.markdown
@@ -178,6 +178,69 @@ resource "google_dns_record_set" "geo" {
}
```
+#### Primary-Backup
+
+```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"
+ ttl = 300
+
+ routing_policy {
+ primary_backup {
+ trickle_ratio = 0.1
+
+ primary {
+ internal_load_balancers {
+ load_balancer_type = "regionalL4ilb"
+ ip_address = google_compute_forwarding_rule.prod.ip_address
+ port = "80"
+ ip_protocol = "tcp"
+ network_url = google_compute_network.prod.id
+ project = google_compute_forwarding_rule.prod.project
+ region = google_compute_forwarding_rule.prod.region
+ }
+ }
+
+ backup_geo {
+ location = "asia-east1"
+ rrdatas = ["10.128.1.1"]
+ }
+
+ backup_geo {
+ location = "us-west1"
+ rrdatas = ["10.130.1.1"]
+ }
+ }
+ }
+}
+
+resource "google_dns_managed_zone" "prod" {
+ name = "prod-zone"
+ dns_name = "prod.mydomain.com."
+}
+
+resource "google_compute_forwarding_rule" "prod" {
+ name = "prod-ilb"
+ region = "us-central1"
+
+ load_balancing_scheme = "INTERNAL"
+ backend_service = google_compute_region_backend_service.prod.id
+ all_ports = true
+ network = google_compute_network.prod.name
+}
+
+resource "google_compute_region_backend_service" "prod" {
+ name = "prod-backend"
+ region = "us-central1"
+}
+
+resource "google_compute_network" "prod" {
+ name = "prod-network"
+}
+```
+
## Argument Reference
The following arguments are supported:
@@ -211,17 +274,61 @@ The following arguments are supported:
* `geo` - (Optional) The configuration for Geolocation based routing policy.
Structure is [document below](#nested_geo).
+* `enable_geo_fencing` - (Optional) Specifies whether to enable fencing for geo queries.
+
+* `primary_backup` - (Optional) The configuration for a primary-backup policy with global to regional failover. Queries are responded to with the global primary targets, but if none of the primary targets are healthy, then we fallback to a regional failover policy.
+ Structure is [document below](#nested_primary_backup).
+
The `wrr` block supports:
* `weight` - (Required) The ratio of traffic routed to the target.
-* `rrdatas` - (Required) Same as `rrdatas` above.
+* `rrdatas` - (Optional) Same as `rrdatas` above.
+
+* `health_checked_targets` - (Optional) The list of targets to be health checked. Note that if DNSSEC is enabled for this zone, only one of `rrdatas` or `health_checked_targets` can be set.
+ Structure is [document below](#nested_health_checked_targets).
The `geo` block supports:
* `location` - (Required) The location name defined in Google Cloud.
-* `rrdatas` - (Required) Same as `rrdatas` above.
+* `rrdatas` - (Optional) Same as `rrdatas` above.
+
+* `health_checked_targets` - (Optional) For A and AAAA types only. The list of targets to be health checked. These can be specified along with `rrdatas` within this item.
+ Structure is [document below](#nested_health_checked_targets).
+
+The `primary_backup` block supports:
+
+* `primary` - (Required) The list of global primary targets to be health checked.
+ Structure is [document below](#nested_health_checked_targets).
+
+* `backup_geo` - (Required) The backup geo targets, which provide a regional failover policy for the otherwise global primary targets.
+ Structure is [document above](#nested_geo).
+
+* `enable_geo_fencing_for_backups` - (Optional) Specifies whether to enable fencing for backup geo queries.
+
+* `trickle_ratio` - (Optional) Specifies the percentage of traffic to send to the backup targets even when the primary targets are healthy.
+
+The `health_checked_targets` block supports:
+
+* `internal_load_balancers` - (Required) The list of internal load balancers to health check.
+ Structure is [document below](#nested_internal_load_balancers).
+
+The `internal_load_balancers` block supports:
+
+* `load_balancer_type` - (Required) The type of load balancer. This value is case-sensitive. Possible values: ["regionalL4ilb"]
+
+* `ip_address` - (Required) The frontend IP address of the load balancer.
+
+* `port` - (Required) The configured port of the load balancer.
+
+* `ip_protocol` - (Required) The configured IP protocol of the load balancer. This value is case-sensitive. Possible values: ["tcp", "udp"]
+
+* `network_url` - (Required) The fully qualified url of the network in which the load balancer belongs. This should be formatted like `projects/{project}/global/networks/{network}` or `https://www.googleapis.com/compute/v1/projects/{project}/global/networks/{network}`.
+
+* `project` - (Required) The ID of the project in which the load balancer belongs.
+
+* `region` - (Optional) The region of the load balancer. Only needed for regional load balancers.
## Attributes Reference