New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support count in resource fields #7034

Closed
oillio opened this Issue Jun 6, 2016 · 73 comments

Comments

Projects
None yet
@oillio
Copy link

oillio commented Jun 6, 2016

I would like to be able to define repeated fields the same way I can define repeated resources. For instance, this could be used to set beanstalk environment vars based on a list passed in by a variable.

resource "aws_elastic_beanstalk_environment" "myEnv" {
  name = "test_environment"
  application = "testing"

  setting {
    count = "${length(var.myvars)}"
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "${var.myvars.*.name}"
    value     = "${var.myvars.*.value}"
  }  

  setting {
    namespace = "aws:autoscaling:asg"
    name = "MinSize"
    value = "1"
  }
}
@daveadams

This comment has been minimized.

Copy link
Contributor

daveadams commented Jun 7, 2016

This would also be useful for aws_autoscaling_group tags and lots of other things.

@srhaber

This comment has been minimized.

Copy link

srhaber commented Jun 16, 2016

This would also be useful for declaring ebs_block_device mappings for an aws_launch_configuration.

@phinze

This comment has been minimized.

Copy link
Member

phinze commented Jun 27, 2016

This is an interesting take on block expansion! On first glance, I like the symmetry w/ resource expansion, but I'm not sure on auto-indexing splat behavior you reference. I'll do some thinking on this and swing back around.

@oillio

This comment has been minimized.

Copy link

oillio commented Jul 5, 2016

We just need a way to reference items in a list based on the count index. The below would work fine as well, I just like how clean the splat syntax looks.

resource "aws_elastic_beanstalk_environment" "myEnv" {
  name = "test_environment"
  application = "testing"

  setting {
    count = "${length(var.myvars)}"
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "${lookup(element(var.myvars,count.index),"name")}"
    value     = "${lookup(element(var.myvars,count.index),"value")}"
  }  

  setting {
    namespace = "aws:autoscaling:asg"
    name = "MinSize"
    value = "1"
  }
}

Now that I look it up, I may have made up that splat syntax. I don't see a reference to it in the documentation.

@dlanner

This comment has been minimized.

Copy link
Contributor

dlanner commented Jul 8, 2016

Just to add to this, it would also be useful for my use-case as well, multiple environment blocks/fields on aws_opsworks_application resources:

Instead of doing this:

resource "aws_opsworks_application" "custom_app" {
    environment = {
      key   = "${element(split(",", var.environment_variable_keys), 0)}"
      value = "${element(split(",", var.environment_variable_values), 0)}"
    }
    environment = {
      key   = "${element(split(",", var.environment_variable_keys), 1)}"
      value = "${element(split(",", var.environment_variable_values), 1)}"
    }
    environment = {
      key   = "${element(split(",", var.environment_variable_keys), 2)}"
      value = "${element(split(",", var.environment_variable_values), 2)}"
    }
}

We could do this:

resource "aws_opsworks_application" "custom_app" {
    environment = {
      count = "3"
      key   = "${element(split(",", var.environment_variable_keys), count.index)}"
      value = "${element(split(",", var.environment_variable_values), count.index)}"
    }
}
@oillio

This comment has been minimized.

Copy link

oillio commented Jul 12, 2016

Would this be a valid syntax option?

resource "aws_elastic_beanstalk_environment" "myEnv" {
  name = "test_environment"
  application = "testing"

  setting {
    count = "${length(var.myvars)}"
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "${var.myvars[count.index].name}"
    value     = "${var.myvars[count.index].value}"
  }  

  setting {
    namespace = "aws:autoscaling:asg"
    name = "MinSize"
    value = "1"
  }
}

Also FYI, @dlanner: With the new list and map support in variables, you probably won't need to pass your configs into your module in CSV format anymore. In 0.7-rc2 you might be able to clean up your current setup to be something like key = "${var.environment_variable_keys[1]}
In the next release @phinze added support for lists of objects, so you could even pass the key/value as a single list key = "${lookup(var.environment_variable[1],"key"}"
You will currently still need to manually duplicate the environment entries though.

@jimsheldon

This comment has been minimized.

Copy link

jimsheldon commented Aug 8, 2016

