Skip to content

Commit

Permalink
resource/aws_launch_template: Prevent encrypted flag cannot be specif…
Browse files Browse the repository at this point in the history
…ied error with block_device_mappings ebs argument

* Convert `block_device_mappings` > `ebs` > `delete_on_termination` and `encrypted` to `schema.TypeString`. This to allow an "unspecified" value for the attributes since `schema.TypeBool` only has true/false with false default. The conversion from bare true/false values in configurations to `schema.TypeString` value is currently safe.

Previously:

```
--- FAIL: TestAccAWSLaunchTemplate_BlockDeviceMappings_EBS (11.23s)
	testing.go:527: Step 0 error: Error applying: 1 error occurred:
			* aws_autoscaling_group.test: 1 error occurred:
			* aws_autoscaling_group.test: Error creating AutoScaling Group: ValidationError: You must use a valid fully-formed launch template. the encrypted flag cannot be specified since device /dev/sda1 has a snapshot specified.
```

After code adjustments:

```
make testacc TEST=./aws TESTARGS='-run=TestAccAWSLaunchTemplate_'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./aws -v -run=TestAccAWSLaunchTemplate_ -timeout 120m
=== RUN   TestAccAWSLaunchTemplate_importBasic
--- PASS: TestAccAWSLaunchTemplate_importBasic (13.63s)
=== RUN   TestAccAWSLaunchTemplate_importData
--- PASS: TestAccAWSLaunchTemplate_importData (12.00s)
=== RUN   TestAccAWSLaunchTemplate_basic
--- PASS: TestAccAWSLaunchTemplate_basic (12.71s)
=== RUN   TestAccAWSLaunchTemplate_BlockDeviceMappings_EBS
--- PASS: TestAccAWSLaunchTemplate_BlockDeviceMappings_EBS (48.73s)
=== RUN   TestAccAWSLaunchTemplate_data
--- PASS: TestAccAWSLaunchTemplate_data (13.59s)
=== RUN   TestAccAWSLaunchTemplate_update
--- PASS: TestAccAWSLaunchTemplate_update (46.88s)
=== RUN   TestAccAWSLaunchTemplate_tags
--- PASS: TestAccAWSLaunchTemplate_tags (21.37s)
=== RUN   TestAccAWSLaunchTemplate_nonBurstable
--- PASS: TestAccAWSLaunchTemplate_nonBurstable (11.47s)
=== RUN   TestAccAWSLaunchTemplate_networkInterface
--- PASS: TestAccAWSLaunchTemplate_networkInterface (30.44s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	211.533s
```
  • Loading branch information
