provider/aws: ForceNew aws_launch_config when root_block_device changes (#14507)

Fixes: #14503

Changes to root_block_device were not picked up as we had a hash func to
return 0. We changed from set -> list as we only allow 1 value and
immediately we can get changes propagating

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSLaunchConfiguration_updateRootBlockDevice'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/05/15 19:27:39 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSLaunchConfiguration_updateRootBlockDevice -timeout 120m
=== RUN   TestAccAWSLaunchConfiguration_updateRootBlockDevice
--- PASS: TestAccAWSLaunchConfiguration_updateRootBlockDevice (51.12s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	51.140s
```
This commit is contained in:
Paul Stack 2017-05-15 20:18:40 +03:00 committed by GitHub
parent bb1559e041
commit 0a645294a0
2 changed files with 107 additions and 51 deletions

View File

@ -28,7 +28,7 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
},
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
@ -45,7 +45,7 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
},
},
"name_prefix": &schema.Schema{
"name_prefix": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
@ -61,32 +61,32 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
},
},
"image_id": &schema.Schema{
"image_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"instance_type": &schema.Schema{
"instance_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"iam_instance_profile": &schema.Schema{
"iam_instance_profile": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"key_name": &schema.Schema{
"key_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"user_data": &schema.Schema{
"user_data": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
@ -101,7 +101,7 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
},
},
"security_groups": &schema.Schema{
"security_groups": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
@ -109,13 +109,13 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
Set: schema.HashString,
},
"vpc_classic_link_id": &schema.Schema{
"vpc_classic_link_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"vpc_classic_link_security_groups": &schema.Schema{
"vpc_classic_link_security_groups": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
@ -123,87 +123,87 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
Set: schema.HashString,
},
"associate_public_ip_address": &schema.Schema{
"associate_public_ip_address": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
Default: false,
},
"spot_price": &schema.Schema{
"spot_price": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"ebs_optimized": &schema.Schema{
"ebs_optimized": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
Computed: true,
},
"placement_tenancy": &schema.Schema{
"placement_tenancy": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"enable_monitoring": &schema.Schema{
"enable_monitoring": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
Default: true,
},
"ebs_block_device": &schema.Schema{
"ebs_block_device": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"delete_on_termination": &schema.Schema{
"delete_on_termination": {
Type: schema.TypeBool,
Optional: true,
Default: true,
ForceNew: true,
},
"device_name": &schema.Schema{
"device_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"iops": &schema.Schema{
"iops": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
},
"snapshot_id": &schema.Schema{
"snapshot_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"volume_size": &schema.Schema{
"volume_size": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
},
"volume_type": &schema.Schema{
"volume_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"encrypted": &schema.Schema{
"encrypted": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
@ -220,18 +220,18 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
},
},
"ephemeral_block_device": &schema.Schema{
"ephemeral_block_device": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"device_name": &schema.Schema{
"device_name": {
Type: schema.TypeString,
Required: true,
},
"virtual_name": &schema.Schema{
"virtual_name": {
Type: schema.TypeString,
Required: true,
},
@ -246,41 +246,38 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
},
},
"root_block_device": &schema.Schema{
// TODO: This is a set because we don't support singleton
// sub-resources today. We'll enforce that the set only ever has
// length zero or one below. When TF gains support for
// sub-resources this can be converted.
Type: schema.TypeSet,
"root_block_device": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
// "You can only modify the volume size, volume type, and Delete on
// Termination flag on the block device mapping entry for the root
// device volume." - bit.ly/ec2bdmap
Schema: map[string]*schema.Schema{
"delete_on_termination": &schema.Schema{
"delete_on_termination": {
Type: schema.TypeBool,
Optional: true,
Default: true,
ForceNew: true,
},
"iops": &schema.Schema{
"iops": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
},
"volume_size": &schema.Schema{
"volume_size": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ForceNew: true,
},
"volume_type": &schema.Schema{
"volume_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
@ -288,10 +285,6 @@ func resourceAwsLaunchConfiguration() *schema.Resource {
},
},
},
Set: func(v interface{}) int {
// there can be only one root device; no need to hash anything
return 0
},
},
},
}
@ -416,10 +409,7 @@ func resourceAwsLaunchConfigurationCreate(d *schema.ResourceData, meta interface
}
if v, ok := d.GetOk("root_block_device"); ok {
vL := v.(*schema.Set).List()
if len(vL) > 1 {
return fmt.Errorf("Cannot specify more than one root_block_device.")
}
vL := v.([]interface{})
for _, v := range vL {
bd := v.(map[string]interface{})
ebs := &autoscaling.Ebs{

View File

@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
@ -23,7 +24,7 @@ func TestAccAWSLaunchConfiguration_basic(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccAWSLaunchConfigurationNoNameConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.bar", &conf),
@ -31,7 +32,7 @@ func TestAccAWSLaunchConfiguration_basic(t *testing.T) {
"aws_launch_configuration.bar", "terraform-"),
),
},
resource.TestStep{
{
Config: testAccAWSLaunchConfigurationPrefixNameConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.baz", &conf),
@ -51,7 +52,7 @@ func TestAccAWSLaunchConfiguration_withBlockDevices(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccAWSLaunchConfigurationConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.bar", &conf),
@ -70,6 +71,35 @@ func TestAccAWSLaunchConfiguration_withBlockDevices(t *testing.T) {
})
}
func TestAccAWSLaunchConfiguration_updateRootBlockDevice(t *testing.T) {
var conf autoscaling.LaunchConfiguration
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLaunchConfigurationConfigWithRootBlockDevice(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.bar", &conf),
resource.TestCheckResourceAttr(
"aws_launch_configuration.bar", "root_block_device.0.volume_size", "11"),
),
},
{
Config: testAccAWSLaunchConfigurationConfigWithRootBlockDeviceUpdated(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.bar", &conf),
resource.TestCheckResourceAttr(
"aws_launch_configuration.bar", "root_block_device.0.volume_size", "20"),
),
},
},
})
}
func TestAccAWSLaunchConfiguration_withSpotPrice(t *testing.T) {
var conf autoscaling.LaunchConfiguration
@ -78,7 +108,7 @@ func TestAccAWSLaunchConfiguration_withSpotPrice(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccAWSLaunchConfigurationWithSpotPriceConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.bar", &conf),
@ -100,7 +130,7 @@ func TestAccAWSLaunchConfiguration_withVpcClassicLink(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccAWSLaunchConfigurationConfig_withVpcClassicLink,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.foo", &conf),
@ -120,7 +150,7 @@ func TestAccAWSLaunchConfiguration_withIAMProfile(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccAWSLaunchConfigurationConfig_withIAMProfile,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.bar", &conf),
@ -164,7 +194,7 @@ func TestAccAWSLaunchConfiguration_withEncryption(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchConfigurationDestroy,
Steps: []resource.TestStep{
resource.TestStep{
{
Config: testAccAWSLaunchConfigurationWithEncryption,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchConfigurationExists("aws_launch_configuration.baz", &conf),
@ -304,6 +334,42 @@ func testAccCheckAWSLaunchConfigurationExists(n string, res *autoscaling.LaunchC
}
}
func testAccAWSLaunchConfigurationConfigWithRootBlockDevice(rInt int) string {
return fmt.Sprintf(`
resource "aws_launch_configuration" "bar" {
name_prefix = "tf-acc-test-%d"
image_id = "ami-21f78e11"
instance_type = "m1.small"
user_data = "foobar-user-data"
associate_public_ip_address = true
root_block_device {
volume_type = "gp2"
volume_size = 11
}
}
`, rInt)
}
func testAccAWSLaunchConfigurationConfigWithRootBlockDeviceUpdated(rInt int) string {
return fmt.Sprintf(`
resource "aws_launch_configuration" "bar" {
name_prefix = "tf-acc-test-%d"
image_id = "ami-21f78e11"
instance_type = "m1.small"
user_data = "foobar-user-data"
associate_public_ip_address = true
root_block_device {
volume_type = "gp2"
volume_size = 20
}
}
`, rInt)
}
var testAccAWSLaunchConfigurationConfig = fmt.Sprintf(`
resource "aws_launch_configuration" "bar" {
name = "terraform-test-%d"