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

aws_instance block_device declaration causes continual resource re-creation #913

Closed
patricklucas opened this issue Feb 3, 2015 · 22 comments · Fixed by #998
Closed

aws_instance block_device declaration causes continual resource re-creation #913

patricklucas opened this issue Feb 3, 2015 · 22 comments · Fixed by #998
Assignees

Comments

@patricklucas
Copy link

I am unable to use latest (c18b01f) Terraform to manage AWS instances because it tries to destroy and re-create them on every invocation. I think it has something to with my block device specifications. I have already launched quite a few instances with Terraform, but I can't make any modifications lest they get destroyed.

Here is the Terraform config and output:

$ cat asdf.tf
provider "aws" {
    region = "us-west-1"
}

resource "aws_instance" "foo-1" {
    ami = "ami-abcd1234"
    instance_type = "m3.large"
    subnet_id = "subnet-ab1234cd"
    security_groups = ["sg-01234567"]
    tags {
        Name = "test-foo-1"
        mytag = "foo"
    }
    block_device {
        device_name = "/dev/sda1"
        volume_type = "gp2"
        volume_size = 16
    }
    block_device {
        device_name = "/dev/sdf"
        volume_type = "gp2"
        volume_size = 1024
    }
}

$ terraform plan
Refreshing Terraform state prior to plan...


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ aws_instance.foo-1
    ami:                                           "" => "ami-abcd1234"
    availability_zone:                             "" => "<computed>"
    block_device.#:                                "" => "2"
    block_device.2382792209.delete_on_termination: "" => "1"
    block_device.2382792209.device_name:           "" => "/dev/sdf"
    block_device.2382792209.encrypted:             "" => "<computed>"
    block_device.2382792209.snapshot_id:           "" => "<computed>"
    block_device.2382792209.virtual_name:          "" => ""
    block_device.2382792209.volume_size:           "" => "1024"
    block_device.2382792209.volume_type:           "" => "gp2"
    block_device.2936417914.delete_on_termination: "" => "1"
    block_device.2936417914.device_name:           "" => "/dev/sda1"
    block_device.2936417914.encrypted:             "" => "<computed>"
    block_device.2936417914.snapshot_id:           "" => "<computed>"
    block_device.2936417914.virtual_name:          "" => ""
    block_device.2936417914.volume_size:           "" => "16"
    block_device.2936417914.volume_type:           "" => "gp2"
    instance_type:                                 "" => "m3.large"
    key_name:                                      "" => "<computed>"
    private_dns:                                   "" => "<computed>"
    private_ip:                                    "" => "<computed>"
    public_dns:                                    "" => "<computed>"
    public_ip:                                     "" => "<computed>"
    security_groups.#:                             "" => "1"
    security_groups.2681880818:                    "" => "sg-01234567"
    subnet_id:                                     "" => "subnet-ab1234cd"
    tags.#:                                        "" => "2"
    tags.Name:                                     "" => "test-foo-1"
    tags.mytag:                                    "" => "foo"
    tenancy:                                       "" => "<computed>"



$ terraform apply
aws_instance.foo-1: Creating...
  ami:                                           "" => "ami-abcd1234"
  availability_zone:                             "" => "<computed>"
  block_device.#:                                "" => "2"
  block_device.2382792209.delete_on_termination: "" => "1"
  block_device.2382792209.device_name:           "" => "/dev/sdf"
  block_device.2382792209.encrypted:             "" => "<computed>"
  block_device.2382792209.snapshot_id:           "" => "<computed>"
  block_device.2382792209.virtual_name:          "" => ""
  block_device.2382792209.volume_size:           "" => "1024"
  block_device.2382792209.volume_type:           "" => "gp2"
  block_device.2936417914.delete_on_termination: "" => "1"
  block_device.2936417914.device_name:           "" => "/dev/sda1"
  block_device.2936417914.encrypted:             "" => "<computed>"
  block_device.2936417914.snapshot_id:           "" => "<computed>"
  block_device.2936417914.virtual_name:          "" => ""
  block_device.2936417914.volume_size:           "" => "16"
  block_device.2936417914.volume_type:           "" => "gp2"
  instance_type:                                 "" => "m3.large"
  key_name:                                      "" => "<computed>"
  private_dns:                                   "" => "<computed>"
  private_ip:                                    "" => "<computed>"
  public_dns:                                    "" => "<computed>"
  public_ip:                                     "" => "<computed>"
  security_groups.#:                             "" => "1"
  security_groups.2681880818:                    "" => "sg-01234567"
  subnet_id:                                     "" => "subnet-ab1234cd"
  tags.#:                                        "" => "2"
  tags.Name:                                     "" => "test-foo-1"
  tags.mytag:                                    "" => "foo"
  tenancy:                                       "" => "<computed>"