I would also like to pass multiple settings to aws_elastic_beanstalk_environment in this way, is there a workable solution now that 0.7 has been released?

@tjboudreaux

This comment has been minimized.

Copy link

tjboudreaux commented Sep 11, 2016

I'm trying to do the same thing as @jimsheldon. Is there a way to do this in 0.7.3?

@borgstrom

This comment has been minimized.

Copy link
Contributor

borgstrom commented Sep 27, 2016

Wanted to add another use case here: launch_specification in AWS spot fleets.

We have to define a launch_specification for each subnet/availability zone, which means that we end up with lots of repetition:

resource "aws_spot_fleet_request" "spot_fleet" {
    ...
    // c4.large
    launch_specification {
    instance_type = "c4.large"
        subnet_id = "${element(data.terraform_remote_state.vpc.private_subnet_ids, 0)}"
        availability_zone = "${element(data.terraform_remote_state.vpc.azs, 0)}"
        ...
    }
    launch_specification {
    instance_type = "c4.large"
        subnet_id = "${element(data.terraform_remote_state.vpc.private_subnet_ids, 1)}"
        availability_zone = "${element(data.terraform_remote_state.vpc.azs, 1)}"
        ...
    }
    launch_specification {
    instance_type = "c4.large"
        subnet_id = "${element(data.terraform_remote_state.vpc.private_subnet_ids, 2)}"
        availability_zone = "${element(data.terraform_remote_state.vpc.azs, 2)}"
        ...
    }

    // c3.large
    launch_specification {
    instance_type = "c3.large"
        subnet_id = "${element(data.terraform_remote_state.vpc.private_subnet_ids, 0)}"
        availability_zone = "${element(data.terraform_remote_state.vpc.azs, 0)}"
        ...
    }
    launch_specification {
    instance_type = "c3.large"
        subnet_id = "${element(data.terraform_remote_state.vpc.private_subnet_ids, 1)}"
        availability_zone = "${element(data.terraform_remote_state.vpc.azs, 1)}"
        ...
    }
    launch_specification {
    instance_type = "c3.large"
        subnet_id = "${element(data.terraform_remote_state.vpc.private_subnet_ids, 2)}"
        availability_zone = "${element(data.terraform_remote_state.vpc.azs, 2)}"
        ...
    }

Having count would make this so much easier to maintain.

@cartolari

This comment has been minimized.

Copy link

cartolari commented Oct 11, 2016

Maybe a new resource type could be created, aws_elastic_beanstalk_environment_setting for example, so the count would work as any other terraform resource, allowing us to write something like this:

resource "aws_elastic_beanstalk_environment" "myEnv" {
  ...
}

resource "aws_elastic_beanstalk_environment_setting" "environment_variables" {
  environment_id = "${aws_elastic_beanstalk_environment.myEnv.id}"
  count          = "${length(var.myvars)}"
  ...
}
@devinsba

This comment has been minimized.

Copy link

devinsba commented Oct 18, 2016

This would be super helpful in my current task of creating a reusable elastic_beanstalk module. Either of the solutions so far would work for me, either a count on setting or a setting resource as long as that resource can be attached to either aws_elastic_beanstalk_environment or aws_elastic_beanstalk_configuration_template

@ottopoellath

This comment has been minimized.

Copy link

ottopoellath commented Oct 24, 2016

I would also like to see this implemented, because creating a reusable elastic_beanstalk module is currently almost impossible. Either proposal would work for our use case.

@elbeanio

This comment has been minimized.

Copy link

elbeanio commented Oct 24, 2016

Just hit the same issue as others trying to create a reusable elastic_beanstalk module. Would be happy with either syntax enhancement or new resource type.

@justintime

This comment has been minimized.

Copy link

justintime commented Nov 4, 2016

Just another vote for the fleet launch specification use case. I reverted to using ERB templates being rendered by a makefile because we have almost 50 specifications per fleet.

@myoung34

This comment has been minimized.

Copy link
Contributor

myoung34 commented Dec 20, 2016

Another vote now that conditionals are allowed in Terraform 0.8

+   setting {
+     count = "${var.spin_down_at_night == "true" ? 1 : 0}"
+     namespace = "aws:autoscaling:scheduledaction"
+     resource = "ScheduledPeriodicScaleup"
+     name = "Recurrence"
+     value = "0 10 * * *" #10am UTC = 4am CST
+   }```
@avistramer

This comment has been minimized.

Copy link

avistramer commented Dec 22, 2016

Wanted to add another vote for the spot fleet launch_specification use case. We end up with 20+ specifications per fleet and have many different fleets so it quickly gets out of control. This looks like a nice elegant solution.

@mike-zenith

This comment has been minimized.

Copy link

mike-zenith commented Dec 23, 2016

I would love to see this feature working \o /

@oillio

This comment has been minimized.

Copy link

oillio commented Jan 20, 2017

Good idea @cartolari. I broke that request out as a separate issue: #11314

Since it doesn't look like count in fields is on the roadmap, maybe we can get that fix implemented.

@KWyckmans

This comment has been minimized.

Copy link

KWyckmans commented Jul 12, 2018

Same here, would be very nice to have this in regards to volumes on ECS.

@mwarkentin

This comment has been minimized.

Copy link
Contributor

mwarkentin commented Jul 12, 2018

I believe this is going to be supported in Terraform 0.12.

@rkul

This comment has been minimized.

Copy link

rkul commented Jul 12, 2018

Yeah, seems like following improvement:

Dynamic blocks. Child blocks such as rule in aws_security_group can now be dynamically generated based on lists/maps and support iteration.

@apparentlymart

This comment has been minimized.

Copy link
Contributor

apparentlymart commented Jul 12, 2018

Indeed, that's what that bullet point in the preview article is talking about. There's a more detailed article on this subject coming very soon, so I'd been holding off for that to link to it. I'll link to that here once it's posted.

@apparentlymart

This comment has been minimized.

Copy link
Contributor

apparentlymart commented Jul 12, 2018

Here we go: For and For Each. This article covers a set of related new constructs for working with collections, including the dynamic block.

For those who'd like more detail on this feature in particular, you might like to read the updated docs from the development branch. These docs will be subject to some more edit passes before final, but the general idea is there.

@robinbowes

This comment has been minimized.

Copy link

robinbowes commented Jul 12, 2018

That looks great - can't wait until it's released.

@mattes

This comment has been minimized.

Copy link

mattes commented Jul 25, 2018

This is the fourth post of the series highlighting new features in Terraform 0.12.:

HashiCorp Terraform 0.12 Preview: Generalized Splat Operator

@saplla

This comment has been minimized.

Copy link

saplla commented Jul 25, 2018

@mattes When will 0.12 be released?

@bcarpio

This comment has been minimized.

Copy link

bcarpio commented Jul 25, 2018

@saplla the only info I can find is this:

Terraform 0.12 will not be released until later this summer

https://www.terraform.io/upgrade-guides/0-12.html

@apparentlymart

This comment has been minimized.

Copy link
Contributor

apparentlymart commented Oct 26, 2018

I tried the following with Terraform v0.12.0-alpha1:

provider "aws" {
  region = "us-west-2"
}

variable "environment_vars" {
  type = map(string)
  default = {
    FOO = "bar"
    BAZ = "boop"
  }
}

resource "aws_elastic_beanstalk_environment" "example" {
  name        = "test_environment"
  application = "testing"

  # Static Setting
  setting {
    namespace = "aws:autoscaling:asg"
    name      = "MinSize"
    value     = "1"
  }

  dynamic "setting" {
    for_each = var.environment_vars
    content {
      namespace = "aws:elasticbeanstalk:application:environment"
      name      = setting.key
      value     = setting.value
    }
  }
}

I don't have sufficient other Elastic Beanstalk infrastructure in my AWS account to apply this, but I was able to see it generating the expected result in terraform plan.

So with all of that said, it seems that the new dynamic block feature serves the use-case presented in this issue, albeit not in exactly the same way as suggested, and so I'm going to close this out. You can try this feature out experimentally in v0.12.0-alpha1, and it'll be also included in the eventual v0.12.0 final release. Thanks everyone for your patience on this one! I know it's been a long time coming. 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment