From 4fcf175eda78f27a04e9e52350dfc65fb51e8ecf Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Thu, 27 Jul 2023 01:37:49 +0530 Subject: [PATCH] [bugfix] Fix DHCP Policies issue in mso_schema_template_bd on NDO 4.1+ (#230) --- go.mod | 4 +- go.sum | 4 +- mso/resource_mso_schema_template_bd.go | 281 ++++++++++++------ .../mso-go-client/client/client_service.go | 4 +- .../mso-go-client/client/template_service.go | 172 +++++++++++ vendor/modules.txt | 2 +- 6 files changed, 366 insertions(+), 101 deletions(-) create mode 100644 vendor/github.com/ciscoecosystem/mso-go-client/client/template_service.go diff --git a/go.mod b/go.mod index a0cf6453..81084a7a 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,6 @@ module github.com/terraform-providers/terraform-provider-mso go 1.13 require ( - github.com/ciscoecosystem/mso-go-client v1.18.1 - github.com/hashicorp/go-version v1.6.0 // indirect + github.com/ciscoecosystem/mso-go-client v1.19.0 github.com/hashicorp/terraform-plugin-sdk v1.17.1 - github.com/zclconf/go-cty v1.8.1 // indirect ) diff --git a/go.sum b/go.sum index 17507de8..82383fd3 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXH github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/ciscoecosystem/mso-go-client v1.18.1 h1:z/Uc4hOFkoPytSYul5wDFDXH/lcJgYxeQJHnU4a1pC8= -github.com/ciscoecosystem/mso-go-client v1.18.1/go.mod h1:swAjH8WZGE4eeKpsNE4DtNzOdREFXI8SkerdbrXwZac= +github.com/ciscoecosystem/mso-go-client v1.19.0 h1:XsaBxNZDiDPx6lD6WPK48GWQIMo615u0HJKGm6IlL54= +github.com/ciscoecosystem/mso-go-client v1.19.0/go.mod h1:swAjH8WZGE4eeKpsNE4DtNzOdREFXI8SkerdbrXwZac= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/mso/resource_mso_schema_template_bd.go b/mso/resource_mso_schema_template_bd.go index fa66bece..0159f4eb 100644 --- a/mso/resource_mso_schema_template_bd.go +++ b/mso/resource_mso_schema_template_bd.go @@ -1,7 +1,6 @@ package mso import ( - "errors" "fmt" "log" "regexp" @@ -9,6 +8,7 @@ import ( "strings" "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" @@ -141,10 +141,11 @@ func resourceMSOTemplateBD() *schema.Resource { Computed: true, }, "dhcp_policy": &schema.Schema{ - Type: schema.TypeMap, - Optional: true, - Description: "Configure dhcp policy in versions before NDO 3.2", - Computed: true, + Type: schema.TypeMap, + Optional: true, + Description: "Configure dhcp policy in versions before NDO 3.2", + Computed: true, + ConflictsWith: []string{"dhcp_policies"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": &schema.Schema{ @@ -171,9 +172,10 @@ func resourceMSOTemplateBD() *schema.Resource { }, }, "dhcp_policies": &schema.Schema{ - Type: schema.TypeSet, - Optional: true, - Description: "Configure dhcp policies in versions NDO 3.2 and higher", + Type: schema.TypeSet, + Optional: true, + Description: "Configure dhcp policies in versions NDO 3.2 and higher", + ConflictsWith: []string{"dhcp_policy"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": &schema.Schema{ @@ -199,15 +201,6 @@ func resourceMSOTemplateBD() *schema.Resource { }, }, }), - CustomizeDiff: func(diff *schema.ResourceDiff, v interface{}) error { - // Plan time validation. - _, policy_ok := diff.GetOk("dhcp_policy") - _, policies_ok := diff.GetOk("dhcp_policies") - if policy_ok && policies_ok { - return errors.New(`"dhcp_policy" and "dhcp_policies" cannot be provided in the same resource.`) - } - return nil - }, } } @@ -226,6 +219,12 @@ func resourceMSOTemplateBDImport(d *schema.ResourceData, m interface{}) ([]*sche return nil, fmt.Errorf("No Template found") } stateTemplate := get_attribute[2] + + versionInt, err := msoClient.CompareVersion("4.0.0.0") + if err != nil { + return nil, err + } + found := false stateBD := get_attribute[4] for i := 0; i < count; i++ { @@ -234,7 +233,6 @@ func resourceMSOTemplateBDImport(d *schema.ResourceData, m interface{}) ([]*sche return nil, err } apiTemplate := models.StripQuotes(tempCont.S("name").String()) - if apiTemplate == stateTemplate { bdCount, err := tempCont.ArrayCount("bds") if err != nil { @@ -320,35 +318,42 @@ func resourceMSOTemplateBDImport(d *schema.ResourceData, m interface{}) ([]*sche } else { dhcpCount = 0 } - if dhcpCount != 0 { - for l := 0; l < dhcpCount; l++ { - dhcpPolicy, err := bdCont.ArrayElement(l, "dhcpLabels") - if err != nil { - return nil, err - } - dhcpPolicyMap := make(map[string]interface{}) - dhcpPolicyMap["name"] = models.StripQuotes(dhcpPolicy.S("name").String()) - version, err := strconv.Atoi(models.StripQuotes(dhcpPolicy.S("version").String())) - if err != nil { - return nil, err + if versionInt == -1 { + dhcpPoliciesNameList, error := getDHCPPolicesNameByRef(dhcpCount, schemaId, stateTemplate, bdCont, msoClient) + if error != nil { + return nil, error } - dhcpPolicyMap["version"] = version - if dhcpPolicy.Exists("dhcpOptionLabel") { - dhcpPolicyMap["dhcp_option_policy_name"] = models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "name").String()) - version, err := strconv.Atoi(models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "version").String())) + dhcpPoliciesList = dhcpPoliciesNameList + } else { + for l := 0; l < dhcpCount; l++ { + dhcpPolicy, err := bdCont.ArrayElement(l, "dhcpLabels") if err != nil { return nil, err } - dhcpPolicyMap["dhcp_option_policy_version"] = version - if dhcpPolicyMap["dhcp_option_policy_name"] == "{}" { - dhcpPolicyMap["dhcp_option_policy_name"] = nil + dhcpPolicyMap := make(map[string]interface{}) + dhcpPolicyMap["name"] = models.StripQuotes(dhcpPolicy.S("name").String()) + version, err := strconv.Atoi(models.StripQuotes(dhcpPolicy.S("version").String())) + if err != nil { + return nil, err } - if dhcpPolicyMap["dhcp_option_policy_version"] == "{}" { - dhcpPolicyMap["dhcp_option_policy_version"] = nil + dhcpPolicyMap["version"] = version + if dhcpPolicy.Exists("dhcpOptionLabel") { + dhcpPolicyMap["dhcp_option_policy_name"] = models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "name").String()) + version, err := strconv.Atoi(models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "version").String())) + if err != nil { + return nil, err + } + dhcpPolicyMap["dhcp_option_policy_version"] = version + if dhcpPolicyMap["dhcp_option_policy_name"] == "{}" { + dhcpPolicyMap["dhcp_option_policy_name"] = nil + } + if dhcpPolicyMap["dhcp_option_policy_version"] == "{}" { + dhcpPolicyMap["dhcp_option_policy_version"] = nil + } } + dhcpPoliciesList = append(dhcpPoliciesList, dhcpPolicyMap) } - dhcpPoliciesList = append(dhcpPoliciesList, dhcpPolicyMap) } } else { if bdCont.Exists("dhcpLabel") { @@ -374,19 +379,14 @@ func resourceMSOTemplateBDImport(d *schema.ResourceData, m interface{}) ([]*sche found = true break } - } } - } - if !found { d.SetId("") } - log.Printf("[DEBUG] %s: Import finished successfully", d.Id()) return []*schema.ResourceData{d}, nil - } func resourceMSOTemplateBDCreate(d *schema.ResourceData, m interface{}) error { @@ -400,6 +400,11 @@ func resourceMSOTemplateBDCreate(d *schema.ResourceData, m interface{}) error { templateName := d.Get("template_name").(string) vrfName := d.Get("vrf_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, ipv6_unknown_multicast_flooding, multi_destination_flooding, unknown_multicast_flooding string @@ -479,22 +484,30 @@ func resourceMSOTemplateBDCreate(d *schema.ResourceData, m interface{}) error { dhcpPolList := make([]interface{}, 0) if dhcpPolicies, ok := d.GetOk("dhcp_policies"); ok { - 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"] + 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 } - dhcpPolicyMap["dhcpOptionLabel"] = dhcpOptionMap + dhcpPolList = append(dhcpPolList, dhcpPolicyMap) } - dhcpPolList = append(dhcpPolList, dhcpPolicyMap) } } else { dhcpPolList = nil @@ -506,7 +519,7 @@ func resourceMSOTemplateBDCreate(d *schema.ResourceData, m interface{}) error { vrfRefMap["vrfName"] = vrfName path := fmt.Sprintf("/templates/%s/bds/-", templateName) bdStruct := models.NewTemplateBD("add", path, name, displayName, layer2_unknown_unicast, unknown_multicast_flooding, multi_destination_flooding, ipv6_unknown_multicast_flooding, virtual_mac_address, description, intersite_bum_traffic, optimize_wan_bandwidth, layer2_stretch, layer3_multicast, arp_flooding, unicast_routing, vrfRefMap, dhcpPolMap, dhcpPolList) - _, err := msoClient.PatchbyID(fmt.Sprintf("api/v1/schemas/%s", schemaID), bdStruct) + _, err = msoClient.PatchbyID(fmt.Sprintf("api/v1/schemas/%s", schemaID), bdStruct) if err != nil { return err @@ -533,6 +546,12 @@ func resourceMSOTemplateBDRead(d *schema.ResourceData, m interface{}) error { stateTemplate := d.Get("template_name").(string) found := false stateBD := d.Get("name") + + versionInt, err := msoClient.CompareVersion("4.0.0.0") + if err != nil { + return err + } + for i := 0; i < count; i++ { tempCont, err := cont.ArrayElement(i, "templates") if err != nil { @@ -630,30 +649,38 @@ func resourceMSOTemplateBDRead(d *schema.ResourceData, m interface{}) error { } if dhcpCount != 0 { - for l := 0; l < dhcpCount; l++ { - dhcpPolicy, err := bdCont.ArrayElement(l, "dhcpLabels") - if err != nil { - return err + if versionInt == -1 { + dhcpPoliciesNameList, error := getDHCPPolicesNameByRef(dhcpCount, schemaId, stateTemplate, bdCont, msoClient) + if error != nil { + return error } - dhcpPolicyMap := make(map[string]interface{}) - dhcpPolicyMap["name"] = models.StripQuotes(dhcpPolicy.S("name").String()) - var version int - if dhcpPolicy.Exists("version") { - version, err = strconv.Atoi(models.StripQuotes(dhcpPolicy.S("version").String())) - } - if err != nil { - return err - } - dhcpPolicyMap["version"] = version - if dhcpPolicy.Exists("dhcpOptionLabel") { - dhcpPolicyMap["dhcp_option_policy_name"] = models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "name").String()) - version, err := strconv.Atoi(models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "version").String())) + dhcpPoliciesList = dhcpPoliciesNameList + } else { + for l := 0; l < dhcpCount; l++ { + dhcpPolicy, err := bdCont.ArrayElement(l, "dhcpLabels") + if err != nil { + return err + } + dhcpPolicyMap := make(map[string]interface{}) + dhcpPolicyMap["name"] = models.StripQuotes(dhcpPolicy.S("name").String()) + var version int + if dhcpPolicy.Exists("version") { + version, err = strconv.Atoi(models.StripQuotes(dhcpPolicy.S("version").String())) + } if err != nil { return err } - dhcpPolicyMap["dhcp_option_policy_version"] = version + dhcpPolicyMap["version"] = version + if dhcpPolicy.Exists("dhcpOptionLabel") { + dhcpPolicyMap["dhcp_option_policy_name"] = models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "name").String()) + version, err := strconv.Atoi(models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "version").String())) + if err != nil { + return err + } + dhcpPolicyMap["dhcp_option_policy_version"] = version + } + dhcpPoliciesList = append(dhcpPoliciesList, dhcpPolicyMap) } - dhcpPoliciesList = append(dhcpPoliciesList, dhcpPolicyMap) } } else { if bdCont.Exists("dhcpLabel") { @@ -705,6 +732,10 @@ func resourceMSOTemplateBDUpdate(d *schema.ResourceData, m interface{}) error { templateName := d.Get("template_name").(string) vrfName := d.Get("vrf_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, ipv6_unknown_multicast_flooding, multi_destination_flooding, unknown_multicast_flooding string @@ -784,22 +815,30 @@ func resourceMSOTemplateBDUpdate(d *schema.ResourceData, m interface{}) error { dhcpPolList := make([]interface{}, 0) if dhcpPolicies, ok := d.GetOk("dhcp_policies"); ok { - 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"] + 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 } - dhcpPolicyMap["dhcpOptionLabel"] = dhcpOptionMap + dhcpPolList = append(dhcpPolList, dhcpPolicyMap) } - dhcpPolList = append(dhcpPolList, dhcpPolicyMap) } } else { dhcpPolList = nil @@ -811,7 +850,7 @@ func resourceMSOTemplateBDUpdate(d *schema.ResourceData, m interface{}) error { vrfRefMap["vrfName"] = vrfName path := fmt.Sprintf("/templates/%s/bds/%s", templateName, name) bdStruct := models.NewTemplateBD("replace", path, name, displayName, layer2_unknown_unicast, unknown_multicast_flooding, multi_destination_flooding, ipv6_unknown_multicast_flooding, virtual_mac_address, description, intersite_bum_traffic, optimize_wan_bandwidth, layer2_stretch, layer3_multicast, arp_flooding, unicast_routing, vrfRefMap, dhcpPolMap, dhcpPolList) - _, err := msoClient.PatchbyID(fmt.Sprintf("api/v1/schemas/%s", schemaID), bdStruct) + _, err = msoClient.PatchbyID(fmt.Sprintf("api/v1/schemas/%s", schemaID), bdStruct) if err != nil { return err @@ -838,3 +877,59 @@ func resourceMSOTemplateBDDelete(d *schema.ResourceData, m interface{}) error { log.Printf("[DEBUG] %s: Delete finished successfully", d.Id()) return nil } + +// getDHCPPolicesNameByRef retrieves the DHCP policies name by reference. +// +// Parameters: +// - dhcpCount: The number of DHCP policies to retrieve. +// - schemaId: The ID of the schema template. +// - stateTemplate: The state template. +// - bdCont: The container. +// - msoClient: The client. +// Returns: +// - []interface{}: The list of DHCP policies name. +// - error: An error if the retrieval fails. +func getDHCPPolicesNameByRef(dhcpCount int, schemaId, stateTemplate string, bdCont *container.Container, msoClient *client.Client) ([]interface{}, error) { + tenantID, err := msoClient.GetTenantIDFromSchemaTemplate(schemaId, stateTemplate) + if err != nil { + return nil, err + } + dhcpPoliciesRefList := make([]interface{}, 0) + for l := 0; l < dhcpCount; l++ { + dhcpPolicy, err := bdCont.ArrayElement(l, "dhcpLabels") + if err != nil { + return nil, err + } + dhcpPolicyMap := make(map[string]interface{}) + dhcpPolicyMap["relayRef"] = models.StripQuotes(dhcpPolicy.S("ref").String()) + dhcpPolicyMap["optionRef"] = models.StripQuotes(dhcpPolicy.S("dhcpOptionLabel", "ref").String()) + dhcpPoliciesRefList = append(dhcpPoliciesRefList, dhcpPolicyMap) + } + return msoClient.GetDHCPPoliciesNameByUUID(tenantID, dhcpPoliciesRefList) +} + +// mapDHCPPoliciesRefByName retrieves a list of DHCP policy UUIDs by name. +// +// Parameters: +// - schemaID: the ID of the schema. +// - templateName: the name of the template. +// - dhcpPolicies: the list of DHCP policies. +// - msoClient: the client used to communicate with the MSO. +// Returns: +// - []interface{}: It returns a list of interface{} containing the UUIDs of the DHCP policies, +// - error: An error if the retrieval fails. +func mapDHCPPoliciesRefByName(schemaID, templateName string, dhcpPolicies interface{}, msoClient *client.Client) ([]interface{}, error) { + tenantID, err := msoClient.GetTenantIDFromSchemaTemplate(schemaID, templateName) + if err != nil { + return nil, err + } + dhcpPolicyNameList := make([]interface{}, 0) + for _, dhcpPolicy := range dhcpPolicies.(*schema.Set).List() { + policy := dhcpPolicy.(map[string]interface{}) + dhcpPolicyNameMap := make(map[string]interface{}) + dhcpPolicyNameMap["relayName"] = policy["name"] + dhcpPolicyNameMap["optionName"] = policy["dhcp_option_policy_name"] + dhcpPolicyNameList = append(dhcpPolicyNameList, dhcpPolicyNameMap) + } + return msoClient.GetDHCPPoliciesUUIDByName(tenantID, dhcpPolicyNameList) +} diff --git a/vendor/github.com/ciscoecosystem/mso-go-client/client/client_service.go b/vendor/github.com/ciscoecosystem/mso-go-client/client/client_service.go index 739632e0..86593487 100644 --- a/vendor/github.com/ciscoecosystem/mso-go-client/client/client_service.go +++ b/vendor/github.com/ciscoecosystem/mso-go-client/client/client_service.go @@ -79,12 +79,12 @@ func (c *Client) Save(endpoint string, obj models.Model) (*container.Container, func CheckForErrors(cont *container.Container, method string) error { if cont.Exists("code") && cont.Exists("message") { - return errors.New(fmt.Sprintf("%s%s", cont.S("message"), cont.S("info"))) + } else if cont.Exists("error") { + return errors.New(fmt.Sprintf("%s %s", models.StripQuotes(cont.S("error").String()), models.StripQuotes(cont.S("error_code").String()))) } else { return nil } - return nil } diff --git a/vendor/github.com/ciscoecosystem/mso-go-client/client/template_service.go b/vendor/github.com/ciscoecosystem/mso-go-client/client/template_service.go new file mode 100644 index 00000000..7c5d5a0c --- /dev/null +++ b/vendor/github.com/ciscoecosystem/mso-go-client/client/template_service.go @@ -0,0 +1,172 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/mso-go-client/container" + "github.com/ciscoecosystem/mso-go-client/models" +) + +// GetTenantIDFromSchemaTemplate retrieves the Tenant ID from the schema template object. +func (client *Client) GetTenantIDFromSchemaTemplate(schemaID, templateName string) (string, error) { + schemaObj, err := client.GetViaURL(fmt.Sprintf("api/v1/schemas/%s", schemaID)) + if err != nil { + return "", err + } + + templatesCount, _ := schemaObj.ArrayCount("templates") + if err != nil { + return "", err + } + + for i := 0; i < templatesCount; i++ { + templateObj, err := schemaObj.ArrayElement(i, "templates") + if err != nil { + return "", err + } + + apiTemplate := models.StripQuotes(templateObj.S("name").String()) + if templateName == apiTemplate { + return models.StripQuotes(templateObj.S("tenantId").String()), nil + } + } + return "", nil +} + +// GetPoliciesByTenantID returns the policies container object based on the tenant id. +func (client *Client) GetPoliciesByTenantID(objectType, tenantID string) (*container.Container, error) { + path := fmt.Sprintf("api/v1/templates/objects?type=%s&tenant-id=%s&include-common=true", objectType, tenantID) + cont, err := client.GetViaURL(path) + if err != nil { + return nil, err + } + return cont, nil +} + +// GetPolicyByTenantID retrieves a policy based on the given object type, object name, and tenant ID. +func (client *Client) GetPolicyByTenantID(objectType, objectName, tenantID string) (map[string]interface{}, error) { + cont, _ := client.GetPoliciesByTenantID(objectType, tenantID) + commonTenantPolicy := make(map[string]interface{}) + for _, policy := range cont.Data().([]interface{}) { + if policyMap, ok := policy.(map[string]interface{}); ok { + if objectName == policyMap["name"].(string) && tenantID == policyMap["tenantId"].(string) { + return policyMap, nil + } else if objectName == policyMap["name"].(string) && policyMap["tenantName"].(string) == "common" { + commonTenantPolicy = policyMap + } + } + } + if len(commonTenantPolicy) != 0 { + return commonTenantPolicy, nil + } + return nil, fmt.Errorf("%s policy with name: %s not found", objectType, objectName) +} + +// GetObjectNameByUUID returns the name of an object given its UUID and boolean indicating whether the object was found or not. +func GetObjectNameByUUID(objectRef string, objectCont *container.Container) (string, bool) { + for _, object := range objectCont.Data().([]interface{}) { + if objectMap, ok := object.(map[string]interface{}); ok { + if objectMap["uuid"].(string) == objectRef { + return objectMap["name"].(string), true + } + } + } + return "", false +} + +// GetObjectUUIDByName returns the UUID of an object given its name and boolean indicating whether the object was found or not. +func GetObjectUUIDByName(objectName string, objectCont *container.Container) (string, bool) { + for _, object := range objectCont.Data().([]interface{}) { + if objectMap, ok := object.(map[string]interface{}); ok { + if objectMap["name"].(string) == objectName { + return objectMap["uuid"].(string), true + } + } + } + return "", false +} + +// GetDHCPPoliciesNameByUUID retrieves the DHCP policies' names by UUID. +// It takes in the tenant ID and a list of object references as parameters. +// The function returns a list of interface{} and an error. +func (client *Client) GetDHCPPoliciesNameByUUID(tenantID string, objectRefs []interface{}) ([]interface{}, error) { + dhcpPoliciesList := make([]interface{}, 0) + dhcpRelayCont, relayError := client.GetPoliciesByTenantID("dhcpRelay", tenantID) + if relayError != nil { + return nil, relayError + } + + dhcpOptionCont, optionError := client.GetPoliciesByTenantID("dhcpOption", tenantID) + if optionError != nil { + return nil, optionError + } + + for _, objectRef := range objectRefs { + var relayObjectFound, optionObjectFound bool + relayRef := objectRef.(map[string]interface{})["relayRef"].(string) + optionRef := objectRef.(map[string]interface{})["optionRef"].(string) + dhcpPolicyMap := make(map[string]interface{}) + dhcpPolicyMap["name"], relayObjectFound = GetObjectNameByUUID(relayRef, dhcpRelayCont) + if !relayObjectFound { + return nil, fmt.Errorf("DHCP Relay: %s policy reference not found", relayRef) + } + if optionRef != "{}" { + dhcpPolicyMap["dhcp_option_policy_name"], optionObjectFound = GetObjectNameByUUID(optionRef, dhcpOptionCont) + if !optionObjectFound { + return nil, fmt.Errorf("DHCP Option: %s policy reference not found", optionRef) + } + } else { + dhcpPolicyMap["dhcp_option_policy_name"] = "" + } + dhcpPoliciesList = append(dhcpPoliciesList, dhcpPolicyMap) + } + return dhcpPoliciesList, nil +} + +// GetDHCPPoliciesUUIDByName retrieves the DHCP policies UUIDs by name for a given tenant ID. +// +// Parameters: +// - tenantID: The ID of the tenant. +// - objectNames: An array of objects containing the relay name and option name. +func (client *Client) GetDHCPPoliciesUUIDByName(tenantID string, objectNames []interface{}) ([]interface{}, error) { + dhcpRelayCont, relayError := client.GetPoliciesByTenantID("dhcpRelay", tenantID) + if relayError != nil { + return nil, relayError + } + dhcpOptionCont, optionError := client.GetPoliciesByTenantID("dhcpOption", tenantID) + if optionError != nil { + return nil, optionError + } + dhcpPoliciesList := make([]interface{}, 0) + for _, objectName := range objectNames { + var relayObjectFound, optionObjectFound bool + var relayUUID, optionUUID string + + relayName := objectName.(map[string]interface{})["relayName"].(string) + optionName := objectName.(map[string]interface{})["optionName"].(string) + + relayUUID, relayObjectFound = GetObjectUUIDByName(relayName, dhcpRelayCont) + if !relayObjectFound { + return nil, fmt.Errorf("DHCP Relay: %s policy not name found", relayName) + } + + if optionName != "" { + optionUUID, optionObjectFound = GetObjectUUIDByName(optionName, dhcpOptionCont) + if !optionObjectFound { + return nil, fmt.Errorf("DHCP Option: %s policy not name found", optionName) + } + } else { + optionObjectFound = true + } + + dhcpPoliciesList = append( + dhcpPoliciesList, map[string]interface{}{ + "ref": relayUUID, + "dhcpOptionLabel": map[string]interface{}{ + "ref": optionUUID, + }, + }, + ) + } + return dhcpPoliciesList, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 7874d355..feeee203 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -78,7 +78,7 @@ github.com/aws/aws-sdk-go/service/sts/stsiface github.com/bgentry/go-netrc/netrc # github.com/bgentry/speakeasy v0.1.0 github.com/bgentry/speakeasy -# github.com/ciscoecosystem/mso-go-client v1.18.1 +# github.com/ciscoecosystem/mso-go-client v1.19.0 github.com/ciscoecosystem/mso-go-client/client github.com/ciscoecosystem/mso-go-client/container github.com/ciscoecosystem/mso-go-client/models