Error using variable of type map as environment variable (in combination with GitLab)

Dear community,

I need some help with a very tough error message. It seems to me like I have some wrong content in my variable from type “map”, but let it explain to you in more detail. I tried my best to give it a good structure:

My environment:

  • GitLab, interacticing with terraform through CI/CD pipelines
  • Terraform version 1.0.0
  • Terraform vra provider version 0.5.1 (just for the sake of completeness)

The error message (terraform plan job):

It is an excerpt from my GitLab CI/CD logs, the most important part is the “missing expression” one. It seems like the other errors below are just results from the both at the beginning and shouldn’t play a role if I’m correct. As you can see below in the variables.tf file, I’m using map variables to be able to select the correct combination of credentials using the hostname of the endpoint as “key” for each resource. It seems to me, that wrong content of my map variable is leading to the error.

¦ Error: Missing expression
¦ 
¦   on <value for var.vra_cloud_account_nsxt_creds> line 1:
¦   (source code not available)
¦ 
¦ Expected the start of an expression, but found the end of the file.


¦ Error: Missing expression
¦ 
¦   on <value for var.vra_cloud_account_vsphere_creds> line 1:
¦   (source code not available)
¦ 
¦ Expected the start of an expression, but found the end of the file.


¦ Error: No value for required variable
¦ 
¦   on variables.tf line 11:
¦   11: variable "vra_cloud_account_nsxt_creds" {
¦ 
¦ The root module input variable "vra_cloud_account_nsxt_creds" is not set,
¦ and has no default value. Use a -var or -var-file command line argument to
¦ provide a value for this variable.


¦ Error: No value for required variable
¦ 
¦   on variables.tf line 18:
¦   18: variable "vra_cloud_account_vsphere_creds" {
¦ 
¦ The root module input variable "vra_cloud_account_vsphere_creds" is not
¦ set, and has no default value. Use a -var or -var-file command line
¦ argument to provide a value for this variable.

When the error exactly occurs:

Everything works fine if I use the default values defined in the variables.tf file. But as soon as I set the actual variable content through GitLab, the error occurs. Here I tried dozens of different combinations with or without escaping and nothing seemed to work properly.

What I want to do:

I have different credentials for my vRealize Automation cloud account endpoints for each resource. It is important to mention the requirement, that it is not allowed to write the credentials to any file inside of the GitLab repository. That’s why it is not allowed to write them directly into the tfvars file because it will lead to the situation, that the credentials will be logged through the version history.


TERRAFORM PART


The main.tf file (excerpt):

Also just for the sake of completeness and that you can understand, how I interact with the variables. But it seems like that is not the reason for the error:

resource "vra_cloud_account_vsphere" "vra_cloud_accounts_vsphere" {
  for_each                     = { for o in var.vra_cloud_accounts_vsphere : lower(replace(o.name, "/[/. ]/", "_")) => o }
  name                         = each.value.name
  description                  = format("%s/%s", "[TFM] ", each.value.description)
  username                     = var.vra_cloud_account_vsphere_creds[split(".", each.value.hostname)[0]].username #untested
  password                     = var.vra_cloud_account_vsphere_creds[split(".", each.value.hostname)[0]].password #untested
  hostname                     = each.value.hostname
  regions                      = each.value.regions
  associated_cloud_account_ids = (each.value.nsxt_index != "" ? [vra_cloud_account_nsxt.vra_cloud_accounts_nsxt[each.value.nsxt_index].id] : null)
  accept_self_signed_cert      = each.value.accept_self_signed_cert

  dynamic "tags" {
    for_each = each.value.tags
    content {
      key   = tags.value.key
      value = tags.value.value
    }
  }
}

The variables.tf file (excerpt, here the trouble seems to start):

variable "vra_cloud_account_vsphere_creds" {
  type    = map(map(string))
  default = {
    "hostname1" = {
      "username" = "myusername1"
      "password" = "mypassword1"
    }
    "hostname2" = {
      "username" = "myusername2"
      "password" = "mypassword2"
    }
  }
}

GITLAB PART


Here is how I try to set the variable content using GitLab. The ${VRA_CLOUD_ACCOUNT_VSPHERE_CREDS} variable is set through GitLab CI/CD variables:

The gitlab.ci.yml file (excerpt):

terraform-plan:
  stage: terraform:plan
  variables:
    #This is for the credentials:
    TF_VAR_vra_cloud_account_vsphere_creds: ${VRA_CLOUD_ACCOUNT_VSPHERE_CREDS}
  script:
    #This is for all the other variables
    - terraform plan -input=false -out=${something} -var-file=${something}/${something}.tfvars
(...)

One of the many versions of the cred variable content:

Note: I also tried content without any special characters with no change in the behavior

"hostname1" = {"username" = "myusername1","password" = "mypassword1"}, "hostname2" = {"username" = "myusername2","password" = "mypassword2"}

Do you have any idea about what I’m doing wrong?

Thank you very much!

Hi @pyra!

I’m afraid I’m not really familiar with GitLab’s pipeline language and so I’m having to guess a little based on what you’ve shared.

I’m assuming that the ${VRA_CLOUD_ACCOUNT_VSPHERE_CREDS} sequence in the YAML file gets replaced by CircleCI with a string you’ve provided elsewhere, and that the example you showed under “One of the many versions of the cred variable content:” is describing one such string.

If so, I think the problem is that your map expression is missing its surrounding braces { ... }. If you add the braces to delimit the overall string as being a map then I think it should work:

{
  "hostname1" = {"username" = "myusername1","password" = "mypassword1"},
  "hostname2" = {"username" = "myusername2","password" = "mypassword2"},
}

I added newlines to this example so it would be readable in the forum here, but depending on CircleCI’s expectations it may be necessary to remove those and place the entire string on one line. (Terraform itself should accept it either way, but we also need to make sure that CircleCI is happy that this is a valid string value in its own language.)