Terraform import: invalid index

Viewed 796

I'm trying to replace deprecated resource 'azurerm_sql_server' with the 'azurerm_mssql_server' and got an 'invalid index' error in the case.

A simplified demo of the situation (with Terraform v0.14.5 and v1.0.5):

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=2.49.0"
    }
  }
}

provider "azurerm" {
  features {}
}

locals {
  prefix = toset(["primary", "secondary"])
}

resource "azurerm_resource_group" "rg" {
  name     = "rgtest"
  location = "Canada Central"
}

resource "random_password" "sql_admin_password" {
  length      = 16
  special     = true
  number      = true
  upper       = true
  lower       = true
  min_special = 2
  min_numeric = 2
  min_upper   = 2
  min_lower   = 2
}

resource "azurerm_sql_server" "instance" {
  for_each = local.prefix

  name                = "${each.value}-sqlsvr"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  version                      = "12.0"
  administrator_login          = "ssadmin"
  administrator_login_password = random_password.sql_admin_password.result
}

locals {
  primary_sql_srv   = azurerm_sql_server.instance["primary"].name
  secondary_sql_srv = azurerm_sql_server.instance["secondary"].name
}

# other TF resources using local.primary_sql_srv and local.secondary_sql_srv

The infrastructure has been deployed and no intention to re-create the database servers so we need to change the resource and import existing servers. According to Terraform document, this can be done with 'terraform state rm' and 'terraform import' command.

So,

  1. Change the configuration script
...

resource "azurerm_mssql_server" "instance" {
...
locals {
  primary_sql_srv   = azurerm_mssql_server.instance["primary"].name
  secondary_sql_srv = azurerm_mssql_server.instance["secondary"].name
}
# other TF resources using local.primary_sql_srv and local.secondary_sql_srv
  1. Remove azurerm_sql_server resource from the state file, both are successful
terraform.exe state rm azurerm_sql_server.instance[`\`"primary`\`"]
terraform.exe state rm azurerm_sql_server.instance[`\`"secondary`\`"]
  1. Import the primary database server
> terraform.exe import azurerm_mssql_server.instance[`\`"primary`\`"] "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rgtest/providers/Microsoft.Sql/servers/primary-sqlsvr"

azurerm_mssql_server.instance["primary"]: Importing from ID "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rgtest/providers/Microsoft.Sql/servers/primary-sqlsvr"...
azurerm_mssql_server.instance["primary"]: Import prepared!
  Prepared azurerm_mssql_server for import
azurerm_mssql_server.instance["primary"]: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rgtest/providers/Microsoft.Sql/servers/primary-sqlsvr]

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.

Current state list

❯ terraform.exe state list

azurerm_mssql_server.instance["primary"]
azurerm_resource_group.rg
random_password.sql_admin_password
  1. Import the secondary database server
> terraform.exe import azurerm_mssql_server.instance[`\`"secondary`\`"] "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rgtest/providers/Microsoft.Sql/servers/secondary-sqlsvr"

azurerm_mssql_server.instance["secondary"]: Importing from ID "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rgtest/providers/Microsoft.Sql/servers/secondary-sqlsvr"...
azurerm_mssql_server.instance["secondary"]: Import prepared!
  Prepared azurerm_mssql_server for import
azurerm_mssql_server.instance["secondary"]: Refreshing state... [id=/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/rgtest/providers/Microsoft.Sql/servers/secondary-sqlsvr]

Error: Invalid index

  on C:\Work\Projects\2021\20210812RenameResource\t1env\main.tf line 49, in locals:
  49:   secondary_sql_srv = azurerm_mssql_server.instance["secondary"].name
    |----------------
    | azurerm_mssql_server.instance is object with 1 attribute "primary"

The given key does not identify an element in this collection value.

The state refresh for the 2nd import hit the locals block and failed due to no 'secondary' server resource.

So to me, this is a deadlock, I cannot import the 'secondary' server resource because of the refresh error and the refresh error was caused by the lack of the 'secondary' server resource.

Two ways I can think of:

  1. Manually add the 'secondary' server resource to the state file, which is definitely not proper
  2. Remove the 'locals' block which is OK in the demo but lots of changes in real code for dependencies.

Any thoughts, please? Thank you.

1 Answers

This is a bug in terraform import that was introduced in version 0.13. During a terraform import execution, it will attempt to validate the local variables in the config containing the resource namespace against non-existent state. There are basically three workarounds for this:

  1. Downgrade temporarily to Terraform 0.12 where this bug does not exist.

This is really not a great option because the version(s) is stored in the state, and you may be locked out of executing terraform CLI commands against the state synced with a later version.

  1. Manually modify the state to contain the resources.

Also really not a great option because this could corrupt the state and/or cause other obvious issues with malformation.

  1. Temporarily comment out the relevant locals and any code referencing the local variable values.

This is what I always ended up using. You can do a multiline comment in the /* ... */ style around the relevant locals that references the exported resource attributes of the imported resource, and you will also need to do so in any other areas of the config that reference the local variables. You can then uncomment the code once the imports are complete.

Related