bflad committed Aug 21, 2018
1 parent 145a0ad commit c79ee01
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 21 deletions.
76 changes: 57 additions & 19 deletions aws/resource_aws_launch_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,30 @@ func resourceAwsLaunchTemplate() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"delete_on_termination": {
Type: schema.TypeBool,
// Use TypeString to allow an "unspecified" value,
// since TypeBool only has true/false with false default.
// The conversion from bare true/false values in
// configurations to TypeString value is currently safe.
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"",
"false",
"true",
}, false),
},
"encrypted": {
Type: schema.TypeBool,
// Use TypeString to allow an "unspecified" value,
// since TypeBool only has true/false with false default.
// The conversion from bare true/false values in
// configurations to TypeString value is currently safe.
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"",
"false",
"true",
}, false),
},
"iops": {
Type: schema.TypeInt,
Expand Down Expand Up @@ -638,14 +656,18 @@ func getBlockDeviceMappings(m []*ec2.LaunchTemplateBlockDeviceMapping) []interfa
"virtual_name": aws.StringValue(v.VirtualName),
}
if v.NoDevice != nil {
mapping["no_device"] = *v.NoDevice
mapping["no_device"] = aws.StringValue(v.NoDevice)
}
if v.Ebs != nil {
ebs := map[string]interface{}{
"delete_on_termination": aws.BoolValue(v.Ebs.DeleteOnTermination),
"encrypted": aws.BoolValue(v.Ebs.Encrypted),
"volume_size": int(aws.Int64Value(v.Ebs.VolumeSize)),
"volume_type": aws.StringValue(v.Ebs.VolumeType),
"volume_size": int(aws.Int64Value(v.Ebs.VolumeSize)),
"volume_type": aws.StringValue(v.Ebs.VolumeType),
}
if v.Ebs.DeleteOnTermination != nil {
ebs["delete_on_termination"] = strconv.FormatBool(aws.BoolValue(v.Ebs.DeleteOnTermination))
}
if v.Ebs.Encrypted != nil {
ebs["encrypted"] = strconv.FormatBool(aws.BoolValue(v.Ebs.Encrypted))
}
if v.Ebs.Iops != nil {
ebs["iops"] = aws.Int64Value(v.Ebs.Iops)
Expand Down Expand Up @@ -857,7 +879,11 @@ func buildLaunchTemplateData(d *schema.ResourceData, meta interface{}) (*ec2.Req
bdms := v.([]interface{})

for _, bdm := range bdms {
blockDeviceMappings = append(blockDeviceMappings, readBlockDeviceMappingFromConfig(bdm.(map[string]interface{})))
blockDeviceMapping, err := readBlockDeviceMappingFromConfig(bdm.(map[string]interface{}))
if err != nil {
return nil, err
}
blockDeviceMappings = append(blockDeviceMappings, blockDeviceMapping)
}
opts.BlockDeviceMappings = blockDeviceMappings
}
Expand Down Expand Up @@ -950,7 +976,7 @@ func buildLaunchTemplateData(d *schema.ResourceData, meta interface{}) (*ec2.Req
return opts, nil
}

func readBlockDeviceMappingFromConfig(bdm map[string]interface{}) *ec2.LaunchTemplateBlockDeviceMappingRequest {
func readBlockDeviceMappingFromConfig(bdm map[string]interface{}) (*ec2.LaunchTemplateBlockDeviceMappingRequest, error) {
blockDeviceMapping := &ec2.LaunchTemplateBlockDeviceMappingRequest{}

if v := bdm["device_name"].(string); v != "" {
Expand All @@ -967,24 +993,36 @@ func readBlockDeviceMappingFromConfig(bdm map[string]interface{}) *ec2.LaunchTem

if v := bdm["ebs"]; len(v.([]interface{})) > 0 {
ebs := v.([]interface{})
if len(ebs) > 0 {
ebsData := ebs[0]
blockDeviceMapping.Ebs = readEbsBlockDeviceFromConfig(ebsData.(map[string]interface{}))
if len(ebs) > 0 && ebs[0] != nil {
ebsData := ebs[0].(map[string]interface{})
launchTemplateEbsBlockDeviceRequest, err := readEbsBlockDeviceFromConfig(ebsData)
if err != nil {
return nil, err
}
blockDeviceMapping.Ebs = launchTemplateEbsBlockDeviceRequest
}
}

return blockDeviceMapping
return blockDeviceMapping, nil
}

func readEbsBlockDeviceFromConfig(ebs map[string]interface{}) *ec2.LaunchTemplateEbsBlockDeviceRequest {
func readEbsBlockDeviceFromConfig(ebs map[string]interface{}) (*ec2.LaunchTemplateEbsBlockDeviceRequest, error) {
ebsDevice := &ec2.LaunchTemplateEbsBlockDeviceRequest{}

if v := ebs["delete_on_termination"]; v != nil {
ebsDevice.DeleteOnTermination = aws.Bool(v.(bool))
if v, ok := ebs["delete_on_termination"]; ok && v.(string) != "" {
vBool, err := strconv.ParseBool(v.(string))
if err != nil {
return nil, fmt.Errorf("error converting delete_on_termination %q from string to boolean: %s", v.(string), err)
}
ebsDevice.DeleteOnTermination = aws.Bool(vBool)
}

if v := ebs["encrypted"]; v != nil {
ebsDevice.Encrypted = aws.Bool(v.(bool))
if v, ok := ebs["encrypted"]; ok && v.(string) != "" {
vBool, err := strconv.ParseBool(v.(string))
if err != nil {
return nil, fmt.Errorf("error converting encrypted %q from string to boolean: %s", v.(string), err)
}
ebsDevice.Encrypted = aws.Bool(vBool)
}

if v := ebs["iops"].(int); v > 0 {
Expand All @@ -1007,7 +1045,7 @@ func readEbsBlockDeviceFromConfig(ebs map[string]interface{}) *ec2.LaunchTemplat
ebsDevice.VolumeType = aws.String(v)
}

return ebsDevice
return ebsDevice, nil
}

func readNetworkInterfacesFromConfig(ni map[string]interface{}) *ec2.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest {
Expand Down
21 changes: 19 additions & 2 deletions aws/resource_aws_launch_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,11 @@ data "aws_ami" "test" {
}
}
data "aws_availability_zones" "available" {}
resource "aws_launch_template" "test" {
image_id = "${data.aws_ami.test.id}"
name = "%s"
name = %q
block_device_mappings {
device_name = "/dev/sda1"
Expand All @@ -305,7 +307,22 @@ resource "aws_launch_template" "test" {
}
}
}
`, rName)
# Creating an AutoScaling Group verifies the launch template
# ValidationError: You must use a valid fully-formed launch template. the encrypted flag cannot be specified since device /dev/sda1 has a snapshot specified.
resource "aws_autoscaling_group" "test" {
availability_zones = ["${data.aws_availability_zones.available.names[0]}"]
desired_capacity = 0
max_size = 0
min_size = 0
name = %q
launch_template {
id = "${aws_launch_template.test.id}"
version = "${aws_launch_template.test.default_version}"
}
}
`, rName, rName)
}

func testAccAWSLaunchTemplateConfig_data(rInt int) string {
Expand Down

0 comments on commit c79ee01

Please sign in to comment.