diff --git a/aws/resource_aws_spot_instance_request.go b/aws/resource_aws_spot_instance_request.go index dade165e4fc..73aa7baefb8 100644 --- a/aws/resource_aws_spot_instance_request.go +++ b/aws/resource_aws_spot_instance_request.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" ) func resourceAwsSpotInstanceRequest() *schema.Resource { @@ -81,8 +82,13 @@ func resourceAwsSpotInstanceRequest() *schema.Resource { s["instance_interruption_behaviour"] = &schema.Schema{ Type: schema.TypeString, Optional: true, - Default: "terminate", + Default: ec2.InstanceInterruptionBehaviorTerminate, ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + ec2.InstanceInterruptionBehaviorTerminate, + ec2.InstanceInterruptionBehaviorStop, + ec2.InstanceInterruptionBehaviorHibernate, + }, false), } return s }(), @@ -115,7 +121,6 @@ func resourceAwsSpotInstanceRequestCreate(d *schema.ResourceData, meta interface ImageId: instanceOpts.ImageID, InstanceType: instanceOpts.InstanceType, KeyName: instanceOpts.KeyName, - Placement: instanceOpts.SpotPlacement, SecurityGroupIds: instanceOpts.SecurityGroupIDs, SecurityGroups: instanceOpts.SecurityGroups, SubnetId: instanceOpts.SubnetID, @@ -132,6 +137,11 @@ func resourceAwsSpotInstanceRequestCreate(d *schema.ResourceData, meta interface spotOpts.LaunchGroup = aws.String(v.(string)) } + // Placement GroupName can only be specified when instanceInterruptionBehavior is not set or set to 'terminate' + if v, exists := d.GetOkExists("instance_interruption_behaviour"); v.(string) == ec2.InstanceInterruptionBehaviorTerminate || !exists { + spotOpts.LaunchSpecification.Placement = instanceOpts.SpotPlacement + } + // Make the spot instance request log.Printf("[DEBUG] Requesting spot bid opts: %s", spotOpts) diff --git a/aws/resource_aws_spot_instance_request_test.go b/aws/resource_aws_spot_instance_request_test.go index 5d096abb627..3b9bad1e8d7 100644 --- a/aws/resource_aws_spot_instance_request_test.go +++ b/aws/resource_aws_spot_instance_request_test.go @@ -389,6 +389,56 @@ func testAccCheckAWSSpotInstanceRequestAttributesVPC( } } +func TestAccAWSSpotInstanceRequestInterruptStop(t *testing.T) { + var sir ec2.SpotInstanceRequest + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotInstanceRequestInterruptConfig("stop"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists( + "aws_spot_instance_request.foo", &sir), + resource.TestCheckResourceAttr( + "aws_spot_instance_request.foo", "spot_bid_status", "fulfilled"), + resource.TestCheckResourceAttr( + "aws_spot_instance_request.foo", "spot_request_state", "active"), + resource.TestCheckResourceAttr( + "aws_spot_instance_request.foo", "instance_interruption_behaviour", "stop"), + ), + }, + }, + }) +} + +func TestAccAWSSpotInstanceRequestInterruptHibernate(t *testing.T) { + var sir ec2.SpotInstanceRequest + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSpotInstanceRequestInterruptConfig("hibernate"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSpotInstanceRequestExists( + "aws_spot_instance_request.foo", &sir), + resource.TestCheckResourceAttr( + "aws_spot_instance_request.foo", "spot_bid_status", "fulfilled"), + resource.TestCheckResourceAttr( + "aws_spot_instance_request.foo", "spot_request_state", "active"), + resource.TestCheckResourceAttr( + "aws_spot_instance_request.foo", "instance_interruption_behaviour", "hibernate"), + ), + }, + }, + }) +} + func testAccAWSSpotInstanceRequestConfig(rInt int) string { return fmt.Sprintf(` resource "aws_key_pair" "debugging" { @@ -589,3 +639,21 @@ func testAccAWSSpotInstanceRequestConfig_getPasswordData(rInt int) string { } `, rInt) } + +func testAccAWSSpotInstanceRequestInterruptConfig(interruption_behavior string) string { + return fmt.Sprintf(` + resource "aws_spot_instance_request" "foo" { + ami = "ami-19e92861" + instance_type = "c5.large" + + // base price is $0.067 hourly, so bidding above that should theoretically + // always fulfill + spot_price = "0.07" + + // we wait for fulfillment because we want to inspect the launched instance + // and verify termination behavior + wait_for_fulfillment = true + + instance_interruption_behaviour = "%s" + }`, interruption_behavior) +}