jamiet
jamiet

Reputation: 12334

terraform nested interpolation with count

Using terraform I wish to refer to the content of a list of files (ultimately I want to zip them up using the archive_file provider, but in the context of this post that isn't important). These files all live within the same directory so I have two variables:

variable "source_root_dir" {
  type        = "string"
  description = "Directory containing all the files"
}

variable "source_files" {
  type        = "list"
  description = "List of files to be added to the cloud function. Locations are relative to source_root_dir"
}

I want to use the template data provider to refer to the content of the files. Given the number of files in source_files can vary I need to use a count to carry out the same operation on all of them.

Thanks to the information provided at https://stackoverflow.com/a/43195932/201657 I know that I can refer to the content of a single file like so:

provider "template" {
  version = "1.0.0"
}

variable "source_root_dir" {
  type        = "string"
}

variable "source_file" {
  type        = "string"
}

data "template_file" "t_file" {
  template = "${file("${var.source_root_dir}/${var.source_file}")}"
}

output "myoutput" {
  value = "${data.template_file.t_file.rendered}"
}

Notice that that contains nested string interpolations. If I run:

terraform init && terraform apply -var source_file="foo" -var source_root_dir="./mydir"

after creating file mydir/foo of course then this is the output: enter image description here

Success!

Now I want to combine that nested string interpolation syntax with my count. Hence my terraform project now looks like this:

provider "template" {
  version = "1.0.0"
}

variable "source_root_dir" {
  type        = "string"
  description = "Directory containing all the files"
}

variable "source_files" {
  type        = "list"
  description = "List of files to be added to the cloud function. Locations are relative to source_root_dir"
}

data "template_file" "t_file" {
  count    = "${length(var.source_files)}"
  template = "${file("${"${var.source_root_dir}"/"${element("${var.source_files}", count.index)}"}")}"
}

output "myoutput" {
  value = "${data.template_file.t_file.*.rendered}"
}

yes it looks complicated but syntactically, its correct (at least I think it is). However, if I run init and apply:
terraform init && terraform apply -var source_files='["foo", "bar"]' -var source_root_dir='mydir'

I get errors:

Error: data.template_file.t_file: 2 error(s) occurred:
* data.template_file.t_file[0]: __builtin_StringToInt: strconv.ParseInt: parsing "mydir": invalid syntax in:
${file("${"${var.source_root_dir}"/"${element("${var.source_files}", count.index)}"}")}
* data.template_file.t_file1: __builtin_StringToInt: strconv.ParseInt: parsing "mydir": invalid syntax in:
${file("${"${var.source_root_dir}"/"${element("${var.source_files}", count.index)}"}")}

enter image description here

My best guess is that its interpreting the / as a division operation hence its attempting to parse the value mydir in source_root_dir as an int.

I've played around with this for ages now and can't figure it out. Can someone figure out how to use nested string interpolations together with a count in order to refer to the content of multiple files using the template provider?

Upvotes: 1

Views: 2614

Answers (1)

jamiet
jamiet

Reputation: 12334

OK, I think I figured it out. formatlist to the rescue

provider "template" {
  version = "1.0.0"
}

variable "source_root_dir" {
  type        = "string"
  description = "Directory containing all the files"
}

variable "source_files" {
  type        = "list"
  description = "List of files to be added to the cloud function. Locations are relative to source_root_dir"
}

locals {
  fully_qualified_source_files = "${formatlist("%s/%s", var.source_root_dir, var.source_files)}"
}

data "template_file" "t_file" {
  count    = "${length(var.source_files)}"
  template = "${file(element("${local.fully_qualified_source_files}", count.index))}"
}

output "myoutput" {
  value = "${data.template_file.t_file.*.rendered}"
}

when applied:

terraform init && terraform apply -var source_files='["foo", "bar"]' -var source_root_dir='mydir'

outputs:

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

myoutput = [ This is the content of foo
,
This is the content of bar

]

enter image description here

Upvotes: 1

Related Questions