diff --git a/ibm/service/vpc/resource_ibm_is_vpc.go b/ibm/service/vpc/resource_ibm_is_vpc.go
index 68e75e6fad..da9104f86c 100644
--- a/ibm/service/vpc/resource_ibm_is_vpc.go
+++ b/ibm/service/vpc/resource_ibm_is_vpc.go
@@ -190,6 +190,18 @@ func ResourceIBMISVPC() *schema.Resource {
Computed: true,
Description: "The type of the DNS resolver used for the VPC.- `delegated`: DNS server addresses are provided by the DNS resolver of the VPC specified in `dns.resolver.vpc`.- `manual`: DNS server addresses are specified in `dns.resolver.manual_servers`.- `system`: DNS server addresses are provided by the system.",
},
+
+ "dns_binding_id": &schema.Schema{
+ Type: schema.TypeString,
+ Computed: true,
+ Description: "The VPC dns binding id whose DNS resolver provides the DNS server addresses for this VPC.",
+ },
+ "dns_binding_name": &schema.Schema{
+ Type: schema.TypeString,
+ Optional: true,
+ Computed: true,
+ Description: "The VPC dns binding name whose DNS resolver provides the DNS server addresses for this VPC.",
+ },
"vpc_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
@@ -714,6 +726,51 @@ func vpcCreate(d *schema.ResourceData, meta interface{}, name, apm, rg string, i
return err
}
+ if dnsresolvertpeOk, ok := d.GetOk("dns.0.resolver.0.type"); ok {
+ if dnsresolvertpeOk.(string) == "delegated" && d.Get("dns.0.resolver.0.vpc_id").(string) != "" {
+ vpcId := d.Get("dns.0.resolver.0.vpc_id").(string)
+ createDnsBindings := &vpcv1.CreateVPCDnsResolutionBindingOptions{
+ VPCID: vpc.ID,
+ VPC: &vpcv1.VPCIdentity{
+ ID: &vpcId,
+ },
+ }
+ if bindingNameOk, ok := d.GetOk("dns.0.resolver.0.dns_binding_name"); ok {
+ bindingName := bindingNameOk.(string)
+ createDnsBindings.Name = &bindingName
+ }
+ _, response, err := sess.CreateVPCDnsResolutionBinding(createDnsBindings)
+ if err != nil {
+ log.Printf("[DEBUG] CreateVPCDnsResolutionBindingWithContext failed %s\n%s", err, response)
+ return fmt.Errorf("[ERROR] CreateVPCDnsResolutionBinding failed in vpc resource %s\n%s", err, response)
+ }
+ resolverType := "delegated"
+ dnsPatch := &vpcv1.VpcdnsPatch{
+ Resolver: &vpcv1.VpcdnsResolverPatch{
+ Type: &resolverType,
+ VPC: &vpcv1.VpcdnsResolverVPCPatch{
+ ID: &vpcId,
+ },
+ },
+ }
+ vpcPatchModel := &vpcv1.VPCPatch{}
+ vpcPatchModel.Dns = dnsPatch
+ vpcPatchModelAsPatch, err := vpcPatchModel.AsPatch()
+ if err != nil {
+ return fmt.Errorf("[ERROR] CreateVPCDnsResolutionBinding failed in vpcpatch as patch %s", err)
+ }
+ updateVpcOptions := &vpcv1.UpdateVPCOptions{
+ ID: vpc.ID,
+ }
+ updateVpcOptions.VPCPatch = vpcPatchModelAsPatch
+ _, response, err = sess.UpdateVPC(updateVpcOptions)
+ if err != nil {
+ log.Printf("[DEBUG] Update vpc with delegated failed %s\n%s", err, response)
+ return fmt.Errorf("[ERROR] Update vpc with delegated failed in vpc resource %s\n%s", err, response)
+ }
+ }
+ }
+
if sgAclRules, ok := d.GetOk(isVPCNoSgAclRules); ok {
sgAclRules := sgAclRules.(bool)
if sgAclRules {
@@ -920,6 +977,38 @@ func vpcGet(d *schema.ResourceData, meta interface{}, id string) error {
if err != nil {
return err
}
+ resolverMapArray := dnsMap["resolver"].([]map[string]interface{})
+ resolverMap := resolverMapArray[0]
+ if resolverMap["type"] != nil && resolverMap["vpc_id"] != nil {
+ resType := resolverMap["type"].(*string)
+ resVpc := resolverMap["vpc_id"].(string)
+ if *resType == "delegated" {
+ listVPCDnsResolutionBindingOptions := &vpcv1.ListVPCDnsResolutionBindingsOptions{
+ VPCID: vpc.ID,
+ }
+
+ pager, err := sess.NewVPCDnsResolutionBindingsPager(listVPCDnsResolutionBindingOptions)
+ if err != nil {
+ return fmt.Errorf("[ERROR] Error getting VPC dns bindings: %s", err)
+ }
+ var allResults []vpcv1.VpcdnsResolutionBinding
+ for pager.HasNext() {
+ nextPage, err := pager.GetNext()
+ if err != nil {
+ return fmt.Errorf("[ERROR] Error getting VPC dns bindings pager next: %s", err)
+ }
+ allResults = append(allResults, nextPage...)
+ }
+ for _, binding := range allResults {
+ if *binding.VPC.ID == resVpc {
+ resolverMap["dns_binding_id"] = binding.ID
+ resolverMap["dns_binding_name"] = binding.Name
+ resolverMapArray[0] = resolverMap
+ dnsMap["resolver"] = resolverMapArray
+ }
+ }
+ }
+ }
if err = d.Set(isVPCDns, []map[string]interface{}{dnsMap}); err != nil {
return fmt.Errorf("[ERROR] Error setting dns: %s", err)
}
@@ -1543,7 +1632,11 @@ func resourceIBMIsVPCMapToVpcdnsPrototype(modelMap map[string]interface{}) (*vpc
func resourceIBMIsVPCMapToVpcdnsResolverPrototype(modelMap map[string]interface{}) (vpcv1.VpcdnsResolverPrototypeIntf, error) {
model := &vpcv1.VpcdnsResolverPrototype{}
if modelMap["type"] != nil && modelMap["type"].(string) != "" {
- model.Type = core.StringPtr(modelMap["type"].(string))
+ if modelMap["type"].(string) == "delegated" {
+ model.Type = core.StringPtr("system")
+ } else {
+ model.Type = core.StringPtr(modelMap["type"].(string))
+ }
}
if modelMap["manual_servers"] != nil && modelMap["manual_servers"].(*schema.Set).Len() > 0 {
model.Type = core.StringPtr("manual")
@@ -1583,6 +1676,7 @@ func resourceIBMIsVPCVpcdnsToMap(model *vpcv1.Vpcdns, vpcId, vpcCrn string) (map
return modelMap, err
}
modelMap["resolver"] = []map[string]interface{}{resolverMap}
+
return modelMap, nil
}
diff --git a/ibm/service/vpc/resource_ibm_is_vpc_test.go b/ibm/service/vpc/resource_ibm_is_vpc_test.go
index 6f9cc88a66..5468af48d1 100644
--- a/ibm/service/vpc/resource_ibm_is_vpc_test.go
+++ b/ibm/service/vpc/resource_ibm_is_vpc_test.go
@@ -298,6 +298,53 @@ func TestAccIBMISVPC_dns_delegated(t *testing.T) {
},
})
}
+func TestAccIBMISVPC_dns_delegated_first(t *testing.T) {
+ var vpc string
+ name1 := fmt.Sprintf("terraformvpcuat-%d", acctest.RandIntRange(10, 100))
+ name2 := fmt.Sprintf("terraformvpcuat-%d", acctest.RandIntRange(10, 100))
+ subnet1 := fmt.Sprintf("terraformsubnet-%d", acctest.RandIntRange(10, 100))
+ subnet2 := fmt.Sprintf("terraformsubnet-%d", acctest.RandIntRange(10, 100))
+ resourecinstance := fmt.Sprintf("terraformresource-%d", acctest.RandIntRange(10, 100))
+ resolver1 := fmt.Sprintf("terraformresolver-%d", acctest.RandIntRange(10, 100))
+ binding := fmt.Sprintf("terraformbinding-%d", acctest.RandIntRange(10, 100))
+ enableHubTrue := true
+ enableHubFalse := false
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { acc.TestAccPreCheck(t) },
+ Providers: acc.TestAccProviders,
+ CheckDestroy: testAccCheckIBMISVPCDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCheckIBMISVPCDnsDelegatedFirstConfig(name1, name2, subnet1, subnet2, resourecinstance, resolver1, binding, enableHubTrue, enableHubFalse),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckIBMISVPCExists("ibm_is_vpc.hub_true", vpc),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_true", "name", name1),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_false_delegated", "name", name2),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_true", "dns.0.enable_hub", fmt.Sprintf("%t", enableHubTrue)),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_true", "dns.0.resolver.0.type", "system"),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_false_delegated", "dns.0.enable_hub", fmt.Sprintf("%t", enableHubFalse)),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.type", "delegated"),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_false_delegated", "dns.0.resolution_binding_count", "1"),
+ resource.TestCheckResourceAttr(
+ "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.dns_binding_name", binding),
+ resource.TestCheckResourceAttrSet(
+ "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.dns_binding_id"),
+ resource.TestCheckResourceAttrSet(
+ "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.vpc_id"),
+ resource.TestCheckResourceAttrSet(
+ "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.vpc_name"),
+ ),
+ },
+ },
+ })
+}
func TestAccIBMISVPC_basic_apm(t *testing.T) {
var vpc string
@@ -597,6 +644,69 @@ func testAccCheckIBMISVPCDnsDelegatedConfig(vpcname, vpcname2, subnetname1, subn
`, vpcname, enableHub, vpcname2, enablehubfalse, subnetname1, acc.ISZoneName, subnetname2, acc.ISZoneName, subnetname3, acc.ISZoneName, subnetname4, acc.ISZoneName, resourceinstance, resolver1, resolver2, bindingname)
+}
+func testAccCheckIBMISVPCDnsDelegatedFirstConfig(vpcname, vpcname2, subnetname1, subnetname2, resourceinstance, resolver1, bindingname string, enableHub, enablehubfalse bool) string {
+ return fmt.Sprintf(`
+ data "ibm_resource_group" "rg" {
+ is_default = true
+ }
+
+ resource ibm_is_vpc hub_true {
+ name = "%s"
+ dns {
+ enable_hub = %t
+ }
+ }
+
+ resource ibm_is_vpc hub_false_delegated {
+ depends_on = [ ibm_dns_custom_resolver.test_hub_true ]
+ name = "%s"
+ dns {
+ enable_hub = %t
+ resolver {
+ type = "delegated"
+ vpc_id = ibm_is_vpc.hub_true.id
+ dns_binding_name = "%s"
+ }
+ }
+ }
+
+ resource "ibm_is_subnet" "hub_true_sub1" {
+ name = "%s"
+ vpc = ibm_is_vpc.hub_true.id
+ zone = "%s"
+ total_ipv4_address_count = 16
+ }
+ resource "ibm_is_subnet" "hub_true_sub2" {
+ name = "%s"
+ vpc = ibm_is_vpc.hub_true.id
+ zone = "%s"
+ total_ipv4_address_count = 16
+ }
+ resource "ibm_resource_instance" "dns-cr-instance" {
+ name = "%s"
+ resource_group_id = data.ibm_resource_group.rg.id
+ location = "global"
+ service = "dns-svcs"
+ plan = "standard-dns"
+ }
+ resource "ibm_dns_custom_resolver" "test_hub_true" {
+ name = "%s"
+ instance_id = ibm_resource_instance.dns-cr-instance.guid
+ description = "new test CR - TF"
+ high_availability = true
+ enabled = true
+ locations {
+ subnet_crn = ibm_is_subnet.hub_true_sub1.crn
+ enabled = true
+ }
+ locations {
+ subnet_crn = ibm_is_subnet.hub_true_sub2.crn
+ enabled = true
+ }
+ }
+ `, vpcname, enableHub, vpcname2, enablehubfalse, bindingname, subnetname1, acc.ISZoneName, subnetname2, acc.ISZoneName, resourceinstance, resolver1)
+
}
func testAccCheckIBMISVPCDnsDelegatedUpdate1Config(vpcname, vpcname2, subnetname1, subnetname2, subnetname3, subnetname4, resourceinstance, resolver1, resolver2, bindingname string, enableHub, enablehubfalse bool) string {
return fmt.Sprintf(`
diff --git a/website/docs/r/is_vpc.html.markdown b/website/docs/r/is_vpc.html.markdown
index 0249e5778b..1ef48546e8 100644
--- a/website/docs/r/is_vpc.html.markdown
+++ b/website/docs/r/is_vpc.html.markdown
@@ -83,6 +83,22 @@ resource "ibm_is_vpc" "example-system" {
}
}
+// delegated type resolver
+
+resource "ibm_is_vpc" "example-delegated" {
+ // required : add a dependency on ibm dns custom resolver of the hub vpc
+ depends_on = [ ibm_dns_custom_resolver.example-hub ]
+ name = "example-hub-false-delegated"
+ dns {
+ enable_hub = false
+ resolver {
+ type = "delegated"
+ vpc_id = ibm_is_vpc.example.id
+ dns_binding_name = "example-vpc-binding"
+ }
+ }
+}
+
```
## Timeouts
@@ -116,6 +132,9 @@ Review the argument references that you can specify for your resource.
- `resolver` - (Optional, List) The zone list this backup policy plan will create snapshot clones in.
Nested scheme for `resolver`:
+ - `dns_binding_id` - (String) The VPC dns binding id whose DNS resolver provides the DNS server addresses for this VPC. (If any)
+ - `dns_binding_name` - (Optional, String) The VPC dns binding name whose DNS resolver provides the DNS server addresses for this VPC. Only applicable for `delegated`, providing value would create binding with this name.
+
~> **Note:**
`manual_servers` must be set if and only if `dns.resolver.type` is manual.
- `manual_servers` - (Optional, List) The DNS servers to use for this VPC, replacing any existing servers. All the DNS servers must either: **have a unique zone_affinity**, or **not have a zone_affinity**.
@@ -139,7 +158,7 @@ Review the argument references that you can specify for your resource.
~> **Note:**
Updating from `manual` requires dns resolver `manual_servers` to be specified as null.
Updating to `manual` requires dns resolver `manual_servers` to be specified and not empty.
- Updating from `delegated` requires `dns.resolver.vpc` to be specified as null.
+ Updating from `delegated` requires `dns.resolver.vpc` to be specified as null. If type is `delegated` while creation then `vpc_id` is required
- `vpc_id` - (Optional, List) (update only) The VPC ID to provide DNS server addresses for this VPC. The specified VPC must be configured with a DNS Services custom resolver and must be in one of this VPC's DNS resolution bindings. Mutually exclusive with `vpc_crn`
~> **Note:**