TD4091433
TD4091433

Reputation: 63

terraforming templatefile with for and escape last comma

I am creating an AWS Stack Set (at org level) which is written in cloud formation. For the cloud formation, it is written in a terraform template file so that variables are passed from terraform. However there one part which I am having issues with.

The for section needs to look the principals and create Principal block in the template. However the last index of the loop contains a comma which will makes the stack template invalid.

Is there away in terraform to prevent the last comma in a loop?

main.tf:

variable "cross_account" {
  type = list(object({
    principals  = list(string)
  }))
  default = [
    {
      principals  = ["ACCOUNT_ID1","ACCOUNT_ID2","ACCOUNT_ID3"]
    }
  ]
}
output "test" {
  value = templatefile("./json.tpl", {
    principals = var.cross_account[0].principals
  })
}

Template file (json.tpl):

"Principal": {
"AWS": [
  %{ for princ in principals ~}
      {
        "Fn::Sub": "arn:aws:iam::${princ}:root"
      }
  , # <--------------- Need to prevent this line on the last loop index
  %{ endfor ~}
]

I have shorten the code down to only the bits needed above. Thanks

Upvotes: 6

Views: 4256

Answers (3)

Pierig Le Saux
Pierig Le Saux

Reputation: 31

I ran into this today, and this was my solution in case it helps anyone.

"Principal": {
"AWS": [
  %{ for princ in principals ~}
      {
        "Fn::Sub": "arn:aws:iam::${princ}:root"
      }
%{ if index(principals, princ) == length(principal)-1 }
  #do nothing-here if we are on the last iteration
%{ else}
  , #add the comma otherwise
%{ endif }
  %{ endfor ~}
]

Upvotes: 3

TD4091433
TD4091433

Reputation: 63

After playing around for a while with the help of @Marcin, was able to get a working code:

main.tf:

variable "cross_account" {
  type = list(object({
    principals  = list(string)
  }))
  default = [
    {
      principals  = ["ACCOUNT_ID1","ACCOUNT_ID2","ACCOUNT_ID3"]
    }
  ]
}

output "test" {
  value = templatefile("./json.tpl", {
    principals = jsonencode([for i in var.cross_account[0].principals: tomap({"Fn::Sub" = "arn:aws:iam::${i}:root"})])
  })
}

Template file (json.tpl):

"Principal": {
"AWS":  ${principals}
}

results in the following without the extra comma:

test = <<-EOT
        "Principal": {
        "AWS":  [{"Fn::Sub":"arn:aws:iam::ACCOUNT_ID1:root"},{"Fn::Sub":"arn:aws:iam::ACCOUNT_ID2:root"},{"Fn::Sub":"arn:aws:iam::ACCOUNT_ID3:root"}]
        }
    EOT

Upvotes: 0

Marcin
Marcin

Reputation: 238081

You can use jsonencode:

"Principal": {
"AWS": ${jsonencode([
  for princ in principals:
      {
        "Fn::Sub": "arn:aws:iam::${princ}:root"
      }
])}

Or you can use it for all template as shown here depending how exactly your template is defined.

Upvotes: 3

Related Questions