From 1a6e7bb53d487d9ee79dc5e79eafa188b359fd5b Mon Sep 17 00:00:00 2001 From: Ujjwal Kumar Date: Fri, 7 Feb 2025 02:13:20 +0530 Subject: [PATCH] fix(vpc): dns name update issue fixed --- ibm/service/vpc/resource_ibm_is_vpc.go | 24 ++- ibm/service/vpc/resource_ibm_is_vpc_test.go | 212 ++++++++++++++++++++ 2 files changed, 233 insertions(+), 3 deletions(-) diff --git a/ibm/service/vpc/resource_ibm_is_vpc.go b/ibm/service/vpc/resource_ibm_is_vpc.go index 3880e02f6ac..2be67048bf9 100644 --- a/ibm/service/vpc/resource_ibm_is_vpc.go +++ b/ibm/service/vpc/resource_ibm_is_vpc.go @@ -1358,11 +1358,27 @@ func vpcUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha if d.HasChange("dns.0.enable_hub") { _, newEH := d.GetChange("dns.0.enable_hub") dnsPatch.EnableHub = core.BoolPtr(newEH.(bool)) + hasDnsChanged = true } if d.HasChange("dns.0.resolver") { - _, newResolver := d.GetChange("dns.0.resolver") - + if d.HasChange("dns.0.resolver.0.dns_binding_name") && (d.Get("dns.0.resolver.0.dns_binding_name").(string) != "null" || d.Get("dns.0.resolver.0.dns_binding_name").(string) != "") { + dnsBindingName := d.Get("dns.0.resolver.0.dns_binding_name").(string) + dnsBindingId := d.Get("dns.0.resolver.0.dns_binding_id").(string) + vpcdnsResolutionBindingPatch := &vpcv1.VpcdnsResolutionBindingPatch{ + Name: &dnsBindingName, + } + vpcdnsResolutionBindingPatchAsPatch, _ := vpcdnsResolutionBindingPatch.AsPatch() + updateVPCDnsResolutionBinding := &vpcv1.UpdateVPCDnsResolutionBindingOptions{ + ID: &dnsBindingId, + VPCID: core.StringPtr(d.Id()), + VpcdnsResolutionBindingPatch: vpcdnsResolutionBindingPatchAsPatch, + } + _, res, err := sess.UpdateVPCDnsResolutionBinding(updateVPCDnsResolutionBinding) + if err != nil { + return fmt.Errorf("[ERROR] Error updating dns_binding_name during VPCPatch: %s\n%s", err, res) + } + } if newResolver != nil && len(newResolver.([]interface{})) > 0 { ResolverModel := &vpcv1.VpcdnsResolverPatch{} if d.HasChange("dns.0.resolver.0.manual_servers") { @@ -1455,6 +1471,7 @@ func vpcUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha } } } + hasDnsChanged = true } if d.HasChange("dns.0.resolver.0.vpc_id") { _, newResolverVpc := d.GetChange("dns.0.resolver.0.vpc_id") @@ -1472,6 +1489,7 @@ func vpcUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha } } } + hasDnsChanged = true } if d.HasChange("dns.0.resolver.0.vpc_crn") { _, newResolverVpc := d.GetChange("dns.0.resolver.0.vpc_crn") @@ -1489,11 +1507,11 @@ func vpcUpdate(d *schema.ResourceData, meta interface{}, id, name string, hasCha } } } + hasDnsChanged = true } dnsPatch.Resolver = ResolverModel } } - hasDnsChanged = true } if hasChanged || hasDnsChanged { updateVpcOptions := &vpcv1.UpdateVPCOptions{ diff --git a/ibm/service/vpc/resource_ibm_is_vpc_test.go b/ibm/service/vpc/resource_ibm_is_vpc_test.go index 8f377718e46..d8c3697bccc 100644 --- a/ibm/service/vpc/resource_ibm_is_vpc_test.go +++ b/ibm/service/vpc/resource_ibm_is_vpc_test.go @@ -1256,3 +1256,215 @@ func testAccCheckIBMISVPCCustomResolverDelegatedToSystemConfig(vpcname1, vpcname } `, vpcname1, acc.ISZoneName, acc.ISZoneName, vpcname2) } + +// VPC DNS name update fix +// TestAccIBMISVPC_ResolverTypeTransitionDnsNameUpdate tests the transition of resolver types in a VPC. +func TestAccIBMISVPC_ResolverTypeTransitionDnsNameUpdate(t *testing.T) { + var vpc string + vpcname1 := fmt.Sprintf("tf-vpc-hub-true-%d", acctest.RandIntRange(10, 100)) + vpcname2 := fmt.Sprintf("tf-vpc-hub-false-%d", acctest.RandIntRange(10, 100)) + dnsName := fmt.Sprintf("tf-dns-%d", acctest.RandIntRange(10, 100)) + dnsNameUpdated := fmt.Sprintf("tf-dns-update-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMISVPCDestroy, + Steps: []resource.TestStep{ + // Step 1: Initial setup with system resolver + { + Config: testAccCheckIBMISVPCResolverSystemConfig(vpcname1, vpcname2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCExists("ibm_is_vpc.hub_false_delegated", vpc), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "name", vpcname2), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.enable_hub", "false"), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.type", "system"), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.vpc_id", ""), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.dns_binding_name", ""), + ), + }, + // Step 2: Change to delegated resolver with no name + { + Config: testAccCheckIBMISVPCCustomResolverDelegatedWithNoNameConfig(vpcname1, vpcname2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCExists("ibm_is_vpc.hub_false_delegated", vpc), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.type", "delegated"), + 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.dns_binding_name"), + ), + }, + // Step 3: Update the binding name + { + Config: testAccCheckIBMISVPCCustomResolverDelegatedWithNameConfig(vpcname1, vpcname2, dnsName), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCExists("ibm_is_vpc.hub_false_delegated", vpc), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.type", "delegated"), + resource.TestCheckResourceAttrSet( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.vpc_id"), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.dns_binding_name", dnsName), + ), + }, + // Step 4: Update the binding name again + { + Config: testAccCheckIBMISVPCCustomResolverDelegatedWithNameConfig(vpcname1, vpcname2, dnsNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCExists("ibm_is_vpc.hub_false_delegated", vpc), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.type", "delegated"), + resource.TestCheckResourceAttrSet( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.vpc_id"), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.dns_binding_name", dnsNameUpdated), + ), + }, + // Step 5: Change back to system resolver + { + Config: testAccCheckIBMISVPCCustomResolverDelegatedToSystemConfig(vpcname1, vpcname2), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISVPCExists("ibm_is_vpc.hub_false_delegated", vpc), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.type", "system"), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.vpc_id", ""), + resource.TestCheckResourceAttr( + "ibm_is_vpc.hub_false_delegated", "dns.0.resolver.0.dns_binding_name", ""), + ), + }, + }, + }) +} + +// Helper function to generate config for custom resolver with hub VPC +func testAccCheckIBMISVPCCustomResolverDelegatedWithNoNameConfig(vpcname1, vpcname2 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "hub_true" { + name = "%s" + dns { + enable_hub = true + } + } + resource "ibm_is_subnet" "hub_true_sub1" { + name = "hub-true-subnet1" + vpc = ibm_is_vpc.hub_true.id + zone = "%s" + total_ipv4_address_count = 16 + } + resource "ibm_is_subnet" "hub_true_sub2" { + name = "hub-true-subnet2" + vpc = ibm_is_vpc.hub_true.id + zone = "%s" + total_ipv4_address_count = 16 + } + resource "ibm_resource_instance" "dns-cr-instance" { + name = "dns-cr-instance" + 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 = "test-hub-true-customresolver" + 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 + } + } + // delegated vpc + resource "ibm_is_vpc" "hub_false_delegated" { + depends_on = [ibm_dns_custom_resolver.test_hub_true] + name = "%s" + dns { + enable_hub = false + resolver { + type = "delegated" + vpc_id = ibm_is_vpc.hub_true.id + } + } + } + + data "ibm_resource_group" "rg" { + is_default = true + } + `, vpcname1, acc.ISZoneName, acc.ISZoneName, vpcname2) +} + +// Helper function to generate config for custom resolver with hub VPC +func testAccCheckIBMISVPCCustomResolverDelegatedWithNameConfig(vpcname1, vpcname2, dnsName string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "hub_true" { + name = "%s" + dns { + enable_hub = true + } + } + resource "ibm_is_subnet" "hub_true_sub1" { + name = "hub-true-subnet1" + vpc = ibm_is_vpc.hub_true.id + zone = "%s" + total_ipv4_address_count = 16 + } + resource "ibm_is_subnet" "hub_true_sub2" { + name = "hub-true-subnet2" + vpc = ibm_is_vpc.hub_true.id + zone = "%s" + total_ipv4_address_count = 16 + } + resource "ibm_resource_instance" "dns-cr-instance" { + name = "dns-cr-instance" + 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 = "test-hub-true-customresolver" + 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 + } + } + // delegated vpc + resource "ibm_is_vpc" "hub_false_delegated" { + depends_on = [ibm_dns_custom_resolver.test_hub_true] + name = "%s" + dns { + enable_hub = false + resolver { + type = "delegated" + dns_binding_name = "%s" + vpc_id = ibm_is_vpc.hub_true.id + } + } + } + + data "ibm_resource_group" "rg" { + is_default = true + } + `, vpcname1, acc.ISZoneName, acc.ISZoneName, vpcname2, dnsName) +}