2
votes

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

2
Please share the error message you are getting when it fails.Alain O'Dea
It's not 100% clear from what you shared here, but this seems like a shell escaping issue: I think by the time Terraform sees your arguments the shell has removed all of the quotes " and so the syntax is no longer valid. It would work in your first case because coincidentally it's valid to omit the quotes on an attribute name, but an unquoted identifier in a normal expression is understood as a reference and references are not allowed in variable values.Martin Atkins
You're using quoting here that should work for a Unix-style shell, but it would not work if you are using a non-Unix-style shell, like the Windows Command Prompt or PowerShell.Martin Atkins
@MartinAtkins. You are right. it worked after escaping the double quotes. I was loosing my sanity over this. Thank you .karas27

2 Answers

2
votes

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.

0
votes

As pointed out by Martin . The issue was regarding unix style shell on power shell. After escaping the double quotes, it worked. Correct syntax for power shell is

terraform plan -var='postgress={"storage_mb":102400,"backup_retention_days":15,"geo_redundant_backup_enabled":false,"administrator_login":\"pgadmin1223\"}'

Also, I agree its better to use tfvars instead of input params especially if you have lot of inputs to terraforms