1

I want to use Terraform for my existing AWS infrastructure. Therefore, I imported an existing EC2 instance with EBS block devices. Then I wrote the Terraform code. But Terraform wants to replace all EBS block devices. Is there any way to not replace the EBS block devices?

Import

I imported my AWS EC2 instance as described in Import:

Import

Instances can be imported using the id, e.g.,

$ terraform import aws_instance.web i-12345678

Code

After I imported the state file, I wrote my Terraform code.

This is the part for the EBS block device:

ebs_block_device {
  device_name = "/dev/sdf"
  volume_type = "gp2"
  volume_size = 20

  tags = {
    Name = "my-test-docker"
  }
}

Plan

After I wrote the code, I run the plan command, see Command: plan.

This is the part for the EBS block device:

- ebs_block_device { # forces replacement
      - delete_on_termination = false -> null
      - device_name           = "/dev/sdf" -> null
      - encrypted             = false -> null
      - iops                  = 100 -> null
      - snapshot_id           = "snap-0e22b434e3106fd51" -> null
      - tags                  = {
          - "Name"            = "my-test-docker"
        } -> null
      - throughput            = 0 -> null
      - volume_id             = "vol-065138961fea23bf4" -> null
      - volume_size           = 20 -> null
      - volume_type           = "gp2" -> null
    }

 + ebs_block_device { # forces replacement
      + delete_on_termination = true
      + device_name           = "/dev/sdf"
      + encrypted             = (known after apply)
      + iops                  = (known after apply)
      + kms_key_id            = (known after apply)
      + snapshot_id           = (known after apply)
      + tags                  = {
          + "Name"            = "my-test-docker"
        }
      + throughput            = (known after apply)
      + volume_id             = (known after apply)
      + volume_size           = 20
      + volume_type           = "gp2"
    }

Research

I tried to set the volume_id in my code, but Terraform didn't allow to set this property.

Actually, the EBS block device shouldn't be replaced after creation, see ebs_block_device:

  • ebs_block_device - (Optional) One or more configuration blocks with additional EBS block devices to attach to the instance. Block device configurations only apply on resource creation. See Block Devices below for details on attributes and drift detection. When accessing this as an attribute reference, it is a set of objects.

Background

One of the reasons for using ebs_block_device instead of aws_ebs_volume with aws_volume_attachment was aws_volume_attachment Error waiting for Volume .

Another reason was

ebs_block_device is still working fine for new (not imported) resources.

The formating and mounting part of my cloud-init user data script:

fs_setup:
  - label: docker
    filesystem: ext4
    device: /dev/xvdf
    overwrite: false

mounts:
  - [ "/dev/xvdf", "/mnt/docker-data", "auto", "defaults,nofail", "0", "2" ]      

Question

Is there any way to give Terraform a hint to match EBS block device in code with EBS block devices in the state file?

dur
  • 15,689
  • 25
  • 79
  • 125

1 Answers1

1

Rather than using ebs_block_device, you should be using aws_ebs_volume and aws_volume_attachment resources to import non-root EBS blocks, according to Terraform docs:

Currently, changes to the ebs_block_device configuration of existing resources cannot be automatically detected by Terraform. To manage changes and attachments of an EBS block to an instance, use the aws_ebs_volume and aws_volume_attachment resources instead. If you use ebs_block_device on an aws_instance, Terraform will assume management over the full set of non-root EBS block devices for the instance, treating additional block devices as drift.

javierlga
  • 1,409
  • 9
  • 14
  • 1
    The first issue about the error waiting for volume, was already fixed in AWS provider version v3.62.0, and the second error about timing issues with cloud-init can be resolved by adding a delay/retry job where you make an API call to the metadata server to retrieve EBS devices associated https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html – javierlga Aug 29 '22 at 18:28
  • Thanks for the information. The first fix (terminate) didn't work for me, but maybe I did something wrong. I can't remember. For the second fix (delay): is there a cloud-init solution? That's the way I create my mounts and users. – dur Aug 29 '22 at 18:31
  • No, there isn't a cloud-init native solution, but what I was suggesting is that before proceeding to mount the disk(s), you could add a shell script that verifies that the EBS devices are available(by using the metadata server) and then proceed with the next steps of creating and mounting the devices. – javierlga Aug 29 '22 at 18:41
  • Do you mean in the `rundcmd` section of cloud-init? I read that this section is not executed at the right time (see https://stackoverflow.com/questions/34095839/cloud-init-what-is-the-execution-order-of-cloud-config-directives). Could you provide any link to an example? – dur Aug 29 '22 at 18:45
  • Not with `runcmd` as that will run after `users` and `mounts` modules but with `bootcmd` – javierlga Aug 29 '22 at 18:54