providers/aws: reduce scope of block_device set hashcodes
Fixes #1409 Resource set hash calculation is a bit of a devil's bargain when it comes to optional, computed attributes. If you omit the optional, computed attribute from the hash function, changing it in an existing config is not properly detected. If you include the optional, computed attribute in the hash and do not specify a value for it in the config, then you'll end up with a perpetual, unresolvable diff. We'll need to think about how to get the best of both worlds, here, but for now I'm switching us to the latter and documenting the fact that changing these attributes requires manual `terraform taint` to apply.
This commit is contained in:
parent
4888c18b61
commit
34c7bbcf4d
|
@ -204,16 +204,8 @@ func resourceAwsInstance() *schema.Resource {
|
||||||
Set: func(v interface{}) int {
|
Set: func(v interface{}) int {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
m := v.(map[string]interface{})
|
m := v.(map[string]interface{})
|
||||||
buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
|
buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
|
||||||
buf.WriteString(fmt.Sprintf("%t-", m["encrypted"].(bool)))
|
|
||||||
// NOTE: Not considering IOPS in hash; when using gp2, IOPS can come
|
|
||||||
// back set to something like "33", which throws off the set
|
|
||||||
// calculation and generates an unresolvable diff.
|
|
||||||
// buf.WriteString(fmt.Sprintf("%d-", m["iops"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string)))
|
buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string)))
|
||||||
buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["volume_type"].(string)))
|
|
||||||
return hashcode.String(buf.String())
|
return hashcode.String(buf.String())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -288,14 +280,8 @@ func resourceAwsInstance() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Set: func(v interface{}) int {
|
Set: func(v interface{}) int {
|
||||||
var buf bytes.Buffer
|
// there can be only one root device; no need to hash anything
|
||||||
m := v.(map[string]interface{})
|
return 0
|
||||||
buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
|
|
||||||
// See the NOTE in "ebs_block_device" for why we skip iops here.
|
|
||||||
// buf.WriteString(fmt.Sprintf("%d-", m["iops"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["volume_type"].(string)))
|
|
||||||
return hashcode.String(buf.String())
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -140,25 +140,25 @@ func TestAccAWSInstance_blockDevices(t *testing.T) {
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "root_block_device.#", "1"),
|
"aws_instance.foo", "root_block_device.#", "1"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "root_block_device.1023169747.volume_size", "11"),
|
"aws_instance.foo", "root_block_device.0.volume_size", "11"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "root_block_device.1023169747.volume_type", "gp2"),
|
"aws_instance.foo", "root_block_device.0.volume_type", "gp2"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.#", "2"),
|
"aws_instance.foo", "ebs_block_device.#", "2"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.2225977507.device_name", "/dev/sdb"),
|
"aws_instance.foo", "ebs_block_device.2576023345.device_name", "/dev/sdb"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.2225977507.volume_size", "9"),
|
"aws_instance.foo", "ebs_block_device.2576023345.volume_size", "9"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.2225977507.volume_type", "standard"),
|
"aws_instance.foo", "ebs_block_device.2576023345.volume_type", "standard"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.1977224956.device_name", "/dev/sdc"),
|
"aws_instance.foo", "ebs_block_device.2554893574.device_name", "/dev/sdc"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.1977224956.volume_size", "10"),
|
"aws_instance.foo", "ebs_block_device.2554893574.volume_size", "10"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.1977224956.volume_type", "io1"),
|
"aws_instance.foo", "ebs_block_device.2554893574.volume_type", "io1"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ebs_block_device.1977224956.iops", "100"),
|
"aws_instance.foo", "ebs_block_device.2554893574.iops", "100"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
"aws_instance.foo", "ephemeral_block_device.#", "1"),
|
"aws_instance.foo", "ephemeral_block_device.#", "1"),
|
||||||
resource.TestCheckResourceAttr(
|
resource.TestCheckResourceAttr(
|
||||||
|
|
|
@ -158,15 +158,8 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
|
||||||
Set: func(v interface{}) int {
|
Set: func(v interface{}) int {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
m := v.(map[string]interface{})
|
m := v.(map[string]interface{})
|
||||||
buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
|
buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
|
||||||
// NOTE: Not considering IOPS in hash; when using gp2, IOPS can come
|
|
||||||
// back set to something like "33", which throws off the set
|
|
||||||
// calculation and generates an unresolvable diff.
|
|
||||||
// buf.WriteString(fmt.Sprintf("%d-", m["iops"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string)))
|
buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string)))
|
||||||
buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["volume_type"].(string)))
|
|
||||||
return hashcode.String(buf.String())
|
return hashcode.String(buf.String())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -240,14 +233,8 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Set: func(v interface{}) int {
|
Set: func(v interface{}) int {
|
||||||
var buf bytes.Buffer
|
// there can be only one root device; no need to hash anything
|
||||||
m := v.(map[string]interface{})
|
return 0
|
||||||
buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
|
|
||||||
// See the NOTE in "ebs_block_device" for why we skip iops here.
|
|
||||||
// buf.WriteString(fmt.Sprintf("%d-", m["iops"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int)))
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-", m["volume_type"].(string)))
|
|
||||||
return hashcode.String(buf.String())
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -109,15 +109,10 @@ list](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html#St
|
||||||
of which ephemeral devices are available on each type. The devices are always
|
of which ephemeral devices are available on each type. The devices are always
|
||||||
identified by the `virtual_name` in the format `"ephemeral{0..N}"`.
|
identified by the `virtual_name` in the format `"ephemeral{0..N}"`.
|
||||||
|
|
||||||
|
~> **NOTE:** Currently, changes to `*_block_device` configuration of _existing_
|
||||||
~> **NOTE:** Because AWS [does not expose Instance Store mapping
|
resources cannot be automatically detected by Terraform. After making updates
|
||||||
details](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html#bdm-instance-metadata)
|
to block device configuration, resource recreation can be manually triggered by
|
||||||
via an externally accessible API, `ephemeral_block_device` configuration may
|
using the [`taint` command](/docs/commands/taint.html).
|
||||||
only be applied at instance creation time, and changes to configuration of
|
|
||||||
existing resources cannot be detected by Terraform. Updates to Instance Store
|
|
||||||
block device configuration can be manually triggered by using the [`taint`
|
|
||||||
command](/docs/commands/taint.html).
|
|
||||||
|
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,11 @@ list](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html#St
|
||||||
of which ephemeral devices are available on each type. The devices are always
|
of which ephemeral devices are available on each type. The devices are always
|
||||||
identified by the `virtual_name` in the format `"ephemeral{0..N}"`.
|
identified by the `virtual_name` in the format `"ephemeral{0..N}"`.
|
||||||
|
|
||||||
|
~> **NOTE:** Changes to `*_block_device` configuration of _existing_ resources
|
||||||
|
cannot currently be detected by Terraform. After updating to block device
|
||||||
|
configuration, resource recreation can be manually triggered by using the
|
||||||
|
[`taint` command](/docs/commands/taint.html).
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
|
Loading…
Reference in New Issue