Not able to pass a list of elements using terraform0.11

387 Views Asked by At

I am trying to pass a variable of type list as follow:

In the cf-app.tf file:

resource "cloudfoundry_app" "my-app" {

service_binding = "${var.service-bindings}"

}

In variables.tf file:

variable "service-bindings" {
  type = "list"
  default = []
}

In deployment.tf file:

module "nested-module" {
source = "../my-app"

  service-bindings = [
    {
      service_instance = "dummy1"
    },
    {
      service_instance = "dummy2"
    }
  ]

}

but I m getting the below error, this is a known terraform 11 issue and has been fixed in terraform 12:

Error: module.nested-module.cloudfoundry_app.myapp: service_binding: should be a list

I followed this issue but my challenge is with the string of elements...

I am currently using terraform version 11.

Can someone help me resolve this in a hacky way?

Thank you in advance!

2

There are 2 best solutions below

0
On

Why do you have:

service_binding = "${var.service-bindings}"

When var.service-bindings is a list and the service_binding input expects a list? Shouldn't this be:

service_binding = var.service-bindings

I don't have Terraform v0.11 installed and I have no intention of installing it to test this, but you could try:

  1. Removing type = "list" from your variable. Will it still throw this error if you don't ask it to validate that the type is correct?

  2. Does 0.11 support the jsonencode function? If so, try:

resource "cloudfoundry_app" "my-app" {
  service_binding = jsondecode(var.service-bindings)
}

variable "service-bindings" {
  type = "string"
  default = "[]"
}
module "nested-module" {
  source = "../my-app"

  service-bindings = jsonencode([
    {
      service_instance = "dummy1"
    },
    {
      service_instance = "dummy2"
    }
  ])
}
0
On

Terraform v0.11's type system does not support this sort of nested data structure. It supports only strings, lists of strings, and maps of strings.

Your example here is therefore combining various capabilities that Terraform v0.11 is not well-suited to support and that were exactly the sort of limitations that prompted the rewrite of the Terraform language for Terraform v0.12.

My best suggestion for your situation would be to discard the idea of factoring out resource "cloudfoundry_app" "my-app" into a shared module and instead write it directly as an inline resource with the settings you need specified directly inside:

resource "cloudfoundry_app" "my-app" {
  service_binding {
    service_instance = "dummy1"
  }

  service_binding {
    service_instance = "dummy2"
  }
}

Once you're ready to upgrade to a more modern version of Terraform, you can rewrite this as a dynamic block to generate multiple service_binding blocks based on your input variable, and then consider factoring it out into a separate module once you can use a sufficiently-expressive Terraform language version:

# This configuration is only for Terraform v0.12 or later

variable "service_bindings" {
  type = list(object({
    service_instance = string
    params_json      = string
  }))
}

resource "cloudfoundry_app" "my-app" {
  dynamic "service_binding" {
    for_each = var.service_bindings
    content {
      service_instance = service_binding.value.service_instance
      params_json      = service_binding.value.params_json
    }
  }
}