From 88e5abe2db5c6c25d8685263cc5367a6b6b53ae7 Mon Sep 17 00:00:00 2001 From: akinross Date: Thu, 9 Apr 2026 15:25:51 +0200 Subject: [PATCH 1/3] [bugfix] allow description and vmac to be set to empty string in the mso_schema_template_bd resource --- mso/resource_mso_schema_template_bd.go | 336 ++++++++++++------------- 1 file changed, 161 insertions(+), 175 deletions(-) diff --git a/mso/resource_mso_schema_template_bd.go b/mso/resource_mso_schema_template_bd.go index 47110677..921e7757 100644 --- a/mso/resource_mso_schema_template_bd.go +++ b/mso/resource_mso_schema_template_bd.go @@ -53,9 +53,10 @@ func resourceMSOTemplateBD() *schema.Resource { ValidateFunc: validation.StringLenBetween(1, 1000), }, "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 128), + Type: schema.TypeString, + Optional: true, + // Set minimal length to 0 to allow removal of description + ValidateFunc: validation.StringLenBetween(0, 128), }, "intersite_bum_traffic": &schema.Schema{ Type: schema.TypeBool, @@ -81,6 +82,10 @@ func resourceMSOTemplateBD() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + "flood", + "proxy", + }, false), }, "unknown_multicast_flooding": &schema.Schema{ Type: schema.TypeString, @@ -118,7 +123,8 @@ func resourceMSOTemplateBD() *schema.Resource { "virtual_mac_address": &schema.Schema{ Type: schema.TypeString, Optional: true, - Computed: true, + // Commented out computed to allow setting vmac to empty string + // Computed: true, }, "unicast_routing": &schema.Schema{ Type: schema.TypeBool, @@ -140,6 +146,7 @@ func resourceMSOTemplateBD() *schema.Resource { Optional: true, Computed: true, }, + // We should deprecate dhcp_policy since it is no longer supported on product "dhcp_policy": &schema.Schema{ Type: schema.TypeMap, Optional: true, @@ -182,6 +189,7 @@ func resourceMSOTemplateBD() *schema.Resource { Type: schema.TypeString, Required: true, }, + // We should investigate the need for this and else deprecate because in ND 4.1 this is not UI "version": &schema.Schema{ Type: schema.TypeInt, Optional: true, @@ -759,246 +767,224 @@ func resourceMSOTemplateBDUpdate(d *schema.ResourceData, m interface{}) error { msoClient := m.(*client.Client) schemaID := d.Get("schema_id").(string) - name := d.Get("name").(string) - displayName := d.Get("display_name").(string) - description := d.Get("description").(string) templateName := d.Get("template_name").(string) - vrfName := d.Get("vrf_name").(string) + name := d.Get("name").(string) versionInt, err := msoClient.CompareVersion("4.0.0.0") if err != nil { return err } - var intersite_bum_traffic, optimize_wan_bandwidth, layer2_stretch, layer3_multicast, unicast_routing, arp_flooding bool - var layer2_unknown_unicast, vrf_schema_id, vrf_template_name, virtual_mac_address, ep_move_detection_mode, ipv6_unknown_multicast_flooding, multi_destination_flooding, unknown_multicast_flooding string - if tempVar, ok := d.GetOk("intersite_bum_traffic"); ok { - intersite_bum_traffic = tempVar.(bool) - } - if tempVar, ok := d.GetOk("optimize_wan_bandwidth"); ok { - optimize_wan_bandwidth = tempVar.(bool) - } - if tempVar, ok := d.GetOk("layer2_stretch"); ok { - layer2_stretch = tempVar.(bool) - } - if tempVar, ok := d.GetOk("layer3_multicast"); ok { - layer3_multicast = tempVar.(bool) - } - if tempVar, ok := d.GetOk("layer2_unknown_unicast"); ok { - layer2_unknown_unicast = tempVar.(string) - } - if tempVar, ok := d.GetOk("unknown_multicast_flooding"); ok { - unknown_multicast_flooding = tempVar.(string) - } - if tempVar, ok := d.GetOk("multi_destination_flooding"); ok { - multi_destination_flooding = tempVar.(string) - } - if tempVar, ok := d.GetOk("ipv6_unknown_multicast_flooding"); ok { - ipv6_unknown_multicast_flooding = tempVar.(string) - } - if tempVar, ok := d.GetOk("unicast_routing"); ok { - unicast_routing = tempVar.(bool) - } - if tempVar, ok := d.GetOk("virtual_mac_address"); ok { - virtual_mac_address = tempVar.(string) - } - if tempVar, ok := d.GetOk("ep_move_detection_mode"); ok { - ep_move_detection_mode = tempVar.(string) - } - if tempVar, ok := d.GetOk("arp_flooding"); ok { - arp_flooding = tempVar.(bool) - } - if tempVar, ok := d.GetOk("vrf_schema_id"); ok { - vrf_schema_id = tempVar.(string) - } else { - vrf_schema_id = schemaID - } - if tempVar, ok := d.GetOk("vrf_template_name"); ok { - vrf_template_name = tempVar.(string) - } else { - vrf_template_name = templateName - } - var dhcpPolMap map[string]interface{} - if tempVar, ok := d.GetOk("dhcp_policy"); ok { - dhcp_policy := tempVar.(map[string]interface{}) - dhcpPolMap = make(map[string]interface{}) - dhcpPolMap["name"] = dhcp_policy["name"] - version, err := strconv.Atoi(dhcp_policy["version"].(string)) + basePath := fmt.Sprintf("/templates/%s/bds/%s", templateName, name) + payloadCon := container.New() + payloadCon.Array() + + if d.HasChange("display_name") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/displayName", basePath), d.Get("display_name").(string)) if err != nil { return err } - dhcpPolMap["version"] = version - - optionName := dhcp_policy["dhcp_option_policy_name"] - optionVersion := dhcp_policy["dhcp_option_policy_version"] - if optionName != nil { - if optionVersion != nil { - dhcpOptionMap := make(map[string]interface{}) - dhcpOptionMap["name"] = optionName - ver, err := strconv.Atoi(optionVersion.(string)) - if err != nil { - return err - } - dhcpOptionMap["version"] = ver - dhcpPolMap["dhcpOptionLabel"] = dhcpOptionMap - } else { - return fmt.Errorf("dhcp_option_policy_version is required with dhcp_option_policy_name") - } - } - } else { - dhcpPolMap = nil } - dhcpPolList := make([]interface{}, 0) - if dhcpPolicies, ok := d.GetOk("dhcp_policies"); ok { - if versionInt == -1 { - dhcpRefList, err := mapDHCPPoliciesRefByName(schemaID, templateName, dhcpPolicies, msoClient) - if err != nil { - return err - } - dhcpPolList = dhcpRefList - } else { - for _, dhcpPolicy := range dhcpPolicies.(*schema.Set).List() { - policy := dhcpPolicy.(map[string]interface{}) - dhcpPolicyMap := make(map[string]interface{}) - dhcpPolicyMap["name"] = policy["name"] - dhcpPolicyMap["version"] = policy["version"] - if policy["dhcp_option_policy_name"] != "" { - dhcpOptionMap := make(map[string]interface{}) - dhcpOptionMap["name"] = policy["dhcp_option_policy_name"] - if policy["version"] != 0 { - dhcpOptionMap["version"] = policy["dhcp_option_policy_version"] - } else { - dhcpOptionMap["version"] = policy["version"] - } - dhcpPolicyMap["dhcpOptionLabel"] = dhcpOptionMap - } - dhcpPolList = append(dhcpPolList, dhcpPolicyMap) - } + if d.HasChange("description") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/description", basePath), d.Get("description").(string)) + if err != nil { + return err } - } else { - dhcpPolList = nil - } - - vrfRefMap := make(map[string]interface{}) - vrfRefMap["schemaId"] = vrf_schema_id - vrfRefMap["templateName"] = vrf_template_name - vrfRefMap["vrfName"] = vrfName - - basePath := fmt.Sprintf("/templates/%s/bds/%s", templateName, name) - payloadCon := container.New() - payloadCon.Array() - - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/displayName", basePath), displayName) - if err != nil { - return err } - if layer2_unknown_unicast != "" { - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/l2UnknownUnicast", basePath), layer2_unknown_unicast) + if d.HasChange("layer2_unknown_unicast") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/l2UnknownUnicast", basePath), d.Get("layer2_unknown_unicast").(string)) if err != nil { return err } } - if unknown_multicast_flooding != "" { - if unknown_multicast_flooding == "optimized_flooding" { - unknown_multicast_flooding = "opt-flood" + if d.HasChange("unknown_multicast_flooding") { + unknownMulticastFlooding := d.Get("unknown_multicast_flooding").(string) + if unknownMulticastFlooding == "optimized_flooding" { + unknownMulticastFlooding = "opt-flood" } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/unkMcastAct", basePath), unknown_multicast_flooding) + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/unkMcastAct", basePath), unknownMulticastFlooding) if err != nil { return err } } - if multi_destination_flooding != "" { - if multi_destination_flooding == "flood_in_encap" { - multi_destination_flooding = "encap-flood" - } else if multi_destination_flooding == "flood_in_bd" { - multi_destination_flooding = "bd-flood" + if d.HasChange("multi_destination_flooding") { + multiDestinationFlooding := d.Get("multi_destination_flooding").(string) + if multiDestinationFlooding == "flood_in_encap" { + multiDestinationFlooding = "encap-flood" + } else if multiDestinationFlooding == "flood_in_bd" { + multiDestinationFlooding = "bd-flood" } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/multiDstPktAct", basePath), multi_destination_flooding) + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/multiDstPktAct", basePath), multiDestinationFlooding) if err != nil { return err } } - if ipv6_unknown_multicast_flooding != "" { - if ipv6_unknown_multicast_flooding == "optimized_flooding" { - ipv6_unknown_multicast_flooding = "opt-flood" + if d.HasChange("ipv6_unknown_multicast_flooding") { + ipv6UnknownMulticastFlooding := d.Get("ipv6_unknown_multicast_flooding").(string) + if ipv6UnknownMulticastFlooding == "optimized_flooding" { + ipv6UnknownMulticastFlooding = "opt-flood" } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/v6unkMcastAct", basePath), ipv6_unknown_multicast_flooding) + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/v6unkMcastAct", basePath), ipv6UnknownMulticastFlooding) if err != nil { return err } } - if virtual_mac_address != "" { - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/vmac", basePath), virtual_mac_address) + if d.HasChange("virtual_mac_address") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/vmac", basePath), d.Get("virtual_mac_address").(string)) if err != nil { return err } } - if ep_move_detection_mode != "" { - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/epMoveDetectMode", basePath), ep_move_detection_mode) + if d.HasChange("ep_move_detection_mode") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/epMoveDetectMode", basePath), d.Get("ep_move_detection_mode").(string)) if err != nil { return err } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/description", basePath), description) - if err != nil { - return err + if d.HasChange("intersite_bum_traffic") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/intersiteBumTrafficAllow", basePath), d.Get("intersite_bum_traffic").(bool)) + if err != nil { + return err + } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/intersiteBumTrafficAllow", basePath), intersite_bum_traffic) - if err != nil { - return err + if d.HasChange("optimize_wan_bandwidth") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/optimizeWanBandwidth", basePath), d.Get("optimize_wan_bandwidth").(bool)) + if err != nil { + return err + } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/optimizeWanBandwidth", basePath), optimize_wan_bandwidth) - if err != nil { - return err + if d.HasChange("layer2_stretch") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/l2Stretch", basePath), d.Get("layer2_stretch").(bool)) + if err != nil { + return err + } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/l2Stretch", basePath), layer2_stretch) - if err != nil { - return err + if d.HasChange("layer3_multicast") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/l3MCast", basePath), d.Get("layer3_multicast").(bool)) + if err != nil { + return err + } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/l3MCast", basePath), layer3_multicast) - if err != nil { - return err + if d.HasChange("arp_flooding") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/arpFlood", basePath), d.Get("arp_flooding").(bool)) + if err != nil { + return err + } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/arpFlood", basePath), arp_flooding) - if err != nil { - return err + if d.HasChange("unicast_routing") { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/unicastRouting", basePath), d.Get("unicast_routing").(bool)) + if err != nil { + return err + } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/unicastRouting", basePath), unicast_routing) - if err != nil { - return err + if d.HasChange("vrf_name") || d.HasChange("vrf_schema_id") || d.HasChange("vrf_template_name") { + vrfSchemaId := d.Get("vrf_schema_id").(string) + if vrfSchemaId == "" { + vrfSchemaId = schemaID + } + vrfTemplateName := d.Get("vrf_template_name").(string) + if vrfTemplateName == "" { + vrfTemplateName = templateName + } + vrfRefMap := map[string]interface{}{ + "schemaId": vrfSchemaId, + "templateName": vrfTemplateName, + "vrfName": d.Get("vrf_name").(string), + } + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/vrfRef", basePath), vrfRefMap) + if err != nil { + return err + } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/vrfRef", basePath), vrfRefMap) - if err != nil { - return err + if d.HasChange("dhcp_policy") { + var dhcpPolMap map[string]interface{} + if tempVar, ok := d.GetOk("dhcp_policy"); ok { + dhcp_policy := tempVar.(map[string]interface{}) + dhcpPolMap = make(map[string]interface{}) + dhcpPolMap["name"] = dhcp_policy["name"] + version, err := strconv.Atoi(dhcp_policy["version"].(string)) + if err != nil { + return err + } + dhcpPolMap["version"] = version + + optionName := dhcp_policy["dhcp_option_policy_name"] + optionVersion := dhcp_policy["dhcp_option_policy_version"] + if optionName != nil { + if optionVersion != nil { + dhcpOptionMap := make(map[string]interface{}) + dhcpOptionMap["name"] = optionName + ver, err := strconv.Atoi(optionVersion.(string)) + if err != nil { + return err + } + dhcpOptionMap["version"] = ver + dhcpPolMap["dhcpOptionLabel"] = dhcpOptionMap + } else { + return fmt.Errorf("dhcp_option_policy_version is required with dhcp_option_policy_name") + } + } + } + if len(dhcpPolMap) != 0 { + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/dhcpLabel", basePath), dhcpPolMap) + if err != nil { + return err + } + } } - if len(dhcpPolMap) != 0 { - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/dhcpLabel", basePath), dhcpPolMap) + if d.HasChange("dhcp_policies") { + dhcpPolList := make([]interface{}, 0) + if dhcpPolicies, ok := d.GetOk("dhcp_policies"); ok { + if versionInt == -1 { + dhcpRefList, err := mapDHCPPoliciesRefByName(schemaID, templateName, dhcpPolicies, msoClient) + if err != nil { + return err + } + dhcpPolList = dhcpRefList + } else { + for _, dhcpPolicy := range dhcpPolicies.(*schema.Set).List() { + policy := dhcpPolicy.(map[string]interface{}) + dhcpPolicyMap := make(map[string]interface{}) + dhcpPolicyMap["name"] = policy["name"] + dhcpPolicyMap["version"] = policy["version"] + if policy["dhcp_option_policy_name"] != "" { + dhcpOptionMap := make(map[string]interface{}) + dhcpOptionMap["name"] = policy["dhcp_option_policy_name"] + if policy["version"] != 0 { + dhcpOptionMap["version"] = policy["dhcp_option_policy_version"] + } else { + dhcpOptionMap["version"] = policy["version"] + } + dhcpPolicyMap["dhcpOptionLabel"] = dhcpOptionMap + } + dhcpPolList = append(dhcpPolList, dhcpPolicyMap) + } + } + } else { + dhcpPolList = nil + } + err := addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/dhcpLabels", basePath), dhcpPolList) if err != nil { return err } } - err = addPatchPayloadToContainer(payloadCon, "replace", fmt.Sprintf("%s/dhcpLabels", basePath), dhcpPolList) - if err != nil { - return err - } - err = doPatchRequest(msoClient, fmt.Sprintf("api/v1/schemas/%s", schemaID), payloadCon) if err != nil { return err From 4c02849d23d4dbfb614a7bdbf5225a601893a0e4 Mon Sep 17 00:00:00 2001 From: akinross Date: Thu, 9 Apr 2026 15:26:29 +0200 Subject: [PATCH 2/3] [ignore] add tests for mso_schema_template_bd resource and datasource --- mso/datasource_mso_schema_template_bd_test.go | 63 ++ mso/resource_mso_schema_template_bd_test.go | 612 +++++++++++++----- mso/test_constants.go | 17 + 3 files changed, 540 insertions(+), 152 deletions(-) create mode 100644 mso/datasource_mso_schema_template_bd_test.go diff --git a/mso/datasource_mso_schema_template_bd_test.go b/mso/datasource_mso_schema_template_bd_test.go new file mode 100644 index 00000000..1a606e79 --- /dev/null +++ b/mso/datasource_mso_schema_template_bd_test.go @@ -0,0 +1,63 @@ +package mso + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccMSOSchemaTemplateBdDataSource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + PreConfig: func() { fmt.Println("Test: Schema Template BD Data Source - Not Found") }, + Config: testAccMSOSchemaTemplateBdDataSourceNotFound(), + ExpectError: regexp.MustCompile(`Unable to find the BD`), + }, + { + PreConfig: func() { fmt.Println("Test: Schema Template BD Data Source") }, + Config: testAccMSOSchemaTemplateBdDataSource(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "display_name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "description", "Terraform test BD"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "layer2_unknown_unicast", "flood"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "unknown_multicast_flooding", "flood"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "multi_destination_flooding", "flood_in_bd"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "ipv6_unknown_multicast_flooding", "flood"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "arp_flooding", "true"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "unicast_routing", "false"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "layer3_multicast", "false"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "intersite_bum_traffic", "true"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "optimize_wan_bandwidth", "false"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "layer2_stretch", "true"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "virtual_mac_address", ""), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "ep_move_detection_mode", "none"), + resource.TestCheckResourceAttr("data.mso_schema_template_bd."+msoSchemaTemplateBdName, "vrf_name", msoSchemaTemplateVrfL3MulticastName), + ), + }, + }, + }) +} + +func testAccMSOSchemaTemplateBdDataSource() string { + return fmt.Sprintf(`%[1]s + data "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema_template_bd.%[2]s.schema_id + template_name = mso_schema_template_bd.%[2]s.template_name + name = "%[2]s" + }`, testAccMSOSchemaTemplateBdConfigCreate(), msoSchemaTemplateBdName) +} + +func testAccMSOSchemaTemplateBdDataSourceNotFound() string { + return fmt.Sprintf(`%[1]s + data "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema_template_bd.%[2]s.schema_id + template_name = mso_schema_template_bd.%[2]s.template_name + name = "non_existing_bd" + }`, testAccMSOSchemaTemplateBdConfigCreate(), msoSchemaTemplateBdName) +} diff --git a/mso/resource_mso_schema_template_bd_test.go b/mso/resource_mso_schema_template_bd_test.go index fb41f968..56b97410 100644 --- a/mso/resource_mso_schema_template_bd_test.go +++ b/mso/resource_mso_schema_template_bd_test.go @@ -2,7 +2,6 @@ package mso import ( "fmt" - "regexp" "testing" "github.com/ciscoecosystem/mso-go-client/client" @@ -11,191 +10,500 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/terraform" ) -func TestAccMSOSchemaTemplateBD_Basic(t *testing.T) { - var ss TemplateBD +// msoSchemaTemplateBdSchemaId is set during the first test step's Check to capture the dynamic schema ID for use in the manual deletion PreConfig step. +var msoSchemaTemplateBdSchemaId string + +func TestAccMSOSchemaTemplateBdResource(t *testing.T) { resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckMSOSchemaTemplateBDDestroy, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckMSOTemplateBDConfig_basic("flood"), - Check: resource.ComposeTestCheckFunc( - testAccCheckMSOSchemaTemplateBDExists("mso_schema_template_bd.bridge_domain", &ss), - testAccCheckMSOSchemaTemplateBDAttributes("flood", &ss), + PreConfig: func() { fmt.Println("Test: Create Schema Template BD") }, + Config: testAccMSOSchemaTemplateBdConfigCreate(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "template_name", msoSchemaTemplateName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "display_name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "description", "Terraform test BD"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "layer2_unknown_unicast", "flood"), + // Capture the dynamic schema ID from state for use in the manual deletion PreConfig step + func(s *terraform.State) error { + rs, ok := s.RootModule().Resources["mso_schema_template_bd."+msoSchemaTemplateBdName] + if !ok { + return fmt.Errorf("BD resource not found in state") + } + msoSchemaTemplateBdSchemaId = rs.Primary.Attributes["schema_id"] + return nil + }, + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "unknown_multicast_flooding", "flood"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "multi_destination_flooding", "flood_in_bd"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "ipv6_unknown_multicast_flooding", "flood"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "arp_flooding", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "unicast_routing", "false"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "layer3_multicast", "false"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "intersite_bum_traffic", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "optimize_wan_bandwidth", "false"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "layer2_stretch", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "virtual_mac_address", ""), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "ep_move_detection_mode", "none"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "vrf_name", msoSchemaTemplateVrfL3MulticastName), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update Schema Template BD layer2_unknown_unicast to proxy") }, + Config: testAccMSOSchemaTemplateBdConfigUpdateL2UnknownUnicast(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "layer2_unknown_unicast", "proxy"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "description", "Terraform test BD"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update Schema Template BD description and enable layer3_multicast") }, + Config: testAccMSOSchemaTemplateBdConfigUpdateDescriptionAndL3Multicast(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "description", "Terraform test BD updated"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "layer3_multicast", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "layer2_unknown_unicast", "proxy"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update Schema Template BD flooding fields") }, + Config: testAccMSOSchemaTemplateBdConfigUpdateFloodingFields(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "unknown_multicast_flooding", "optimized_flooding"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "multi_destination_flooding", "flood_in_encap"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "ipv6_unknown_multicast_flooding", "optimized_flooding"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update Schema Template BD remaining attributes") }, + Config: testAccMSOSchemaTemplateBdConfigUpdateRemainingAttributes(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "arp_flooding", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "unicast_routing", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "optimize_wan_bandwidth", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "virtual_mac_address", "00:00:5E:00:01:01"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "ep_move_detection_mode", "garp"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update Schema Template BD by removing description and virtual_mac_address") }, + Config: testAccMSOSchemaTemplateBdConfigRemoveDescription(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "description", ""), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "arp_flooding", "true"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "unicast_routing", "false"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "optimize_wan_bandwidth", "false"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "virtual_mac_address", ""), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "ep_move_detection_mode", "none"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Import BD") }, + ResourceName: "mso_schema_template_bd." + msoSchemaTemplateBdName, + ImportState: true, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources["mso_schema_template_bd."+msoSchemaTemplateBdName] + if !ok { + return "", fmt.Errorf("BD resource not found in state") + } + return fmt.Sprintf("%s/templates/%s/bds/%s", rs.Primary.Attributes["schema_id"], rs.Primary.Attributes["template_name"], rs.Primary.Attributes["name"]), nil + }, + ImportStateVerify: true, + }, + { + PreConfig: func() { + fmt.Println("Test: Recreate BD after manual deletion from NDO") + msoClient := testAccProvider.Meta().(*client.Client) + bdRemovePatchPayload := models.GetRemovePatchPayload(fmt.Sprintf("/templates/%s/bds/%s", msoSchemaTemplateName, msoSchemaTemplateBdName)) + _, err := msoClient.PatchbyID(fmt.Sprintf("api/v1/schemas/%s", msoSchemaTemplateBdSchemaId), bdRemovePatchPayload) + if err != nil { + t.Fatalf("Failed to manually delete BD: %v", err) + } + }, + Config: testAccMSOSchemaTemplateBdConfigRemoveDescription(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "display_name", msoSchemaTemplateBdName), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Add subnet child to BD") }, + Config: testAccMSOSchemaTemplateBdConfigWithChildren(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "display_name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd_subnet."+msoSchemaTemplateBdName+"_subnet", "ip", msoSchemaTemplateBdSubnetIp), + resource.TestCheckResourceAttr("mso_schema_template_bd_subnet."+msoSchemaTemplateBdName+"_subnet", "scope", "private"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update BD description with children present") }, + Config: testAccMSOSchemaTemplateBdConfigWithChildrenUpdateDescription(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "description", "Terraform test BD with children"), + resource.TestCheckResourceAttr("mso_schema_template_bd_subnet."+msoSchemaTemplateBdName+"_subnet", "ip", msoSchemaTemplateBdSubnetIp), + resource.TestCheckResourceAttr("mso_schema_template_bd_subnet."+msoSchemaTemplateBdName+"_subnet", "scope", "private"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Remove children from BD") }, + Config: testAccMSOSchemaTemplateBdConfigRemoveChildren(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "description", "Terraform test BD with children"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Add one DHCP policy to BD") }, + Config: testAccMSOSchemaTemplateBdConfigWithOneDhcpPolicy(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "dhcp_policies.#", "1"), ), }, - }, - }) -} - -func TestAccMSOSchemaTemplateBD_Update(t *testing.T) { - var ss TemplateBD - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckMSOSchemaTemplateBDDestroy, - Steps: []resource.TestStep{ { - Config: testAccCheckMSOTemplateBDConfig_basic("flood"), - Check: resource.ComposeTestCheckFunc( - testAccCheckMSOSchemaTemplateBDExists("mso_schema_template_bd.bridge_domain", &ss), - testAccCheckMSOSchemaTemplateBDAttributes("flood", &ss), + PreConfig: func() { fmt.Println("Test: Update BD to two DHCP policies") }, + Config: testAccMSOSchemaTemplateBdConfigWithTwoDhcpPolicies(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "dhcp_policies.#", "2"), ), }, { - Config: testAccCheckMSOTemplateBDConfig_basic("proxy"), - Check: resource.ComposeTestCheckFunc( - testAccCheckMSOSchemaTemplateBDExists("mso_schema_template_bd.bridge_domain", &ss), - testAccCheckMSOSchemaTemplateBDAttributes("proxy", &ss), + PreConfig: func() { fmt.Println("Test: Update BD back to one DHCP policy") }, + Config: testAccMSOSchemaTemplateBdConfigWithOneDhcpPolicy(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "dhcp_policies.#", "1"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Remove all DHCP policies from BD") }, + Config: testAccMSOSchemaTemplateBdConfigRemoveDhcpPolicies(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("mso_schema_template_bd."+msoSchemaTemplateBdName, "schema_id"), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "name", msoSchemaTemplateBdName), + resource.TestCheckResourceAttr("mso_schema_template_bd."+msoSchemaTemplateBdName, "dhcp_policies.#", "0"), ), }, }, + CheckDestroy: testCheckResourceDestroyPolicyWithArguments("mso_schema_template_bd", "bd"), }) } -func testAccCheckMSOTemplateBDConfig_basic(unicast string) string { - return fmt.Sprintf(` - resource "mso_schema_template_bd" "bridge_domain" { - schema_id = "5ea809672c00003bc40a2799" - template_name = "Template1" - name = "testAccBD" - display_name = "testAcc" - vrf_name = "demo" - layer2_unknown_unicast = "%s" - } -`, unicast) +func testAccMSOSchemaTemplateBdPrerequisiteConfig() string { + return fmt.Sprintf(`%s%s%s%s`, testSiteConfigAnsibleTest(), testTenantConfig(), testSchemaConfig(), testSchemaTemplateVrfL3MulticastConfig()) } -func testAccCheckMSOSchemaTemplateBDExists(bdName string, ss *TemplateBD) resource.TestCheckFunc { - return func(s *terraform.State) error { - client := testAccProvider.Meta().(*client.Client) - rs1, err1 := s.RootModule().Resources[bdName] +func testAccMSOSchemaTemplateBdConfigCreate() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "Terraform test BD" + layer2_unknown_unicast = "flood" + layer2_stretch = true + intersite_bum_traffic = true + arp_flooding = true + vrf_name = mso_schema_template_vrf.%[5]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) +} - if !err1 { - return fmt.Errorf("BD %s not found", bdName) - } - if rs1.Primary.ID == "" { - return fmt.Errorf("No Schema id was set") - } +func testAccMSOSchemaTemplateBdConfigUpdateL2UnknownUnicast() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "Terraform test BD" + layer2_unknown_unicast = "proxy" + vrf_name = mso_schema_template_vrf.%[5]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) +} - cont, err := client.GetViaURL("api/v1/schemas/5ea809672c00003bc40a2799") - if err != nil { - return err - } - count, err := cont.ArrayCount("templates") - if err != nil { - return fmt.Errorf("No Template found") - } - tp := TemplateBD{} - found := false - for i := 0; i < count; i++ { - tempCont, err := cont.ArrayElement(i, "templates") - if err != nil { - return err - } - - apiTemplateName := models.StripQuotes(tempCont.S("name").String()) - if apiTemplateName == "Template1" { - bdCount, err := tempCont.ArrayCount("bds") - if err != nil { - return fmt.Errorf("Unable to get BD list") - } - for j := 0; j < bdCount; j++ { - bdCont, err := tempCont.ArrayElement(j, "bds") - if err != nil { - return err - } - apiBD := models.StripQuotes(bdCont.S("name").String()) - if apiBD == "testAccBD" { - tp.display_name = models.StripQuotes(bdCont.S("displayName").String()) - tp.layer2_unknown_unicast = models.StripQuotes(bdCont.S("l2UnknownUnicast").String()) - vrfRef := models.StripQuotes(bdCont.S("vrfRef").String()) - re := regexp.MustCompile("/schemas/(.*)/templates/(.*)/vrfs/(.*)") - match := re.FindStringSubmatch(vrfRef) - tp.vrf_name = match[3] - found = true - break +func testAccMSOSchemaTemplateBdConfigUpdateDescriptionAndL3Multicast() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "Terraform test BD updated" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + vrf_name = mso_schema_template_vrf.%[5]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) +} - } - } - } - } +func testAccMSOSchemaTemplateBdConfigUpdateFloodingFields() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "Terraform test BD updated" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_encap" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = false + intersite_bum_traffic = false + vrf_name = mso_schema_template_vrf.%[5]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) +} - if !found { - return fmt.Errorf("BD not found from API") - } +func testAccMSOSchemaTemplateBdConfigUpdateRemainingAttributes() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "Terraform test BD updated" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_encap" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = false + intersite_bum_traffic = false + arp_flooding = true + unicast_routing = true + optimize_wan_bandwidth = true + virtual_mac_address = "00:00:5E:00:01:01" + ep_move_detection_mode = "garp" + vrf_name = mso_schema_template_vrf.%[5]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) +} - tp1 := &tp +func testAccMSOSchemaTemplateBdConfigRemoveDescription() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_encap" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = false + intersite_bum_traffic = false + arp_flooding = true + unicast_routing = false + optimize_wan_bandwidth = false + virtual_mac_address = "" + ep_move_detection_mode = "none" + vrf_name = mso_schema_template_vrf.%[5]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) +} - *ss = *tp1 - return nil - } +func testAccMSOSchemaTemplateBdConfigWithChildren() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_bd" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = true + intersite_bum_traffic = true + arp_flooding = true + unicast_routing = false + vrf_name = mso_schema_template_vrf.%[5]s.name + }%[6]s`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName, testSchemaTemplateBdSubnetConfig()) } -func testAccCheckMSOSchemaTemplateBDDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*client.Client) +func testAccMSOSchemaTemplateBdConfigWithChildrenUpdateDescription() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "Terraform test BD with children" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_bd" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = true + intersite_bum_traffic = true + arp_flooding = true + unicast_routing = false + vrf_name = mso_schema_template_vrf.%[5]s.name + }%[6]s`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName, testSchemaTemplateBdSubnetConfig()) +} - for _, rs := range s.RootModule().Resources { +func testAccMSOSchemaTemplateBdConfigRemoveChildren() string { + return fmt.Sprintf(`%[1]s + resource "mso_schema_template_bd" "%[2]s" { + schema_id = mso_schema.%[3]s.id + template_name = "%[4]s" + name = "%[2]s" + display_name = "%[2]s" + description = "Terraform test BD with children" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_bd" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = true + intersite_bum_traffic = true + arp_flooding = true + unicast_routing = false + vrf_name = mso_schema_template_vrf.%[5]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) +} - if rs.Type == "mso_schema_template_bd" { - cont, err := client.GetViaURL("api/v1/schemas/5ea809672c00003bc40a2799") - if err != nil { - return nil - } else { - count, err := cont.ArrayCount("templates") - if err != nil { - return fmt.Errorf("No Template found") - } - for i := 0; i < count; i++ { - tempCont, err := cont.ArrayElement(i, "templates") - if err != nil { - return fmt.Errorf("No Template exists") - } - apiTemplateName := models.StripQuotes(tempCont.S("name").String()) - if apiTemplateName == "Template1" { - bdCount, err := tempCont.ArrayCount("bds") - if err != nil { - return fmt.Errorf("Unable to get BD list") - } - for j := 0; j < bdCount; j++ { - bdCont, err := tempCont.ArrayElement(j, "bds") - if err != nil { - return err - } - apiBD := models.StripQuotes(bdCont.S("name").String()) - if apiBD == "testAccBD" { - return fmt.Errorf("template bridge domain still exists.") - } - } - } +func testAccMSOSchemaTemplateBdDhcpPrerequisiteConfig() string { + return fmt.Sprintf(`%[1]s%[2]s%[3]s%[4]s%[5]s`, + testSchemaTemplateAnpConfig(), + testSchemaTemplateAnpEpgConfig(), + testSchemaTemplateVrfConfig(), + testSchemaTemplateExtEpgConfig(), + testTenantPolicyTemplateConfig(), + ) +} - } - } - } +func testAccMSOSchemaTemplateBdDhcpRelayPolicyConfig() string { + return fmt.Sprintf(` +resource "mso_tenant_policies_dhcp_relay_policy" "%[1]s" { + name = "%[1]s" + template_id = mso_template.%[3]s.id + dhcp_relay_providers { + dhcp_server_address = "1.1.1.1" + application_epg_uuid = mso_schema_template_anp_epg.%[4]s.uuid } - return nil } -func testAccCheckMSOSchemaTemplateBDAttributes(layer2_unknown_unicast string, ss *TemplateBD) resource.TestCheckFunc { - return func(s *terraform.State) error { - if layer2_unknown_unicast != ss.layer2_unknown_unicast { - return fmt.Errorf("Bad Template BD layer2_unknown_unicast %s", ss.layer2_unknown_unicast) - } +resource "mso_tenant_policies_dhcp_relay_policy" "%[2]s" { + name = "%[2]s" + template_id = mso_template.%[3]s.id + dhcp_relay_providers { + dhcp_server_address = "2.2.2.2" + application_epg_uuid = mso_schema_template_anp_epg.%[4]s.uuid + } +} +`, msoTenantPoliciesDhcpRelayPolicyName, msoTenantPoliciesDhcpRelayPolicyName2, msoTenantPolicyTemplateName, msoSchemaTemplateAnpEpgName) +} + +func testAccMSOSchemaTemplateBdDhcpOptionPolicyConfig() string { + return fmt.Sprintf(` +resource "mso_tenant_policies_dhcp_option_policy" "%[1]s" { + template_id = mso_template.%[2]s.id + name = "%[1]s" + options { + name = "option_1" + id = 1 + data = "data_1" + } +} +`, msoTenantPoliciesDhcpOptionPolicyName, msoTenantPolicyTemplateName) +} - if "testAcc" != ss.display_name { - return fmt.Errorf("Bad Template BD display name %s", ss.display_name) +func testAccMSOSchemaTemplateBdConfigWithOneDhcpPolicy() string { + return fmt.Sprintf(`%[1]s%[2]s%[3]s%[4]s + resource "mso_schema_template_bd" "%[5]s" { + schema_id = mso_schema.%[6]s.id + template_name = "%[7]s" + name = "%[5]s" + display_name = "%[5]s" + description = "Terraform test BD with children" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_bd" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = true + intersite_bum_traffic = true + arp_flooding = true + unicast_routing = false + vrf_name = mso_schema_template_vrf.%[8]s.name + dhcp_policies { + name = mso_tenant_policies_dhcp_relay_policy.%[9]s.name + dhcp_option_policy_name = mso_tenant_policies_dhcp_option_policy.%[11]s.name } + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), testAccMSOSchemaTemplateBdDhcpPrerequisiteConfig(), testAccMSOSchemaTemplateBdDhcpRelayPolicyConfig(), testAccMSOSchemaTemplateBdDhcpOptionPolicyConfig(), + msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName, + msoTenantPoliciesDhcpRelayPolicyName, msoTenantPoliciesDhcpRelayPolicyName2, msoTenantPoliciesDhcpOptionPolicyName) +} - if "demo" != ss.vrf_name { - return fmt.Errorf("Bad Template BD VRF name %s", ss.vrf_name) +func testAccMSOSchemaTemplateBdConfigWithTwoDhcpPolicies() string { + return fmt.Sprintf(`%[1]s%[2]s%[3]s%[4]s + resource "mso_schema_template_bd" "%[5]s" { + schema_id = mso_schema.%[6]s.id + template_name = "%[7]s" + name = "%[5]s" + display_name = "%[5]s" + description = "Terraform test BD with children" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_bd" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = true + intersite_bum_traffic = true + arp_flooding = true + unicast_routing = false + vrf_name = mso_schema_template_vrf.%[8]s.name + dhcp_policies { + name = mso_tenant_policies_dhcp_relay_policy.%[9]s.name + dhcp_option_policy_name = mso_tenant_policies_dhcp_option_policy.%[11]s.name } - return nil - } + dhcp_policies { + name = mso_tenant_policies_dhcp_relay_policy.%[10]s.name + } + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), testAccMSOSchemaTemplateBdDhcpPrerequisiteConfig(), testAccMSOSchemaTemplateBdDhcpRelayPolicyConfig(), testAccMSOSchemaTemplateBdDhcpOptionPolicyConfig(), + msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName, + msoTenantPoliciesDhcpRelayPolicyName, msoTenantPoliciesDhcpRelayPolicyName2, msoTenantPoliciesDhcpOptionPolicyName) } -type TemplateBD struct { - display_name string - vrf_name string - layer2_unknown_unicast string +func testAccMSOSchemaTemplateBdConfigRemoveDhcpPolicies() string { + return fmt.Sprintf(`%[1]s%[2]s%[3]s%[4]s + resource "mso_schema_template_bd" "%[5]s" { + schema_id = mso_schema.%[6]s.id + template_name = "%[7]s" + name = "%[5]s" + display_name = "%[5]s" + description = "Terraform test BD with children" + layer2_unknown_unicast = "proxy" + layer3_multicast = true + unknown_multicast_flooding = "optimized_flooding" + multi_destination_flooding = "flood_in_bd" + ipv6_unknown_multicast_flooding = "optimized_flooding" + layer2_stretch = true + intersite_bum_traffic = true + arp_flooding = true + unicast_routing = false + vrf_name = mso_schema_template_vrf.%[8]s.name + }`, testAccMSOSchemaTemplateBdPrerequisiteConfig(), testAccMSOSchemaTemplateBdDhcpPrerequisiteConfig(), testAccMSOSchemaTemplateBdDhcpRelayPolicyConfig(), testAccMSOSchemaTemplateBdDhcpOptionPolicyConfig(), + msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) } diff --git a/mso/test_constants.go b/mso/test_constants.go index d6ac91e7..0ec05b82 100644 --- a/mso/test_constants.go +++ b/mso/test_constants.go @@ -31,8 +31,12 @@ var msoSchemaTemplateFilterName = acctest.RandStringFromCharSet(10, acctest.Char var msoSchemaTemplateContractName = acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) var msoSchemaTemplateBdL3MulticastName = acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) var msoSchemaTemplateVrfL3MulticastName = acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) +var msoTenantPoliciesDhcpRelayPolicyName = acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) +var msoTenantPoliciesDhcpRelayPolicyName2 = acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) +var msoTenantPoliciesDhcpOptionPolicyName = acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) const msoSchemaTemplateAnpEpgSubnetIp = "10.0.0.1/24" +const msoSchemaTemplateBdSubnetIp = "10.1.0.1/24" func testSiteConfigAnsibleTest() string { return fmt.Sprintf(` @@ -236,6 +240,19 @@ resource "mso_schema_template_bd" "%[1]s" { `, msoSchemaTemplateBdL3MulticastName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateVrfL3MulticastName) } +func testSchemaTemplateBdSubnetConfig() string { + return fmt.Sprintf(` +resource "mso_schema_template_bd_subnet" "%[1]s_subnet" { + schema_id = mso_schema.%[2]s.id + template_name = "%[3]s" + bd_name = mso_schema_template_bd.%[1]s.name + ip = "%[4]s" + scope = "private" + shared = false +} +`, msoSchemaTemplateBdName, msoSchemaName, msoSchemaTemplateName, msoSchemaTemplateBdSubnetIp) +} + func testSchemaTemplateFilterEntryConfig() string { return fmt.Sprintf(` resource "mso_schema_template_filter_entry" "%[1]s" { From f548fda08779670d2779c4cddd1e8fd6d9d73bd1 Mon Sep 17 00:00:00 2001 From: akinross Date: Sat, 11 Apr 2026 10:30:45 +0200 Subject: [PATCH 3/3] [ignore] add dependency for test removal of relay policies --- mso/resource_mso_schema_template_bd_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/mso/resource_mso_schema_template_bd_test.go b/mso/resource_mso_schema_template_bd_test.go index 56b97410..625df6b7 100644 --- a/mso/resource_mso_schema_template_bd_test.go +++ b/mso/resource_mso_schema_template_bd_test.go @@ -405,6 +405,7 @@ resource "mso_tenant_policies_dhcp_relay_policy" "%[1]s" { } } resource "mso_tenant_policies_dhcp_relay_policy" "%[2]s" { + depends_on = [mso_tenant_policies_dhcp_relay_policy.%[1]s] name = "%[2]s" template_id = mso_template.%[3]s.id dhcp_relay_providers {