diff --git a/examples/tenant_policies_igmp_interface_policy/main.tf b/examples/tenant_policies_igmp_interface_policy/main.tf new file mode 100644 index 00000000..feb8e3e0 --- /dev/null +++ b/examples/tenant_policies_igmp_interface_policy/main.tf @@ -0,0 +1,78 @@ +terraform { + required_providers { + mso = { + source = "CiscoDevNet/mso" + } + } +} + +provider "mso" { + username = "" # + password = "" # + url = "" # + insecure = true +} + +data "mso_tenant" "example_tenant" { + name = "example_tenant" +} + +# tenant template example + +resource "mso_template" "tenant_template" { + template_name = "tenant_template" + template_type = "tenant" + tenant_id = data.mso_tenant.example_tenant.id +} + +resource "mso_tenant_policies_route_map_policy_multicast" "state_limit" { + template_id = mso_template.tenant_template.id + name = "tf_test_state_limit" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } +} + +resource "mso_tenant_policies_route_map_policy_multicast" "report_policy" { + template_id = mso_tenant_policies_route_map_policy_multicast.state_limit.template_id + name = "tf_test_report_policy" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } +} + +resource "mso_tenant_policies_route_map_policy_multicast" "static_report" { + template_id = mso_tenant_policies_route_map_policy_multicast.report_policy.template_id + name = "tf_test_static_report" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } +} + +# tenant policies igmp interface policy example + +resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.tenant_template.id + name = "test_igmp_interface_policy" + description = "With Route Maps" + igmp_version = "v3" + state_limit_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.state_limit.uuid + report_policy_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.report_policy.uuid + static_report_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.static_report.uuid + maximum_multicast_entries = 5000000 +} diff --git a/mso/datasource_mso_tenant_policies_igmp_interface_policy.go b/mso/datasource_mso_tenant_policies_igmp_interface_policy.go new file mode 100644 index 00000000..3341027a --- /dev/null +++ b/mso/datasource_mso_tenant_policies_igmp_interface_policy.go @@ -0,0 +1,150 @@ +package mso + +import ( + "fmt" + "log" + + "github.com/ciscoecosystem/mso-go-client/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func datasourceMSOIGMPInterfacePolicy() *schema.Resource { + return &schema.Resource{ + Read: dataSourceMSOIGMPInterfacePolicyRead, + + Schema: map[string]*schema.Schema{ + "template_id": { + Type: schema.TypeString, + Required: true, + Description: "The ID of the tenant policy template.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the IGMP Interface Policy.", + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the IGMP Interface Policy.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the IGMP Interface Policy.", + }, + "version3_asm": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable IGMP version 3 ASM.", + }, + "fast_leave": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable fast leave.", + }, + "report_link_local_groups": { + Type: schema.TypeBool, + Computed: true, + Description: "Enable or disable reporting link-local groups.", + }, + "igmp_version": { + Type: schema.TypeString, + Computed: true, + Description: "The IGMP version (v2 or v3).", + }, + "group_timeout": { + Type: schema.TypeInt, + Computed: true, + Description: "The group timeout value in seconds.", + }, + "query_interval": { + Type: schema.TypeInt, + Computed: true, + Description: "The query interval value in seconds.", + }, + "query_response_interval": { + Type: schema.TypeInt, + Computed: true, + Description: "The query response interval value in seconds.", + }, + "last_member_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The last member query count value.", + }, + "last_member_response_time": { + Type: schema.TypeInt, + Computed: true, + Description: "The last member query response time value in seconds.", + }, + "startup_query_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The startup query count value.", + }, + "startup_query_interval": { + Type: schema.TypeInt, + Computed: true, + Description: "The startup query interval value in seconds.", + }, + "querier_timeout": { + Type: schema.TypeInt, + Computed: true, + Description: "The querier timeout value in seconds.", + }, + "robustness_variable": { + Type: schema.TypeInt, + Computed: true, + Description: "The robustness variable value.", + }, + "state_limit_route_map_uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the state limit route map policy for multicast.", + }, + "report_policy_route_map_uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the report policy route map for multicast.", + }, + "static_report_route_map_uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the static report route map for multicast.", + }, + "maximum_multicast_entries": { + Type: schema.TypeInt, + Computed: true, + Description: "The maximum multicast entries value.", + }, + "reserved_multicast_entries": { + Type: schema.TypeInt, + Computed: true, + Description: "The reserved multicast entries value.", + }, + }, + } +} + +func dataSourceMSOIGMPInterfacePolicyRead(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] MSO IGMP Interface Policy Data Source - Beginning Read") + msoClient := m.(*client.Client) + + templateId := d.Get("template_id").(string) + policyName := d.Get("name").(string) + + response, err := msoClient.GetViaURL(fmt.Sprintf("api/v1/templates/%s", templateId)) + if err != nil { + return err + } + + policy, err := GetPolicyByName(response, policyName, "tenantPolicyTemplate", "template", "igmpInterfacePolicies") + if err != nil { + return err + } + + setIGMPInterfacePolicyData(d, policy, templateId) + log.Printf("[DEBUG] MSO IGMP Interface Policy Data Source - Read Complete: %v", d.Id()) + return nil +} diff --git a/mso/datasource_mso_tenant_policies_igmp_interface_policy_test.go b/mso/datasource_mso_tenant_policies_igmp_interface_policy_test.go new file mode 100644 index 00000000..1057bac4 --- /dev/null +++ b/mso/datasource_mso_tenant_policies_igmp_interface_policy_test.go @@ -0,0 +1,86 @@ +package mso + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccMSOTenantPoliciesIGMPInterfacePolicyDataSource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + PreConfig: func() { fmt.Println("Test: IGMP Interface Policy Data Source") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyDataSource(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy_max"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "description", "Maximum Values Test"), + resource.TestCheckResourceAttrSet("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "uuid"), + resource.TestCheckResourceAttrSet("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "template_id"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "version3_asm", "true"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "fast_leave", "true"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "report_link_local_groups", "true"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "igmp_version", "v3"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "group_timeout", "65535"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_interval", "18000"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_response_interval", "25"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_count", "5"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_response_time", "25"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_count", "10"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_interval", "18000"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "querier_timeout", "65535"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "robustness_variable", "7"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "maximum_multicast_entries", "4294967295"), + resource.TestCheckResourceAttr("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "reserved_multicast_entries", "4294967295"), + resource.TestCheckResourceAttrSet("data.mso_tenant_policies_igmp_interface_policy.igmp_policy", "static_report_route_map_uuid"), + ), + }, + }, + }) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyDataSource() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_route_map_policy_multicast" "static_report" { + template_id = mso_template.template_tenant.id + name = "test_static_report_route_map" + description = "Static Report Route Map for IGMP" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } + } + + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy_max" + description = "Maximum Values Test" + version3_asm = true + fast_leave = true + report_link_local_groups = true + igmp_version = "v3" + group_timeout = 65535 + query_interval = 18000 + query_response_interval = 25 + last_member_count = 5 + last_member_response_time = 25 + startup_query_count = 10 + startup_query_interval = 18000 + querier_timeout = 65535 + robustness_variable = 7 + maximum_multicast_entries = 4294967295 + reserved_multicast_entries = 4294967295 + static_report_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.static_report.uuid + } + + data "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = mso_tenant_policies_igmp_interface_policy.igmp_policy.name + }`, testAccMSOTemplateResourceTenantConfig()) +} diff --git a/mso/provider.go b/mso/provider.go index 18d1c7ab..6cd1d688 100644 --- a/mso/provider.go +++ b/mso/provider.go @@ -142,6 +142,7 @@ func Provider() terraform.ResourceProvider { "mso_tenant_policies_ipsla_track_list": resourceMSOIPSLATrackList(), "mso_tenant_policies_l3out_interface_routing_policy": resourceMSOL3OutInterfaceRoutingPolicy(), "mso_fabric_policies_interface_setting": resourceMSOInterfaceSetting(), + "mso_tenant_policies_igmp_interface_policy": resourceMSOIGMPInterfacePolicy(), }, DataSourcesMap: map[string]*schema.Resource{ @@ -217,6 +218,7 @@ func Provider() terraform.ResourceProvider { "mso_tenant_policies_ipsla_track_list": datasourceMSOIPSLATrackList(), "mso_tenant_policies_l3out_interface_routing_policy": datasourceMSOL3OutInterfaceRoutingPolicy(), "mso_fabric_policies_interface_setting": datasourceMSOInterfaceSetting(), + "mso_tenant_policies_igmp_interface_policy": datasourceMSOIGMPInterfacePolicy(), }, ConfigureFunc: configureClient, diff --git a/mso/resource_mso_tenant_policies_igmp_interface_policy.go b/mso/resource_mso_tenant_policies_igmp_interface_policy.go new file mode 100644 index 00000000..8746e51e --- /dev/null +++ b/mso/resource_mso_tenant_policies_igmp_interface_policy.go @@ -0,0 +1,590 @@ +package mso + +import ( + "fmt" + "log" + + "github.com/ciscoecosystem/mso-go-client/client" + "github.com/ciscoecosystem/mso-go-client/container" + "github.com/ciscoecosystem/mso-go-client/models" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceMSOIGMPInterfacePolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceMSOIGMPInterfacePolicyCreate, + Read: resourceMSOIGMPInterfacePolicyRead, + Update: resourceMSOIGMPInterfacePolicyUpdate, + Delete: resourceMSOIGMPInterfacePolicyDelete, + Importer: &schema.ResourceImporter{ + State: resourceMSOIGMPInterfacePolicyImport, + }, + + SchemaVersion: 1, + Schema: map[string]*schema.Schema{ + "template_id": { + Type: schema.TypeString, + Required: true, + Description: "The ID of the tenant policy template.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 64), + Description: "The name of the IGMP Interface Policy.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the IGMP Interface Policy.", + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the IGMP Interface Policy.", + }, + "version3_asm": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Enable or disable IGMP version 3 ASM. Default: false (disabled) when unset during creation.", + }, + "fast_leave": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Enable or disable fast leave. Default: false (disabled) when unset during creation.", + }, + "report_link_local_groups": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Enable or disable reporting link-local groups. Default: false (disabled) when unset during creation.", + }, + "igmp_version": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + "v2", "v3", + }, false), + Description: "The IGMP version. Default: v2 when unset during creation.", + }, + "group_timeout": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(3, 65535), + Description: "The group timeout value in seconds. Default: 260 when unset during creation. Range: 3-65535.", + }, + "query_interval": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 18000), + Description: "The query interval value in seconds. Default: 125 when unset during creation. Range: 1-18000.", + }, + "query_response_interval": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 25), + Description: "The query response interval value in seconds. Default: 10 when unset during creation. Range: 1-25.", + }, + "last_member_count": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 5), + Description: "The last member query count value. Default: 2 when unset during creation. Range: 1-5.", + }, + "last_member_response_time": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 25), + Description: "The last member query response time value in seconds. Default: 1 when unset during creation. Range: 1-25.", + }, + "startup_query_count": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 10), + Description: "The startup query count value. Default: 2 when unset during creation. Range: 1-10.", + }, + "startup_query_interval": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 18000), + Description: "The startup query interval value in seconds. Default: 31 when unset during creation. Range: 1-18000.", + }, + "querier_timeout": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 65535), + Description: "The querier timeout value in seconds. Default: 255 when unset during creation. Range: 1-65535.", + }, + "robustness_variable": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 7), + Description: "The robustness variable value. Default: 2 when unset during creation. Range: 1-7.", + }, + "state_limit_route_map_uuid": { + Type: schema.TypeString, + Optional: true, + Description: "The UUID of the state limit route map policy for multicast.", + }, + "report_policy_route_map_uuid": { + Type: schema.TypeString, + Optional: true, + Description: "The UUID of the report policy route map for multicast.", + }, + "static_report_route_map_uuid": { + Type: schema.TypeString, + Optional: true, + Description: "The UUID of the static report route map for multicast.", + }, + "maximum_multicast_entries": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validateUint32Range(1, 4294967295), + Description: "The maximum multicast entries value. Default: 4294967295 when unset during creation. Range: 1-4294967295. Only applicable when state_limit_route_map is configured.", + }, + "reserved_multicast_entries": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validateUint32Range(0, 4294967295), + Description: "The reserved multicast entries value. Default: 0 when unset during creation. Range: 0-4294967295.", + }, + }, + } +} + +func setIGMPInterfacePolicyData(d *schema.ResourceData, response *container.Container, templateId string) error { + d.SetId(fmt.Sprintf("templateId/%s/IGMPInterfacePolicy/%s", templateId, models.StripQuotes(response.S("name").String()))) + d.Set("template_id", templateId) + d.Set("name", models.StripQuotes(response.S("name").String())) + d.Set("description", models.StripQuotes(response.S("description").String())) + d.Set("uuid", models.StripQuotes(response.S("uuid").String())) + + if response.Exists("enableV3Asm") { + if enableV3Asm, ok := response.S("enableV3Asm").Data().(bool); ok { + d.Set("version3_asm", enableV3Asm) + } + } + + if response.Exists("enableFastLeaveControl") { + if fastLeave, ok := response.S("enableFastLeaveControl").Data().(bool); ok { + d.Set("fast_leave", fastLeave) + } + } + + if response.Exists("enableReportLinkLocalGroups") { + if reportLinkLocal, ok := response.S("enableReportLinkLocalGroups").Data().(bool); ok { + d.Set("report_link_local_groups", reportLinkLocal) + } + } + + if response.Exists("igmpQuerierVersion") { + d.Set("igmp_version", models.StripQuotes(response.S("igmpQuerierVersion").String())) + } + if response.Exists("groupTimeout") { + d.Set("group_timeout", int(response.S("groupTimeout").Data().(float64))) + } + if response.Exists("queryInterval") { + d.Set("query_interval", int(response.S("queryInterval").Data().(float64))) + } + if response.Exists("queryResponseInterval") { + d.Set("query_response_interval", int(response.S("queryResponseInterval").Data().(float64))) + } + if response.Exists("lastMemberCount") { + d.Set("last_member_count", int(response.S("lastMemberCount").Data().(float64))) + } + if response.Exists("lastMemberResponseInterval") { + d.Set("last_member_response_time", int(response.S("lastMemberResponseInterval").Data().(float64))) + } + if response.Exists("startQueryCount") { + d.Set("startup_query_count", int(response.S("startQueryCount").Data().(float64))) + } + if response.Exists("startQueryInterval") { + d.Set("startup_query_interval", int(response.S("startQueryInterval").Data().(float64))) + } + if response.Exists("querierTimeout") { + d.Set("querier_timeout", int(response.S("querierTimeout").Data().(float64))) + } + if response.Exists("robustnessFactor") { + d.Set("robustness_variable", int(response.S("robustnessFactor").Data().(float64))) + } + if response.Exists("maximumMulticastEntries") { + d.Set("maximum_multicast_entries", int(response.S("maximumMulticastEntries").Data().(float64))) + } + if response.Exists("reservedMulticastEntries") { + d.Set("reserved_multicast_entries", int(response.S("reservedMulticastEntries").Data().(float64))) + } + + d.Set("state_limit_route_map_uuid", models.StripQuotes(response.S("stateLimitRouteMapRef").String())) + d.Set("report_policy_route_map_uuid", models.StripQuotes(response.S("reportPolicyRouteMapRef").String())) + d.Set("static_report_route_map_uuid", models.StripQuotes(response.S("staticReportRouteMapRef").String())) + + return nil +} + +func resourceMSOIGMPInterfacePolicyImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Beginning Import: %v", d.Id()) + resourceMSOIGMPInterfacePolicyRead(d, m) + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Import Complete: %v", d.Id()) + return []*schema.ResourceData{d}, nil +} + +func resourceMSOIGMPInterfacePolicyCreate(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Beginning Create: %v", d.Id()) + msoClient := m.(*client.Client) + + payload := map[string]interface{}{} + + payload["name"] = d.Get("name").(string) + + if description, ok := d.GetOk("description"); ok { + payload["description"] = description.(string) + } + + if version3Asm, ok := d.GetOk("version3_asm"); ok { + payload["enableV3Asm"] = version3Asm.(bool) + } + + if fastLeave, ok := d.GetOk("fast_leave"); ok { + payload["enableFastLeaveControl"] = fastLeave.(bool) + } + + if reportLinkLocal, ok := d.GetOk("report_link_local_groups"); ok { + payload["enableReportLinkLocalGroups"] = reportLinkLocal.(bool) + } + + if igmpVersion, ok := d.GetOk("igmp_version"); ok { + payload["igmpQuerierVersion"] = igmpVersion.(string) + } + + if groupTimeout, ok := d.GetOk("group_timeout"); ok { + payload["groupTimeout"] = groupTimeout.(int) + } + + if queryInterval, ok := d.GetOk("query_interval"); ok { + payload["queryInterval"] = queryInterval.(int) + } + + if queryResponseInterval, ok := d.GetOk("query_response_interval"); ok { + payload["queryResponseInterval"] = queryResponseInterval.(int) + } + + if lastMemberCount, ok := d.GetOk("last_member_count"); ok { + payload["lastMemberCount"] = lastMemberCount.(int) + } + + if lastMemberResponseTime, ok := d.GetOk("last_member_response_time"); ok { + payload["lastMemberResponseInterval"] = lastMemberResponseTime.(int) + } + + if startupQueryCount, ok := d.GetOk("startup_query_count"); ok { + payload["startQueryCount"] = startupQueryCount.(int) + } + + if startupQueryInterval, ok := d.GetOk("startup_query_interval"); ok { + payload["startQueryInterval"] = startupQueryInterval.(int) + } + + if querierTimeout, ok := d.GetOk("querier_timeout"); ok { + payload["querierTimeout"] = querierTimeout.(int) + } + + if robustnessVariable, ok := d.GetOk("robustness_variable"); ok { + payload["robustnessFactor"] = robustnessVariable.(int) + } + + if maxMulticastEntries, ok := d.GetOk("maximum_multicast_entries"); ok { + payload["maximumMulticastEntries"] = maxMulticastEntries.(int) + } + + if reservedMulticastEntries, ok := d.GetOk("reserved_multicast_entries"); ok { + payload["reservedMulticastEntries"] = reservedMulticastEntries.(int) + } + + if stateLimitUUID, ok := d.GetOk("state_limit_route_map_uuid"); ok { + payload["stateLimitRouteMapRef"] = stateLimitUUID.(string) + } + + if reportPolicyUUID, ok := d.GetOk("report_policy_route_map_uuid"); ok { + payload["reportPolicyRouteMapRef"] = reportPolicyUUID.(string) + } + + if staticReportUUID, ok := d.GetOk("static_report_route_map_uuid"); ok { + payload["staticReportRouteMapRef"] = staticReportUUID.(string) + } + + payloadModel := models.GetPatchPayload("add", "/tenantPolicyTemplate/template/igmpInterfacePolicies/-", payload) + templateId := d.Get("template_id").(string) + + _, err := msoClient.PatchbyID(fmt.Sprintf("api/v1/templates/%s", templateId), payloadModel) + if err != nil { + return err + } + + d.SetId(fmt.Sprintf("templateId/%s/IGMPInterfacePolicy/%s", templateId, d.Get("name").(string))) + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Create Complete: %v", d.Id()) + return resourceMSOIGMPInterfacePolicyRead(d, m) +} + +func resourceMSOIGMPInterfacePolicyRead(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Beginning Read: %v", d.Id()) + msoClient := m.(*client.Client) + + templateId, err := GetTemplateIdFromResourceId(d.Id()) + if err != nil { + return err + } + + response, err := msoClient.GetViaURL(fmt.Sprintf("api/v1/templates/%s", templateId)) + if err != nil { + return err + } + + policyName, err := GetPolicyNameFromResourceId(d.Id(), "IGMPInterfacePolicy") + if err != nil { + return err + } + + policy, err := GetPolicyByName(response, policyName, "tenantPolicyTemplate", "template", "igmpInterfacePolicies") + if err != nil { + return err + } + + setIGMPInterfacePolicyData(d, policy, templateId) + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Read Complete: %v", d.Id()) + return nil +} + +func resourceMSOIGMPInterfacePolicyUpdate(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Beginning Update: %v", d.Id()) + msoClient := m.(*client.Client) + templateId := d.Get("template_id").(string) + + templateCont, err := msoClient.GetViaURL(fmt.Sprintf("api/v1/templates/%s", templateId)) + if err != nil { + return err + } + + policyIndex, err := GetPolicyIndexByKeyAndValue(templateCont, "uuid", d.Get("uuid").(string), "tenantPolicyTemplate", "template", "igmpInterfacePolicies") + if err != nil { + return err + } + + updatePath := fmt.Sprintf("/tenantPolicyTemplate/template/igmpInterfacePolicies/%d", policyIndex) + + payloadCont := container.New() + payloadCont.Array() + + if d.HasChange("name") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/name", updatePath), d.Get("name").(string)) + if err != nil { + return err + } + } + + if d.HasChange("description") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/description", updatePath), d.Get("description").(string)) + if err != nil { + return err + } + } + + if d.HasChange("version3_asm") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/enableV3Asm", updatePath), d.Get("version3_asm").(bool)) + if err != nil { + return err + } + } + + if d.HasChange("fast_leave") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/enableFastLeaveControl", updatePath), d.Get("fast_leave").(bool)) + if err != nil { + return err + } + } + + if d.HasChange("report_link_local_groups") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/enableReportLinkLocalGroups", updatePath), d.Get("report_link_local_groups").(bool)) + if err != nil { + return err + } + } + + if d.HasChange("igmp_version") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/igmpQuerierVersion", updatePath), d.Get("igmp_version").(string)) + if err != nil { + return err + } + } + + if d.HasChange("group_timeout") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/groupTimeout", updatePath), d.Get("group_timeout").(int)) + if err != nil { + return err + } + } + + if d.HasChange("query_interval") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/queryInterval", updatePath), d.Get("query_interval").(int)) + if err != nil { + return err + } + } + + if d.HasChange("query_response_interval") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/queryResponseInterval", updatePath), d.Get("query_response_interval").(int)) + if err != nil { + return err + } + } + + if d.HasChange("last_member_count") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/lastMemberCount", updatePath), d.Get("last_member_count").(int)) + if err != nil { + return err + } + } + + if d.HasChange("last_member_response_time") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/lastMemberResponseInterval", updatePath), d.Get("last_member_response_time").(int)) + if err != nil { + return err + } + } + + if d.HasChange("startup_query_count") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/startQueryCount", updatePath), d.Get("startup_query_count").(int)) + if err != nil { + return err + } + } + + if d.HasChange("startup_query_interval") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/startQueryInterval", updatePath), d.Get("startup_query_interval").(int)) + if err != nil { + return err + } + } + + if d.HasChange("querier_timeout") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/querierTimeout", updatePath), d.Get("querier_timeout").(int)) + if err != nil { + return err + } + } + + if d.HasChange("robustness_variable") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/robustnessFactor", updatePath), d.Get("robustness_variable").(int)) + if err != nil { + return err + } + } + + if d.HasChange("maximum_multicast_entries") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/maximumMulticastEntries", updatePath), d.Get("maximum_multicast_entries").(int)) + if err != nil { + return err + } + } + + if d.HasChange("reserved_multicast_entries") { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/reservedMulticastEntries", updatePath), d.Get("reserved_multicast_entries").(int)) + if err != nil { + return err + } + } + + if d.HasChange("state_limit_route_map_uuid") { + uuid := d.Get("state_limit_route_map_uuid").(string) + if uuid != "" { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/stateLimitRouteMapRef", updatePath), uuid) + if err != nil { + return err + } + } else { + err := addPatchPayloadToContainer(payloadCont, "remove", fmt.Sprintf("%s/stateLimitRouteMapRef", updatePath), nil) + if err != nil { + return err + } + } + } + + if d.HasChange("report_policy_route_map_uuid") { + uuid := d.Get("report_policy_route_map_uuid").(string) + if uuid != "" { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/reportPolicyRouteMapRef", updatePath), uuid) + if err != nil { + return err + } + } else { + err := addPatchPayloadToContainer(payloadCont, "remove", fmt.Sprintf("%s/reportPolicyRouteMapRef", updatePath), nil) + if err != nil { + return err + } + } + } + + if d.HasChange("static_report_route_map_uuid") { + uuid := d.Get("static_report_route_map_uuid").(string) + if uuid != "" { + err := addPatchPayloadToContainer(payloadCont, "replace", fmt.Sprintf("%s/staticReportRouteMapRef", updatePath), uuid) + if err != nil { + return err + } + } else { + err := addPatchPayloadToContainer(payloadCont, "remove", fmt.Sprintf("%s/staticReportRouteMapRef", updatePath), nil) + if err != nil { + return err + } + } + } + err = doPatchRequest(msoClient, fmt.Sprintf("api/v1/templates/%s", templateId), payloadCont) + if err != nil { + return err + } + + d.SetId(fmt.Sprintf("templateId/%s/IGMPInterfacePolicy/%s", templateId, d.Get("name").(string))) + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Update Complete: %v", d.Id()) + return resourceMSOIGMPInterfacePolicyRead(d, m) +} + +func resourceMSOIGMPInterfacePolicyDelete(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Beginning Delete: %v", d.Id()) + msoClient := m.(*client.Client) + + templateId := d.Get("template_id").(string) + templateCont, err := msoClient.GetViaURL(fmt.Sprintf("api/v1/templates/%s", templateId)) + if err != nil { + return err + } + + policyIndex, err := GetPolicyIndexByKeyAndValue(templateCont, "uuid", d.Get("uuid").(string), "tenantPolicyTemplate", "template", "igmpInterfacePolicies") + if err != nil { + return err + } + + payloadModel := models.GetRemovePatchPayload(fmt.Sprintf("/tenantPolicyTemplate/template/igmpInterfacePolicies/%d", policyIndex)) + + _, err = msoClient.PatchbyID(fmt.Sprintf("api/v1/templates/%s", templateId), payloadModel) + if err != nil { + return err + } + + d.SetId("") + log.Printf("[DEBUG] MSO IGMP Interface Policy Resource - Delete Complete: %v", d.Id()) + return nil +} diff --git a/mso/resource_mso_tenant_policies_igmp_interface_policy_test.go b/mso/resource_mso_tenant_policies_igmp_interface_policy_test.go new file mode 100644 index 00000000..c3d432f0 --- /dev/null +++ b/mso/resource_mso_tenant_policies_igmp_interface_policy_test.go @@ -0,0 +1,370 @@ +package mso + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccMSOTenantPoliciesIGMPInterfacePolicyResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + PreConfig: func() { fmt.Println("Test: Create IGMP Interface Policy") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigCreate(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "description", "Test IGMP Interface Policy"), + resource.TestCheckResourceAttrSet("mso_tenant_policies_igmp_interface_policy.igmp_policy", "uuid"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "version3_asm", "true"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "fast_leave", "true"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "report_link_local_groups", "true"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "igmp_version", "v3"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "group_timeout", "300"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_interval", "125"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_response_interval", "10"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_count", "2"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_response_time", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_count", "2"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_interval", "31"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "querier_timeout", "255"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "robustness_variable", "2"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "maximum_multicast_entries", "1000000"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "reserved_multicast_entries", "100000"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update IGMP Interface Policy - Change to v2") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateV2(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "description", "Updated to IGMP v2"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "version3_asm", "false"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "fast_leave", "false"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "report_link_local_groups", "false"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "igmp_version", "v2"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "group_timeout", "260"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_interval", "100"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update IGMP Interface Policy - With Route Maps") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateWithRouteMaps(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy"), + resource.TestCheckResourceAttrSet("mso_tenant_policies_igmp_interface_policy.igmp_policy", "state_limit_route_map_uuid"), + resource.TestCheckResourceAttrSet("mso_tenant_policies_igmp_interface_policy.igmp_policy", "report_policy_route_map_uuid"), + resource.TestCheckResourceAttrSet("mso_tenant_policies_igmp_interface_policy.igmp_policy", "static_report_route_map_uuid"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update IGMP Interface Policy - Remove Route Maps") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateRemoveRouteMaps(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "state_limit_route_map_uuid", ""), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "report_policy_route_map_uuid", ""), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "static_report_route_map_uuid", ""), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update IGMP Interface Policy - Change Timer Values") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateTimers(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "group_timeout", "500"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_interval", "200"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_response_interval", "15"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_count", "3"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_response_time", "2"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_count", "5"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_interval", "50"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "querier_timeout", "300"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "robustness_variable", "3"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update IGMP Interface Policy - Maximum Values") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateMaxValues(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy_max"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "group_timeout", "65535"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_interval", "18000"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_response_interval", "25"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_count", "5"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_response_time", "25"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_count", "10"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_interval", "18000"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "querier_timeout", "65535"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "robustness_variable", "7"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "maximum_multicast_entries", "4294967295"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "reserved_multicast_entries", "4294967295"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update IGMP Interface Policy - Minimum Values") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateMinValues(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy_min"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "group_timeout", "3"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_interval", "2"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "query_response_interval", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_count", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "last_member_response_time", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_count", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "startup_query_interval", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "querier_timeout", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "robustness_variable", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "maximum_multicast_entries", "1"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "reserved_multicast_entries", "0"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Update IGMP Interface Policy Name with UUID") }, + Config: testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateName(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "name", "test_igmp_interface_policy_renamed"), + resource.TestCheckResourceAttr("mso_tenant_policies_igmp_interface_policy.igmp_policy", "description", "Renamed Policy"), + ), + }, + { + PreConfig: func() { fmt.Println("Test: Import IGMP Interface Policy") }, + ResourceName: "mso_tenant_policies_igmp_interface_policy.igmp_policy", + ImportState: true, + ImportStateVerify: true, + }, + }, + CheckDestroy: testCheckResourceDestroyPolicyWithArguments("mso_tenant_policies_igmp_interface_policy", "igmpInterface"), + }) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigCreate() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy" + description = "Test IGMP Interface Policy" + version3_asm = true + fast_leave = true + report_link_local_groups = true + igmp_version = "v3" + group_timeout = 300 + query_interval = 125 + query_response_interval = 10 + last_member_count = 2 + last_member_response_time = 1 + startup_query_count = 2 + startup_query_interval = 31 + querier_timeout = 255 + robustness_variable = 2 + maximum_multicast_entries = 1000000 + reserved_multicast_entries = 100000 + }`, testAccMSOTemplateResourceTenantConfig()) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateV2() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy" + description = "Updated to IGMP v2" + version3_asm = false + fast_leave = false + report_link_local_groups = false + igmp_version = "v2" + group_timeout = 260 + query_interval = 100 + query_response_interval = 10 + last_member_count = 2 + last_member_response_time = 1 + startup_query_count = 2 + startup_query_interval = 31 + querier_timeout = 255 + robustness_variable = 2 + }`, testAccMSOTemplateResourceTenantConfig()) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateWithRouteMaps() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_route_map_policy_multicast" "state_limit" { + template_id = mso_template.template_tenant.id + name = "tf_test_state_limit" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } + } + + resource "mso_tenant_policies_route_map_policy_multicast" "report_policy" { + template_id = mso_tenant_policies_route_map_policy_multicast.state_limit.template_id + name = "tf_test_report_policy" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } + } + + resource "mso_tenant_policies_route_map_policy_multicast" "static_report" { + template_id = mso_tenant_policies_route_map_policy_multicast.report_policy.template_id + name = "tf_test_static_report" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } + } + + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy" + description = "With Route Maps" + igmp_version = "v3" + state_limit_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.state_limit.uuid + report_policy_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.report_policy.uuid + static_report_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.static_report.uuid + maximum_multicast_entries = 5000000 + }`, testAccMSOTemplateResourceTenantConfig()) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateRemoveRouteMaps() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_route_map_policy_multicast" "state_limit" { + template_id = mso_template.template_tenant.id + name = "tf_test_state_limit" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } + } + + resource "mso_tenant_policies_route_map_policy_multicast" "report_policy" { + template_id = mso_tenant_policies_route_map_policy_multicast.state_limit.template_id + name = "tf_test_report_policy" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } + } + + resource "mso_tenant_policies_route_map_policy_multicast" "static_report" { + template_id = mso_tenant_policies_route_map_policy_multicast.report_policy.template_id + name = "tf_test_static_report" + description = "Terraform test Route Map Policy for Multicast" + route_map_multicast_entries { + order = 1 + group_ip = "226.2.2.2/8" + source_ip = "1.1.1.1/1" + rendezvous_point_ip = "1.1.1.2" + action = "permit" + } + } + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy" + description = "Route Maps Removed" + igmp_version = "v3" + state_limit_route_map_uuid = "" + report_policy_route_map_uuid = "" + static_report_route_map_uuid = "" + }`, testAccMSOTemplateResourceTenantConfig()) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateTimers() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy" + description = "Updated Timers" + igmp_version = "v3" + group_timeout = 500 + query_interval = 200 + query_response_interval = 15 + last_member_count = 3 + last_member_response_time = 2 + startup_query_count = 5 + startup_query_interval = 50 + querier_timeout = 300 + robustness_variable = 3 + }`, testAccMSOTemplateResourceTenantConfig()) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateMaxValues() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy_max" + description = "Maximum Values Test" + version3_asm = true + fast_leave = true + report_link_local_groups = true + igmp_version = "v3" + group_timeout = 65535 + query_interval = 18000 + query_response_interval = 25 + last_member_count = 5 + last_member_response_time = 25 + startup_query_count = 10 + startup_query_interval = 18000 + querier_timeout = 65535 + robustness_variable = 7 + maximum_multicast_entries = 4294967295 + reserved_multicast_entries = 4294967295 + }`, testAccMSOTemplateResourceTenantConfig()) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateMinValues() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy_min" + description = "Minimum Values Test" + version3_asm = false + fast_leave = false + report_link_local_groups = false + igmp_version = "v2" + group_timeout = 3 + query_interval = 2 + query_response_interval = 1 + last_member_count = 1 + last_member_response_time = 1 + startup_query_count = 1 + startup_query_interval = 1 + querier_timeout = 1 + robustness_variable = 1 + maximum_multicast_entries = 1 + reserved_multicast_entries = 0 + }`, testAccMSOTemplateResourceTenantConfig()) +} + +func testAccMSOTenantPoliciesIGMPInterfacePolicyConfigUpdateName() string { + return fmt.Sprintf(`%s + resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy_renamed" + description = "Renamed Policy" + igmp_version = "v3" + group_timeout = 300 + }`, testAccMSOTemplateResourceTenantConfig()) +} diff --git a/mso/utils.go b/mso/utils.go index 7fc0678c..70afd847 100644 --- a/mso/utils.go +++ b/mso/utils.go @@ -540,3 +540,29 @@ func GetDeployedSiteIdsForApplicationTemplate(msoClient *client.Client, schemaId } return siteIds, nil } + +// validateUint32Range is a validation function that checks if an integer +// is within the specified uint32 range. This approach avoids compile-time overflow +// errors on 32-bit systems by storing boundaries as uint32 and performing runtime +// validation using int64 comparisons. +// This validation is done in CI. +func validateUint32Range(min, max uint32) schema.SchemaValidateFunc { + minInt64 := int64(min) + maxInt64 := int64(max) + + return func(i interface{}, k string) ([]string, []error) { + v, ok := i.(int) + if !ok { + return nil, []error{fmt.Errorf("expected type of %s to be int", k)} + } + + val := int64(v) + if val < minInt64 || val > maxInt64 { + return nil, []error{ + fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v), + } + } + + return nil, nil + } +} diff --git a/website/docs/d/tenant_policies_igmp_interface_policy.html.markdown b/website/docs/d/tenant_policies_igmp_interface_policy.html.markdown new file mode 100644 index 00000000..57320bd9 --- /dev/null +++ b/website/docs/d/tenant_policies_igmp_interface_policy.html.markdown @@ -0,0 +1,53 @@ +--- +layout: "mso" +page_title: "MSO: mso_tenant_policies_igmp_interface_policy" +sidebar_current: "docs-mso-data-source-tenant_policies_igmp_interface_policy" +description: |- + Data source for IGMP Interface Policy. +--- + +# mso_tenant_policies_igmp_interface_policy # + +Data source for Internet Group Management Protocol (IGMP) Interface Policy. This data source is supported in NDO v4.3 and higher. + +## GUI Information ## + +* `Location` - Manage -> Tenant Template -> Tenant Policies -> IGMP Interface Policy + +## Example Usage ## + +```hcl +data "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy" +} +``` + +## Argument Reference ## + +* `template_id` - (Required) The unique ID of the tenant policy template. +* `name` - (Required) The name of the IGMP Interface Policy to retrieve. + +## Attribute Reference ## + +* `uuid` - (Read-Only) The NDO UUID of the IGMP Interface Policy. +* `id` - (Read-Only) The unique terraform identifier of the IGMP Interface Policy in the template. +* `description` - (Read-Only) The description of the IGMP Interface Policy. +* `version3_asm`- (Read-Only) Enable or disable IGMP version 3 Any-Source Multicast (ASM). +* `fast_leave` - (Read-Only) Enable or disable fast leave processing. When enabled, the interface immediately removes the group entry upon receiving an IGMP leave message. +* `report_link_local_groups` - (Read-Only) Enable or disable reporting of link-local multicast groups. +* `igmp_version` - (Read-Only) The IGMP protocol version to use on the interface. +* `group_timeout` - (Read-Only) The time in seconds before a multicast group is removed if no IGMP reports are received. +* `query_interval` - (Read-Only) The interval in seconds between IGMP general query messages sent by the querier. +* `query_response_interval` - (Read-Only) The maximum time in seconds that hosts can wait before responding to an IGMP query. +* `last_member_count` - (Read-Only) The number of group-specific queries sent before the router assumes there are no local members. +* `last_member_response_time` - (Read-Only) The maximum time in seconds to wait for a response to a group-specific query before removing the group. +* `startup_query_count` - (Read-Only) The number of queries sent at startup separated by the startup query interval. +* `startup_query_interval` - (Read-Only) The interval in seconds between general queries sent at startup. +* `querier_timeout` - (Read-Only) The time in seconds before a router considers the IGMP querier to be down. +* `robustness_variable` - (Read-Only) Allows tuning for expected packet loss. Higher values provide more robustness but increase recovery time. +* `state_limit_route_map_uuid` - (Read-Only) The NDO UUID of the route map policy for multicast that controls which multicast groups can be joined. +* `report_policy_route_map_uuid` - (Read-Only) The NDO UUID of the route map policy for multicast that filters IGMP reports. +* `static_report_route_map_uuid` - (Read-Only) The NDO UUID of the route map policy for multicast that defines static multicast group memberships. +* `maximum_multicast_entries` - (Read-Only) The maximum number of multicast route entries allowed. +* `reserved_multicast_entries` - (Read-Only) The number of multicast entries reserved and guaranteed for this policy. diff --git a/website/docs/r/tenant_policies_igmp_interface_policy.html.markdown b/website/docs/r/tenant_policies_igmp_interface_policy.html.markdown new file mode 100644 index 00000000..c0bc858a --- /dev/null +++ b/website/docs/r/tenant_policies_igmp_interface_policy.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "mso" +page_title: "MSO: mso_tenant_policies_igmp_interface_policy" +sidebar_current: "docs-mso-resource-tenant_policies_igmp_interface_policy" +description: |- + Manages IGMP Interface Policies on Cisco Nexus Dashboard Orchestrator (NDO) +--- + +# mso_tenant_policies_igmp_interface_policy # + +Manages Internet Group Management Protocol (IGMP) Interface Policies on Cisco Nexus Dashboard Orchestrator (NDO). This resource is supported in NDO v4.3 and higher. + +## GUI Information ## + +* `Location` - Manage -> Tenant Template -> Tenant Policies -> IGMP Interface Policy + +## Example Usage ## + +```hcl +resource "mso_tenant_policies_igmp_interface_policy" "igmp_policy" { + template_id = mso_template.template_tenant.id + name = "test_igmp_interface_policy" + description = "Test IGMP Interface Policy" + version3_asm = true + fast_leave = true + report_link_local_groups = true + igmp_version = "v3" + group_timeout = 300 + query_interval = 125 + query_response_interval = 10 + last_member_count = 2 + last_member_response_time = 1 + startup_query_count = 2 + startup_query_interval = 31 + querier_timeout = 255 + robustness_variable = 2 + state_limit_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.state_limit.uuid + report_policy_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.report_policy.uuid + static_report_route_map_uuid = mso_tenant_policies_route_map_policy_multicast.static_report.uuid +} +``` + +## Argument Reference ## + +* `template_id` - (Required) The unique ID of the tenant policy template. +* `name` - (Required) The name of the IGMP Interface Policy. +* `description` - (Optional) The description of the IGMP Interface Policy. When unset during creation, no description is applied. +* `version3_asm`- (Optional) Enable or disable IGMP version 3 Any-Source Multicast (ASM). Default: `false` (disabled) when unset during creation. +* `fast_leave` - (Optional) Enable or disable fast leave processing. When enabled, the interface immediately removes the group entry upon receiving an IGMP leave message. Default: `false` (disabled) when unset during creation. +* `report_link_local_groups` - (Optional) Enable or disable reporting of link-local multicast groups. Default: `false` (disabled) when unset during creation. +* `igmp_version` - (Optional) The IGMP protocol version to use on the interface. Default: `v2` when unset during creation. Valid values: `v2`, `v3`. +* `group_timeout` - (Optional) The time in seconds before a multicast group is removed if no IGMP reports are received. Default: 260 when unset during creation. Valid range: 3-65535 seconds. +* `query_interval` - (Optional) The interval in seconds between IGMP general query messages sent by the querier. Default: 125 when unset during creation. Valid range: 1-18000 seconds. +* `query_response_interval` - (Optional) The maximum time in seconds that hosts can wait before responding to an IGMP query. Default: 10 when unset during creation. Valid range: 1-25 seconds. +* `last_member_count` - (Optional) The number of group-specific queries sent before the router assumes there are no local members. Default: 2 when unset during creation. Valid range: 1-5. +* `last_member_response_time` - (Optional) The maximum time in seconds to wait for a response to a group-specific query before removing the group. Default: 1 when unset during creation. Valid range: 1-25 seconds. +* `startup_query_count` - (Optional) The number of queries sent at startup separated by the startup query interval. Default: 2 when unset during creation. Valid range: 1-10. +* `startup_query_interval` - (Optional) The interval in seconds between general queries sent at startup. Default: 31 when unset during creation. Valid range: 1-18000 seconds. +* `querier_timeout` - (Optional) The time in seconds before a router considers the IGMP querier to be down. Default: 255 when unset during creation. Valid range: 1-65535 seconds. +* `robustness_variable` - (Optional) Allows tuning for expected packet loss. Higher values provide more robustness but increase recovery time. Default: 2 when unset during creation. Valid range: 1-7. +* `state_limit_route_map_uuid` - (Optional) The NDO UUID of the route map policy for multicast that controls which multicast groups can be joined. +* `report_policy_route_map_uuid` - (Optional) The NDO UUID of the route map policy for multicast that filters IGMP reports. +* `static_report_route_map_uuid` - (Optional) The NDO UUID of the route map policy for multicast that defines static multicast group memberships. +* `maximum_multicast_entries` - (Optional) The maximum number of multicast route entries allowed. Default: 4294967295 when unset during creation. Valid range: 1-4294967295. Note: This parameter is only applicable when state_limit_route_map_uuid is configured. +* `reserved_multicast_entries` - (Optional) The number of multicast entries reserved and guaranteed for this policy. Default: 0 when unset during creation. Valid range: 0-4294967295. + +## Attribute Reference ## + +* `uuid` - The NDO UUID of the IGMP Interface Policy. +* `id` - The unique terraform identifier of the IGMP Interface Policy in the template. + +## Importing ## + +An existing MSO IGMP Interface Policy can be [imported][docs-import] into this resource via its ID/path, via the following command: [docs-import]: https://www.terraform.io/docs/import/index.html + + +```bash +terraform import mso_tenant_policies_igmp_interface_policy.igmp_policy templateId/{template_id}/IGMPInterfacePolicy/{name} +```