Skip to content
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 · 78 comments
Closed

Support count in resource fields #7034

oillio opened this issue Jun 6, 2016 · 78 comments

Comments

@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
Copy link
Contributor

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

@srhaber
Copy link

srhaber commented Jun 16, 2016

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

@phinze
Copy link
Contributor

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
Copy link
Author

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
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
Copy link
Author

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
Copy link

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
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
Copy link
Contributor

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
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
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
Copy link

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
Copy link

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
Copy link

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
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
Copy link

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
Copy link

mike-zenith commented Dec 23, 2016

I would love to see this feature working \o /

@oillio
Copy link
Author

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.

@apparentlymart
Copy link
Member

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. 🎉

@apparentlymart apparentlymart added this to the v0.12.0 milestone Oct 29, 2018
@petrokashlikov
Copy link

petrokashlikov commented Apr 11, 2019

@apparentlymart will this new dynamic setting also support 0 resource blocks? So for example if I left variable empty, it won't create this blocks at all?

@mwarkentin
Copy link
Contributor

@petrokashlikov yes I believe that should be the case.

@Johnch9
Copy link

Johnch9 commented May 24, 2019

I couldn't get this to work. We build out two environments one with AAD integration and one without, so I was trying to dynamically create the azure_active_directory dependent on whether or not the params have been provided.

This is the terraform defn

    role_based_access_control {
        enabled = "true"
        dynamic "azure_active_directory" {
            for_each = "${var.aad_tenant_id != "" ? list("aad_reqd") : list("")}"
            content {
                client_app_id = "${var.aks_client_app_id}"
                server_app_id = "${var.aks_server_app_id}"
                server_app_secret = "${var.aks_server_app_secret}"
                tenant_id = "${var.aad_tenant_id}"
           }
        }
    }

On terraform plan I get this:

      + role_based_access_control {
          + enabled = true

          + azure_active_directory {
              + client_app_id     = (known after apply)
              + server_app_id     = (known after apply)
              + server_app_secret = (sensitive value)
              + tenant_id         = (known after apply)
            }
        }

But on terraform apply I get the error
The value of parameter aadProfile.clientId is invalid
So, I assume the block has been created

@Johnch9
Copy link

Johnch9 commented May 24, 2019

My bad

I hadn't defined an empty list correctly

for_each = "${var.aad_tenant_id != "" ? list("aad_reqd") : []}"

Now works now :)

@ghost
Copy link

ghost commented Jul 25, 2019

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.

@ghost ghost locked and limited conversation to collaborators Jul 25, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests