diff --git a/aci/data_source_aci_l2ifpol.go b/aci/data_source_aci_l2ifpol.go deleted file mode 100644 index 23c128abd..000000000 --- a/aci/data_source_aci_l2ifpol.go +++ /dev/null @@ -1,72 +0,0 @@ -package aci - -import ( - "context" - "fmt" - - "github.com/ciscoecosystem/aci-go-client/v2/client" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func dataSourceAciL2InterfacePolicy() *schema.Resource { - return &schema.Resource{ - - ReadContext: dataSourceAciL2InterfacePolicyRead, - - SchemaVersion: 1, - - Schema: AppendBaseAttrSchema(map[string]*schema.Schema{ - - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - }, - - "name_alias": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - "qinq": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - "vepa": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - "vlan_scope": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - }), - } -} - -func dataSourceAciL2InterfacePolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - aciClient := m.(*client.Client) - - name := d.Get("name").(string) - - rn := fmt.Sprintf("infra/l2IfP-%s", name) - - dn := fmt.Sprintf("uni/%s", rn) - - l2IfPol, err := getRemoteL2InterfacePolicy(aciClient, dn) - - if err != nil { - return diag.FromErr(err) - } - _, err = setL2InterfacePolicyAttributes(l2IfPol, d) - if err != nil { - return diag.FromErr(err) - } - return nil -} diff --git a/aci/provider.go b/aci/provider.go index 212388a39..c8184873c 100644 --- a/aci/provider.go +++ b/aci/provider.go @@ -95,7 +95,6 @@ func Provider() *schema.Provider { "aci_bfd_multihop_interface_policy": resourceAciBfdMultihopInterfacePolicy(), "aci_bfd_multihop_node_policy": resourceAciBFDMultihopNodePolicy(), "aci_interface_fc_policy": resourceAciInterfaceFCPolicy(), - "aci_l2_interface_policy": resourceAciL2InterfacePolicy(), "aci_leaf_access_bundle_policy_group": resourceAciPCVPCInterfacePolicyGroup(), "aci_leaf_access_bundle_policy_sub_group": resourceAciOverridePCVPCPolicyGroup(), "aci_leaf_access_port_policy_group": resourceAciLeafAccessPortPolicyGroup(), @@ -324,7 +323,6 @@ func Provider() *schema.Provider { "aci_bfd_multihop_interface_policy": dataSourceAciBfdMultihopInterfacePolicy(), "aci_bfd_multihop_node_policy": dataSourceAciBFDMultihopNodePolicy(), "aci_interface_fc_policy": dataSourceAciInterfaceFCPolicy(), - "aci_l2_interface_policy": dataSourceAciL2InterfacePolicy(), "aci_leaf_access_bundle_policy_group": dataSourceAciPCVPCInterfacePolicyGroup(), "aci_leaf_access_bundle_policy_sub_group": dataSourceAciOverridePCVPCPolicyGroup(), "aci_leaf_access_port_policy_group": dataSourceAciLeafAccessPortPolicyGroup(), diff --git a/aci/resource_aci_l2ifpol.go b/aci/resource_aci_l2ifpol.go deleted file mode 100644 index 973b25569..000000000 --- a/aci/resource_aci_l2ifpol.go +++ /dev/null @@ -1,246 +0,0 @@ -package aci - -import ( - "context" - "fmt" - "log" - - "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" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -func resourceAciL2InterfacePolicy() *schema.Resource { - return &schema.Resource{ - CreateContext: resourceAciL2InterfacePolicyCreate, - UpdateContext: resourceAciL2InterfacePolicyUpdate, - ReadContext: resourceAciL2InterfacePolicyRead, - DeleteContext: resourceAciL2InterfacePolicyDelete, - - Importer: &schema.ResourceImporter{ - State: resourceAciL2InterfacePolicyImport, - }, - - SchemaVersion: 1, - - Schema: AppendBaseAttrSchema(map[string]*schema.Schema{ - - "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "name_alias": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - - "qinq": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - "disabled", - "edgePort", - "corePort", - "doubleQtagPort", - }, false), - }, - - "vepa": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - "disabled", - "enabled", - }, false), - }, - - "vlan_scope": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - "global", - "portlocal", - }, false), - }, - }), - } -} -func getRemoteL2InterfacePolicy(client *client.Client, dn string) (*models.L2InterfacePolicy, error) { - l2IfPolCont, err := client.Get(dn) - if err != nil { - return nil, err - } - - l2IfPol := models.L2InterfacePolicyFromContainer(l2IfPolCont) - - if l2IfPol.DistinguishedName == "" { - return nil, fmt.Errorf("L2 Interface Policy %s not found", dn) - } - - return l2IfPol, nil -} - -func setL2InterfacePolicyAttributes(l2IfPol *models.L2InterfacePolicy, d *schema.ResourceData) (*schema.ResourceData, error) { - d.SetId(l2IfPol.DistinguishedName) - d.Set("description", l2IfPol.Description) - l2IfPolMap, err := l2IfPol.ToMap() - if err != nil { - return d, err - } - d.Set("name", l2IfPolMap["name"]) - - d.Set("annotation", l2IfPolMap["annotation"]) - d.Set("name_alias", l2IfPolMap["nameAlias"]) - d.Set("qinq", l2IfPolMap["qinq"]) - d.Set("vepa", l2IfPolMap["vepa"]) - d.Set("vlan_scope", l2IfPolMap["vlanScope"]) - return d, nil -} - -func resourceAciL2InterfacePolicyImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { - log.Printf("[DEBUG] %s: Beginning Import", d.Id()) - aciClient := m.(*client.Client) - - dn := d.Id() - - l2IfPol, err := getRemoteL2InterfacePolicy(aciClient, dn) - - if err != nil { - return nil, err - } - schemaFilled, err := setL2InterfacePolicyAttributes(l2IfPol, d) - if err != nil { - return nil, err - } - - log.Printf("[DEBUG] %s: Import finished successfully", d.Id()) - - return []*schema.ResourceData{schemaFilled}, nil -} - -func resourceAciL2InterfacePolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - log.Printf("[DEBUG] L2InterfacePolicy: Beginning Creation") - aciClient := m.(*client.Client) - desc := d.Get("description").(string) - - name := d.Get("name").(string) - - l2IfPolAttr := models.L2InterfacePolicyAttributes{} - if Annotation, ok := d.GetOk("annotation"); ok { - l2IfPolAttr.Annotation = Annotation.(string) - } else { - l2IfPolAttr.Annotation = "{}" - } - if NameAlias, ok := d.GetOk("name_alias"); ok { - l2IfPolAttr.NameAlias = NameAlias.(string) - } - if Qinq, ok := d.GetOk("qinq"); ok { - l2IfPolAttr.Qinq = Qinq.(string) - } - if Vepa, ok := d.GetOk("vepa"); ok { - l2IfPolAttr.Vepa = Vepa.(string) - } - if VlanScope, ok := d.GetOk("vlan_scope"); ok { - l2IfPolAttr.VlanScope = VlanScope.(string) - } - l2IfPol := models.NewL2InterfacePolicy(fmt.Sprintf("infra/l2IfP-%s", name), "uni", desc, l2IfPolAttr) - - err := aciClient.Save(l2IfPol) - if err != nil { - return diag.FromErr(err) - } - - d.SetId(l2IfPol.DistinguishedName) - log.Printf("[DEBUG] %s: Creation finished successfully", d.Id()) - - return resourceAciL2InterfacePolicyRead(ctx, d, m) -} - -func resourceAciL2InterfacePolicyUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - log.Printf("[DEBUG] L2InterfacePolicy: Beginning Update") - - aciClient := m.(*client.Client) - desc := d.Get("description").(string) - - name := d.Get("name").(string) - - l2IfPolAttr := models.L2InterfacePolicyAttributes{} - if Annotation, ok := d.GetOk("annotation"); ok { - l2IfPolAttr.Annotation = Annotation.(string) - } else { - l2IfPolAttr.Annotation = "{}" - } - if NameAlias, ok := d.GetOk("name_alias"); ok { - l2IfPolAttr.NameAlias = NameAlias.(string) - } - if Qinq, ok := d.GetOk("qinq"); ok { - l2IfPolAttr.Qinq = Qinq.(string) - } - if Vepa, ok := d.GetOk("vepa"); ok { - l2IfPolAttr.Vepa = Vepa.(string) - } - if VlanScope, ok := d.GetOk("vlan_scope"); ok { - l2IfPolAttr.VlanScope = VlanScope.(string) - } - l2IfPol := models.NewL2InterfacePolicy(fmt.Sprintf("infra/l2IfP-%s", name), "uni", desc, l2IfPolAttr) - - l2IfPol.Status = "modified" - - err := aciClient.Save(l2IfPol) - - if err != nil { - return diag.FromErr(err) - } - - d.SetId(l2IfPol.DistinguishedName) - log.Printf("[DEBUG] %s: Update finished successfully", d.Id()) - - return resourceAciL2InterfacePolicyRead(ctx, d, m) - -} - -func resourceAciL2InterfacePolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - log.Printf("[DEBUG] %s: Beginning Read", d.Id()) - - aciClient := m.(*client.Client) - - dn := d.Id() - l2IfPol, err := getRemoteL2InterfacePolicy(aciClient, dn) - - if err != nil { - return errorForObjectNotFound(err, dn, d) - } - _, err = setL2InterfacePolicyAttributes(l2IfPol, d) - if err != nil { - d.SetId("") - return nil - } - - log.Printf("[DEBUG] %s: Read finished successfully", d.Id()) - - return nil -} - -func resourceAciL2InterfacePolicyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { - log.Printf("[DEBUG] %s: Beginning Destroy", d.Id()) - - aciClient := m.(*client.Client) - dn := d.Id() - err := aciClient.DeleteByDn(dn, "l2IfPol") - if err != nil { - return diag.FromErr(err) - } - - log.Printf("[DEBUG] %s: Destroy finished successfully", d.Id()) - - d.SetId("") - return diag.FromErr(err) -} diff --git a/aci/resource_aci_l2ifpol_test.go b/aci/resource_aci_l2ifpol_test.go deleted file mode 100644 index d14e84104..000000000 --- a/aci/resource_aci_l2ifpol_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package aci - -import ( - "fmt" - "testing" - - "github.com/ciscoecosystem/aci-go-client/v2/client" - "github.com/ciscoecosystem/aci-go-client/v2/models" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" -) - -func TestAccAciL2InterfacePolicy_Basic(t *testing.T) { - var l2_interface_policy models.L2InterfacePolicy - description := "l2_interface_policy created while acceptance testing" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAciL2InterfacePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckAciL2InterfacePolicyConfig_basic(description, "global"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAciL2InterfacePolicyExists("aci_l2_interface_policy.fool2_interface_policy", &l2_interface_policy), - testAccCheckAciL2InterfacePolicyAttributes(description, "global", &l2_interface_policy), - ), - }, - }, - }) -} - -func TestAccAciL2InterfacePolicy_update(t *testing.T) { - var l2_interface_policy models.L2InterfacePolicy - description := "l2_interface_policy created while acceptance testing" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAciL2InterfacePolicyDestroy, - Steps: []resource.TestStep{ - { - Config: testAccCheckAciL2InterfacePolicyConfig_basic(description, "global"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAciL2InterfacePolicyExists("aci_l2_interface_policy.fool2_interface_policy", &l2_interface_policy), - testAccCheckAciL2InterfacePolicyAttributes(description, "global", &l2_interface_policy), - ), - }, - { - Config: testAccCheckAciL2InterfacePolicyConfig_basic(description, "portlocal"), - Check: resource.ComposeTestCheckFunc( - testAccCheckAciL2InterfacePolicyExists("aci_l2_interface_policy.fool2_interface_policy", &l2_interface_policy), - testAccCheckAciL2InterfacePolicyAttributes(description, "portlocal", &l2_interface_policy), - ), - }, - }, - }) -} - -func testAccCheckAciL2InterfacePolicyConfig_basic(description, vlan_scope string) string { - return fmt.Sprintf(` - - resource "aci_l2_interface_policy" "fool2_interface_policy" { - description = "%s" - name = "demo_l2_pol" - annotation = "tag_l2_pol" - name_alias = "alias_l2_pol" - qinq = "disabled" - vepa = "disabled" - vlan_scope = "%s" - } - - `, description, vlan_scope) -} - -func testAccCheckAciL2InterfacePolicyExists(name string, l2_interface_policy *models.L2InterfacePolicy) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] - - if !ok { - return fmt.Errorf("L2 Interface Policy %s not found", name) - } - - if rs.Primary.ID == "" { - return fmt.Errorf("No L2 Interface Policy dn was set") - } - - client := testAccProvider.Meta().(*client.Client) - - cont, err := client.Get(rs.Primary.ID) - if err != nil { - return err - } - - l2_interface_policyFound := models.L2InterfacePolicyFromContainer(cont) - if l2_interface_policyFound.DistinguishedName != rs.Primary.ID { - return fmt.Errorf("L2 Interface Policy %s not found", rs.Primary.ID) - } - *l2_interface_policy = *l2_interface_policyFound - return nil - } -} - -func testAccCheckAciL2InterfacePolicyDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*client.Client) - - for _, rs := range s.RootModule().Resources { - - if rs.Type == "aci_l2_interface_policy" { - cont, err := client.Get(rs.Primary.ID) - l2_interface_policy := models.L2InterfacePolicyFromContainer(cont) - if err == nil { - return fmt.Errorf("L2 Interface Policy %s Still exists", l2_interface_policy.DistinguishedName) - } - - } else { - continue - } - } - - return nil -} - -func testAccCheckAciL2InterfacePolicyAttributes(description, vlan_scope string, l2_interface_policy *models.L2InterfacePolicy) resource.TestCheckFunc { - return func(s *terraform.State) error { - - if description != l2_interface_policy.Description { - return fmt.Errorf("Bad l2_interface_policy Description %s", l2_interface_policy.Description) - } - - if "demo_l2_pol" != l2_interface_policy.Name { - return fmt.Errorf("Bad l2_interface_policy name %s", l2_interface_policy.Name) - } - - if "tag_l2_pol" != l2_interface_policy.Annotation { - return fmt.Errorf("Bad l2_interface_policy annotation %s", l2_interface_policy.Annotation) - } - - if "alias_l2_pol" != l2_interface_policy.NameAlias { - return fmt.Errorf("Bad l2_interface_policy name_alias %s", l2_interface_policy.NameAlias) - } - - if "disabled" != l2_interface_policy.Qinq { - return fmt.Errorf("Bad l2_interface_policy qinq %s", l2_interface_policy.Qinq) - } - - if "disabled" != l2_interface_policy.Vepa { - return fmt.Errorf("Bad l2_interface_policy vepa %s", l2_interface_policy.Vepa) - } - - if vlan_scope != l2_interface_policy.VlanScope { - return fmt.Errorf("Bad l2_interface_policy vlan_scope %s", l2_interface_policy.VlanScope) - } - - return nil - } -} diff --git a/docs/data-sources/l2_interface_policy.md b/docs/data-sources/l2_interface_policy.md index 476302771..ca8e27edd 100644 --- a/docs/data-sources/l2_interface_policy.md +++ b/docs/data-sources/l2_interface_policy.md @@ -1,4 +1,7 @@ --- +# Documentation generated by "gen/generator.go"; DO NOT EDIT. +# In order to regenerate this file execute `go generate` from the repository root. +# More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md). subcategory: "Access Policies" layout: "aci" page_title: "ACI: aci_l2_interface_policy" @@ -7,28 +10,52 @@ description: |- Data source for ACI L2 Interface Policy --- -# aci_l2_interface_policy +# aci_l2_interface_policy # Data source for ACI L2 Interface Policy -## Example Usage +## API Information ## -```hcl -data "aci_l2_interface_policy" "dev_l2_int_pol" { - name = "foo_l2_int_pol" -} -``` +* Class: [l2IfPol](https://pubhub.devnetcloud.com/media/model-doc-latest/docs/app/index.html#/objects/l2IfPol/overview) + +* Supported in ACI versions: 1.1(1j) and later. + +* Distinguished Name Format: `uni/infra/l2IfP-{name}` + +## GUI Information ## -## Argument Reference +* Location: `Fabric -> Access Policies -> Policies -> Interface -> L2 Interface` -- `name` - (Required) Name of Object L2 interface policy. +## Example Usage ## -## Attribute Reference +```hcl + +data "aci_l2_interface_policy" "example" { + name = "test_name" +} + +``` -- `id` - Attribute id set to the Dn of the L2 Interface Policy. -- `annotation` - (Optional) Annotation for object L2 interface policy. -- `description` - (Optional) Description for object L2 interface policy. -- `name_alias` - (Optional) Name alias for object L2 interface policy. -- `qinq` - (Optional) Determines if QinQ is disabled or if the port should be considered a core or edge port. -- `vepa` - (Optional) Determines if Virtual Ethernet Port Aggregator is disabled or enabled. -- `vlan_scope` - (Optional) The scope of the VLAN. +## Schema ## + +### Required ### + +* `name` (name) - (string) The name of the L2 Interface Policy object. + +### Read-Only ### + +* `id` - (string) The distinguished name (DN) of the L2 Interface Policy object. +* `annotation` (annotation) - (string) The annotation of the L2 Interface Policy object. This attribute is supported in ACI versions: 3.2(1l) and later. +* `description` (descr) - (string) The description of the L2 Interface Policy object. +* `name_alias` (nameAlias) - (string) The name alias of the L2 Interface Policy object. This attribute is supported in ACI versions: 2.2(1k) and later. +* `owner_key` (ownerKey) - (string) The key for enabling clients to own their data for entity correlation. +* `owner_tag` (ownerTag) - (string) A tag for enabling clients to add their own data. For example, to indicate who created this object. +* `qinq` (qinq) - (string) The QinQ port type of the L2 Interface Policy object. This attribute is supported in ACI versions: 2.2(1k) and later. +* `reflective_relay` (vepa) - (string) The reflective relay (802.1Qbg) state of the L2 Interface Policy object. This attribute is supported in ACI versions: 2.3(1e) and later. +* `vlan_scope` (vlanScope) - (string) The vlan scope of the L2 Interface Policy object. +* `annotations` - (list) A list of Annotations (ACI object [tagAnnotation](https://pubhub.devnetcloud.com/media/model-doc-latest/docs/app/index.html#/objects/tagAnnotation/overview)). This attribute is supported in ACI versions: 3.2(1l) and later. + * `key` (key) - (string) The key used to uniquely identify this configuration object. + * `value` (value) - (string) The value of the property. +* `tags` - (list) A list of Tags (ACI object [tagTag](https://pubhub.devnetcloud.com/media/model-doc-latest/docs/app/index.html#/objects/tagTag/overview)). This attribute is supported in ACI versions: 3.2(1l) and later. + * `key` (key) - (string) The key used to uniquely identify this configuration object. + * `value` (value) - (string) The value of the property. diff --git a/docs/resources/l2_interface_policy.md b/docs/resources/l2_interface_policy.md index c0b796dcf..012340471 100644 --- a/docs/resources/l2_interface_policy.md +++ b/docs/resources/l2_interface_policy.md @@ -1,4 +1,7 @@ --- +# Documentation generated by "gen/generator.go"; DO NOT EDIT. +# In order to regenerate this file execute `go generate` from the repository root. +# More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md). subcategory: "Access Policies" layout: "aci" page_title: "ACI: aci_l2_interface_policy" @@ -7,44 +10,122 @@ description: |- Manages ACI L2 Interface Policy --- -# aci_l2_interface_policy +# aci_l2_interface_policy # Manages ACI L2 Interface Policy -## Example Usage + + !> This resource has been migrated to the terraform plugin protocol version 6, refer to the [migration guide](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/guides/migration) for more details and implications for already managed resources. + +## API Information ## + +* Class: [l2IfPol](https://pubhub.devnetcloud.com/media/model-doc-latest/docs/app/index.html#/objects/l2IfPol/overview) + +* Supported in ACI versions: 1.1(1j) and later. + +* Distinguished Name Format: `uni/infra/l2IfP-{name}` + +## GUI Information ## + +* Location: `Fabric -> Access Policies -> Policies -> Interface -> L2 Interface` + +## Example Usage ## + +The configuration snippet below creates a L2 Interface Policy with only required attributes. ```hcl + resource "aci_l2_interface_policy" "example" { - name = "demo_l2_pol" - annotation = "tag_l2_pol" - description = "from terraform" - name_alias = "alias_l2_pol" - qinq = "disabled" - vepa = "disabled" - vlan_scope = "global" + name = "test_name" +} + +``` +The configuration snippet below shows all possible attributes of the L2 Interface Policy. + +!> This example might not be valid configuration and is only used to show all possible attributes. + +```hcl + +resource "aci_l2_interface_policy" "full_example" { + annotation = "annotation" + description = "description_1" + name = "test_name" + name_alias = "name_alias_1" + owner_key = "owner_key_1" + owner_tag = "owner_tag_1" + qinq = "corePort" + reflective_relay = "enabled" + vlan_scope = "portlocal" + annotations = [ + { + key = "key_0" + value = "value_1" + } + ] + tags = [ + { + key = "key_0" + value = "value_1" + } + ] } + ``` -## Argument Reference +All examples for the L2 Interface Policy resource can be found in the [examples](https://github.com/CiscoDevNet/terraform-provider-aci/tree/master/examples/resources/aci_l2_interface_policy) folder. + +## Schema ## + +### Required ### + +* `name` (name) - (string) The name of the L2 Interface Policy object. -- `name` - (Required) Name of Object L2 interface policy. -- `annotation` - (Optional) Annotation for object L2 interface policy. -- `description` - (Optional) Description for object L2 interface policy. -- `name_alias` - (Optional) Name alias for object L2 interface policy. -- `qinq` - (Optional) Determines if QinQ is disabled or if the port should be considered a core or edge port. Allowed values are "disabled", "edgePort", "corePort" and "doubleQtagPort". Default is "disabled". -- `vepa` - (Optional) Determines if Virtual Ethernet Port Aggregator is disabled or enabled. Allowed values are "disabled" and "enabled". Default is "disabled". -- `vlan_scope` - (Optional) The scope of the VLAN. Allowed values are "global" and "portlocal". Default is "global". +### Read-Only ### -## Attribute Reference +* `id` - (string) The distinguished name (DN) of the L2 Interface Policy object. -The only attribute that this resource exports is the `id`, which is set to the -Dn of the L2 Interface Policy. +### Optional ### + +* `annotation` (annotation) - (string) The annotation of the L2 Interface Policy object. This attribute is supported in ACI versions: 3.2(1l) and later. + - Default: `"orchestrator:terraform"` +* `description` (descr) - (string) The description of the L2 Interface Policy object. +* `name_alias` (nameAlias) - (string) The name alias of the L2 Interface Policy object. This attribute is supported in ACI versions: 2.2(1k) and later. +* `owner_key` (ownerKey) - (string) The key for enabling clients to own their data for entity correlation. +* `owner_tag` (ownerTag) - (string) A tag for enabling clients to add their own data. For example, to indicate who created this object. +* `qinq` (qinq) - (string) The QinQ port type of the L2 Interface Policy object. This attribute is supported in ACI versions: 2.2(1k) and later. + - Default: `"disabled"` + - Valid Values: `"corePort"`, `"disabled"`, `"doubleQtagPort"`, `"edgePort"`. +* `reflective_relay` (vepa) - (string) The reflective relay (802.1Qbg) state of the L2 Interface Policy object. This attribute is supported in ACI versions: 2.3(1e) and later. + - Default: `"disabled"` + - Valid Values: `"disabled"`, `"enabled"`. +* `vlan_scope` (vlanScope) - (string) The vlan scope of the L2 Interface Policy object. + - Default: `"global"` + - Valid Values: `"global"`, `"portlocal"`. +* `annotations` - (list) A list of Annotations (ACI object [tagAnnotation](https://pubhub.devnetcloud.com/media/model-doc-latest/docs/app/index.html#/objects/tagAnnotation/overview)). Annotations can also be configured using a separate [aci_annotation](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/annotation) resource. This attribute is supported in ACI versions: 3.2(1l) and later. + #### Required #### + + * `key` (key) - (string) The key used to uniquely identify this configuration object. + * `value` (value) - (string) The value of the property. +* `tags` - (list) A list of Tags (ACI object [tagTag](https://pubhub.devnetcloud.com/media/model-doc-latest/docs/app/index.html#/objects/tagTag/overview)). Tags can also be configured using a separate [aci_tag](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/tag) resource. This attribute is supported in ACI versions: 3.2(1l) and later. + #### Required #### + + * `key` (key) - (string) The key used to uniquely identify this configuration object. + * `value` (value) - (string) The value of the property. ## Importing -An existing L2 Interface Policy can be [imported][docs-import] into this resource via its Dn, via the following command: -[docs-import]: +An existing L2 Interface Policy can be [imported](https://www.terraform.io/docs/import/index.html) into this resource with its distinguished name (DN), via the following command: + +``` +terraform import aci_l2_interface_policy.example uni/infra/l2IfP-{name} +``` -```bash -terraform import aci_l2_interface_policy.example +Starting in Terraform version 1.5, an existing L2 Interface Policy can be imported +using [import blocks](https://developer.hashicorp.com/terraform/language/import) via the following configuration: + +``` +import { + id = "uni/infra/l2IfP-{name}" + to = aci_l2_interface_policy.example +} ``` diff --git a/examples/data-sources/aci_l2_interface_policy/data-source.tf b/examples/data-sources/aci_l2_interface_policy/data-source.tf new file mode 100644 index 000000000..3a31c29d8 --- /dev/null +++ b/examples/data-sources/aci_l2_interface_policy/data-source.tf @@ -0,0 +1,4 @@ + +data "aci_l2_interface_policy" "example" { + name = "test_name" +} diff --git a/examples/data-sources/aci_l2_interface_policy/provider.tf b/examples/data-sources/aci_l2_interface_policy/provider.tf new file mode 100644 index 000000000..975fca093 --- /dev/null +++ b/examples/data-sources/aci_l2_interface_policy/provider.tf @@ -0,0 +1,14 @@ +terraform { + required_providers { + aci = { + source = "ciscodevnet/aci" + } + } +} + +provider "aci" { + username = "" + password = "" + url = "" + insecure = true +} \ No newline at end of file diff --git a/examples/resources/aci_l2_interface_policy/provider.tf b/examples/resources/aci_l2_interface_policy/provider.tf new file mode 100644 index 000000000..975fca093 --- /dev/null +++ b/examples/resources/aci_l2_interface_policy/provider.tf @@ -0,0 +1,14 @@ +terraform { + required_providers { + aci = { + source = "ciscodevnet/aci" + } + } +} + +provider "aci" { + username = "" + password = "" + url = "" + insecure = true +} \ No newline at end of file diff --git a/examples/resources/aci_l2_interface_policy/resource-all-attributes.tf b/examples/resources/aci_l2_interface_policy/resource-all-attributes.tf new file mode 100644 index 000000000..14e936af2 --- /dev/null +++ b/examples/resources/aci_l2_interface_policy/resource-all-attributes.tf @@ -0,0 +1,24 @@ + +resource "aci_l2_interface_policy" "full_example" { + annotation = "annotation" + description = "description_1" + name = "test_name" + name_alias = "name_alias_1" + owner_key = "owner_key_1" + owner_tag = "owner_tag_1" + qinq = "corePort" + reflective_relay = "enabled" + vlan_scope = "portlocal" + annotations = [ + { + key = "key_0" + value = "value_1" + } + ] + tags = [ + { + key = "key_0" + value = "value_1" + } + ] +} diff --git a/examples/resources/aci_l2_interface_policy/resource.tf b/examples/resources/aci_l2_interface_policy/resource.tf new file mode 100644 index 000000000..5e5e6438d --- /dev/null +++ b/examples/resources/aci_l2_interface_policy/resource.tf @@ -0,0 +1,4 @@ + +resource "aci_l2_interface_policy" "example" { + name = "test_name" +} diff --git a/gen/definitions/classes.yaml b/gen/definitions/classes.yaml index 567a3256e..a4f4caef8 100644 --- a/gen/definitions/classes.yaml +++ b/gen/definitions/classes.yaml @@ -1266,3 +1266,16 @@ infraRsAccBndlSubgrp: infraAccBndlSubgrp: resource_name: "leaf_access_bundle_policy_sub_group" + +l2IfPol: + resource_name: "l2_interface_policy" + sub_category: "Access Policies" + ui_locations: + - "Fabric -> Access Policies -> Policies -> Interface -> L2 Interface" + contained_by: + - "polUni" + rn_prepend: "infra" + migration_version: 1 + migration_blocks: + l2IfPol: + vepa: reflective_relay diff --git a/gen/definitions/properties.yaml b/gen/definitions/properties.yaml index 96af5d8a4..32329e137 100644 --- a/gen/definitions/properties.yaml +++ b/gen/definitions/properties.yaml @@ -2895,3 +2895,14 @@ infraRsAccBndlSubgrp: # Response Status Code: 400, Error Code: 182, Error Message: Validation failed PortBlk has a reln to AccBndlSubgrp not contained by AccBndlGrp its parent is associated to. target_dn: "" +l2IfPol: + overwrites: + vepa: reflective_relay + documentation: + qinq: "The QinQ port type of the %s object." + vepa: "The reflective relay (802.1Qbg) state of the %s object." + vlanScope: "The vlan scope of the %s object." + test_values: + all: + reflective_relay: "enabled" + vlan_scope: "portlocal" diff --git a/gen/meta/l2IfPol.json b/gen/meta/l2IfPol.json new file mode 100644 index 000000000..41218c6a4 --- /dev/null +++ b/gen/meta/l2IfPol.json @@ -0,0 +1,857 @@ +{ + "l2:IfPol": { + "contains": { + "aaa:RbacAnnotation": "", + "fault:Delegate": "", + "l2:RtL2IfPol": "", + "l2:RtL2IfPolCons": "", + "l2:RtLabelL2IfPolCons": "", + "tag:Annotation": "", + "tag:Tag": "" + }, + "rnMap": { + "annotationKey-": "tag:Annotation", + "fd-": "fault:Delegate", + "rbacDom-": "aaa:RbacAnnotation", + "rtinfraL2IfPol-": "l2:RtL2IfPol", + "rtl1L2IfPolCons-": "l2:RtL2IfPolCons", + "rtnwLabelL2IfPolCons-": "l2:RtLabelL2IfPolCons", + "tagKey-": "tag:Tag" + }, + "identifiedBy": [ + "name" + ], + "rnFormat": "l2IfP-{name}", + "containedBy": { + "infra:Infra": "" + }, + "superClasses": [ + "fabric:L2IfPol", + "fabric:ProtoIfPol", + "fabric:ProtoPol", + "pol:Def", + "pol:Obj", + "naming:NamedObject" + ], + "subClasses": { + + }, + "relationFrom": { + "l2:RtL2IfPol": "infra:AccGrp", + "l2:RtL2IfPolCons": "l1:EthIf", + "l2:RtLabelL2IfPolCons": "nw:LabelEp" + }, + "relationTo": { + + }, + "dnFormats": [ + "uni/infra/l2IfP-{name}" + ], + "writeAccess": [ + "access-connectivity", + "access-protocol", + "admin", + "custom-port-privilege" + ], + "readAccess": [ + "access-connectivity", + "access-protocol", + "admin", + "custom-port-privilege" + ], + "faults": { + + }, + "events": { + "E4212416": "creation||l2:IfPol", + "E4212417": "modification||l2:IfPol", + "E4212418": "deletion||l2:IfPol" + }, + "stats": { + + }, + "versions": "1.1(1j)-", + "isAbstract": false, + "isConfigurable": true, + "isContextRoot": false, + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false, + "isEncrypted": false, + "isExportable": true, + "isPersistent": true, + "isSubjectToQuota": false, + "isObservable": false, + "hasStats": false, + "isStat": false, + "isFaultable": false, + "isDomainable": false, + "isHealthScorable": false, + "shouldCollectHealthStats": false, + "healthCollectionSource": "faults", + "hasEventRules": false, + "abstractionLayer": "logical", + "apicNxProcessing": false, + "monitoringPolicySource": "Parent", + "isCreatableDeletable": "always", + "platformFlavors": [ + "apic" + ], + "classId": "6140", + "className": "IfPol", + "classPkg": "l2", + "featureTag": "", + "moCategory": "Regular", + "label": "L2 Interface Policy", + "comment": [ + "" + ], + "properties": { + "annotation": { + "versions": "3.2(1l)-", + "comment": [ + "User annotation. Suggested format orchestrator:value" + ], + "isConfigurable": true, + "propGlobalId": "38194", + "propLocalId": "8719", + "label": "Annotation", + "baseType": "string:Basic", + "modelType": "mo:Annotation", + "needsPropDelimiters": false, + "uitype": "string", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validators": [ + {"min" : 0, "max": 128, + "regexs": [ + {"regex" : "^[a-zA-Z0-9_.:-]+$", "type": "include"} + ] + } + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "childAction": { + "versions": "1.0(1e)-", + "comment": [ + "Delete or ignore. For internal use only." + ], + "isConfigurable": false, + "propGlobalId": "4", + "propLocalId": "5", + "label": "childAction", + "baseType": "scalar:Bitmask32", + "modelType": "mo:ModificationChildAction", + "needsPropDelimiters": false, + "uitype": "bitmask", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "16384", "localName": "deleteAll", + "platformFlavors": [ + + ], + "label": "Delete All "}, + { "value": "8192", "localName": "deleteNonPresent", + "platformFlavors": [ + + ], + "label": "Delete Non Present "}, + { "value": "4096", "localName": "ignore", + "platformFlavors": [ + + ], + "label": "Ignore "} + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "descr": { + "versions": "1.0(1e)-", + "comment": [ + "Specifies a description of the policy definition." + ], + "isConfigurable": true, + "propGlobalId": "5579", + "propLocalId": "28", + "label": "Description", + "baseType": "string:Basic", + "modelType": "naming:Descr", + "needsPropDelimiters": false, + "uitype": "string", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": true, + "likeProp": "naming:Described:descr", + "validators": [ + {"min" : 0, "max": 128, + "regexs": [ + {"regex" : "^[a-zA-Z0-9\\\\!#$%()*,-./:;@ _{|}~?&+]+$", "type": "include"} + ] + } + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "dn": { + "versions": "1.0(1e)-", + "comment": [ + "A tag or metadata is a non-hierarchical keyword or term assigned to the fabric module." + ], + "isConfigurable": false, + "propGlobalId": "1", + "propLocalId": "2", + "label": "dn", + "baseType": "reference:BinRef", + "modelType": "reference:BinRef", + "needsPropDelimiters": true, + "uitype": "auto", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "extMngdBy": { + "versions": "3.2(1l)-", + "comment": [ + "Indicates which orchestrator is managing this MO" + ], + "isConfigurable": false, + "propGlobalId": "40333", + "propLocalId": "8023", + "label": "Managed By", + "baseType": "scalar:Bitmask32", + "modelType": "mo:ExtMngdByType", + "needsPropDelimiters": false, + "uitype": "bitmask", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "undefined", "localName": "defaultValue", + "platformFlavors": [ + + ], + "label": " "}, + { "value": "1", "localName": "msc", + "platformFlavors": [ + + ], + "label": "MSC "}, + { "value": "0", "localName": "undefined", + "platformFlavors": [ + + ], + "label": "Undefined "} + ], + "default": "undefined", + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "lcOwn": { + "versions": "1.0(1e)-", + "comment": [ + "A value that indicates how this object was created. For internal use only." + ], + "isConfigurable": false, + "propGlobalId": "9", + "propLocalId": "9", + "label": "lcOwn", + "baseType": "scalar:Enum8", + "modelType": "mo:Owner", + "needsPropDelimiters": false, + "uitype": "enum", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "local", "localName": "defaultValue", + "platformFlavors": [ + + ], + "label": " "}, + { "value": "4", "localName": "implicit", + "platformFlavors": [ + + ], + "label": "Implicit "}, + { "value": "0", "localName": "local", + "platformFlavors": [ + + ], + "label": "Local "}, + { "value": "1", "localName": "policy", + "platformFlavors": [ + + ], + "label": "Policy "}, + { "value": "2", "localName": "replica", + "platformFlavors": [ + + ], + "label": "Replica "}, + { "value": "3", "localName": "resolveOnBehalf", + "platformFlavors": [ + + ], + "label": "Resolved On Behalf "} + ], + "default": "local", + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "modTs": { + "versions": "1.0(1e)-", + "comment": [ + "The time when this object was last modified." + ], + "isConfigurable": false, + "propGlobalId": "7", + "propLocalId": "7", + "label": "modTs", + "baseType": "scalar:Date", + "modelType": "mo:TStamp", + "needsPropDelimiters": false, + "uitype": "auto", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "never", "localName": "defaultValue", + "platformFlavors": [ + + ], + "label": " "}, + { "value": "0", "localName": "never", + "platformFlavors": [ + + ], + "label": "Never "} + ], + "default": "never", + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "name": { + "versions": "1.1(1j)-", + "comment": [ + "The name of the object." + ], + "isConfigurable": true, + "propGlobalId": "18250", + "propLocalId": "13", + "label": "Name", + "baseType": "string:Basic", + "modelType": "naming:Name", + "needsPropDelimiters": false, + "uitype": "string", + "createOnly": false, + "readWrite": false, + "readOnly": false, + "isNaming": true, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": true, + "isLike": false, + "validators": [ + {"min" : 1, "max": 64, + "regexs": [ + {"regex" : "^[a-zA-Z0-9_.:-]+$", "type": "include"} + ] + } + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "nameAlias": { + "versions": "2.2(1k)-", + "isConfigurable": true, + "propGlobalId": "28417", + "propLocalId": "6719", + "label": "Display Name", + "baseType": "string:Basic", + "modelType": "naming:NameAlias", + "needsPropDelimiters": false, + "uitype": "string", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validators": [ + {"min" : 0, "max": 63, + "regexs": [ + {"regex" : "^[a-zA-Z0-9_.-]+$", "type": "include"} + ] + } + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "ownerKey": { + "versions": "1.0(1e)-", + "comment": [ + "The key for enabling clients to own their data for entity correlation." + ], + "isConfigurable": true, + "propGlobalId": "15230", + "propLocalId": "4100", + "label": "ownerKey", + "baseType": "string:Basic", + "modelType": "naming:Descr", + "needsPropDelimiters": false, + "uitype": "string", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validators": [ + {"min" : 0, "max": 128, + "regexs": [ + {"regex" : "^[a-zA-Z0-9\\\\!#$%()*,-./:;@ _{|}~?&+]+$", "type": "include"} + ] + } + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "ownerTag": { + "versions": "1.0(1e)-", + "comment": [ + "A tag for enabling clients to add their own data. For example, to indicate who created this object." + ], + "isConfigurable": true, + "propGlobalId": "15231", + "propLocalId": "4101", + "label": "ownerTag", + "baseType": "string:Basic", + "modelType": "naming:Descr", + "needsPropDelimiters": false, + "uitype": "string", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validators": [ + {"min" : 0, "max": 64, + "regexs": [ + {"regex" : "^[a-zA-Z0-9\\\\!#$%()*,-./:;@ _{|}~?&+]+$", "type": "include"} + ] + } + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "qinq": { + "versions": "2.2(1k)-", + "comment": [ + "QinQ Configuration" + ], + "isConfigurable": true, + "propGlobalId": "27239", + "propLocalId": "6380", + "label": "dot1q-tunnel Policy Configuration", + "baseType": "scalar:Enum8", + "modelType": "l2:QinQConfig", + "needsPropDelimiters": false, + "uitype": "enum", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "2", "localName": "corePort", + "platformFlavors": [ + + ], + "label": "corePort "}, + { "value": "disabled", "localName": "defaultValue", + "platformFlavors": [ + + ], + "label": " "}, + { "value": "0", "localName": "disabled", + "platformFlavors": [ + + ], + "label": "disabled "}, + { "value": "3", "localName": "doubleQtagPort", + "platformFlavors": [ + + ], + "label": "doubleQtagPort "}, + { "value": "1", "localName": "edgePort", + "platformFlavors": [ + + ], + "label": "edgePort "} + ], + "default": "disabled", + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "rn": { + "versions": "1.0(1e)-", + "comment": [ + "Identifies an object from its siblings within the context of its parent object. The distinguished name contains a sequence of relative names." + ], + "isConfigurable": false, + "propGlobalId": "2", + "propLocalId": "3", + "label": "rn", + "baseType": "reference:BinRN", + "modelType": "reference:BinRN", + "needsPropDelimiters": true, + "uitype": "auto", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "status": { + "versions": "1.0(1e)-", + "comment": [ + "The upgrade status. This property is for internal use only." + ], + "isConfigurable": false, + "propGlobalId": "3", + "propLocalId": "4", + "label": "status", + "baseType": "scalar:Bitmask32", + "modelType": "mo:ModificationStatus", + "needsPropDelimiters": false, + "uitype": "bitmask", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "2", "localName": "created", + "platformFlavors": [ + + ], + "comment": [ + "In a setter method: specifies that an object should be created. An error is returned if the object already exists. \nIn the return value of a setter method: indicates that an object has been created. \n" + ], + "label": "Created "}, + { "value": "8", "localName": "deleted", + "platformFlavors": [ + + ], + "comment": [ + "In a setter method: specifies that an object should be deleted. \nIn the return value of a setter method: indicates that an object has been deleted.\n" + ], + "label": "Deleted "}, + { "value": "4", "localName": "modified", + "platformFlavors": [ + + ], + "comment": [ + "In a setter method: specifies that an object should be modified \nIn the return value of a setter method: indicates that an object has been modified.\n" + ], + "label": "Modified "} + ], + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "uid": { + "versions": "1.0(1e)-", + "comment": [ + "A unique identifier for this object." + ], + "isConfigurable": false, + "propGlobalId": "8", + "propLocalId": "8", + "label": "uid", + "baseType": "scalar:Uint16", + "modelType": "scalar:Uint16", + "needsPropDelimiters": false, + "uitype": "auto", + "createOnly": false, + "readWrite": false, + "readOnly": true, + "isNaming": false, + "secure": false, + "implicit": true, + "mandatory": false, + "isOverride": false, + "isLike": false, + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "userdom": { + "versions": "5.0(1k)-", + "isConfigurable": true, + "propGlobalId": "60657", + "propLocalId": "13244", + "label": "userdom", + "baseType": "string:Basic", + "modelType": "mo:UserDomType", + "needsPropDelimiters": false, + "uitype": "string", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validators": [ + {"min" : 0, "max": 1024, + "regexs": [ + {"regex" : "^[a-zA-Z0-9_.:-]+$", "type": "include"} + ] + } + ], + "validValues": [ + { "value": "all", "localName": "defaultValue", + "platformFlavors": [ + + ], + "label": " "} + ], + "default": "all", + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "vepa": { + "versions": "2.3(1e)-", + "comment": [ + "Vepa Configuration" + ], + "isConfigurable": true, + "propGlobalId": "32652", + "propLocalId": "7832", + "label": "Vepa Policy Configuration", + "baseType": "scalar:Enum8", + "modelType": "l2:VepaConfig", + "needsPropDelimiters": false, + "uitype": "enum", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "disabled", "localName": "defaultValue", + "platformFlavors": [ + + ], + "label": " "}, + { "value": "0", "localName": "disabled", + "platformFlavors": [ + + ], + "label": "disabled "}, + { "value": "1", "localName": "enabled", + "platformFlavors": [ + + ], + "label": "enabled "} + ], + "default": "disabled", + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + }, + "vlanScope": { + "versions": "1.1(1j)-", + "comment": [ + "The Layer 2 interface VLAN scope" + ], + "isConfigurable": true, + "propGlobalId": "18248", + "propLocalId": "4712", + "label": "VLAN scope, can be global or port-local", + "baseType": "scalar:Enum8", + "modelType": "l2:VlanScope", + "needsPropDelimiters": false, + "uitype": "enum", + "createOnly": false, + "readWrite": true, + "readOnly": false, + "isNaming": false, + "secure": false, + "implicit": false, + "mandatory": false, + "isOverride": false, + "isLike": false, + "validValues": [ + { "value": "global", "localName": "defaultValue", + "platformFlavors": [ + + ], + "label": " "}, + { "value": "0", "localName": "global", + "platformFlavors": [ + + ], + "label": "Global Scope "}, + { "value": "1", "localName": "portlocal", + "platformFlavors": [ + + ], + "label": "Port Local Scope "} + ], + "default": "global", + "platformFlavors": [ + + ], + "isNxosConverged": false, + "isDeprecated": false, + "isHidden": false + } + } + } +} diff --git a/gen/templates/resource.md.tmpl b/gen/templates/resource.md.tmpl index d34c2b816..cbfca70f7 100644 --- a/gen/templates/resource.md.tmpl +++ b/gen/templates/resource.md.tmpl @@ -123,8 +123,8 @@ All examples for the {{.ResourceNameAsDescription}} resource can be found in the {{- if eq .ValueType "bitmask"}} * `{{- overwriteProperty .PkgName .SnakeCaseName $.Definitions}}` ({{- .PropertyName}}) - (list) {{.Comment}}{{if and (ne $.Versions .Versions) (ne .Versions "")}} This attribute is supported in ACI versions: {{ .Versions}}{{- end}} {{- if .DefaultValue }} - {{- if eq .DefaultValue "@aci_gen_default_value_overwrite_to_empty_string!"}} - - Default: `""` + {{- if eq .DefaultValue "@aci_gen_default_value_overwrite_to_empty_list!"}} + - Default: `[]` {{- else}} - Default: `"{{ .DefaultValue }}"` {{- end}} @@ -241,6 +241,8 @@ import { {{- if .DefaultValue }} {{- if eq .DefaultValue "@aci_gen_default_value_overwrite_to_empty_string!"}} {{ $indent }}- Default: `""` + {{- else if eq .DefaultValue "@aci_gen_default_value_overwrite_to_empty_list!"}} + {{ $indent }}- Default: `[]` {{- else}} {{ $indent }}- Default: `"{{ .DefaultValue }}"` {{- end}} diff --git a/gen/templates/resource_test.go.tmpl b/gen/templates/resource_test.go.tmpl index 940929783..ddc7fcc7b 100644 --- a/gen/templates/resource_test.go.tmpl +++ b/gen/templates/resource_test.go.tmpl @@ -1290,6 +1290,11 @@ func TestAccResource{{.resourceClassName}}(t *testing.T) { {{- else }} {{- if eq $child_key "target_dn"}} resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}", "{{getTestTargetDn $.child_targets $key $child_value false nil $child_index false}}"), + {{- else if (isInterfaceSlice $child_value)}} + resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}.#", "{{len $child_value}}"), + {{- range $index, $subvalue := $child_value}} + resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}.{{$index}}", "{{$subvalue}}"), + {{- end}} {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}", "{{$child_value}}"), {{- end}} @@ -1392,9 +1397,14 @@ func TestAccResource{{.resourceClassName}}(t *testing.T) { {{- end }}), {{- end }} {{- else }} - {{- if eq $child_key "target_dn"}} + {{- if eq $child_key "target_dn"}} resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}", "{{getTestTargetDn $.child_targets $key $child_value false nil $child_index false}}"), - {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} + {{- else if (isInterfaceSlice $child_value)}} + resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}.#", "{{len $child_value}}"), + {{- range $index, $subvalue := $child_value}} + resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}.{{$index}}", "{{$subvalue}}"), + {{- end}} + {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.{{$child_index}}.{{$child_key}}", "{{$child_value}}"), {{- end}} {{- end}} @@ -1496,9 +1506,14 @@ func TestAccResource{{.resourceClassName}}(t *testing.T) { {{- end }}), {{- end }} {{- else }} - {{- if eq $child_key "target_dn"}} + {{- if eq $child_key "target_dn"}} resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.0.{{$child_key}}", "{{getTestTargetDn $.child_targets $key $child_value false nil 1 false}}"), - {{- else}} + {{- else if (isInterfaceSlice $child_value)}} + resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.0.{{$child_key}}.#", "{{len $child_value}}"), + {{- range $index, $subvalue := $child_value}} + resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.0.{{$child_key}}.{{$index}}", "{{$subvalue}}"), + {{- end}} + {{- else}} resource.TestCheckResourceAttr("aci_{{$.resourceName}}.test", "{{$key}}.0.{{$child_key}}", "{{$child_value}}"), {{- end}} {{- end}} @@ -2508,6 +2523,12 @@ resource "aci_{{$.resourceName}}" "test" { {{- else }} {{- if eq $child_key "target_dn"}}{{$attributeValue := getTestTargetDn $.child_targets $key $child_value true nil $index false}} {{$child_key}} = {{if isReference $attributeValue}}{{$attributeValue}}{{- else if isInterfaceSlice $attributeValue}}{{- if lt 0 (len $attributeValue)}}[{{fromInterfacesToString $attributeValue}}]{{else}}[]{{end}}{{else}}"{{$attributeValue}}"{{end}} + {{- else if (isInterfaceSlice $child_value)}} + {{- if lt 0 (len $child_value)}} + {{$child_key}} = [{{range $index, $subvalue := $child_value}}{{if lt $index (subtract (len $child_value) 1)}}"{{$subvalue}}", {{else}}"{{$subvalue}}"{{end}}{{end}}] + {{- else}} + {{$child_key}} = [] + {{- end}} {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} {{$child_key}} = "{{$child_value}}" {{- end}} @@ -2537,7 +2558,7 @@ resource "aci_{{$.resourceName}}" "test" { {{- range $key, $value := $.resource_required}} {{- if eq $key "target_dn" }}{{$attributeValue := getTestTargetDn $.targets $.resourceName $value true nil 0 false}} {{$key}} = {{if isReference $attributeValue}}{{$attributeValue}}{{- else if isInterfaceSlice $attributeValue}}{{- if lt 0 (len $attributeValue)}}[{{fromInterfacesToString $attributeValue}}]{{else}}[]{{end}}{{else}}"{{$attributeValue}}"{{end}} - {{- else }} + {{- else }} {{$key}} = "{{$value}}" {{- end }} {{- end}} @@ -2610,7 +2631,13 @@ resource "aci_{{$.resourceName}}" "test" { {{- else }} {{- if eq $child_key "target_dn"}}{{$attributeValue := getTestTargetDn $.child_targets $key $child_value true nil 1 false}} {{$child_key}} = {{if isReference $attributeValue}}{{$attributeValue}}{{- else if isInterfaceSlice $attributeValue}}{{- if lt 0 (len $attributeValue)}}[{{fromInterfacesToString $attributeValue}}]{{else}}[]{{end}}{{else}}"{{$attributeValue}}"{{end}} - {{- else }} + {{- else if (isInterfaceSlice $child_value)}} + {{- if lt 0 (len $child_value)}} + {{$child_key}} = [{{range $index, $subvalue := $child_value}}{{if lt $index (subtract (len $child_value) 1)}}"{{$subvalue}}", {{else}}"{{$subvalue}}"{{end}}{{end}}] + {{- else}} + {{$child_key}} = [] + {{- end}} + {{- else }} {{$child_key}} = "{{$child_value}}" {{- end}} {{- end}} @@ -3170,16 +3197,16 @@ resource "aci_{{$.resourceName}}" "test" { {{- end }}{{- end }}), {{- end }} {{- else }} - {{- if eq $child_key "target_dn"}} + {{- if eq $child_key "target_dn"}} resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_key}}", "{{getTestTargetDn $.child_targets $key $child_value false nil $child_index false}}"), - {{- else if (isInterfaceSlice $child_value)}} + {{- else if (isInterfaceSlice $child_value)}} resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_key}}.#", "{{len $child_value}}"), - {{- range $index, $subvalue := $child_value}} + {{- range $index, $subvalue := $child_value}} resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_key}}.{{$index}}", "{{$subvalue}}"), - {{- end}} - {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} + {{- end}} + {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_key}}", "{{$child_value}}"), - {{- end}} + {{- end}} {{- end}} {{- end}} {{- end }} @@ -3196,9 +3223,14 @@ resource "aci_{{$.resourceName}}" "test" { {{- end }}), {{- end }} {{- else }} - {{- if eq $child_key "target_dn"}} + {{- if eq $child_key "target_dn"}} resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_index}}.{{$child_key}}", "{{getTestTargetDn $.child_targets $key $child_value false nil $child_index false}}"), - {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} + {{- else if (isInterfaceSlice $child_value)}} + resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_key}}.#", "{{len $child_value}}"), + {{- range $index, $subvalue := $child_value}} + resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_key}}.{{$index}}", "{{$subvalue}}"), + {{- end}} + {{- else if and (ne $child_key "deletable_child") (ne $child_key "child_required")}} resource.TestCheckResourceAttr("{{$resourceName}}", "{{$inheritedKey}}.{{$key}}.{{$child_index}}.{{$child_key}}", "{{$child_value}}"), {{- end}} {{- end}} diff --git a/gen/testvars/l2IfPol.yaml b/gen/testvars/l2IfPol.yaml new file mode 100644 index 000000000..31a558132 --- /dev/null +++ b/gen/testvars/l2IfPol.yaml @@ -0,0 +1,54 @@ +# Code generated by "gen/generator.go"; DO NOT EDIT. +# In order to regenerate this file execute `go generate` from the repository root. +# More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md). +legacy_attributes: + vepa: "disabled" + + +default: + annotation: "orchestrator:terraform" + description: "" + name_alias: "" + owner_key: "" + owner_tag: "" + qinq: "disabled" + reflective_relay: "disabled" + vlan_scope: "global" + +datasource_non_existing: + name: "non_existing_name" + +datasource_required: + name: "test_name" + +resource_required: + name: "test_name" + +all: + annotation: "annotation" + description: "description_1" + name_alias: "name_alias_1" + owner_key: "owner_key_1" + owner_tag: "owner_tag_1" + qinq: "corePort" + reflective_relay: "enabled" + vlan_scope: "portlocal" + +children: + annotations: + - key: "key_0" + value: "value_1" + + - key: "key_1" + value: "test_value" + + tags: + - key: "key_0" + value: "value_1" + + - key: "key_1" + value: "test_value" + + +test_type: apic +class_version: 1.1(1j)- diff --git a/internal/provider/data_source_aci_l2_interface_policy.go b/internal/provider/data_source_aci_l2_interface_policy.go new file mode 100644 index 000000000..4d2abe1fc --- /dev/null +++ b/internal/provider/data_source_aci_l2_interface_policy.go @@ -0,0 +1,180 @@ +// Code generated by "gen/generator.go"; DO NOT EDIT. +// In order to regenerate this file execute `go generate` from the repository root. +// More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md). + +package provider + +import ( + "context" + "fmt" + + "github.com/ciscoecosystem/aci-go-client/v2/client" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ datasource.DataSource = &L2IfPolDataSource{} + +func NewL2IfPolDataSource() datasource.DataSource { + return &L2IfPolDataSource{} +} + +// L2IfPolDataSource defines the data source implementation. +type L2IfPolDataSource struct { + client *client.Client +} + +func (d *L2IfPolDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + tflog.Debug(ctx, "Start metadata of datasource: aci_l2_interface_policy") + resp.TypeName = req.ProviderTypeName + "_l2_interface_policy" + tflog.Debug(ctx, "End metadata of datasource: aci_l2_interface_policy") +} + +func (d *L2IfPolDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + tflog.Debug(ctx, "Start schema of datasource: aci_l2_interface_policy") + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "The l2_interface_policy datasource for the 'l2IfPol' class", + + Attributes: map[string]schema.Attribute{ + // Deprecated attributes + "vepa": schema.StringAttribute{ + Computed: true, + DeprecationMessage: "Attribute 'vepa' is deprecated, please refer to 'reflective_relay' instead. The attribute will be removed in the next major version of the provider.", + }, + // End of deprecated attributes + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The distinguished name (DN) of the L2 Interface Policy object.", + }, + "annotation": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The annotation of the L2 Interface Policy object.`, + }, + "description": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The description of the L2 Interface Policy object.`, + }, + "name": schema.StringAttribute{ + Required: true, + MarkdownDescription: `The name of the L2 Interface Policy object.`, + }, + "name_alias": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The name alias of the L2 Interface Policy object.`, + }, + "owner_key": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The key for enabling clients to own their data for entity correlation.`, + }, + "owner_tag": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `A tag for enabling clients to add their own data. For example, to indicate who created this object.`, + }, + "qinq": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The QinQ port type of the L2 Interface Policy object.`, + }, + "reflective_relay": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The reflective relay (802.1Qbg) state of the L2 Interface Policy object.`, + }, + "vlan_scope": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The vlan scope of the L2 Interface Policy object.`, + }, + "annotations": schema.SetNestedAttribute{ + MarkdownDescription: ``, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The key used to uniquely identify this configuration object.`, + }, + "value": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The value of the property.`, + }, + }, + }, + }, + "tags": schema.SetNestedAttribute{ + MarkdownDescription: ``, + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The key used to uniquely identify this configuration object.`, + }, + "value": schema.StringAttribute{ + Computed: true, + MarkdownDescription: `The value of the property.`, + }, + }, + }, + }, + }, + Blocks: map[string]schema.Block{}, + } + tflog.Debug(ctx, "End schema of datasource: aci_l2_interface_policy") +} + +func (d *L2IfPolDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + tflog.Debug(ctx, "Start configure of datasource: aci_l2_interface_policy") + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client + tflog.Debug(ctx, "End configure of datasource: aci_l2_interface_policy") +} + +func (d *L2IfPolDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + tflog.Debug(ctx, "Start read of datasource: aci_l2_interface_policy") + var data *L2IfPolResourceModel + + // Read Terraform configuration data into the model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + setL2IfPolId(ctx, data) + + // Create a copy of the Id for when not found during getAndSetL2IfPolAttributes + cachedId := data.Id.ValueString() + + tflog.Debug(ctx, fmt.Sprintf("Read of datasource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) + + getAndSetL2IfPolAttributes(ctx, &resp.Diagnostics, d.client, data) + + if data.Id.IsNull() { + resp.Diagnostics.AddError( + "Failed to read aci_l2_interface_policy data source", + fmt.Sprintf("The aci_l2_interface_policy data source with id '%s' has not been found", cachedId), + ) + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + tflog.Debug(ctx, fmt.Sprintf("End read of datasource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) +} diff --git a/internal/provider/data_source_aci_l2_interface_policy_test.go b/internal/provider/data_source_aci_l2_interface_policy_test.go new file mode 100644 index 000000000..b9d891bf6 --- /dev/null +++ b/internal/provider/data_source_aci_l2_interface_policy_test.go @@ -0,0 +1,52 @@ +// Code generated by "gen/generator.go"; DO NOT EDIT. +// In order to regenerate this file execute `go generate` from the repository root. +// More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md). + +package provider + +import ( + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccDataSourceL2IfPol(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t, "apic", "1.1(1j)-") }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testConfigL2IfPolDataSource, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "annotation", "annotation"), + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "description", "description_1"), + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "name_alias", "name_alias_1"), + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "owner_key", "owner_key_1"), + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "owner_tag", "owner_tag_1"), + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "qinq", "corePort"), + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "reflective_relay", "enabled"), + resource.TestCheckResourceAttr("data.aci_l2_interface_policy.test", "vlan_scope", "portlocal"), + ), + }, + { + Config: testConfigL2IfPolNotExisting, + ExpectError: regexp.MustCompile("Failed to read aci_l2_interface_policy data source"), + }, + }, + }) +} + +const testConfigL2IfPolDataSource = testConfigL2IfPolAll + ` +data "aci_l2_interface_policy" "test" { + name = "test_name" + depends_on = [aci_l2_interface_policy.test] +} +` + +const testConfigL2IfPolNotExisting = testConfigL2IfPolAll + ` +data "aci_l2_interface_policy" "test_non_existing" { + name = "non_existing_name" +} +` diff --git a/internal/provider/provider.go b/internal/provider/provider.go index d2b05da06..04d34d21c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -261,6 +261,7 @@ func (p *AciProvider) Resources(ctx context.Context) []func() resource.Resource NewInfraRsDomPResource, NewInfraSHPortSResource, NewInfraSpAccPortPResource, + NewL2IfPolResource, NewL3extConsLblResource, NewL3extInstPResource, NewL3extProvLblResource, @@ -364,6 +365,7 @@ func (p *AciProvider) DataSources(ctx context.Context) []func() datasource.DataS NewInfraRsDomPDataSource, NewInfraSHPortSDataSource, NewInfraSpAccPortPDataSource, + NewL2IfPolDataSource, NewL3extConsLblDataSource, NewL3extInstPDataSource, NewL3extProvLblDataSource, diff --git a/internal/provider/resource_aci_l2_interface_policy.go b/internal/provider/resource_aci_l2_interface_policy.go new file mode 100644 index 000000000..0914c99cb --- /dev/null +++ b/internal/provider/resource_aci_l2_interface_policy.go @@ -0,0 +1,911 @@ +// Code generated by "gen/generator.go"; DO NOT EDIT. +// In order to regenerate this file execute `go generate` from the repository root. +// More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md). + +package provider + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/ciscoecosystem/aci-go-client/v2/client" + "github.com/ciscoecosystem/aci-go-client/v2/container" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.Resource = &L2IfPolResource{} +var _ resource.ResourceWithImportState = &L2IfPolResource{} + +func NewL2IfPolResource() resource.Resource { + return &L2IfPolResource{} +} + +// L2IfPolResource defines the resource implementation. +type L2IfPolResource struct { + client *client.Client +} + +// L2IfPolResourceModel describes the resource data model. +type L2IfPolResourceModel struct { + Id types.String `tfsdk:"id"` + Annotation types.String `tfsdk:"annotation"` + Descr types.String `tfsdk:"description"` + Name types.String `tfsdk:"name"` + NameAlias types.String `tfsdk:"name_alias"` + OwnerKey types.String `tfsdk:"owner_key"` + OwnerTag types.String `tfsdk:"owner_tag"` + Qinq types.String `tfsdk:"qinq"` + Vepa types.String `tfsdk:"reflective_relay"` + VlanScope types.String `tfsdk:"vlan_scope"` + TagAnnotation types.Set `tfsdk:"annotations"` + TagTag types.Set `tfsdk:"tags"` + DeprecatedVepa types.String `tfsdk:"vepa"` +} + +func getEmptyL2IfPolResourceModel() *L2IfPolResourceModel { + return &L2IfPolResourceModel{ + Id: basetypes.NewStringNull(), + Annotation: basetypes.NewStringNull(), + Descr: basetypes.NewStringNull(), + Name: basetypes.NewStringNull(), + NameAlias: basetypes.NewStringNull(), + OwnerKey: basetypes.NewStringNull(), + OwnerTag: basetypes.NewStringNull(), + Qinq: basetypes.NewStringNull(), + Vepa: basetypes.NewStringNull(), + VlanScope: basetypes.NewStringNull(), + TagAnnotation: types.SetNull(types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "key": types.StringType, + "value": types.StringType, + }, + }), + TagTag: types.SetNull(types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "key": types.StringType, + "value": types.StringType, + }, + }), + DeprecatedVepa: types.String{}, + } +} + +// TagAnnotationL2IfPolResourceModel describes the resource data model for the children without relation ships. +type TagAnnotationL2IfPolResourceModel struct { + Key types.String `tfsdk:"key"` + Value types.String `tfsdk:"value"` +} + +func getEmptyTagAnnotationL2IfPolResourceModel() TagAnnotationL2IfPolResourceModel { + return TagAnnotationL2IfPolResourceModel{ + Key: basetypes.NewStringNull(), + Value: basetypes.NewStringNull(), + } +} + +var TagAnnotationL2IfPolType = types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "key": types.StringType, + "value": types.StringType, + }, +} + +// TagTagL2IfPolResourceModel describes the resource data model for the children without relation ships. +type TagTagL2IfPolResourceModel struct { + Key types.String `tfsdk:"key"` + Value types.String `tfsdk:"value"` +} + +func getEmptyTagTagL2IfPolResourceModel() TagTagL2IfPolResourceModel { + return TagTagL2IfPolResourceModel{ + Key: basetypes.NewStringNull(), + Value: basetypes.NewStringNull(), + } +} + +var TagTagL2IfPolType = types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "key": types.StringType, + "value": types.StringType, + }, +} + +type L2IfPolIdentifier struct { + Name types.String +} + +type L2IfPolResourceModelV1 struct { + Annotation types.String `tfsdk:"annotation"` + Descr types.String `tfsdk:"description"` + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + NameAlias types.String `tfsdk:"name_alias"` + Qinq types.String `tfsdk:"qinq"` + Vepa types.String `tfsdk:"vepa"` + VlanScope types.String `tfsdk:"vlan_scope"` +} + +func (r *L2IfPolResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 1: { + PriorSchema: &schema.Schema{ + Attributes: map[string]schema.Attribute{ + "annotation": schema.StringAttribute{ + Required: false, + Optional: true, + Computed: true, + }, + "description": schema.StringAttribute{ + Required: false, + Optional: true, + Computed: true, + }, + "id": schema.StringAttribute{ + Required: false, + Optional: true, + Computed: true, + }, + "name": schema.StringAttribute{ + Required: true, + Optional: false, + Computed: false, + }, + "name_alias": schema.StringAttribute{ + Required: false, + Optional: true, + Computed: true, + }, + "qinq": schema.StringAttribute{ + Required: false, + Optional: true, + Computed: true, + }, + "vepa": schema.StringAttribute{ + Required: false, + Optional: true, + Computed: true, + }, + "vlan_scope": schema.StringAttribute{ + Required: false, + Optional: true, + Computed: true, + }, + }, + Blocks: map[string]schema.Block{}, + }, + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + var priorStateData L2IfPolResourceModelV1 + + resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...) + + if resp.Diagnostics.HasError() { + return + } + + upgradedStateData := L2IfPolResourceModel{ + Id: priorStateData.Id, + Annotation: priorStateData.Annotation, + Descr: priorStateData.Descr, + Name: priorStateData.Name, + NameAlias: priorStateData.NameAlias, + OwnerKey: basetypes.NewStringNull(), + OwnerTag: basetypes.NewStringNull(), + Qinq: priorStateData.Qinq, + Vepa: priorStateData.Vepa, + VlanScope: priorStateData.VlanScope, + DeprecatedVepa: priorStateData.Vepa, + } + + upgradedStateData.TagAnnotation = types.SetNull( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "key": basetypes.StringType{}, + "value": basetypes.StringType{}, + }, + }, + ) + + upgradedStateData.TagTag = types.SetNull( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "key": basetypes.StringType{}, + "value": basetypes.StringType{}, + }, + }, + ) + + resp.Diagnostics.Append(resp.State.Set(ctx, upgradedStateData)...) + }, + }, + } +} + +func setL2IfPolLegacyAttributes(ctx context.Context, diags *diag.Diagnostics, data, staticData *L2IfPolResourceModel, classReadInfo []interface{}) { + attributes := classReadInfo[0].(map[string]interface{})["attributes"].(map[string]interface{}) + for attributeName, attributeValue := range attributes { + if attributeName == "vepa" { + data.DeprecatedVepa = basetypes.NewStringValue(attributeValue.(string)) + } + } +} + +func (r *L2IfPolResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if !req.Plan.Raw.IsNull() { + var planData, stateData, configData *L2IfPolResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...) + resp.Diagnostics.Append(req.State.Get(ctx, &stateData)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &configData)...) + + if resp.Diagnostics.HasError() { + return + } + + if (planData.Id.IsUnknown() || planData.Id.IsNull()) && !planData.Name.IsUnknown() { + setL2IfPolId(ctx, planData) + } + + if stateData == nil && !globalAllowExistingOnCreate && !planData.Id.IsUnknown() && !planData.Id.IsNull() { + CheckDn(ctx, &resp.Diagnostics, r.client, "l2IfPol", planData.Id.ValueString()) + if resp.Diagnostics.HasError() { + return + } + } + + if !configData.DeprecatedVepa.IsNull() { + planData.Vepa = configData.DeprecatedVepa + } + + // Workaround to compare the state with plan to avoid plan changes with only known after apply + if stateData != nil { + avoidL2IfPolPlanChangeForKnownAfterApplyOnly(ctx, planData, stateData, configData) + } + + resp.Diagnostics.Append(resp.Plan.Set(ctx, &planData)...) + } +} + +func avoidL2IfPolPlanChangeForKnownAfterApplyOnly(ctx context.Context, planData, stateData, configData *L2IfPolResourceModel) { + // Set read-only and deprecated attributes in planData from stateData + if configData.DeprecatedVepa.IsNull() { + planData.DeprecatedVepa = stateData.DeprecatedVepa + } + + // Compare the string representation of the planData and stateData because structs cannot be compared directly + if fmt.Sprintf("%s", planData) != fmt.Sprintf("%s", stateData) { + if configData.DeprecatedVepa.IsNull() { + planData.DeprecatedVepa = basetypes.NewStringUnknown() + } + } +} + +func (r *L2IfPolResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + tflog.Debug(ctx, "Start metadata of resource: aci_l2_interface_policy") + resp.TypeName = req.ProviderTypeName + "_l2_interface_policy" + tflog.Debug(ctx, "End metadata of resource: aci_l2_interface_policy") +} + +func (r *L2IfPolResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + tflog.Debug(ctx, "Start schema of resource: aci_l2_interface_policy") + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "The l2_interface_policy resource for the 'l2IfPol' class", + Version: 2, + + Attributes: map[string]schema.Attribute{ + // Deprecated attributes + "vepa": schema.StringAttribute{ + Optional: true, + Computed: true, + DeprecationMessage: "Attribute 'vepa' is deprecated, please refer to 'reflective_relay' instead. The attribute will be removed in the next major version of the provider.", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.Expressions{ + path.MatchRoot("reflective_relay"), + }...), + }, + }, + // End of deprecated attributes + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The distinguished name (DN) of the L2 Interface Policy object.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "annotation": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + Default: stringdefault.StaticString(globalAnnotation), + MarkdownDescription: `The annotation of the L2 Interface Policy object.`, + }, + "description": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + MarkdownDescription: `The description of the L2 Interface Policy object.`, + }, + "name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + stringplanmodifier.RequiresReplace(), + }, + MarkdownDescription: `The name of the L2 Interface Policy object.`, + }, + "name_alias": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + MarkdownDescription: `The name alias of the L2 Interface Policy object.`, + }, + "owner_key": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + MarkdownDescription: `The key for enabling clients to own their data for entity correlation.`, + }, + "owner_tag": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + MarkdownDescription: `A tag for enabling clients to add their own data. For example, to indicate who created this object.`, + }, + "qinq": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + Validators: []validator.String{ + stringvalidator.OneOf("corePort", "disabled", "doubleQtagPort", "edgePort"), + }, + MarkdownDescription: `The QinQ port type of the L2 Interface Policy object.`, + }, + "reflective_relay": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + Validators: []validator.String{ + stringvalidator.OneOf("disabled", "enabled"), + }, + MarkdownDescription: `The reflective relay (802.1Qbg) state of the L2 Interface Policy object.`, + }, + "vlan_scope": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + SetToStringNullWhenStateIsNullPlanIsUnknownDuringUpdate(), + }, + Validators: []validator.String{ + stringvalidator.OneOf("global", "portlocal"), + }, + MarkdownDescription: `The vlan scope of the L2 Interface Policy object.`, + }, + "annotations": schema.SetNestedAttribute{ + MarkdownDescription: ``, + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), + }, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + MarkdownDescription: `The key used to uniquely identify this configuration object.`, + }, + "value": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + MarkdownDescription: `The value of the property.`, + }, + }, + }, + }, + "tags": schema.SetNestedAttribute{ + MarkdownDescription: ``, + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), + }, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + MarkdownDescription: `The key used to uniquely identify this configuration object.`, + }, + "value": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + MarkdownDescription: `The value of the property.`, + }, + }, + }, + }, + }, + Blocks: map[string]schema.Block{}, + } + tflog.Debug(ctx, "End schema of resource: aci_l2_interface_policy") +} + +func (r *L2IfPolResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + tflog.Debug(ctx, "Start configure of resource: aci_l2_interface_policy") + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client + tflog.Debug(ctx, "End configure of resource: aci_l2_interface_policy") +} + +func (r *L2IfPolResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + tflog.Debug(ctx, "Start create of resource: aci_l2_interface_policy") + // On create retrieve information on current state prior to making any changes in order to determine child delete operations + var stateData *L2IfPolResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &stateData)...) + if stateData.Id.IsUnknown() || stateData.Id.IsNull() { + setL2IfPolId(ctx, stateData) + } + getAndSetL2IfPolAttributes(ctx, &resp.Diagnostics, r.client, stateData) + if !globalAllowExistingOnCreate && !stateData.Id.IsNull() { + resp.Diagnostics.AddError( + "Object Already Exists", + fmt.Sprintf("The l2IfPol object with DN '%s' already exists.", stateData.Id.ValueString()), + ) + return + } + + var data *L2IfPolResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + if data.Id.IsUnknown() || data.Id.IsNull() { + setL2IfPolId(ctx, data) + } + + tflog.Debug(ctx, fmt.Sprintf("Create of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) + + var tagAnnotationPlan, tagAnnotationState []TagAnnotationL2IfPolResourceModel + data.TagAnnotation.ElementsAs(ctx, &tagAnnotationPlan, false) + stateData.TagAnnotation.ElementsAs(ctx, &tagAnnotationState, false) + var tagTagPlan, tagTagState []TagTagL2IfPolResourceModel + data.TagTag.ElementsAs(ctx, &tagTagPlan, false) + stateData.TagTag.ElementsAs(ctx, &tagTagState, false) + jsonPayload := getL2IfPolCreateJsonPayload(ctx, &resp.Diagnostics, true, data, tagAnnotationPlan, tagAnnotationState, tagTagPlan, tagTagState) + + if resp.Diagnostics.HasError() { + return + } + + DoRestRequest(ctx, &resp.Diagnostics, r.client, fmt.Sprintf("api/mo/%s.json", data.Id.ValueString()), "POST", jsonPayload) + + if resp.Diagnostics.HasError() { + return + } + + getAndSetL2IfPolAttributes(ctx, &resp.Diagnostics, r.client, data) + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + tflog.Debug(ctx, fmt.Sprintf("End create of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) +} + +func (r *L2IfPolResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + tflog.Debug(ctx, "Start read of resource: aci_l2_interface_policy") + var data *L2IfPolResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, fmt.Sprintf("Read of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) + + getAndSetL2IfPolAttributes(ctx, &resp.Diagnostics, r.client, data) + + // Save updated data into Terraform state + if data.Id.IsNull() { + var emptyData *L2IfPolResourceModel + resp.Diagnostics.Append(resp.State.Set(ctx, &emptyData)...) + } else { + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + } + + tflog.Debug(ctx, fmt.Sprintf("End read of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) +} + +func (r *L2IfPolResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + tflog.Debug(ctx, "Start update of resource: aci_l2_interface_policy") + var data *L2IfPolResourceModel + var stateData *L2IfPolResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &stateData)...) + + if resp.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, fmt.Sprintf("Update of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) + + var tagAnnotationPlan, tagAnnotationState []TagAnnotationL2IfPolResourceModel + data.TagAnnotation.ElementsAs(ctx, &tagAnnotationPlan, false) + stateData.TagAnnotation.ElementsAs(ctx, &tagAnnotationState, false) + var tagTagPlan, tagTagState []TagTagL2IfPolResourceModel + data.TagTag.ElementsAs(ctx, &tagTagPlan, false) + stateData.TagTag.ElementsAs(ctx, &tagTagState, false) + jsonPayload := getL2IfPolCreateJsonPayload(ctx, &resp.Diagnostics, false, data, tagAnnotationPlan, tagAnnotationState, tagTagPlan, tagTagState) + + if resp.Diagnostics.HasError() { + return + } + + DoRestRequest(ctx, &resp.Diagnostics, r.client, fmt.Sprintf("api/mo/%s.json", data.Id.ValueString()), "POST", jsonPayload) + + if resp.Diagnostics.HasError() { + return + } + + getAndSetL2IfPolAttributes(ctx, &resp.Diagnostics, r.client, data) + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + tflog.Debug(ctx, fmt.Sprintf("End update of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) +} + +func (r *L2IfPolResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + tflog.Debug(ctx, "Start delete of resource: aci_l2_interface_policy") + var data *L2IfPolResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, fmt.Sprintf("Delete of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) + jsonPayload := GetDeleteJsonPayload(ctx, &resp.Diagnostics, "l2IfPol", data.Id.ValueString()) + if resp.Diagnostics.HasError() { + return + } + DoRestRequest(ctx, &resp.Diagnostics, r.client, fmt.Sprintf("api/mo/%s.json", data.Id.ValueString()), "POST", jsonPayload) + if resp.Diagnostics.HasError() { + return + } + tflog.Debug(ctx, fmt.Sprintf("End delete of resource aci_l2_interface_policy with id '%s'", data.Id.ValueString())) +} + +func (r *L2IfPolResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + tflog.Debug(ctx, "Start import state of resource: aci_l2_interface_policy") + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + + var stateData *L2IfPolResourceModel + resp.Diagnostics.Append(resp.State.Get(ctx, &stateData)...) + tflog.Debug(ctx, fmt.Sprintf("Import state of resource aci_l2_interface_policy with id '%s'", stateData.Id.ValueString())) + + tflog.Debug(ctx, "End import of state resource: aci_l2_interface_policy") +} + +func getAndSetL2IfPolAttributes(ctx context.Context, diags *diag.Diagnostics, client *client.Client, data *L2IfPolResourceModel) { + requestData := DoRestRequest(ctx, diags, client, fmt.Sprintf("api/mo/%s.json?rsp-subtree=full&rsp-subtree-class=%s", data.Id.ValueString(), "l2IfPol,tagAnnotation,tagTag"), "GET", nil) + + readData := getEmptyL2IfPolResourceModel() + + if diags.HasError() { + return + } + if requestData.Search("imdata").Search("l2IfPol").Data() != nil { + classReadInfo := requestData.Search("imdata").Search("l2IfPol").Data().([]interface{}) + if len(classReadInfo) == 1 { + attributes := classReadInfo[0].(map[string]interface{})["attributes"].(map[string]interface{}) + for attributeName, attributeValue := range attributes { + if attributeName == "dn" { + readData.Id = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "annotation" { + readData.Annotation = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "descr" { + readData.Descr = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "name" { + readData.Name = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "nameAlias" { + readData.NameAlias = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "ownerKey" { + readData.OwnerKey = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "ownerTag" { + readData.OwnerTag = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "qinq" { + readData.Qinq = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "vepa" { + readData.Vepa = basetypes.NewStringValue(attributeValue.(string)) + } + if attributeName == "vlanScope" { + readData.VlanScope = basetypes.NewStringValue(attributeValue.(string)) + } + } + TagAnnotationL2IfPolList := make([]TagAnnotationL2IfPolResourceModel, 0) + TagTagL2IfPolList := make([]TagTagL2IfPolResourceModel, 0) + _, ok := classReadInfo[0].(map[string]interface{})["children"] + if ok { + children := classReadInfo[0].(map[string]interface{})["children"].([]interface{}) + for _, child := range children { + for childClassName, childClassDetails := range child.(map[string]interface{}) { + childAttributes := childClassDetails.(map[string]interface{})["attributes"].(map[string]interface{}) + if childClassName == "tagAnnotation" { + TagAnnotationL2IfPol := getEmptyTagAnnotationL2IfPolResourceModel() + for childAttributeName, childAttributeValue := range childAttributes { + if childAttributeName == "key" { + TagAnnotationL2IfPol.Key = basetypes.NewStringValue(childAttributeValue.(string)) + } + if childAttributeName == "value" { + TagAnnotationL2IfPol.Value = basetypes.NewStringValue(childAttributeValue.(string)) + } + + } + TagAnnotationL2IfPolList = append(TagAnnotationL2IfPolList, TagAnnotationL2IfPol) + } + if childClassName == "tagTag" { + TagTagL2IfPol := getEmptyTagTagL2IfPolResourceModel() + for childAttributeName, childAttributeValue := range childAttributes { + if childAttributeName == "key" { + TagTagL2IfPol.Key = basetypes.NewStringValue(childAttributeValue.(string)) + } + if childAttributeName == "value" { + TagTagL2IfPol.Value = basetypes.NewStringValue(childAttributeValue.(string)) + } + + } + TagTagL2IfPolList = append(TagTagL2IfPolList, TagTagL2IfPol) + } + } + } + } + tagAnnotationSet, _ := types.SetValueFrom(ctx, readData.TagAnnotation.ElementType(ctx), TagAnnotationL2IfPolList) + readData.TagAnnotation = tagAnnotationSet + tagTagSet, _ := types.SetValueFrom(ctx, readData.TagTag.ElementType(ctx), TagTagL2IfPolList) + readData.TagTag = tagTagSet + setL2IfPolLegacyAttributes(ctx, diags, readData, data, classReadInfo) + } else { + diags.AddError( + "too many results in response", + fmt.Sprintf("%v matches returned for class 'l2IfPol'. Please report this issue to the provider developers.", len(classReadInfo)), + ) + } + } else { + readData.Id = basetypes.NewStringNull() + } + *data = *readData +} + +func getL2IfPolRn(ctx context.Context, data *L2IfPolResourceModel) string { + return fmt.Sprintf("infra/l2IfP-%s", data.Name.ValueString()) +} + +func setL2IfPolId(ctx context.Context, data *L2IfPolResourceModel) { + rn := getL2IfPolRn(ctx, data) + data.Id = types.StringValue(fmt.Sprintf("%s/%s", strings.Split([]string{"uni/infra/l2IfP-{name}"}[0], "/")[0], rn)) +} + +func getL2IfPolTagAnnotationChildPayloads(ctx context.Context, diags *diag.Diagnostics, data *L2IfPolResourceModel, tagAnnotationL2IfPolPlan, tagAnnotationL2IfPolState []TagAnnotationL2IfPolResourceModel) []map[string]interface{} { + childPayloads := []map[string]interface{}{} + if !data.TagAnnotation.IsNull() && !data.TagAnnotation.IsUnknown() { + tagAnnotationIdentifiers := []TagAnnotationIdentifier{} + for _, tagAnnotationL2IfPol := range tagAnnotationL2IfPolPlan { + childMap := NewAciObject() + if !tagAnnotationL2IfPol.Key.IsNull() && !tagAnnotationL2IfPol.Key.IsUnknown() { + childMap.Attributes["key"] = tagAnnotationL2IfPol.Key.ValueString() + } + if !tagAnnotationL2IfPol.Value.IsNull() && !tagAnnotationL2IfPol.Value.IsUnknown() { + childMap.Attributes["value"] = tagAnnotationL2IfPol.Value.ValueString() + } + childPayloads = append(childPayloads, map[string]interface{}{"tagAnnotation": childMap}) + tagAnnotationIdentifier := TagAnnotationIdentifier{} + tagAnnotationIdentifier.Key = tagAnnotationL2IfPol.Key + tagAnnotationIdentifiers = append(tagAnnotationIdentifiers, tagAnnotationIdentifier) + } + for _, tagAnnotation := range tagAnnotationL2IfPolState { + delete := true + for _, tagAnnotationIdentifier := range tagAnnotationIdentifiers { + if tagAnnotationIdentifier.Key == tagAnnotation.Key { + delete = false + break + } + } + if delete { + tagAnnotationChildMapForDelete := NewAciObject() + tagAnnotationChildMapForDelete.Attributes["status"] = "deleted" + tagAnnotationChildMapForDelete.Attributes["key"] = tagAnnotation.Key.ValueString() + childPayloads = append(childPayloads, map[string]interface{}{"tagAnnotation": tagAnnotationChildMapForDelete}) + } + } + } else { + data.TagAnnotation = types.SetNull(data.TagAnnotation.ElementType(ctx)) + } + + return childPayloads +} + +func getL2IfPolTagTagChildPayloads(ctx context.Context, diags *diag.Diagnostics, data *L2IfPolResourceModel, tagTagL2IfPolPlan, tagTagL2IfPolState []TagTagL2IfPolResourceModel) []map[string]interface{} { + childPayloads := []map[string]interface{}{} + if !data.TagTag.IsNull() && !data.TagTag.IsUnknown() { + tagTagIdentifiers := []TagTagIdentifier{} + for _, tagTagL2IfPol := range tagTagL2IfPolPlan { + childMap := NewAciObject() + if !tagTagL2IfPol.Key.IsNull() && !tagTagL2IfPol.Key.IsUnknown() { + childMap.Attributes["key"] = tagTagL2IfPol.Key.ValueString() + } + if !tagTagL2IfPol.Value.IsNull() && !tagTagL2IfPol.Value.IsUnknown() { + childMap.Attributes["value"] = tagTagL2IfPol.Value.ValueString() + } + childPayloads = append(childPayloads, map[string]interface{}{"tagTag": childMap}) + tagTagIdentifier := TagTagIdentifier{} + tagTagIdentifier.Key = tagTagL2IfPol.Key + tagTagIdentifiers = append(tagTagIdentifiers, tagTagIdentifier) + } + for _, tagTag := range tagTagL2IfPolState { + delete := true + for _, tagTagIdentifier := range tagTagIdentifiers { + if tagTagIdentifier.Key == tagTag.Key { + delete = false + break + } + } + if delete { + tagTagChildMapForDelete := NewAciObject() + tagTagChildMapForDelete.Attributes["status"] = "deleted" + tagTagChildMapForDelete.Attributes["key"] = tagTag.Key.ValueString() + childPayloads = append(childPayloads, map[string]interface{}{"tagTag": tagTagChildMapForDelete}) + } + } + } else { + data.TagTag = types.SetNull(data.TagTag.ElementType(ctx)) + } + + return childPayloads +} + +func getL2IfPolCreateJsonPayload(ctx context.Context, diags *diag.Diagnostics, createType bool, data *L2IfPolResourceModel, tagAnnotationPlan, tagAnnotationState []TagAnnotationL2IfPolResourceModel, tagTagPlan, tagTagState []TagTagL2IfPolResourceModel) *container.Container { + payloadMap := map[string]interface{}{} + payloadMap["attributes"] = map[string]string{} + + if createType && !globalAllowExistingOnCreate { + payloadMap["attributes"].(map[string]string)["status"] = "created" + } + childPayloads := []map[string]interface{}{} + + TagAnnotationchildPayloads := getL2IfPolTagAnnotationChildPayloads(ctx, diags, data, tagAnnotationPlan, tagAnnotationState) + if TagAnnotationchildPayloads == nil { + return nil + } + childPayloads = append(childPayloads, TagAnnotationchildPayloads...) + + TagTagchildPayloads := getL2IfPolTagTagChildPayloads(ctx, diags, data, tagTagPlan, tagTagState) + if TagTagchildPayloads == nil { + return nil + } + childPayloads = append(childPayloads, TagTagchildPayloads...) + + payloadMap["children"] = childPayloads + if !data.Annotation.IsNull() && !data.Annotation.IsUnknown() { + payloadMap["attributes"].(map[string]string)["annotation"] = data.Annotation.ValueString() + } + if !data.Descr.IsNull() && !data.Descr.IsUnknown() { + payloadMap["attributes"].(map[string]string)["descr"] = data.Descr.ValueString() + } + if !data.Name.IsNull() && !data.Name.IsUnknown() { + payloadMap["attributes"].(map[string]string)["name"] = data.Name.ValueString() + } + if !data.NameAlias.IsNull() && !data.NameAlias.IsUnknown() { + payloadMap["attributes"].(map[string]string)["nameAlias"] = data.NameAlias.ValueString() + } + if !data.OwnerKey.IsNull() && !data.OwnerKey.IsUnknown() { + payloadMap["attributes"].(map[string]string)["ownerKey"] = data.OwnerKey.ValueString() + } + if !data.OwnerTag.IsNull() && !data.OwnerTag.IsUnknown() { + payloadMap["attributes"].(map[string]string)["ownerTag"] = data.OwnerTag.ValueString() + } + if !data.Qinq.IsNull() && !data.Qinq.IsUnknown() { + payloadMap["attributes"].(map[string]string)["qinq"] = data.Qinq.ValueString() + } + if !data.Vepa.IsNull() && !data.Vepa.IsUnknown() { + payloadMap["attributes"].(map[string]string)["vepa"] = data.Vepa.ValueString() + } + if !data.VlanScope.IsNull() && !data.VlanScope.IsUnknown() { + payloadMap["attributes"].(map[string]string)["vlanScope"] = data.VlanScope.ValueString() + } + payload, err := json.Marshal(map[string]interface{}{"l2IfPol": payloadMap}) + if err != nil { + diags.AddError( + "Marshalling of json payload failed", + fmt.Sprintf("Err: %s. Please report this issue to the provider developers.", err), + ) + return nil + } + + jsonPayload, err := container.ParseJSON(payload) + + if err != nil { + diags.AddError( + "Construction of json payload failed", + fmt.Sprintf("Err: %s. Please report this issue to the provider developers.", err), + ) + return nil + } + return jsonPayload +} diff --git a/internal/provider/resource_aci_l2_interface_policy_test.go b/internal/provider/resource_aci_l2_interface_policy_test.go new file mode 100644 index 000000000..b901f34c3 --- /dev/null +++ b/internal/provider/resource_aci_l2_interface_policy_test.go @@ -0,0 +1,372 @@ +// Code generated by "gen/generator.go"; DO NOT EDIT. +// In order to regenerate this file execute `go generate` from the repository root. +// More details can be found in the [README](https://github.com/CiscoDevNet/terraform-provider-aci/blob/master/README.md). + +package provider + +import ( + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccResourceL2IfPol(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t, "apic", "1.1(1j)-") }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create with minimum config and verify default APIC values + { + Config: testConfigL2IfPolMinAllowExisting, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "vlan_scope", "global"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "vlan_scope", "global"), + ), + }, + }, + }) + + setEnvVariable(t, "ACI_ALLOW_EXISTING_ON_CREATE", "false") + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t, "apic", "1.1(1j)-") }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create with minimum config and verify default APIC values + { + Config: testConfigL2IfPolMinAllowExisting, + ExpectError: regexp.MustCompile("Object Already Exists"), + }, + }, + }) + + setEnvVariable(t, "ACI_ALLOW_EXISTING_ON_CREATE", "true") + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t, "apic", "1.1(1j)-") }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create with minimum config and verify default APIC values + { + Config: testConfigL2IfPolMinAllowExisting, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test", "vlan_scope", "global"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.allow_test_2", "vlan_scope", "global"), + ), + }, + }, + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t, "apic", "1.1(1j)-") }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create with minimum config and verify default APIC values + { + Config: testConfigL2IfPolMin, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "global"), + ), + }, + // Update with all config and verify default APIC values + { + Config: testConfigL2IfPolAll, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "annotation"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", "description_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", "name_alias_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", "owner_key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", "owner_tag_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "corePort"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "enabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "portlocal"), + ), + }, + // Update with minimum config and verify config is unchanged + { + Config: testConfigL2IfPolMin, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", "description_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", "name_alias_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", "owner_key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", "owner_tag_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "corePort"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "enabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "portlocal"), + ), + }, + // Update with empty strings config or default value + { + Config: testConfigL2IfPolReset, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name", "test_name"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "global"), + ), + }, + // Import testing + { + ResourceName: "aci_l2_interface_policy.test", + ImportState: true, + ImportStateVerify: true, + }, + // Update with children + { + Config: testConfigL2IfPolChildren, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "global"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.0.key", "key_0"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.0.value", "value_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.1.key", "key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.1.value", "test_value"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.#", "2"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.0.key", "key_0"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.0.value", "value_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.1.key", "key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.1.value", "test_value"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.#", "2"), + ), + }, + // Update with children removed from config + { + Config: testConfigL2IfPolChildrenRemoveFromConfig, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "global"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.0.key", "key_0"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.0.value", "value_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.1.key", "key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.1.value", "test_value"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.#", "2"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.0.key", "key_0"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.0.value", "value_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.1.key", "key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.1.value", "test_value"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.#", "2"), + ), + }, + // Update with children first child removed + { + Config: testConfigL2IfPolChildrenRemoveOne, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "global"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.0.key", "key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.0.value", "test_value"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.#", "1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.0.key", "key_1"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.0.value", "test_value"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.#", "1"), + ), + }, + // Update with all children removed + { + Config: testConfigL2IfPolChildrenRemoveAll, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotation", "orchestrator:terraform"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "description", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "name_alias", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_key", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "owner_tag", ""), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "qinq", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "reflective_relay", "disabled"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "vlan_scope", "global"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "annotations.#", "0"), + resource.TestCheckResourceAttr("aci_l2_interface_policy.test", "tags.#", "0"), + ), + }, + // Update with legacy attribute config + { + Config: testConfigL2IfPolLegacyAttributes, + }, + }, + CheckDestroy: testCheckResourceDestroy, + }) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t, "apic", "1.0(1e)-") }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create with legacy attribute config + { + Config: testConfigL2IfPolLegacyAttributes, + }, + }, + CheckDestroy: testCheckResourceDestroy, + }) +} + +const testConfigL2IfPolMinAllowExisting = ` +resource "aci_l2_interface_policy" "allow_test" { + name = "test_name" +} +resource "aci_l2_interface_policy" "allow_test_2" { + name = "test_name" + depends_on = [aci_l2_interface_policy.allow_test] +} +` + +const testConfigL2IfPolMin = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" +} +` + +const testConfigL2IfPolAll = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" + annotation = "annotation" + description = "description_1" + name_alias = "name_alias_1" + owner_key = "owner_key_1" + owner_tag = "owner_tag_1" + qinq = "corePort" + reflective_relay = "enabled" + vlan_scope = "portlocal" +} +` + +const testConfigL2IfPolReset = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" + annotation = "orchestrator:terraform" + description = "" + name_alias = "" + owner_key = "" + owner_tag = "" + qinq = "disabled" + reflective_relay = "disabled" + vlan_scope = "global" +} +` +const testConfigL2IfPolChildren = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" + annotations = [ + { + key = "key_0" + value = "value_1" + }, + { + key = "key_1" + value = "test_value" + }, + ] + tags = [ + { + key = "key_0" + value = "value_1" + }, + { + key = "key_1" + value = "test_value" + }, + ] +} +` + +const testConfigL2IfPolChildrenRemoveFromConfig = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" +} +` + +const testConfigL2IfPolChildrenRemoveOne = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" + annotations = [ + { + key = "key_1" + value = "test_value" + }, + ] + tags = [ + { + key = "key_1" + value = "test_value" + }, + ] +} +` + +const testConfigL2IfPolChildrenRemoveAll = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" + annotations = [] + tags = [] +} +` + +const testConfigL2IfPolLegacyAttributes = ` +resource "aci_l2_interface_policy" "test" { + name = "test_name" + vepa = "disabled" +} +` diff --git a/legacy-docs/docs/d/l2_interface_policy.html.markdown b/legacy-docs/docs/d/l2_interface_policy.html.markdown deleted file mode 100644 index 476302771..000000000 --- a/legacy-docs/docs/d/l2_interface_policy.html.markdown +++ /dev/null @@ -1,34 +0,0 @@ ---- -subcategory: "Access Policies" -layout: "aci" -page_title: "ACI: aci_l2_interface_policy" -sidebar_current: "docs-aci-data-source-aci_l2_interface_policy" -description: |- - Data source for ACI L2 Interface Policy ---- - -# aci_l2_interface_policy - -Data source for ACI L2 Interface Policy - -## Example Usage - -```hcl -data "aci_l2_interface_policy" "dev_l2_int_pol" { - name = "foo_l2_int_pol" -} -``` - -## Argument Reference - -- `name` - (Required) Name of Object L2 interface policy. - -## Attribute Reference - -- `id` - Attribute id set to the Dn of the L2 Interface Policy. -- `annotation` - (Optional) Annotation for object L2 interface policy. -- `description` - (Optional) Description for object L2 interface policy. -- `name_alias` - (Optional) Name alias for object L2 interface policy. -- `qinq` - (Optional) Determines if QinQ is disabled or if the port should be considered a core or edge port. -- `vepa` - (Optional) Determines if Virtual Ethernet Port Aggregator is disabled or enabled. -- `vlan_scope` - (Optional) The scope of the VLAN. diff --git a/legacy-docs/docs/r/l2_interface_policy.html.markdown b/legacy-docs/docs/r/l2_interface_policy.html.markdown deleted file mode 100644 index c0b796dcf..000000000 --- a/legacy-docs/docs/r/l2_interface_policy.html.markdown +++ /dev/null @@ -1,50 +0,0 @@ ---- -subcategory: "Access Policies" -layout: "aci" -page_title: "ACI: aci_l2_interface_policy" -sidebar_current: "docs-aci-resource-aci_l2_interface_policy" -description: |- - Manages ACI L2 Interface Policy ---- - -# aci_l2_interface_policy - -Manages ACI L2 Interface Policy - -## Example Usage - -```hcl -resource "aci_l2_interface_policy" "example" { - name = "demo_l2_pol" - annotation = "tag_l2_pol" - description = "from terraform" - name_alias = "alias_l2_pol" - qinq = "disabled" - vepa = "disabled" - vlan_scope = "global" -} -``` - -## Argument Reference - -- `name` - (Required) Name of Object L2 interface policy. -- `annotation` - (Optional) Annotation for object L2 interface policy. -- `description` - (Optional) Description for object L2 interface policy. -- `name_alias` - (Optional) Name alias for object L2 interface policy. -- `qinq` - (Optional) Determines if QinQ is disabled or if the port should be considered a core or edge port. Allowed values are "disabled", "edgePort", "corePort" and "doubleQtagPort". Default is "disabled". -- `vepa` - (Optional) Determines if Virtual Ethernet Port Aggregator is disabled or enabled. Allowed values are "disabled" and "enabled". Default is "disabled". -- `vlan_scope` - (Optional) The scope of the VLAN. Allowed values are "global" and "portlocal". Default is "global". - -## Attribute Reference - -The only attribute that this resource exports is the `id`, which is set to the -Dn of the L2 Interface Policy. - -## Importing - -An existing L2 Interface Policy can be [imported][docs-import] into this resource via its Dn, via the following command: -[docs-import]: - -```bash -terraform import aci_l2_interface_policy.example -```