CiscoDevNet / terraform-provider-mso

Terraform Cisco MSO provider
https://registry.terraform.io/providers/CiscoDevNet/mso/latest/docs
Mozilla Public License 2.0
10 stars 32 forks source link

Minor issue - importing mso_schema_template_external_epg_subnet sets a name value of jsonencode({}) #112

Closed mike-guy closed 2 years ago

mike-guy commented 2 years ago

Community Note

Terraform Version

terraform version Terraform v1.1.4 on windows_amd64

provider registry.terraform.io/ciscodevnet/mso v0.4.1

MSO version

Nexus Dashboard Version 2.0(2g)

Multi-Site Orchestrator Version: 3.3(1e)

dCloud Cisco Nexus Dashboard Orchestrator for ACI Lab v1

APIC version and APIC Platform for Site Level Resources

N/A

Affected Resource(s)

Terraform Configuration Files

terraform {
  required_providers {
    mso = {
      source  = "CiscoDevNet/mso"
      version = "0.4.1"
    }
  }
}

provider "mso" {
  # Creds provided as environment variables
}

resource "mso_schema_template_external_epg_subnet" "eepg_subnet" {
  aggregate         = []
  external_epg_name = "test_eepg"
  ip                = "10.0.0.0/8"
  schema_id         = "62165ca82e0000150370b5de"
  scope = [
    "export-rtctrl",
    "import-security",
  ]
  template_name = "test_template"
}

Expected Behavior

Manually created configuration should not include the value jsonencode({}) for an attribute that is not exposed in the MSO GUI.

Whilst this is a minor issue that has no serious impact, the value should be returned as "null" or the value omitted from terraform configuration altogether.

Actual Behavior

If an existing external epg has been created in the MSO GUI, importing it causes the name value to be jsonencode({}). This can then not be omitted in the Terraform configuration. It must either be specified exactly as jsonencode({}) or replaced with an alternative value.

This name attribute is not exposed in the GUI.

Steps to Reproduce

  1. Create an external EEPG with a subnet associated in the MSO GUI under a schema template
  2. Import the resource into Terraform

Important Factoids

GUI Configuration

image

Import command and output

terraform import 'mso_schema_template_external_epg_subnet.eepg_subnet' '62165ca82e0000150370b5de/tempalte/test_template/externalEPG/test_eepg/ip/10.0.0.0/8'
mso_schema_template_external_epg_subnet.eepg_subnet: Importing from ID "62165ca82e0000150370b5de/tempalte/test_template/externalEPG/test_eepg/ip/10.0.0.0/8"...
mso_schema_template_external_epg_subnet.eepg_subnet: Import prepared!
  Prepared mso_schema_template_external_epg_subnet for import
mso_schema_template_external_epg_subnet.eepg_subnet: Refreshing state... [id=10.0.0.0]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

Terraform state after import

$ terraform show
# mso_schema_template_external_epg_subnet.eepg_subnet:
resource "mso_schema_template_external_epg_subnet" "eepg_subnet" {
    aggregate         = []
    external_epg_name = "test_eepg"
    id                = "10.0.0.0/8"
    ip                = "10.0.0.0/8"
    name              = jsonencode({})
    schema_id         = "62165ca82e0000150370b5de"
    scope             = [
        "export-rtctrl",
        "import-security",
    ]
    template_name     = "test_template"
}

Apply of configuration with matches the GUI (except for the non-existent name attribute)

$ terraform plan
mso_schema_template_external_epg_subnet.eepg_subnet: Refreshing state... [id=10.0.0.0/8]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # mso_schema_template_external_epg_subnet.eepg_subnet will be updated in-place
  ~ resource "mso_schema_template_external_epg_subnet" "eepg_subnet" {
        id                = "10.0.0.0/8"
      - name              = jsonencode({}) -> null
        # (6 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.
mike-guy commented 2 years ago

I've looked into this a little. The "name" attribute is not exposed in the GUI - so in existing environments will often be unset. When this is imported it ends up as a blank string.

Even if this is not set (for example, using an if statement so skip d.Set("name"...), the Terraform plugin SDK seems to set it to "{}", hence after import a change is detected as needing to be made. I suspect two things will need to be implemented to resolve.

  1. Assigning a value of "Default: nil" to the schema. e.g.

    "name": &schema.Schema{
                Type:         schema.TypeString,
                Optional:     true,
                ValidateFunc: validation.StringLenBetween(1, 1000),
                Defau
  2. Adjusting the import code to include an if statement. Something along the lines of...

    if name := models.StripQuotes(subnetsCont.S("name").String()); name != "{}" {
        d.Set("name", name)
    }

Just as I was about to test, my dCloud lab finished, so for now - I'm off for a beer. I'll take a look tomorrow if I can!

I also notice the the Default value is not used elsewhere in the Schema's - there may be reasons I'm unaware of as to why this is the case. I guess an alternative approach would be to handle the blank name value in the mso-go-client.

If you have a preference, let me know and I'm happy to code, do some smoke testing and issue a PR!