terraform map and object variables as input

12,908

Since the second config works with the defaults for the variable, the config isn't the issue, the terraform apply -var must be the issue. It's a very tricky thing to get right and has a number of problematic interactions with shell parsing rules that can trip you up.

I find using .tfvars files far more reliable and I no longer try to get -var working for my Terraform work.

terraform.tfvars:

storageProfile2 = {
  storage_mb                      = 102400
  backup_retention_days           = 15
  geo_redundant_backup_enabled    = false
  administrator_login             = "pgadmin1223"
}

Ceate terraform.tfvars as above in the same directory and then run terraform plan and terraform apply without -var. It should resolve your issue.

Original answer

There are several significant changes in the azurerm provider that are intended to be backwards compatible, but are likedly causing the issue here.

geo_redundant_backup is a deprecated attribute as of v2.7.0 or v2.10.0 depending on which database resource you are using. You should use geo_redundant_backup_enabled instead and specify it as boolean (bool type). I suspect the backwards-compatibility isn't completely reliable.

storage_profile blocks are also deprecated and all of their attributes are now top-level on the corresponding.

The examples in the azurerm provider documentation using storage_profile are incorrect and this:

storage_profile {
  storage_mb            = var.storageProfile2.storageMb
  backup_retention_days = var.storageProfile2.backupRetentionDays
  geo_redundant_backup  = var.storageProfile2.geoRedundantBackup
}

Should be rewritten as (direct properties on the resource, not inside a block):

storage_mb                    = var.storageProfile2.storageMb
backup_retention_days         = var.storageProfile2.backupRetentionDays
geo_redundant_backup_enabled  = var.storageProfile2.geoRedundantBackup

And your storageProfile2 variable declaration should be updated to set the type of geoRedundantBackup to bool:

variable storageProfile2 {
  default = {
    storageMb = 102400
    backupRetentionDays = 15
    geoRedundantBackup  = false
  }
  type = object({ storageMb=number, backupRetentionDays=number, geoRedundantBackup=bool })
}

Since azurerm provider v2.7.0 was released on April 23rd, 2020 including these changes:

  • azurerm_postgres_server - all properties in the storage_profile block have been moved to the top level (#6459)
  • azurerm_postgres_server - the following properties were renamed and changed to a boolean type: ssl_enforcement to ssl_enforcement_enabled, geo_redundant_backup to backup_geo_redundant_enabled, and auto_grow to auto_grow_enabled (#6459)

Since azurerm provider v2.10.0 was released on May 12th, 2020 additional storage_profile were flattened:

  • azurerm_mariadb_server - all properties in the storage_profile block have been moved to the top level (#6865)
  • azurerm_mysql_server - all properties in the storage_profile block have been moved to the top level (#6833)
  • azurerm_mariadb_server - the following properties were renamed and changed to a boolean type: ssl_enforcement to ssl_enforcement_enabled, geo_redundant_backup to geo_redundant_backup_enabled, and auto_grow azurerm_mysql_server - support for the create_mode property allowing the creation of replicas, point in time restores, and geo restors (#6833)
  • azurerm_mysql_server - the following properties were renamed and changed to a boolean type: ssl_enforcement to ssl_enforcement_enabled, geo_redundant_backup to geo_redundant_backup_enabled, and auto_grow to auto_grow_enabled (#6833)

Aside: Code Style

Conventional code style in Terraform:

  • Use snake_case instead of camelCase (not formalized, but every provider follows this as do the examples)
  • Quote top-level names like resource and variable names
  • Align equals signs in groups (those without multiple line breaks between them)
variable "storage_profile_2" {
  default = {
    storage_mb                   = 102400
    backup_retention_days        = 15
    geo_redundant_backup_enabled = false
  }
  type = object(
    {
      storage_mb                   = number
      backup_retention_days        = number
      geo_redundant_backup_enabled = bool
    }
  )
}

And assign attributes as follows

storage_mb                   = var.storage_profile_2.storage_mb
backup_retention_days        = var.storage_profile_2.backup_retention_days
geo_redundant_backup_enabled = var.storage_profile_2.geo_redundant_backup_enabled

The more consistent Terraform code is globally, the easier it will be for all of us practitioners should we ever need to work on someone else's code.

Share:
12,908
karas27
Author by

karas27

Updated on June 23, 2022

Comments

  • karas27
    karas27 almost 2 years

    There is issue with command line input for any string attribute inside a map/object variable. the below configuration works with below command. But the moment I use any string attribute inside the object variable. it fails

    terraform plan -var='storageProfile2={"storage_mb":102400,"backup_retention_days":15,"geo_redundant_backup_enabled":false}'
    
    //main.tf
    resource "azurerm_postgresql_server" "dmcdevops_postgress" {
      name                          = "pstgressdb101" 
      location                      = azurerm_resource_group.dmc_rg_creation.location
      resource_group_name           = azurerm_resource_group.dmc_rg_creation.name
      sku_name                      = "GP_Gen5_4"
      backup_retention_days         = var.storageProfile2.backup_retention_days
      storage_mb                    = var.storageProfile2.storage_mb
      geo_redundant_backup_enabled  = var.storageProfile2.geo_redundant_backup_enabled 
      administrator_login           = "sdfgsgfsg"
      administrator_login_password  = "H@Sh1CoR3!"
      version                       = "11"
      ssl_enforcement_enabled       = true
    
    }
    //variables.tf
    variable "storageProfile2" {
    default = {
        storage_mb                      = 102400
        backup_retention_days           = 15
        geo_redundant_backup_enabled    = false
      }
    
      type = object(
        {
            storage_mb                    = number
            backup_retention_days         = number
            geo_redundant_backup_enabled  = bool
       }
          )
    } 
    

    Below config doesn't work. I just added administrator_login as string attribute to the object variable. terraform plan and apply works with default values tho.

    terraform plan -var='storageProfile2={"storage_mb":102400,"backup_retention_days":15,"geo_redundant_backup_enabled":false,"administrator_login":"pgadmin1223"}'
    
    //main.tf 
    resource "azurerm_postgresql_server" "dmcdevops_postgress" {
      name                          = "pstgressdb101" 
      location                      = azurerm_resource_group.dmc_rg_creation.location
      resource_group_name           = azurerm_resource_group.dmc_rg_creation.name
      sku_name                      = "GP_Gen5_4"
      backup_retention_days         = var.storageProfile2.backup_retention_days
      storage_mb                    = var.storageProfile2.storage_mb
      geo_redundant_backup_enabled  = var.storageProfile2.geo_redundant_backup_enabled 
      administrator_login           =  var.storageProfile2.administrator_login 
      administrator_login_password  = "H@Sh1CoR3!"
      version                       = "11"
      ssl_enforcement_enabled       = true
    
    }
    
    //varibale.tf
    variable "storageProfile2" {
    default = {
        storage_mb                      = 102400
        backup_retention_days           = 15
        geo_redundant_backup_enabled    = false
        administrator_login             = "pgadmin"
      }
    
      type = object(
        {
            storage_mb                    = number
            backup_retention_days         = number
            geo_redundant_backup_enabled  = bool
            administrator_login           = string 
       }
          )
    }
    

    Error message

    enter image description here