Skip to content

Commit

Permalink
Merge pull request #6325 from gazoakley/f-asg-capacity-reservation
Browse files Browse the repository at this point in the history
resource/aws_launch_configuration: Add support for capacity reservations
  • Loading branch information
bflad committed Nov 1, 2018
2 parents 54bbd5d + cc61b0d commit 4b93067
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 4 deletions.
92 changes: 92 additions & 0 deletions aws/resource_aws_launch_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,37 @@ func resourceAwsLaunchTemplate() *schema.Resource {
},
},

"capacity_reservation_specification": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"capacity_reservation_preference": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
ec2.CapacityReservationPreferenceOpen,
ec2.CapacityReservationPreferenceNone,
}, false),
},
"capacity_reservation_target": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"capacity_reservation_id": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
},
},

"credit_specification": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -574,6 +605,10 @@ func resourceAwsLaunchTemplateRead(d *schema.ResourceData, meta interface{}) err
return err
}

if err := d.Set("capacity_reservation_specification", getCapacityReservationSpecification(ltData.CapacityReservationSpecification)); err != nil {
return err
}

if strings.HasPrefix(aws.StringValue(ltData.InstanceType), "t2") || strings.HasPrefix(aws.StringValue(ltData.InstanceType), "t3") {
if err := d.Set("credit_specification", getCreditSpecification(ltData.CreditSpecification)); err != nil {
return err
Expand Down Expand Up @@ -706,6 +741,27 @@ func getBlockDeviceMappings(m []*ec2.LaunchTemplateBlockDeviceMapping) []interfa
return s
}

func getCapacityReservationSpecification(crs *ec2.LaunchTemplateCapacityReservationSpecificationResponse) []interface{} {
s := []interface{}{}
if crs != nil {
s = append(s, map[string]interface{}{
"capacity_reservation_preference": aws.StringValue(crs.CapacityReservationPreference),
"capacity_reservation_target": getCapacityReservationTarget(crs.CapacityReservationTarget),
})
}
return s
}

func getCapacityReservationTarget(crt *ec2.CapacityReservationTargetResponse) []interface{} {
s := []interface{}{}
if crt != nil {
s = append(s, map[string]interface{}{
"capacity_reservation_id": aws.StringValue(crt.CapacityReservationId),
})
}
return s
}

func getCreditSpecification(cs *ec2.CreditSpecification) []interface{} {
s := []interface{}{}
if cs != nil {
Expand Down Expand Up @@ -933,6 +989,14 @@ func buildLaunchTemplateData(d *schema.ResourceData, meta interface{}) (*ec2.Req
opts.BlockDeviceMappings = blockDeviceMappings
}

if v, ok := d.GetOk("capacity_reservation_specification"); ok {
crs := v.([]interface{})

if len(crs) > 0 {
opts.CapacityReservationSpecification = readCapacityReservationSpecificationFromConfig(crs[0].(map[string]interface{}))
}
}

if v, ok := d.GetOk("credit_specification"); ok && (strings.HasPrefix(instanceType, "t2") || strings.HasPrefix(instanceType, "t3")) {
cs := v.([]interface{})

Expand Down Expand Up @@ -1174,6 +1238,34 @@ func readIamInstanceProfileFromConfig(iip map[string]interface{}) *ec2.LaunchTem
return iamInstanceProfile
}

func readCapacityReservationSpecificationFromConfig(crs map[string]interface{}) *ec2.LaunchTemplateCapacityReservationSpecificationRequest {
capacityReservationSpecification := &ec2.LaunchTemplateCapacityReservationSpecificationRequest{}

if v, ok := crs["capacity_reservation_preference"].(string); ok && v != "" {
capacityReservationSpecification.CapacityReservationPreference = aws.String(v)
}

if v, ok := crs["capacity_reservation_target"]; ok {
crt := v.([]interface{})

if len(crt) > 0 {
capacityReservationSpecification.CapacityReservationTarget = readCapacityReservationTargetFromConfig(crt[0].(map[string]interface{}))
}
}

return capacityReservationSpecification
}

func readCapacityReservationTargetFromConfig(crt map[string]interface{}) *ec2.CapacityReservationTarget {
capacityReservationTarget := &ec2.CapacityReservationTarget{}

if v, ok := crt["capacity_reservation_id"].(string); ok && v != "" {
capacityReservationTarget.CapacityReservationId = aws.String(v)
}

return capacityReservationTarget
}

func readCreditSpecificationFromConfig(cs map[string]interface{}) *ec2.CreditSpecificationRequest {
creditSpecification := &ec2.CreditSpecificationRequest{}

Expand Down
75 changes: 75 additions & 0 deletions aws/resource_aws_launch_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,46 @@ func TestAccAWSLaunchTemplate_tags(t *testing.T) {
})
}

func TestAccAWSLaunchTemplate_capacityReservation_preference(t *testing.T) {
var template ec2.LaunchTemplate
resName := "aws_launch_template.foo"
rInt := acctest.RandInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchTemplateDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLaunchTemplateConfig_capacityReservation_preference(rInt, "open"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchTemplateExists(resName, &template),
),
},
},
})
}