aws_instance.foo-1: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

$ terraform plan
Refreshing Terraform state prior to plan...

aws_instance.foo-1: Refreshing state... (ID: i-5381849b)

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

-/+ aws_instance.foo-1
    ami:                                           "ami-abcd1234" => "ami-abcd1234"
    availability_zone:                             "us-west-1a" => "<computed>"
    block_device.#:                                "1" => "2"
    block_device.2382792209.delete_on_termination: "true" => "1" (forces new resource)
    block_device.2382792209.device_name:           "/dev/sdf" => "/dev/sdf" (forces new resource)
    block_device.2382792209.encrypted:             "false" => "<computed>"
    block_device.2382792209.snapshot_id:           "" => "<computed>"
    block_device.2382792209.virtual_name:          "" => ""
    block_device.2382792209.volume_size:           "1024" => "1024" (forces new resource)
    block_device.2382792209.volume_type:           "gp2" => "gp2" (forces new resource)
    block_device.2936417914.delete_on_termination: "" => "1" (forces new resource)
    block_device.2936417914.device_name:           "" => "/dev/sda1" (forces new resource)
    block_device.2936417914.encrypted:             "" => "<computed>" (forces new resource)
    block_device.2936417914.snapshot_id:           "" => "<computed>" (forces new resource)
    block_device.2936417914.virtual_name:          "" => "" (forces new resource)
    block_device.2936417914.volume_size:           "" => "16" (forces new resource)
    block_device.2936417914.volume_type:           "" => "gp2" (forces new resource)
    instance_type:                                 "m3.large" => "m3.large"
    key_name:                                      "" => "<computed>"
    private_dns:                                   "ip-10-40-11-63.example.com" => "<computed>"
    private_ip:                                    "10.40.11.63" => "<computed>"
    public_dns:                                    "" => "<computed>"
    public_ip:                                     "" => "<computed>"
    security_groups.#:                             "1" => "1"
    security_groups.2681880818:                    "sg-01234567" => "sg-01234567"
    subnet_id:                                     "subnet-ab1234cd" => "subnet-ab1234cd"
    tags.#:                                        "2" => "2"
    tags.Name:                                     "test-foo-1" => "test-foo-1"
    tags.mytag:                                    "foo" => "foo"
    tenancy:                                       "default" => "<computed>"



$ terraform apply
aws_instance.foo-1: Refreshing state... (ID: i-5381849b)
aws_instance.foo-1: Destroying...
aws_instance.foo-1: Destruction complete
aws_instance.foo-1: Creating...
  ami:                                           "" => "ami-abcd1234"
  availability_zone:                             "" => "<computed>"
  block_device.#:                                "" => "2"
  block_device.2382792209.delete_on_termination: "" => "1"
  block_device.2382792209.device_name:           "" => "/dev/sdf"
  block_device.2382792209.encrypted:             "" => "<computed>"
  block_device.2382792209.snapshot_id:           "" => "<computed>"
  block_device.2382792209.virtual_name:          "" => ""
  block_device.2382792209.volume_size:           "" => "1024"
  block_device.2382792209.volume_type:           "" => "gp2"
  block_device.2936417914.delete_on_termination: "" => "1"
  block_device.2936417914.device_name:           "" => "/dev/sda1"
  block_device.2936417914.encrypted:             "" => "<computed>"
  block_device.2936417914.snapshot_id:           "" => "<computed>"
  block_device.2936417914.virtual_name:          "" => ""
  block_device.2936417914.volume_size:           "" => "16"
  block_device.2936417914.volume_type:           "" => "gp2"
  instance_type:                                 "" => "m3.large"
  key_name:                                      "" => "<computed>"
  private_dns:                                   "" => "<computed>"
  private_ip:                                    "" => "<computed>"
  public_dns:                                    "" => "<computed>"
  public_ip:                                     "" => "<computed>"
  security_groups.#:                             "" => "1"
  security_groups.2681880818:                    "" => "sg-01234567"
  subnet_id:                                     "" => "subnet-ab1234cd"
  tags.#:                                        "" => "2"
  tags.Name:                                     "" => "test-foo-1"
  tags.mytag:                                    "" => "foo"
  tenancy:                                       "" => "<computed>"
