Quantcast
Channel: Terraform - HashiCorp Discuss
Viewing all articles
Browse latest Browse all 11357

Using for, foreach to declare multiple resources

$
0
0

I am trying to create a module that creates an EC2 instance with a variable number of attached volumes. The volumes need to be declared as separate resources and become attached to the instance via the volume_attachment resource, because this is for a fileserver where the volumes will persist if I do a terraform apply using a new AMI id (i.e., I deploy the server, use it to write some data to the volumes, then I create a new AMI, run a terraform apply, and terraform destroys the attachment resource, retains the volumes because they haven’t changed, destroys the instance, launches a new instance, and creates new attachment resources which will attach the old volumes to the new instance).

I am in need of help getting the syntax and correct method for declaring the various resources and their links using for_each.

Example:
I have a .tf file which will contain 3 modules. The modules are for the same subfolder, ec2_instance, where the module definition passes parameters in, which takes a “vols” parameter containing the volume definitions. For each invocation of the module, there are differing numbers of volumes:

Module 1 might use:

vols = {
    data01 = {
        device_name = "xvde"
        size        = "100"
        type        = "gp2"
    }
    data02 = {
        device_name = "xvdh"
        size        = "200"
        type        = "gp2"
    }
}

and Module 2 might use:

vols = {
    output01 = {
        device_name = "xvde"
        size        = "800"
        type        = "gp2"
    }
}

Currently, this is my file which declares 1 instance, 2 volumes and 2 volume_attachments. It will create a single instance with 2 volumes attached (and will be the basis of the inside of my new module):

resource "aws_instance" "storage" {
    ami                     = data.aws_ami.storage.id
    ...
    user_data               = data.template_file.userdata_executescript.rendered
    root_block_device {
        volume_type           = "gp2"
        volume_size           = 80
        delete_on_termination = true
    }

    tags = merge(
        var.common_tags,
        {
        "Name"   = format("%s_storage", var.instance_name)
        "Role"   = format("%s_storage", var.stack_name)
        "Backup" = "true"
        },
    )
}

resource "aws_ebs_volume" "volume_input" {
    availability_zone = local.availability_zone
    size              = 100
    type              = "gp2"
    encrypted         = true

    tags = merge(
        var.common_tags,
        {
        "Name"   = format("%s_storage-%s", var.stack_name, "data01")
        "Backup" = "true"
        },
    )
}

resource "aws_ebs_volume" "volume_input__backup" {
    availability_zone = local.availability_zone
    size              = 200
    type              = "gp2"
    encrypted         = true
    tags = merge(
        var.common_tags,
        {
        "Name"   = format("%s_storage-%s", var.stack_name, "data02")
        "Backup" = "true"
        },
    )
}

resource "aws_volume_attachment" "volume_input" {
    device_name = "xvde"
    volume_id   = aws_ebs_volume.volume_input.id
    instance_id = aws_instance.storage.id
}

resource "aws_volume_attachment" "volume_input__backup" {
    device_name = "xvdh"
    volume_id   = aws_ebs_volume.volume_input__backup.id
    instance_id = aws_instance.storage.id
}

As there will be a differing number of volumes and volume attachments each time the module is invoked, I thought I’d do this using a for_each to declare the volume and volume_attachment resources (at the top of each resource I’ve put the common values, then the ‘each’ values beneath where they differ per resource):

resource "aws_ebs_volume" "volume" {
    for_each = var.vols

    availability_zone = local.availability_zone
    encrypted         = true

    size = each.value.size
    type = each.value.type

    tags = merge(
        var.common_tags,
        {
        "Name"   = format("%s_storage-%s", var.stack_name, each.key)
        "Backup" = "true"
        },
    )
}

resource "aws_volume_attachment" "volume" {
    for_each = var.vols

    instance_id = aws_instance.storage.id

    device_name = each.value.device_name
    volume_id   = aws_ebs_volume.volume["${lookup(var.vols[each.key], each.key, "")}"].id
}

What I need help with is understanding how to specify the volume_id in the aws_volume_attachment resource. I’ve made an attempt at it so you can see the type of value I am trying to lookup/get.

Once I’ve got this set of declarations working, I also need help understanding how to output the volume details into the userdata. I’m using EC2Launch v2 for Windows, which takes yaml input. Essentially, I need to create a userdata file which contains something like this, but with a different number of devices each time:

version: 1.0
tasks:
  - task: initializeVolume
    inputs:
      initialize: devices
      devices:
        - device: xvde
          name: data01
          letter: D
          partition: gpt
        - device: xvdh
          name: data02
          letter: E
          partition: gpt

I’m new to the for/for_each concepts in terraform and can’t seem to figure out the correct syntaxes and formats for repeating elements. Help is appreciated.

9 posts - 2 participants

Read full topic


Viewing all articles
Browse latest Browse all 11357

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>