func TestAccAWSLaunchTemplate_capacityReservation_target(t *testing.T) {
var template ec2.LaunchTemplate
resName := "aws_launch_template.foo"
rInt := acctest.RandInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLaunchTemplateDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLaunchTemplateConfig_capacityReservation_target(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSLaunchTemplateExists(resName, &template),
),
},
},
})
}

func TestAccAWSLaunchTemplate_creditSpecification_nonBurstable(t *testing.T) {
var template ec2.LaunchTemplate
rName := acctest.RandomWithPrefix("tf-acc-test")
Expand Down Expand Up @@ -771,6 +811,41 @@ resource "aws_launch_template" "foo" {
`, rInt)
}

func testAccAWSLaunchTemplateConfig_capacityReservation_preference(rInt int, preference string) string {
return fmt.Sprintf(`
resource "aws_launch_template" "foo" {
name = "foo_%d"
capacity_reservation_specification {
capacity_reservation_preference = %q
}
}
`, rInt, preference)
}

func testAccAWSLaunchTemplateConfig_capacityReservation_target(rInt int) string {
return fmt.Sprintf(`
data "aws_availability_zones" "available" {}
resource "aws_ec2_capacity_reservation" "test" {
availability_zone = "${data.aws_availability_zones.available.names[0]}"
instance_count = 1
instance_platform = "Linux/UNIX"
instance_type = "t2.micro"
}
resource "aws_launch_template" "foo" {
name = "foo_%d"
capacity_reservation_specification {
capacity_reservation_target {
capacity_reservation_id = "${aws_ec2_capacity_reservation.test.id}"
}
}
}
`, rInt)
}

func testAccAWSLaunchTemplateConfig_creditSpecification(rName, instanceType, cpuCredits string) string {
return fmt.Sprintf(`
resource "aws_launch_template" "foo" {
Expand Down
24 changes: 20 additions & 4 deletions website/docs/r/launch_template.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ resource "aws_launch_template" "foo" {
}
}
capacity_reservation_specification {
capacity_reservation_preference = "open"
}
credit_specification {
cpu_credits = "standard"
}
Expand Down Expand Up @@ -75,7 +79,7 @@ resource "aws_launch_template" "foo" {
Name = "test"
}
}
user_data = "${base64encode(...)}"
}
```
Expand All @@ -89,7 +93,8 @@ The following arguments are supported:
* `description` - Description of the launch template.
* `block_device_mappings` - Specify volumes to attach to the instance besides the volumes specified by the AMI.
See [Block Devices](#block-devices) below for details.
* `credit_specification` - Customize the credit specification of the instance. See [Credit
* `capacity_reservation_specification` - Targeting for EC2 capacity reservations. See [Capacity Reservation Specification](#capacity-reservation-specification) below for more details.
* `credit_specification` - Customize the credit specification of the instance. See [Credit
Specification](#credit-specification) below for more details.
* `disable_api_termination` - If `true`, enables [EC2 Instance
Termination Protection](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination)
Expand All @@ -107,7 +112,7 @@ The following arguments are supported:
* `kernel_id` - The kernel ID.
* `key_name` - The key name to use for the instance.
* `monitoring` - The monitoring option for the instance. See [Monitoring](#monitoring) below for more details.
* `network_interfaces` - Customize network interfaces to be attached at instance boot time. See [Network
* `network_interfaces` - Customize network interfaces to be attached at instance boot time. See [Network
Interfaces](#network-interfaces) below for more details.
* `placement` - The placement of the instance. See [Placement](#placement) below for more details.
* `ram_disk_id` - The ID of the RAM disk.
Expand Down Expand Up @@ -149,6 +154,17 @@ The `ebs` block supports the following:
* `volume_size` - The size of the volume in gigabytes.
* `volume_type` - The type of volume. Can be `"standard"`, `"gp2"`, or `"io1"`. (Default: `"standard"`).

### Capacity Reservation Specification

The `capacity_reservation_specification` block supports the following:

* `capacity_reservation_preference` - Indicates the instance's Capacity Reservation preferences. Can be `open` or `none`. (Default `none`).
* `capacity_reservation_target` - Used to target a specific Capacity Reservation:

The `capacity_reservation_target` block supports the following:

* `capacity_reservation_id` - The ID of the Capacity Reservation to target.

### Credit Specification

Credit specification can be applied/modified to the EC2 Instance at any time.
Expand Down Expand Up @@ -187,7 +203,7 @@ The `instance_market_options` block supports the following:
The `spot_options` block supports the following:

* `block_duration_minutes` - The required duration in minutes. This value must be a multiple of 60.
* `instance_interruption_behavior` - The behavior when a Spot Instance is interrupted. Can be `hibernate`,
* `instance_interruption_behavior` - The behavior when a Spot Instance is interrupted. Can be `hibernate`,
`stop`, or `terminate`. (Default: `terminate`).
* `max_price` - The maximum hourly price you're willing to pay for the Spot Instances.
* `spot_instance_type` - The Spot Instance request type. Can be `one-time`, or `persistent`.
Expand Down

0 comments on commit 4b93067

Please sign in to comment.