aws_instance.foo-1: Creation complete

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate

$ terraform plan
Refreshing Terraform state prior to plan...

aws_instance.foo-1: Refreshing state... (ID: i-4386838b)

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

-/+ aws_instance.foo-1
    ami:                                           "ami-abcd1234" => "ami-abcd1234"
    availability_zone:                             "us-west-1a" => "<computed>"
    block_device.#:                                "1" => "2"
    block_device.2382792209.delete_on_termination: "true" => "1" (forces new resource)
    block_device.2382792209.device_name:           "/dev/sdf" => "/dev/sdf" (forces new resource)
    block_device.2382792209.encrypted:             "false" => "<computed>"
    block_device.2382792209.snapshot_id:           "" => "<computed>"
    block_device.2382792209.virtual_name:          "" => ""
    block_device.2382792209.volume_size:           "1024" => "1024" (forces new resource)
    block_device.2382792209.volume_type:           "gp2" => "gp2" (forces new resource)
    block_device.2936417914.delete_on_termination: "" => "1" (forces new resource)
    block_device.2936417914.device_name:           "" => "/dev/sda1" (forces new resource)
    block_device.2936417914.encrypted:             "" => "<computed>" (forces new resource)
    block_device.2936417914.snapshot_id:           "" => "<computed>" (forces new resource)
    block_device.2936417914.virtual_name:          "" => "" (forces new resource)
    block_device.2936417914.volume_size:           "" => "16" (forces new resource)
    block_device.2936417914.volume_type:           "" => "gp2" (forces new resource)
    instance_type:                                 "m3.large" => "m3.large"
    key_name:                                      "" => "<computed>"
    private_dns:                                   "ip-10-40-10-56.example.com" => "<computed>"
    private_ip:                                    "10.40.10.56" => "<computed>"
    public_dns:                                    "" => "<computed>"
    public_ip:                                     "" => "<computed>"
    security_groups.#:                             "1" => "1"
    security_groups.2681880818:                    "sg-01234567" => "sg-01234567"
    subnet_id:                                     "subnet-ab1234cd" => "subnet-ab1234cd"
    tags.#:                                        "2" => "2"
    tags.Name:                                     "test-foo-1" => "test-foo-1"
    tags.mytag:                                    "foo" => "foo"
    tenancy:                                       "default" => "<computed>"
@phinze
Copy link
Contributor

phinze commented Feb 3, 2015

Hey @patricklucas - sorry this is causing you trouble.

Over in #859 we determined that terraform should ignore root devices, which is the current behavior in master. It looks like your config is declaring a root device - do you get coherent behavior when you only specify the non-root device in your config and let AWS auto-create the other one?

@patricklucas
Copy link
Author

If I remove the /dev/sda1 block_device, it does indeed start to work.

But, I need to specify the root device because I need to override its volume type and size—I want gp2/16GB instead of the default standard/8GB.

Is this not possible with Terraform?

@phinze
Copy link
Contributor

phinze commented Feb 3, 2015

The solution we landed on in #859 may have been insufficient. Let me think about this a bit.

@threetee
Copy link

threetee commented Feb 4, 2015

I see this behavior even when I don't specify the root device. Here's my config:

resource "aws_instance" "my_instance" {
  ami = "${var.my_ami}"
  instance_type = "t2.small"
  availability_zone = "us-west-2a"
  key_name = "my_key"
  subnet_id = "${aws_subnet.my_subnet.id}"

  block_device = {
    device_name = "/dev/sdf"
    volume_type = "standard"
    volume_size = "100"
    delete_on_termination = false
  }
}

terraform apply forces a new resource, with this relevant output:

    block_device.#:                                "2" => "1"
    block_device.2577914260.delete_on_termination: "false" => "0" (forces new resource)
    block_device.2577914260.device_name:           "/dev/sdf" => "/dev/sdf" (forces new resource)
    block_device.2577914260.encrypted:             "false" => "<computed>"
    block_device.2577914260.snapshot_id:           "" => "<computed>"
    block_device.2577914260.virtual_name:          "" => ""
    block_device.2577914260.volume_size:           "100" => "100" (forces new resource)
    block_device.2577914260.volume_type:           "standard" => "standard" (forces new resource)

