From 6dbe396264f76ebf5efe48657c48b587da3c199a Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Wed, 18 Jan 2023 00:26:11 +0530 Subject: [PATCH] [bugfix] Fix resource aci_external_network_instance_profile idempotency and relationship attribute import issues (#976) --- aci/data_source_aci_l3extinstp.go | 85 ++++++- aci/resource_aci_l3extinstp.go | 228 ++++++++++++------ aci/utils.go | 9 + .../main.tf | 111 +++++++-- ...nal_network_instance_profile.html.markdown | 45 ++-- ...nal_network_instance_profile.html.markdown | 86 ++++--- 6 files changed, 408 insertions(+), 156 deletions(-) diff --git a/aci/data_source_aci_l3extinstp.go b/aci/data_source_aci_l3extinstp.go index 3b82e9d44..f84dc0c99 100644 --- a/aci/data_source_aci_l3extinstp.go +++ b/aci/data_source_aci_l3extinstp.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ciscoecosystem/aci-go-client/v2/client" + "github.com/ciscoecosystem/aci-go-client/v2/models" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -16,7 +17,7 @@ func dataSourceAciExternalNetworkInstanceProfile() *schema.Resource { SchemaVersion: 1, - Schema: AppendBaseAttrSchema(map[string]*schema.Schema{ + Schema: AppendBaseAttrSchema(AppendNameAliasAttrSchema(map[string]*schema.Schema{ "l3_outside_dn": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -45,12 +46,6 @@ func dataSourceAciExternalNetworkInstanceProfile() *schema.Resource { Computed: true, }, - "name_alias": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "pref_gr_memb": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -68,7 +63,60 @@ func dataSourceAciExternalNetworkInstanceProfile() *schema.Resource { Optional: true, Computed: true, }, - }), + "relation_fv_rs_sec_inherited": &schema.Schema{ + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Computed: true, + }, + "relation_fv_rs_prov": &schema.Schema{ + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Computed: true, + }, + "relation_fv_rs_cons_if": &schema.Schema{ + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Computed: true, + }, + "relation_l3ext_rs_inst_p_to_profile": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "tn_rtctrl_profile_dn": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "direction": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + "relation_fv_rs_cons": &schema.Schema{ + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Computed: true, + }, + "relation_fv_rs_prot_by": &schema.Schema{ + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Set: schema.HashString, + Computed: true, + }, + })), } } @@ -77,7 +125,7 @@ func dataSourceAciExternalNetworkInstanceProfileRead(ctx context.Context, d *sch name := d.Get("name").(string) - rn := fmt.Sprintf("instP-%s", name) + rn := fmt.Sprintf(models.Rnl3extinstp, name) L3OutsideDn := d.Get("l3_outside_dn").(string) dn := fmt.Sprintf("%s/%s", L3OutsideDn, rn) @@ -92,5 +140,24 @@ func dataSourceAciExternalNetworkInstanceProfileRead(ctx context.Context, d *sch if err != nil { return diag.FromErr(err) } + + // Importing l3extRsInstPToProfile object + getAndSetReadRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsSecInherited object + getAndSetReadRelationfvRsSecInheritedFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsProv object + getAndSetReadRelationfvRsProvFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsConsIf object + getAndSetReadRelationfvRsConsIfFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsCons object + getAndSetReadRelationfvRsConsFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsProtBy object + getAndSetReadRelationfvRsProtByFromExternalNetworkInstanceProfile(aciClient, dn, d) + return nil } diff --git a/aci/resource_aci_l3extinstp.go b/aci/resource_aci_l3extinstp.go index f4244981d..85f840eac 100644 --- a/aci/resource_aci_l3extinstp.go +++ b/aci/resource_aci_l3extinstp.go @@ -25,7 +25,7 @@ func resourceAciExternalNetworkInstanceProfile() *schema.Resource { SchemaVersion: 1, - Schema: AppendBaseAttrSchema(map[string]*schema.Schema{ + Schema: AppendBaseAttrSchema(AppendNameAliasAttrSchema(map[string]*schema.Schema{ "l3_outside_dn": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -66,12 +66,6 @@ func resourceAciExternalNetworkInstanceProfile() *schema.Resource { }, false), }, - "name_alias": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "pref_gr_memb": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -167,15 +161,25 @@ func resourceAciExternalNetworkInstanceProfile() *schema.Resource { "relation_l3ext_rs_inst_p_to_profile": &schema.Schema{ Type: schema.TypeSet, Optional: true, + MaxItems: 2, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "tn_rtctrl_profile_name": { + Type: schema.TypeString, + Optional: true, + Deprecated: "Use tn_rtctrl_profile_dn instead of tn_rtctrl_profile_name", + }, + "tn_rtctrl_profile_dn": { Type: schema.TypeString, - Required: true, + Optional: true, }, "direction": { Type: schema.TypeString, - Required: true, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "export", + "import", + }, false), }, }, }, @@ -199,21 +203,19 @@ func resourceAciExternalNetworkInstanceProfile() *schema.Resource { Set: schema.HashString, Deprecated: "relation_fv_rs_intra_epg attribute is no longer available", }, - }), + })), } } + func getRemoteExternalNetworkInstanceProfile(client *client.Client, dn string) (*models.ExternalNetworkInstanceProfile, error) { l3extInstPCont, err := client.Get(dn) if err != nil { return nil, err } - l3extInstP := models.ExternalNetworkInstanceProfileFromContainer(l3extInstPCont) - if l3extInstP.DistinguishedName == "" { - return nil, fmt.Errorf("ExternalNetworkInstanceProfile %s not found", l3extInstP.DistinguishedName) + return nil, fmt.Errorf("External Network Instance Profile %s not found", dn) } - return l3extInstP, nil } @@ -229,7 +231,7 @@ func setExternalNetworkInstanceProfileAttributes(l3extInstP *models.ExternalNetw if err != nil { return d, err } - d.Set("l3_outside_dn", GetParentDn(dn, fmt.Sprintf("/instP-%s", l3extInstPMap["name"]))) + d.Set("l3_outside_dn", GetParentDn(dn, fmt.Sprintf("/%s", fmt.Sprintf(models.Rnl3extinstp, l3extInstPMap["name"])))) d.Set("name", l3extInstPMap["name"]) d.Set("annotation", l3extInstPMap["annotation"]) @@ -243,6 +245,92 @@ func setExternalNetworkInstanceProfileAttributes(l3extInstP *models.ExternalNetw return d, nil } +func getAndSetReadRelationfvRsProtByFromExternalNetworkInstanceProfile(client *client.Client, dn string, d *schema.ResourceData) (*schema.ResourceData, error) { + fvRsProtByData, err := client.ReadRelationfvRsProtByFromExternalNetworkInstanceProfile(dn) + if err != nil { + log.Printf("[DEBUG] Error while reading relation fvRsProtBy %v", err) + d.Set("relation_fv_rs_prot_by", make([]interface{}, 0, 1)) + return nil, err + } else { + d.Set("relation_fv_rs_prot_by", toStringList(fvRsProtByData.(*schema.Set).List())) + log.Printf("[DEBUG]: fvRsProtBy: %s reading finished successfully", toStringList(fvRsProtByData.(*schema.Set).List())) + } + return d, nil +} + +func getAndSetReadRelationfvRsConsFromExternalNetworkInstanceProfile(client *client.Client, dn string, d *schema.ResourceData) (*schema.ResourceData, error) { + fvRsConsData, err := client.ReadRelationfvRsConsFromExternalNetworkInstanceProfile(dn) + if err != nil { + log.Printf("[DEBUG] Error while reading relation fvRsCons %v", err) + d.Set("relation_fv_rs_cons", make([]interface{}, 0, 1)) + return nil, err + } else { + d.Set("relation_fv_rs_cons", toStringList(fvRsConsData.(*schema.Set).List())) + log.Printf("[DEBUG]: fvRsCons: %s reading finished successfully", toStringList(fvRsConsData.(*schema.Set).List())) + } + return d, nil +} + +func getAndSetReadRelationfvRsConsIfFromExternalNetworkInstanceProfile(client *client.Client, dn string, d *schema.ResourceData) (*schema.ResourceData, error) { + fvRsConsIfData, err := client.ReadRelationfvRsConsIfFromExternalNetworkInstanceProfile(dn) + if err != nil { + log.Printf("[DEBUG] Error while reading relation fvRsConsIf %v", err) + d.Set("relation_fv_rs_cons_if", make([]interface{}, 0, 1)) + return nil, err + } else { + d.Set("relation_fv_rs_cons_if", toStringList(fvRsConsIfData.(*schema.Set).List())) + log.Printf("[DEBUG]: fvRsConsIf: %s reading finished successfully", toStringList(fvRsConsIfData.(*schema.Set).List())) + } + return d, nil +} + +func getAndSetReadRelationfvRsProvFromExternalNetworkInstanceProfile(client *client.Client, dn string, d *schema.ResourceData) (*schema.ResourceData, error) { + fvRsProvData, err := client.ReadRelationfvRsProvFromExternalNetworkInstanceProfile(dn) + if err != nil { + log.Printf("[DEBUG] Error while reading relation fvRsProv %v", err) + d.Set("relation_fv_rs_prov", make([]interface{}, 0, 1)) + return nil, err + } else { + d.Set("relation_fv_rs_prov", toStringList(fvRsProvData.(*schema.Set).List())) + log.Printf("[DEBUG]: fvRsProv: %s reading finished successfully", toStringList(fvRsProvData.(*schema.Set).List())) + } + return d, nil +} + +func getAndSetReadRelationfvRsSecInheritedFromExternalNetworkInstanceProfile(client *client.Client, dn string, d *schema.ResourceData) (*schema.ResourceData, error) { + fvRsSecInheritedData, err := client.ReadRelationfvRsSecInheritedFromExternalNetworkInstanceProfile(dn) + if err != nil { + log.Printf("[DEBUG] Error while reading relation fvRsSecInherited %v", err) + d.Set("relation_fv_rs_sec_inherited", make([]interface{}, 0, 1)) + return nil, err + } else { + d.Set("relation_fv_rs_sec_inherited", toStringList(fvRsSecInheritedData.(*schema.Set).List())) + log.Printf("[DEBUG]: fvRsSecInherited: %s reading finished successfully", toStringList(fvRsSecInheritedData.(*schema.Set).List())) + } + return d, nil +} + +func getAndSetReadRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(client *client.Client, dn string, d *schema.ResourceData) (*schema.ResourceData, error) { + l3extRsInstPToProfileData, err := client.ReadRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(dn) + l3extRsInstPToProfileMap := make([]map[string]string, 0, 1) + if err != nil { + log.Printf("[DEBUG] Error while reading relation l3extRsInstPToProfile %v", err) + d.Set("relation_l3ext_rs_inst_p_to_profile", l3extRsInstPToProfileMap) + return nil, err + } else { + l3extRsInstPToProfileMap := make([]map[string]string, 0, 1) + for _, obj := range l3extRsInstPToProfileData.([]map[string]string) { + l3extRsInstPToProfileMap = append(l3extRsInstPToProfileMap, map[string]string{ + "tn_rtctrl_profile_dn": obj["tDn"], + "direction": obj["direction"], + }) + } + d.Set("relation_l3ext_rs_inst_p_to_profile", l3extRsInstPToProfileMap) + log.Printf("[DEBUG]: l3extRsInstPToProfile: %s reading finished successfully", l3extRsInstPToProfileMap) + } + return d, nil +} + func resourceAciExternalNetworkInstanceProfileImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { log.Printf("[DEBUG] %s: Beginning Import", d.Id()) aciClient := m.(*client.Client) @@ -259,12 +347,31 @@ func resourceAciExternalNetworkInstanceProfileImport(d *schema.ResourceData, m i return nil, err } name := l3extInstPMap["name"] - pDN := GetParentDn(dn, fmt.Sprintf("/instP-%s", name)) + pDN := GetParentDn(dn, fmt.Sprintf("/%s", fmt.Sprintf(models.Rnl3extinstp, name))) d.Set("l3_outside_dn", pDN) schemaFilled, err := setExternalNetworkInstanceProfileAttributes(l3extInstP, d) if err != nil { return nil, err } + + // Importing l3extRsInstPToProfile object + getAndSetReadRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsSecInherited object + getAndSetReadRelationfvRsSecInheritedFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsProv object + getAndSetReadRelationfvRsProvFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsConsIf object + getAndSetReadRelationfvRsConsIfFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsCons object + getAndSetReadRelationfvRsConsFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsProtBy object + getAndSetReadRelationfvRsProtByFromExternalNetworkInstanceProfile(aciClient, dn, d) + log.Printf("[DEBUG] %s: Import finished successfully", d.Id()) return []*schema.ResourceData{schemaFilled}, nil @@ -306,7 +413,7 @@ func resourceAciExternalNetworkInstanceProfileCreate(ctx context.Context, d *sch if TargetDscp, ok := d.GetOk("target_dscp"); ok { l3extInstPAttr.TargetDscp = TargetDscp.(string) } - l3extInstP := models.NewExternalNetworkInstanceProfile(fmt.Sprintf("instP-%s", name), L3OutsideDn, desc, l3extInstPAttr) + l3extInstP := models.NewExternalNetworkInstanceProfile(fmt.Sprintf(models.Rnl3extinstp, name), L3OutsideDn, desc, l3extInstPAttr) err := aciClient.Save(l3extInstP) @@ -441,7 +548,8 @@ func resourceAciExternalNetworkInstanceProfileCreate(ctx context.Context, d *sch relationParamList := relationTol3extRsInstPToProfile.(*schema.Set).List() for _, relationParam := range relationParamList { paramMap := relationParam.(map[string]interface{}) - err = aciClient.CreateRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(l3extInstP.DistinguishedName, GetMOName(paramMap["tn_rtctrl_profile_name"].(string)), paramMap["direction"].(string)) + l3extRsInstPToProfileName := getTargetObjectName(paramMap, "tn_rtctrl_profile_dn", "tn_rtctrl_profile_name") + err = aciClient.CreateRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(l3extInstP.DistinguishedName, l3extRsInstPToProfileName, paramMap["direction"].(string)) if err != nil { return diag.FromErr(err) } @@ -525,9 +633,7 @@ func resourceAciExternalNetworkInstanceProfileUpdate(ctx context.Context, d *sch if TargetDscp, ok := d.GetOk("target_dscp"); ok { l3extInstPAttr.TargetDscp = TargetDscp.(string) } - l3extInstP := models.NewExternalNetworkInstanceProfile(fmt.Sprintf("instP-%s", name), L3OutsideDn, desc, l3extInstPAttr) - - l3extInstP.Status = "modified" + l3extInstP := models.NewExternalNetworkInstanceProfile(fmt.Sprintf(models.Rnl3extinstp, name), L3OutsideDn, desc, l3extInstPAttr) err := aciClient.Save(l3extInstP) @@ -738,7 +844,8 @@ func resourceAciExternalNetworkInstanceProfileUpdate(ctx context.Context, d *sch newRelList := newRel.(*schema.Set).List() for _, relationParam := range oldRelList { paramMap := relationParam.(map[string]interface{}) - err = aciClient.DeleteRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(l3extInstP.DistinguishedName, GetMOName(paramMap["tn_rtctrl_profile_name"].(string)), paramMap["direction"].(string)) + l3extRsInstPToProfileName := getTargetObjectName(paramMap, "tn_rtctrl_profile_dn", "tn_rtctrl_profile_name") + err = aciClient.DeleteRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(l3extInstP.DistinguishedName, l3extRsInstPToProfileName, paramMap["direction"].(string)) if err != nil { return diag.FromErr(err) } @@ -746,7 +853,8 @@ func resourceAciExternalNetworkInstanceProfileUpdate(ctx context.Context, d *sch } for _, relationParam := range newRelList { paramMap := relationParam.(map[string]interface{}) - err = aciClient.CreateRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(l3extInstP.DistinguishedName, GetMOName(paramMap["tn_rtctrl_profile_name"].(string)), paramMap["direction"].(string)) + l3extRsInstPToProfileName := getTargetObjectName(paramMap, "tn_rtctrl_profile_dn", "tn_rtctrl_profile_name") + err = aciClient.CreateRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(l3extInstP.DistinguishedName, l3extRsInstPToProfileName, paramMap["direction"].(string)) if err != nil { return diag.FromErr(err) } @@ -857,22 +965,6 @@ func resourceAciExternalNetworkInstanceProfileRead(ctx context.Context, d *schem return nil } - fvRsSecInheritedData, err := aciClient.ReadRelationfvRsSecInheritedFromExternalNetworkInstanceProfile(dn) - if err != nil { - log.Printf("[DEBUG] Error while reading relation fvRsSecInherited %v", err) - setRelationAttribute(d, "relation_fv_rs_sec_inherited", make([]interface{}, 0, 1)) - } else { - setRelationAttribute(d, "relation_fv_rs_sec_inherited", toStringList(fvRsSecInheritedData.(*schema.Set).List())) - } - - fvRsProvData, err := aciClient.ReadRelationfvRsProvFromExternalNetworkInstanceProfile(dn) - if err != nil { - log.Printf("[DEBUG] Error while reading relation fvRsProv %v", err) - setRelationAttribute(d, "relation_fv_rs_prov", make([]interface{}, 0, 1)) - } else { - setRelationAttribute(d, "relation_fv_rs_prov", toStringList(fvRsProvData.(*schema.Set).List())) - } - l3extRsL3InstPToDomPData, err := aciClient.ReadRelationl3extRsL3InstPToDomPFromExternalNetworkInstanceProfile(dn) if err != nil { log.Printf("[DEBUG] Error while reading relation l3extRsL3InstPToDomP %v", err) @@ -891,14 +983,6 @@ func resourceAciExternalNetworkInstanceProfileRead(ctx context.Context, d *schem setRelationAttribute(d, "relation_l3ext_rs_inst_p_to_nat_mapping_epg", l3extRsInstPToNatMappingEPgData.(string)) } - fvRsConsIfData, err := aciClient.ReadRelationfvRsConsIfFromExternalNetworkInstanceProfile(dn) - if err != nil { - log.Printf("[DEBUG] Error while reading relation fvRsConsIf %v", err) - setRelationAttribute(d, "relation_fv_rs_cons_if", make([]interface{}, 0, 1)) - } else { - setRelationAttribute(d, "relation_fv_rs_cons_if", toStringList(fvRsConsIfData.(*schema.Set).List())) - } - fvRsCustQosPolData, err := aciClient.ReadRelationfvRsCustQosPolFromExternalNetworkInstanceProfile(dn) if err != nil { log.Printf("[DEBUG] Error while reading relation fvRsCustQosPol %v", err) @@ -908,38 +992,6 @@ func resourceAciExternalNetworkInstanceProfileRead(ctx context.Context, d *schem setRelationAttribute(d, "relation_fv_rs_cust_qos_pol", fvRsCustQosPolData.(string)) } - l3extRsInstPToProfileData, err := aciClient.ReadRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(dn) - if err != nil { - log.Printf("[DEBUG] Error while reading relation l3extRsInstPToProfile %v", err) - - } else { - relMapList := make([]map[string]string, 0, 1) - relMaps := l3extRsInstPToProfileData.([]map[string]string) - for _, obj := range relMaps { - relMapList = append(relMapList, map[string]string{ - "tn_rtctrl_profile_name": obj["tnRtctrlProfileName"], - "direction": obj["direction"], - }) - } - d.Set("relation_l3ext_rs_inst_p_to_profile", relMapList) - } - - fvRsConsData, err := aciClient.ReadRelationfvRsConsFromExternalNetworkInstanceProfile(dn) - if err != nil { - log.Printf("[DEBUG] Error while reading relation fvRsCons %v", err) - setRelationAttribute(d, "relation_fv_rs_cons", make([]interface{}, 0, 1)) - } else { - setRelationAttribute(d, "relation_fv_rs_cons", toStringList(fvRsConsData.(*schema.Set).List())) - } - - fvRsProtByData, err := aciClient.ReadRelationfvRsProtByFromExternalNetworkInstanceProfile(dn) - if err != nil { - log.Printf("[DEBUG] Error while reading relation fvRsProtBy %v", err) - setRelationAttribute(d, "relation_fv_rs_prot_by", make([]interface{}, 0, 1)) - } else { - setRelationAttribute(d, "relation_fv_rs_prot_by", toStringList(fvRsProtByData.(*schema.Set).List())) - } - fvRsIntraEpgData, err := aciClient.ReadRelationfvRsIntraEpgFromExternalNetworkInstanceProfile(dn) if err != nil { log.Printf("[DEBUG] Error while reading relation fvRsIntraEpg %v", err) @@ -948,6 +1000,24 @@ func resourceAciExternalNetworkInstanceProfileRead(ctx context.Context, d *schem setRelationAttribute(d, "relation_fv_rs_intra_epg", toStringList(fvRsIntraEpgData.(*schema.Set).List())) } + // Importing l3extRsInstPToProfile object + getAndSetReadRelationl3extRsInstPToProfileFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsSecInherited object + getAndSetReadRelationfvRsSecInheritedFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsProv object + getAndSetReadRelationfvRsProvFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsConsIf object + getAndSetReadRelationfvRsConsIfFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsCons object + getAndSetReadRelationfvRsConsFromExternalNetworkInstanceProfile(aciClient, dn, d) + + // Importing fvRsProtBy object + getAndSetReadRelationfvRsProtByFromExternalNetworkInstanceProfile(aciClient, dn, d) + log.Printf("[DEBUG] %s: Read finished successfully", d.Id()) return nil diff --git a/aci/utils.go b/aci/utils.go index 551e77bc0..c309caafc 100644 --- a/aci/utils.go +++ b/aci/utils.go @@ -352,3 +352,12 @@ func getOldObjectsNotInNew(keyName string, oldSet, newSet *schema.Set) (oldObjec } return oldObjects } + +// Return the name of the object based on the given Distinguished Name +func getTargetObjectName(paramMap map[string]interface{}, targetDn, targetName string) string { + if paramMap[targetDn] != "" { + return GetMOName(paramMap[targetDn].(string)) + } else { + return paramMap[targetName].(string) + } +} diff --git a/examples/aci_external_network_instance_profile/main.tf b/examples/aci_external_network_instance_profile/main.tf index ad0aa2d9c..b804abb15 100644 --- a/examples/aci_external_network_instance_profile/main.tf +++ b/examples/aci_external_network_instance_profile/main.tf @@ -12,26 +12,91 @@ provider "aci" { url = "" insecure = true } -resource "aci_tenant" "example" { - name = "test_acc_tenant" -} - -resource "aci_l3_outside" "example" { - tenant_dn = aci_tenant.example.id - name = "demo_l3out" - target_dscp = "CS0" -} - -resource "aci_external_network_instance_profile" "fooexternal_network_instance_profile" { - l3_outside_dn = aci_l3_outside.example.id - description = "%s" - name = "demo_inst_prof" - annotation = "tag_network_profile" - exception_tag = "2" - flood_on_encap = "disabled" - match_t = "ALL" - name_alias = "alias_profile" - pref_gr_memb = "exclude" - prio = "level1" - target_dscp = "unspecified" -} \ No newline at end of file + +# Tenant Setup +resource "aci_tenant" "terraform_tenant" { + name = "terraform_tenant" +} + +data "aci_tenant" "common" { + name = "common" +} + +# Route Control Profile Setup +data "aci_route_control_profile" "shared_route_control_profile" { + parent_dn = data.aci_tenant.common.id + name = "ok" +} + +# VRF Setup +data "aci_vrf" "default_vrf" { + tenant_dn = data.aci_tenant.common.id + name = "default" +} + +# L3 Domain Setup +resource "aci_l3_domain_profile" "l3_domain_profile" { + name = "l3_domain_profile" +} + +# L3Outside Domain +resource "aci_l3_outside" "l3_outside" { + tenant_dn = aci_tenant.terraform_tenant.id + name = "l3_outside" +} + +# Taboo Contract Setup +resource "aci_taboo_contract" "taboo_contract" { + tenant_dn = aci_tenant.terraform_tenant.id + name = "taboo_contract" +} + +# Contract Setup +resource "aci_contract" "web_contract" { + tenant_dn = aci_tenant.terraform_tenant.id + name = "web_contract" +} + +# Imported Contract Setup +resource "aci_imported_contract" "contract_interface" { + tenant_dn = aci_tenant.terraform_tenant.id + name = "contract_interface" +} + +# Route Control Profile Setup +resource "aci_route_control_profile" "route_control_profile_export" { + parent_dn = aci_tenant.terraform_tenant.id + name = "route_control_profile_export" +} + +resource "aci_route_control_profile" "route_control_profile_import" { + parent_dn = aci_tenant.terraform_tenant.id + name = "route_control_profile_import" +} + +# External EPG Setup +resource "aci_external_network_instance_profile" "external_epg_1" { + l3_outside_dn = aci_l3_outside.l3_outside.id + name = "external_epg_1" +} + +resource "aci_external_network_instance_profile" "external_epg_2" { + l3_outside_dn = aci_l3_outside.l3_outside.id + name = "external_epg_2" + + # Route Control Profile - Every direction(export/import) allows only one object + relation_l3ext_rs_inst_p_to_profile { + tn_rtctrl_profile_dn = aci_route_control_profile.route_control_profile_export.id + direction = "export" + } + relation_l3ext_rs_inst_p_to_profile { + tn_rtctrl_profile_dn = aci_route_control_profile.route_control_profile_import.id + direction = "import" + } + + relation_fv_rs_sec_inherited = [aci_external_network_instance_profile.external_epg_1.id] + relation_fv_rs_cons_if = [aci_imported_contract.contract_interface.id] + relation_fv_rs_prov = [aci_contract.web_contract.id] + relation_fv_rs_cons = [aci_contract.web_contract.id] + relation_fv_rs_prot_by = [aci_taboo_contract.taboo_contract.id] +} diff --git a/website/docs/d/external_network_instance_profile.html.markdown b/website/docs/d/external_network_instance_profile.html.markdown index 6da84e0e1..148d6bca9 100644 --- a/website/docs/d/external_network_instance_profile.html.markdown +++ b/website/docs/d/external_network_instance_profile.html.markdown @@ -11,28 +11,45 @@ description: |- Data source for ACI External Network Instance Profile +## API Information ## + +* `Class` - l3extOut +* `Distinguished Name` - uni/tn-{tenant}/out-{l3out}/instP-{external_epg} + +## GUI Information ## + +* `Location` - Tenant -> Networking -> L3Outs -> External EPGs + ## Example Usage ```hcl -data "aci_external_network_instance_profile" "dev_ext_net_prof" { - l3_outside_dn = aci_l3_outside.example.id - name = "foo_ext_net_prof" +data "aci_external_network_instance_profile" "external_epg" { + l3_outside_dn = aci_l3_outside.l3_outside.id + name = "external_epg" } ``` ## Argument Reference -- `l3_outside_dn` - (Required) Distinguished name of parent L3Outside object. -- `name` - (Required) Name of Object external network instance profile. +* `l3_outside_dn` - (Required) Distinguished name of the parent L3Outside object. +* `name` - (Required) Name of the External Network Instance Profile object. ## Attribute Reference -- `id` - Attribute id set to the Dn of the External Network Instance Profile. -- `annotation` - (Optional) Annotation for object external network instance profile. -- `exception_tag` - (Optional) Exception tag for object external network instance profile. -- `flood_on_encap` - (Optional) Control at EPG level if the traffic L2 Multicast/Broadcast and Link Local Layer should be flooded only on ENCAP or based on bridg-domain settings. -- `match_t` - (Optional) The provider label match criteria. -- `name_alias` - (Optional) Name alias for object external network instance profile. -- `pref_gr_memb` - (Optional) Represents parameter used to determine if EPg is part of a group that does not a contract for communication. -- `prio` - (Optional) The QoS priority class identifier. -- `target_dscp` - (Optional) The target differentiated services code point (DSCP) of the path attached to the layer 3 outside profile. +* `id` - Attribute id set to the Dn of the External Network Instance Profile. +* `annotation` - (Optional) Annotation of the External Network Instance Profile object. +* `exception_tag` - (Optional) Exception tag of the External Network Instance Profile object. +* `flood_on_encap` - (Optional) Control at EPG level if the traffic L2 Multicast/Broadcast and Link Local Layer should be flooded only on ENCAP or based on bridg-domain settings. +* `match_t` - (Optional) The provider label match criteria of the External Network Instance Profile object. +* `name_alias` - (Optional) Name alias of the External Network Instance Profile object. +* `pref_gr_memb` - (Optional) Represents parameter used to determine if an External EPG is part of a group that does not require a contract for communication. +* `prio` - (Optional) The QoS priority class identifier of the External Network Instance Profile object. +* `target_dscp` - (Optional) The target differentiated services code point (DSCP) of the path attached to the layer 3 outside profile. +* `relation_fv_rs_sec_inherited` - (Optional) Relation to EPGs to be used as Contract Masters (class fvEPg). Cardinality - N_TO_M. Type - Set of String. +* `relation_fv_rs_prov` - (Optional) Relation to Provided Contracts (class vzBrCP). Cardinality - N_TO_M. Type - Set of String. +* `relation_fv_rs_cons_if` - (Optional) Relation to Provided Contract Interfaces (class vzCPIf). Cardinality - N_TO_M. Type - Set of String. +* `relation_l3ext_rs_inst_p_to_profile` - (Optional) Relation to Route Control Profiles (class rtctrlProfile). Cardinality - N_TO_M. Type: Block. + * tn_rtctrl_profile_dn - (Optional) Distinguished name of the Route map for import and export route control. + * direction - (Optional) Direction of the Route Control Profile. +* `relation_fv_rs_cons` - (Optional) Relation to Consumed Contracts (class vzBrCP). Cardinality - N_TO_M. Type - Set of String. +* `relation_fv_rs_prot_by` - (Optional) Relation to Taboo Contracts (vzTaboo). Cardinality - N_TO_M. Type - Set of String. diff --git a/website/docs/r/external_network_instance_profile.html.markdown b/website/docs/r/external_network_instance_profile.html.markdown index 302041ace..3f1e6f533 100644 --- a/website/docs/r/external_network_instance_profile.html.markdown +++ b/website/docs/r/external_network_instance_profile.html.markdown @@ -11,44 +11,68 @@ description: |- Manages ACI External Network Instance Profile +## API Information ## + +* `Class` - l3extOut +* `Distinguished Name` - uni/tn-{tenant}/out-{l3out}/instP-{external_epg} + +## GUI Information ## + +* `Location` - Tenant -> Networking -> L3Outs -> External EPGs + ## Example Usage ```hcl - resource "aci_external_network_instance_profile" "fooexternal_network_instance_profile" { - l3_outside_dn = aci_l3_outside.example.id - description = "from terraform" - name = "demo_inst_prof" - annotation = "tag_network_profile" - exception_tag = "2" - flood_on_encap = "disabled" - match_t = "All" - name_alias = "alias_profile" - pref_gr_memb = "exclude" - prio = "level1" - target_dscp = "unspecified" - } +resource "aci_external_network_instance_profile" "external_epg" { + l3_outside_dn = aci_l3_outside.l3_outside.id + name = "external_epg" + exception_tag = "2" + flood_on_encap = "disabled" + match_t = "All" + pref_gr_memb = "exclude" + prio = "level1" + target_dscp = "unspecified" + + # Route Control Profile - Every direction(export/import) allows only one object + relation_l3ext_rs_inst_p_to_profile { + tn_rtctrl_profile_dn = aci_route_control_profile.route_control_profile_export.id + direction = "export" + } + relation_l3ext_rs_inst_p_to_profile { + tn_rtctrl_profile_dn = aci_route_control_profile.route_control_profile_import.id + direction = "import" + } + + relation_fv_rs_sec_inherited = [aci_external_network_instance_profile.external_epg_1.id] + relation_fv_rs_cons_if = [aci_imported_contract.contract_interface.id] + relation_fv_rs_prov = [aci_contract.web_contract.id] + relation_fv_rs_cons = [aci_contract.web_contract.id] + relation_fv_rs_prot_by = [aci_taboo_contract.taboo_contract.id] +} + ``` ## Argument Reference -- `l3_outside_dn` - (Required) Distinguished name of parent L3Outside object. -- `name` - (Required) Name of Object external network instance profile. -- `annotation` - (Optional) Annotation for object external network instance profile. -- `exception_tag` - (Optional) Exception tag for object external network instance profile. Allowed value range is "0" - "512". -- `flood_on_encap` - (Optional) Control at EPG level if the traffic L2 Multicast/Broadcast and Link Local Layer should be flooded only on ENCAP or based on bridg-domain settings. Allowed values are "disabled" and "enabled". Default value is "disabled". -- `match_t` - (Optional) The provider label match criteria. Allowed values are "All", "AtleastOne", "AtmostOne" and "None". Default is "AtleastOne". -- `name_alias` - (Optional) Name alias for object external network instance profile. -- `pref_gr_memb` - (Optional) Represents parameter used to determine if EPg is part of a group that does not a contract for communication. Allowed values are "include" and "exclude". Default is "exclude". - -- `prio` - (Optional) The QoS priority class identifier. Allowed values are "unspecified", "level1", "level2", "level3", "level4", "level5" and "level6". Default is "unspecified". -- `target_dscp` - (Optional) The target differentiated services code point (DSCP) of the path attached to the layer 3 outside profile. Allowed values are "CS0", "CS1", "AF11", "AF12", "AF13", "CS2", "AF21", "AF22", "AF23", "CS3", "AF31", "AF32", "AF33", "CS4", "AF41", "AF42", "AF43", "CS5", "VA", "EF", "CS6", "CS7" and "unspecified". Default is "unspecified". - -- `relation_fv_rs_sec_inherited` - (Optional) Relation to class fvEPg. Cardinality - N_TO_M. Type - Set of String. -- `relation_fv_rs_prov` - (Optional) Relation to class vzBrCP. Cardinality - N_TO_M. Type - Set of String. -- `relation_fv_rs_cons_if` - (Optional) Relation to class vzCPIf. Cardinality - N_TO_M. Type - Set of String. -- `relation_l3ext_rs_inst_p_to_profile` - (Optional) Relation to class rtctrlProfile. Cardinality - N_TO_M. Type - Set of Map. -- `relation_fv_rs_cons` - (Optional) Relation to class vzBrCP. Cardinality - N_TO_M. Type - Set of String. -- `relation_fv_rs_prot_by` - (Optional) Relation to class vzTaboo. Cardinality - N_TO_M. Type - Set of String. +* `l3_outside_dn` - (Required) Distinguished name of the parent L3Outside object. +* `name` - (Required) Name of the External Network Instance Profile object. +* `annotation` - (Optional) Annotation of the External Network Instance Profile object. +* `exception_tag` - (Optional) Exception tag of the External Network Instance Profile object. Allowed value range is "0" - "512". +* `flood_on_encap` - (Optional) Control at EPG level if the traffic L2 Multicast/Broadcast and Link Local Layer should be flooded only on ENCAP or based on bridg-domain settings. Allowed values are "disabled" and "enabled". Default value is "disabled". +* `match_t` - (Optional) The provider label match criteria of the External Network Instance Profile object. Allowed values are "All", "AtleastOne", "AtmostOne" and "None". Default is "AtleastOne". +* `name_alias` - (Optional) Name alias of the External Network Instance Profile object. +* `pref_gr_memb` - (Optional) Represents parameter used to determine if an External EPG is part of a group that does not require a contract for communication. Allowed values are "include" and "exclude". Default is "exclude". +* `prio` - (Optional) The QoS priority class identifier of the External Network Instance Profile object. Allowed values are "unspecified", "level1", "level2", "level3", "level4", "level5" and "level6". Default is "unspecified". +* `target_dscp` - (Optional) The target differentiated services code point (DSCP) of the path attached to the layer 3 outside profile. Allowed values are "CS0", "CS1", "AF11", "AF12", "AF13", "CS2", "AF21", "AF22", "AF23", "CS3", "AF31", "AF32", "AF33", "CS4", "AF41", "AF42", "AF43", "CS5", "VA", "EF", "CS6", "CS7" and "unspecified". Default is "unspecified". +* `relation_fv_rs_sec_inherited` - (Optional) Relation to EPGs to be used as Contract Masters (class fvEPg). Cardinality - N_TO_M. Type - Set of String. +* `relation_fv_rs_prov` - (Optional) Relation to Provided Contracts (class vzBrCP). Cardinality - N_TO_M. Type - Set of String. +* `relation_fv_rs_cons_if` - (Optional) Relation to Provided Contract Interfaces (class vzCPIf). Cardinality - N_TO_M. Type - Set of String. +* `relation_l3ext_rs_inst_p_to_profile` - (Optional) Relation to Route Control Profiles (class rtctrlProfile). Every direction(export/import) allows only one object. Cardinality - N_TO_M. Type: Block. + * tn_rtctrl_profile_name - (Deprecated) Name of the Route map for import and export route control. + * tn_rtctrl_profile_dn - (Optional) Distinguished name of the Route map for import and export route control. + * direction - (Optional) Direction of the Route Control Profile. Allowed values are "export" and "import". +* `relation_fv_rs_cons` - (Optional) Relation to Consumed Contracts (class vzBrCP). Cardinality - N_TO_M. Type - Set of String. +* `relation_fv_rs_prot_by` - (Optional) Relation to Taboo Contracts (vzTaboo). Cardinality - N_TO_M. Type - Set of String. ## Attribute Reference