Terraform: Use list of map in module

Created on 28 Feb 2017  ·  16Comments  ·  Source: hashicorp/terraform

Not sure if this is a bug report or feature request.

I would like to use aws_dynamodb_table in a module and pass in a list of literal attribute maps. I can pass the list of literal maps but I can't figure out how to assign it to the attribute property.

_./modules/table.tf_

resource "aws_dynamodb_table" "basic_dynamodb_table" {
    name                = "${var.table_name}"
    read_capacity       = "${var.read_capacity}"
    write_capacity      = "${var.write_capacity}"
    hash_key            = "${var.primary_key}"

    attribute {
        name            = "${var.primary_key}"
        type            = "${var.primary_key_type}"
    }

    attribute = "${var.attribute}"
}

variable "table_name" {}

variable "read_capacity" {
    default     = "1"
}

variable "write_capacity" {
    default     = "1"
}

variable "primary_key" {}

variable "primary_key_type" {}

variable "attribute" {
    default = []
    description = "List of defined attributes, map of { name, type }"
    type = "list"
}

_./dynamo.tf_

module "basic_table" {
    source              = "./modules/table"

    table_name          = "test-table"
    primary_key         = "Id"
    primary_key_type    = "S"

    attribute {
        name = "SecondaryId"
        type = "S"
    }

    attribute {
        name = "Type"
        type = "N"
    }
}

if I output attribute variable it show it as

attributes = [
    {
        name = SecondaryId,
        type = S
    },
    {
        name = Type,
        type = N
    }
]

however when I run terraform get it get Error loading .terraform\modules\93790fb028cae1e6f9168662d159650c\table.tf: Error reading config for aws_dynamodb_table[basic_dynamodb_table]: At 25:17: unknown slice type: *ast.LiteralType

Version:
Terraform v0.8.6

OS:
Windows 10 Home (Build: 14393.693)

bug config

Most helpful comment

* calling the module*

module "my-awesome-alb" {
    source = "../terraform_modules/my-alb-module"
    .
    .
    .
    listeners = [
        {
            port = 443
            certificate = "${data.aws_acm_certificate.wildcardDotComtravoDotCom.arn}"
        },
        {
            port = 444
            certificate = "${data.aws_acm_certificate.wildcardDotComtravoDotCom.arn}"
        }
    ]
    .
    .
    .
}

* Inside the module*

resource "aws_alb_listener" "listener" {
  count = "${length(var.listeners)}"

  load_balancer_arn = "${aws_alb.alb.arn}"
# access list via index and not via element
  port              = "${lookup(var.listeners[count.index], "port")}"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = "${lookup(var.listeners[count.index], "certificate")}"

  default_action {
    target_group_arn = "${element(aws_alb_target_group.dummy.*.arn, count.index)}"
    type             = "forward"
  }
}

All 16 comments

I have the exact same problem but with the aws_elastic_beanstalk_environment resource where I am trying to set the setting parameter with a variable list. (0.9.0-beta2)

This doesn't work:

variable "settings" {
  type = "list"
  default = [
    {
      namespace = "aws:elasticbeanstalk:application:environment"
      name      = "B"
      value     = "true"
    },
    {
      namespace = "aws:elasticbeanstalk:application:environment"
      name      = "A"
      value     = "true"
    }
  ]
}

resource "aws_elastic_beanstalk_environment" "application" {
  name          = "${var.name}-application"
  application   = "${aws_elastic_beanstalk_application.application.name}"
  template_name = "${aws_elastic_beanstalk_configuration_template.application.name}"
  tier          = "WebServer"
  setting = "${var.settings}"
...
}

However setting it directly works:

resource "aws_elastic_beanstalk_environment" "application" {
  name          = "${var.name}-application"
  application   = "${aws_elastic_beanstalk_application.application.name}"
  template_name = "${aws_elastic_beanstalk_configuration_template.application.name}"
  tier          = "WebServer"
setting = [
    {
      namespace = "aws:elasticbeanstalk:application:environment"
      name      = "B"
      value     = "true"
    },
    {
      namespace = "aws:elasticbeanstalk:application:environment"
      name      = "A"
      value     = "true"
    }
  ]
...
}

Error reading config for aws_elastic_beanstalk_environment[application]: At 376:13: unknown slice type: *ast.LiteralType

Any update on this? I am facing the same issue.

I'd like to see an update on this issue as well.

I think this also speaks to a fairly sizable gap in documentation around "module-izing" resources with variable-length attribute mappings. There seems to be no canonically established way to write a module such that you can easily accept different end-user use-cases.

we should have the attribute added like a resource to dynamo-db just like we have for security groups with rules. Dynamo-db allows adding a table with only primary key or partition with defaults and then changing them.

I'm facing the same problem as @thomaschaaf. I've created a module for our beanstalk configuration and would like to pass in application environment settings, but running into this issue. Is there any update, or another way of doing this? thanks

Same issue here.

Hi I'm not sure because I only did a terraform plan, but I think this might actually work if you just add brackets in with the list. Terraform expects lists to be passed bracketed like this ["${var.settings}"] Thought I'd post in case it fixes the issue, example -

variable "settings" {
  type = "list"
  default = [
    {
      namespace = "aws:elasticbeanstalk:application:environment"
      name      = "B"
      value     = "true"
    },
    {
      namespace = "aws:elasticbeanstalk:application:environment"
      name      = "A"
      value     = "true"
    }
  ]
}

resource "aws_elastic_beanstalk_environment" "application" {
  name          = "..."
  application   = "..."
  template_name = "..."
  tier          = "..."
  setting = ["${var.settings}"]
}

@sbaum1994's example seems to be working, there is one issue though.
When one writes
setting = ["${var.settings}"]
in the resource and the list is empty like

variable "settings" {
  type = "list"
  default = []
}

The following error is displayed:

1 error(s) occurred:

* module.elastic_beanstalk_environment.aws_elastic_beanstalk_environment.elastic_beanstalk_environment: setting.46: expected object, got invalid

Writing
setting = []
in the resource works though.
Seems like a bug with passing empty lists.

@vpal @sbaum1994 how do you look up the values? I seem to get an error: lookup: argument 1 should be type map, got type string

Update
Figured it out. :) Instead of using element parse the list using count.index

@Puneeth-n can you please give an example how you solved it, thanks.

* calling the module*

module "my-awesome-alb" {
    source = "../terraform_modules/my-alb-module"
    .
    .
    .
    listeners = [
        {
            port = 443
            certificate = "${data.aws_acm_certificate.wildcardDotComtravoDotCom.arn}"
        },
        {
            port = 444
            certificate = "${data.aws_acm_certificate.wildcardDotComtravoDotCom.arn}"
        }
    ]
    .
    .
    .
}

* Inside the module*

resource "aws_alb_listener" "listener" {
  count = "${length(var.listeners)}"

  load_balancer_arn = "${aws_alb.alb.arn}"
# access list via index and not via element
  port              = "${lookup(var.listeners[count.index], "port")}"
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = "${lookup(var.listeners[count.index], "certificate")}"

  default_action {
    target_group_arn = "${element(aws_alb_target_group.dummy.*.arn, count.index)}"
    type             = "forward"
  }
}

@sbaum1994's solution doesn't work for me. It works if I write out settings explicitly inline like:

setting = [
  {...},
  {...}
]

but when I try to use a variable I get the following error:
root.setting[0]: not an object type for map (*ast.LiteralType)
I also get the same error when trying to use locals

Maybe there was a regression in a recent version of terraform?

update
I figured it out after finding this issue: https://github.com/terraform-providers/terraform-provider-aws/issues/3558. It turns out you need to put the setting = ["..."] statement above all other setting statements 🤷‍♂️

This bug report is addressing two different issues. The OP incorrectly described how aws_dynamodb_table works, attribute is a a "nested field" not a simple argument that takes a list such as settings in aws_elastic_beanstalk_environment.

If nested fields supported count like resources do this issue could be resolved actually. How should we go about submitting a feature request for count to be added to nested fields?

This would solve for more than just attribute but also global_secondary_index.

Looks like there is a feature request open for this already #7034

Hi all!

Some outdated labelling on this issue caused me to miss it on the first pass of updating issues but indeed @bcarpio is right that this is covering the same problem as #7034, which has now been closed due to the new feature that will address it being merged in to master in preparation for the forthcoming v0.12.0 release. I left a comment over there showing how the new construct can be used.

Since there's a change already merged, I'm going to close this out. Sorry for the silence here!

I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rkulagowski picture rkulagowski  ·  3Comments

zeninfinity picture zeninfinity  ·  3Comments

c4milo picture c4milo  ·  3Comments

ketzacoatl picture ketzacoatl  ·  3Comments

shanmugakarna picture shanmugakarna  ·  3Comments