@MerlinDMC
Copy link
Contributor

In my terraform plan output I got the following block_device mapping shown:

block_device.#:                                "1" => "1"
block_device.3403969019.delete_on_termination: "" => "1" (forces new resource)
block_device.3403969019.device_name:           "" => "xvdb" (forces new resource)
block_device.3403969019.encrypted:             "" => "<computed>" (forces new resource)
block_device.3403969019.snapshot_id:           "" => "<computed>" (forces new resource)
block_device.3403969019.virtual_name:          "" => "ephemeral0" (forces new resource)
block_device.3403969019.volume_size:           "" => "<computed>" (forces new resource)
block_device.3403969019.volume_type:           "" => "<computed>" (forces new resource)

while the statefile from the last apply has the following mapping registered:

"block_device.#": "1",
"block_device.2849382189.delete_on_termination": "false",
"block_device.2849382189.device_name": "",
"block_device.2849382189.encrypted": "false",
"block_device.2849382189.snapshot_id": "snap-01fe7529",
"block_device.2849382189.virtual_name": "",
"block_device.2849382189.volume_size": "16",
"block_device.2849382189.volume_type": "standard",

The fact that those numeric ids don't match lets me assume that terraform does think it has to recreate the whole device every time as it is a unknown one.

Can someone point me to the commit where the diff introduced the numeric id for lists?

@phinze
Copy link
Contributor

phinze commented Feb 4, 2015

Thanks for the feedback folks. We'll get this all untangled.

@threetee is your case one where you are adding a block device to an existing instance, or was that /dev/sdf device there on creation?

I think one important issue here for updates is that we're currently marking every attribute of block_devices as ForceNew -

Schema: map[string]*schema.Schema{
"device_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"virtual_name": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"snapshot_id": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"volume_type": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"volume_size": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
},
"delete_on_termination": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: true,
ForceNew: true,
},
"encrypted": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Computed: true,
ForceNew: true,

This is because the Update function is pretty anemic right now - it only supports passing SourceDestCheck to the AWS ModifyInstance API -

func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error {

@MerlinDMC Same question for you - is this for a new instance or for updates? FWIW we're tracking ephemeral storage support over in #858, though all of this stuff is very intertwined.

So teasing out the different issues we have so far:

  • The problem for @patricklucas: if you specify the root block device for an instance, terraform will perpetually believe it needs to replace the instance
  • The problem for @threetee (barring contradictory new information): block devices cannot be updated without instance replacement
  • The problem for @MerlinDMC: possibly same as @threetee, waiting for more information on the scenario.

@MerlinDMC
Copy link
Contributor

@phinze I created a new instance in a clean environment and then ran terraform plan again

transscript is: https://gist.github.com/MerlinDMC/5bfd28ccd98eded278d9

using terraform 0.3.6 installed via homebrew

config used:

provider "aws" {
  region = "eu-west-1"
}

resource "aws_instance" "test" {
  ami = "ami-00b11177"
  instance_type = "m3.medium"
  associate_public_ip_address = true

  block_device {
    device_name = "xvdb"
    virtual_name = "ephemeral0"
    delete_on_termination = 1
  }

  count = 1

  key_name = "${var.key_name}"

  tags {
    Name = "Test Kill Me!"
  }

  connection {
    user = "ubuntu"
    key_file = "${var.key_path}"
  }

  provisioner "remote-exec" {
    inline = [
      "uname -a",
    ]
  }
}

@phinze phinze self-assigned this Feb 4, 2015
@jschneiderhan
Copy link
Contributor

I hope I'm not way off here, but while trying to debug this (with a very limited knowledge of Go) it looks like the delete_on_termination value at https://github.com/hashicorp/terraform/blob/master/builtin/providers/aws/resource_aws_instance.go#L513 is being set to false even when the value of the actual resource in AWS is true. If I hard-code true here the hash in the statefile and the hash in the new resource match and a re-creation doesn't occur.

@phinze
Copy link
Contributor

phinze commented Feb 5, 2015

Hey @jschneiderhan - thanks the debugging assist!

I think you're right that there's a problem with delete_on_termination down there. This issue is next on my list of terraform bugs to pick up - I'll add this to my notes and report back here when I make progress. 👍

@jschneiderhan
Copy link
Contributor

As a workaround, if you specify delete_on_termination = true in the aws_instance instead of relying on the default, it works just fine.

@patricklucas
Copy link
Author

@jschneiderhan: That doesn't work for me. Even when explicitly setting it to true, terraform tries to refresh the resources on every run.

@jschneiderhan
Copy link
Contributor

@patricklucas noted - perhaps it's dependent on the version I'm using, 0.3.5, which is a bit older. The following leads to re-creation of the instance:

provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region = "${var.region}"
}

resource "aws_instance" "nat" {
    ami = "[REDACTED]"
    key_name = "[REDACTED]"
    instance_type = "m3.medium"
    availability_zone = "us-east-1b"
    security_groups =["default"]
    block_device {
      device_name = "/dev/sda1"
      volume_size = "150"
      #delete_on_termination = true
    }
}

But this does not:

provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region = "${var.region}"
}

resource "aws_instance" "nat" {
    ami = "[REDACTED]"
    key_name = "[REDACTED]"
    instance_type = "m3.medium"
    availability_zone = "us-east-1b"
    security_groups =["default"]
    block_device {
      device_name = "/dev/sda1"
      volume_size = "150"
      delete_on_termination = true
    }
}

@jschneiderhan
Copy link
Contributor

I just installed v0.3.6 and see the same behavior with the above template. It must be conditional on something, but I don't know what.

I need to move on to something else, but if there is anything more I can try to help please let me know.

@threetee
Copy link

threetee commented Feb 6, 2015

is your case one where you are adding a block device to an existing instance, or was that /dev/sdf device there on creation?

@phinze sorry, upon re-reading my post, I can see how it wasn't clear exactly how I arrived at the problem. The /dev/sdf device was in fact there on creation. I just ran through the whole process again to ensure I could still replicate, and here are the exact steps to duplicate for me:

  1. Add the configuration described in my post (aws_instance resource with an associated block device, mounted at /dev/sdf)
  2. Run 'terraform apply', instance and block device are created properly
  3. Immediately run 'terraform plan', with the following output:
-/+ aws_instance.myinstance
    ami:                                           "ami-d3adb33f" => "ami-d3adb33f"
    availability_zone:                             "us-west-2a" => "us-west-2a"
    block_device.#:                                "2" => "1"
    block_device.2577914260.delete_on_termination: "false" => "0" (forces new resource)
    block_device.2577914260.device_name:           "/dev/sdf" => "/dev/sdf" (forces new resource)
    block_device.2577914260.encrypted:             "false" => "<computed>"
    block_device.2577914260.snapshot_id:           "" => "<computed>"
    block_device.2577914260.virtual_name:          "" => ""
    block_device.2577914260.volume_size:           "100" => "100" (forces new resource)
    block_device.2577914260.volume_type:           "standard" => "standard" (forces new resource)
    instance_type:                                 "t2.small" => "t2.small"
    key_name:                                      "mykey" => "mykey"
    private_dns:                                   "ip-1-2-3-4.us-west-2.compute.internal" => "<computed>"
    private_ip:                                    "1.2.3.4" => "<computed>"
    public_dns:                                    "" => "<computed>"
    public_ip:                                     "" => "<computed>"
    security_groups.#:                             "4" => "4"
    security_groups.1887157646:                    "sg-12345678" => "sg-12345678"
    security_groups.2806254740:                    "sg-87654321" => "sg-87654321"
    security_groups.3046043015:                    "sg-d3adb33f" => "sg-d3adb33f"
    security_groups.3548738533:                    "sg-10101010" => "sg-10101010"
    subnet_id:                                     "subnet-efefefef" => "subnet-efefefef"
    tags.#:                                        "1" => "1"
    tags.Name:                                     "myinstance" => "myinstance"
    tenancy:                                       "default" => "<computed>"
    user_data:                                     "576ca5e7da108364c385e21f8b230ffd34b33fcf" => "576ca5e7da108364c385e21f8b230ffd34b33fcf"
  1. Run 'terraform apply' again, instance is destroyed and recreated:
aws_instance.myinstance: Destruction complete
aws_instance.myinstance: Creating...
<snip>

I'm running terraform v0.3.6, installed via homebrew on OS X Yosemite.

@axelpavageau
Copy link

I'm having the same issue :

-/+ aws_instance.aws-admin
    ami:                                           "ami-2278cc55" => "ami-2278cc55"
    associate_public_ip_address:                   "true" => "1"
    availability_zone:                             "eu-west-1b" => "eu-west-1b"
    block_device.#:                                "2" => "1"
    block_device.3293284504.delete_on_termination: "false" => "0" (forces new resource)
    block_device.3293284504.device_name:           "/dev/sdb" => "/dev/sdb" (forces new resource)
    block_device.3293284504.encrypted:             "false" => "<computed>"
    block_device.3293284504.snapshot_id:           "" => "<computed>"
    block_device.3293284504.virtual_name:          "" => ""
    block_device.3293284504.volume_size:           "50" => "50" (forces new resource)
    block_device.3293284504.volume_type:           "gp2" => "gp2" (forces new resource)
    ebs_optimized:                                 "false" => "0"
    instance_type:                                 "t1.micro" => "t1.micro"

    [...]    

@patricklucas
Copy link
Author

My current workaround is to create the instance with the root block device defined, then remove it for subsequent runs.

If you always want the same root device spec, you can also make it your account default. When you launch an instance with Terraform without defining your root device it will use those settings.

@pmoust
Copy link
Contributor

pmoust commented Feb 16, 2015

@patricklucas this is not an option however as it defies the IaC purpose.

@phinze
Copy link
Contributor

phinze commented Feb 17, 2015

Hey folks, sorry for all the trouble with this.

We're seeing this pattern of sadness in several different places where the backing API provides a collection of objects in which a subset has certain special properties - particularly where a subset of the collection can be auto-populated while the rest is managed.

In this case, the collection of block_devices can be auto-populated with a root device, or the root device can be managed by config, all while the remainder of block devices can be optionally specified.

Today I'm working on a candidate solution for this that I'd love to get feedback on in case it's not the right direction.

Basically I'd like to try splitting out the root device into a separate sub-resource like this:

resource "aws_instance" "foo" {
  ami = "ami-55a7ea65"
  instance_type = "m1.small"
  root_block_device {
    device_name = "/dev/sda1"
    volume_size = 10
  }
  block_device {
    device_name = "/dev/sdb"
    volume_size = 11
  }
  block_device {
    device_name = "/dev/sdc"
    volume_size = 12
  }
  // ...
}

I believe this will make the behavior much clearer. Let me know what you think!

@joegoggins
Copy link

+1 on a root_block_device sub-resource. This would result in a large amount of bliss in my world. :)

Would it be safe to default the device_name to "/dev/sda1" instead of require that a user specify it? The EC2/EBS documentation makes it pretty clear that this is always the default for linux boxes and would prevent mistakes (like the one I just made) where a user specifies /dev/sda instead of /dev/sda1. Also, for this root_block_device sub-resource--I assume it would force the volume_type to "gp2", yea?

In the meantime, until this ships, I'm going with this approach to making the root volume larger:

block_device {
  device_name = "/dev/sda1"
  volume_size = 100
  volume_type = "gp2"
  delete_on_termination = true
}

Please let me know if there is a better way for now (with Terraform 0.3.5 or 0.3.6). Thanks!

@pmoust
Copy link
Contributor

pmoust commented Feb 18, 2015 via email

@patricklucas
Copy link
Author

@phinze: sgtm

I concur with @joegoggins that device_name can likely be safely defaulted to /dev/sda1, though I believe that volume_size and volume_type should fall back to your account defaults as is the current behavior.

phinze added a commit that referenced this issue Feb 18, 2015
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:

 (a) The root volume
 (b) Ephemeral storage
 (c) Additional EBS volumes

Each of these types has slightly different semantics [1].

(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.

(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".

(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.

After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.

Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.

Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.

Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.

[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype

Fixes #913
Refs #858
yahyapo pushed a commit to yahyapo/terraform that referenced this issue Mar 13, 2015
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:

 (a) The root volume
 (b) Ephemeral storage
 (c) Additional EBS volumes

Each of these types has slightly different semantics [1].

(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.

(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".

(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.

After deciding to ignore root block devices to fix hashicorp#859, we had users
with configurations that were attempting to manage the root block device chime
in on hashicorp#913.

Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.

Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.

Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.

[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype

Fixes hashicorp#913
Refs hashicorp#858
@ghost
Copy link

ghost commented May 4, 2020

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 May 4, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants