Skip to content

Commit 546b424

Browse files
authored
provider/aws: Allow aws_instances to be resized rather than forcing a (#11998)
new instance Fixes: #9157 ``` % make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSInstance_changeInstanceType' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/02/16 15:13:21 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSInstance_changeInstanceType -timeout 120m === RUN TestAccAWSInstance_changeInstanceType --- PASS: TestAccAWSInstance_changeInstanceType (303.85s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 303.876s ```
1 parent f81616d commit 546b424

File tree

2 files changed

+145
-27
lines changed

2 files changed

+145
-27
lines changed

builtin/providers/aws/resource_aws_instance.go

+54-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ func resourceAwsInstance() *schema.Resource {
6363
"instance_type": {
6464
Type: schema.TypeString,
6565
Required: true,
66-
ForceNew: true,
6766
},
6867

6968
"key_name": {
@@ -606,6 +605,60 @@ func resourceAwsInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
606605
}
607606
}
608607

608+
if d.HasChange("instance_type") && !d.IsNewResource() {
609+
log.Printf("[INFO] Stopping Instance %q for instance_type change", d.Id())
610+
_, err := conn.StopInstances(&ec2.StopInstancesInput{
611+
InstanceIds: []*string{aws.String(d.Id())},
612+
})
613+
614+
stateConf := &resource.StateChangeConf{
615+
Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"},
616+
Target: []string{"stopped"},
617+
Refresh: InstanceStateRefreshFunc(conn, d.Id()),
618+
Timeout: 10 * time.Minute,
619+
Delay: 10 * time.Second,
620+
MinTimeout: 3 * time.Second,
621+
}
622+
623+
_, err = stateConf.WaitForState()
624+
if err != nil {
625+
return fmt.Errorf(
626+
"Error waiting for instance (%s) to stop: %s", d.Id(), err)
627+
}
628+
629+
log.Printf("[INFO] Modifying instance type %s", d.Id())
630+
_, err = conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeInput{
631+
InstanceId: aws.String(d.Id()),
632+
InstanceType: &ec2.AttributeValue{
633+
Value: aws.String(d.Get("instance_type").(string)),
634+
},
635+
})
636+
if err != nil {
637+
return err
638+
}
639+
640+
log.Printf("[INFO] Starting Instance %q after instance_type change", d.Id())
641+
_, err = conn.StartInstances(&ec2.StartInstancesInput{
642+
InstanceIds: []*string{aws.String(d.Id())},
643+
})
644+
645+
stateConf = &resource.StateChangeConf{
646+
Pending: []string{"pending", "stopped"},
647+
Target: []string{"running"},
648+
Refresh: InstanceStateRefreshFunc(conn, d.Id()),
649+
Timeout: 10 * time.Minute,
650+
Delay: 10 * time.Second,
651+
MinTimeout: 3 * time.Second,
652+
}
653+
654+
_, err = stateConf.WaitForState()
655+
if err != nil {
656+
return fmt.Errorf(
657+
"Error waiting for instance (%s) to become ready: %s",
658+
d.Id(), err)
659+
}
660+
}
661+
609662
if d.HasChange("disable_api_termination") {
610663
_, err := conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeInput{
611664
InstanceId: aws.String(d.Id()),

builtin/providers/aws/resource_aws_instance_test.go

+91-26
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestAccAWSInstance_basic(t *testing.T) {
4545
CheckDestroy: testAccCheckInstanceDestroy,
4646
Steps: []resource.TestStep{
4747
// Create a volume to cover #1249
48-
resource.TestStep{
48+
{
4949
// Need a resource in this config so the provisioner will be available
5050
Config: testAccInstanceConfig_pre,
5151
Check: func(*terraform.State) error {
@@ -59,7 +59,7 @@ func TestAccAWSInstance_basic(t *testing.T) {
5959
},
6060
},
6161

62-
resource.TestStep{
62+
{
6363
Config: testAccInstanceConfig,
6464
Check: resource.ComposeTestCheckFunc(
6565
testAccCheckInstanceExists(
@@ -77,7 +77,7 @@ func TestAccAWSInstance_basic(t *testing.T) {
7777
// We repeat the exact same test so that we can be sure
7878
// that the user data hash stuff is working without generating
7979
// an incorrect diff.
80-
resource.TestStep{
80+
{
8181
Config: testAccInstanceConfig,
8282
Check: resource.ComposeTestCheckFunc(
8383
testAccCheckInstanceExists(
@@ -93,7 +93,7 @@ func TestAccAWSInstance_basic(t *testing.T) {
9393
},
9494

9595
// Clean up volume created above
96-
resource.TestStep{
96+
{
9797
Config: testAccInstanceConfig,
9898
Check: func(*terraform.State) error {
9999
conn := testAccProvider.Meta().(*AWSClient).ec2conn
@@ -134,7 +134,7 @@ func TestAccAWSInstance_GP2IopsDevice(t *testing.T) {
134134
Providers: testAccProviders,
135135
CheckDestroy: testAccCheckInstanceDestroy,
136136
Steps: []resource.TestStep{
137-
resource.TestStep{
137+
{
138138
Config: testAccInstanceGP2IopsDevice,
139139
//Config: testAccInstanceConfigBlockDevices,
140140
Check: resource.ComposeTestCheckFunc(
@@ -199,7 +199,7 @@ func TestAccAWSInstance_blockDevices(t *testing.T) {
199199
Providers: testAccProviders,
200200
CheckDestroy: testAccCheckInstanceDestroy,
201201
Steps: []resource.TestStep{
202-
resource.TestStep{
202+
{
203203
Config: testAccInstanceConfigBlockDevices,
204204
Check: resource.ComposeTestCheckFunc(
205205
testAccCheckInstanceExists(
@@ -254,7 +254,7 @@ func TestAccAWSInstance_rootInstanceStore(t *testing.T) {
254254
Providers: testAccProviders,
255255
CheckDestroy: testAccCheckInstanceDestroy,
256256
Steps: []resource.TestStep{
257-
resource.TestStep{
257+
{
258258
Config: `
259259
resource "aws_instance" "foo" {
260260
# us-west-2
@@ -323,7 +323,7 @@ func TestAcctABSInstance_noAMIEphemeralDevices(t *testing.T) {
323323
Providers: testAccProviders,
324324
CheckDestroy: testAccCheckInstanceDestroy,
325325
Steps: []resource.TestStep{
326-
resource.TestStep{
326+
{
327327
Config: `
328328
resource "aws_instance" "foo" {
329329
# us-west-2
@@ -400,23 +400,23 @@ func TestAccAWSInstance_sourceDestCheck(t *testing.T) {
400400
Providers: testAccProviders,
401401
CheckDestroy: testAccCheckInstanceDestroy,
402402
Steps: []resource.TestStep{
403-
resource.TestStep{
403+
{
404404
Config: testAccInstanceConfigSourceDestDisable,
405405
Check: resource.ComposeTestCheckFunc(
406406
testAccCheckInstanceExists("aws_instance.foo", &v),
407407
testCheck(false),
408408
),
409409
},
410410

411-
resource.TestStep{
411+
{
412412
Config: testAccInstanceConfigSourceDestEnable,
413413
Check: resource.ComposeTestCheckFunc(
414414
testAccCheckInstanceExists("aws_instance.foo", &v),
415415
testCheck(true),
416416
),
417417
},
418418

419-
resource.TestStep{
419+
{
420420
Config: testAccInstanceConfigSourceDestDisable,
421421
Check: resource.ComposeTestCheckFunc(
422422
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -454,15 +454,15 @@ func TestAccAWSInstance_disableApiTermination(t *testing.T) {
454454
Providers: testAccProviders,
455455
CheckDestroy: testAccCheckInstanceDestroy,
456456
Steps: []resource.TestStep{
457-
resource.TestStep{
457+
{
458458
Config: testAccInstanceConfigDisableAPITermination(true),
459459
Check: resource.ComposeTestCheckFunc(
460460
testAccCheckInstanceExists("aws_instance.foo", &v),
461461
checkDisableApiTermination(true),
462462
),
463463
},
464464

465-
resource.TestStep{
465+
{
466466
Config: testAccInstanceConfigDisableAPITermination(false),
467467
Check: resource.ComposeTestCheckFunc(
468468
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -483,7 +483,7 @@ func TestAccAWSInstance_vpc(t *testing.T) {
483483
Providers: testAccProviders,
484484
CheckDestroy: testAccCheckInstanceDestroy,
485485
Steps: []resource.TestStep{
486-
resource.TestStep{
486+
{
487487
Config: testAccInstanceConfigVPC,
488488
Check: resource.ComposeTestCheckFunc(
489489
testAccCheckInstanceExists(
@@ -517,7 +517,7 @@ func TestAccAWSInstance_multipleRegions(t *testing.T) {
517517
ProviderFactories: providerFactories,
518518
CheckDestroy: testAccCheckInstanceDestroyWithProviders(&providers),
519519
Steps: []resource.TestStep{
520-
resource.TestStep{
520+
{
521521
Config: testAccInstanceConfigMultipleRegions,
522522
Check: resource.ComposeTestCheckFunc(
523523
testAccCheckInstanceExistsWithProviders(
@@ -540,7 +540,7 @@ func TestAccAWSInstance_NetworkInstanceSecurityGroups(t *testing.T) {
540540
Providers: testAccProviders,
541541
CheckDestroy: testAccCheckInstanceDestroy,
542542
Steps: []resource.TestStep{
543-
resource.TestStep{
543+
{
544544
Config: testAccInstanceNetworkInstanceSecurityGroups,
545545
Check: resource.ComposeTestCheckFunc(
546546
testAccCheckInstanceExists(
@@ -560,7 +560,7 @@ func TestAccAWSInstance_NetworkInstanceVPCSecurityGroupIDs(t *testing.T) {
560560
Providers: testAccProviders,
561561
CheckDestroy: testAccCheckInstanceDestroy,
562562
Steps: []resource.TestStep{
563-
resource.TestStep{
563+
{
564564
Config: testAccInstanceNetworkInstanceVPCSecurityGroupIDs,
565565
Check: resource.ComposeTestCheckFunc(
566566
testAccCheckInstanceExists(
@@ -583,7 +583,7 @@ func TestAccAWSInstance_tags(t *testing.T) {
583583
Providers: testAccProviders,
584584
CheckDestroy: testAccCheckInstanceDestroy,
585585
Steps: []resource.TestStep{
586-
resource.TestStep{
586+
{
587587
Config: testAccCheckInstanceConfigTags,
588588
Check: resource.ComposeTestCheckFunc(
589589
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -593,7 +593,7 @@ func TestAccAWSInstance_tags(t *testing.T) {
593593
),
594594
},
595595

596-
resource.TestStep{
596+
{
597597
Config: testAccCheckInstanceConfigTagsUpdate,
598598
Check: resource.ComposeTestCheckFunc(
599599
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -624,7 +624,7 @@ func TestAccAWSInstance_privateIP(t *testing.T) {
624624
Providers: testAccProviders,
625625
CheckDestroy: testAccCheckInstanceDestroy,
626626
Steps: []resource.TestStep{
627-
resource.TestStep{
627+
{
628628
Config: testAccInstanceConfigPrivateIP,
629629
Check: resource.ComposeTestCheckFunc(
630630
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -655,7 +655,7 @@ func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) {
655655
Providers: testAccProviders,
656656
CheckDestroy: testAccCheckInstanceDestroy,
657657
Steps: []resource.TestStep{
658-
resource.TestStep{
658+
{
659659
Config: testAccInstanceConfigAssociatePublicIPAndPrivateIP,
660660
Check: resource.ComposeTestCheckFunc(
661661
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -691,7 +691,7 @@ func TestAccAWSInstance_keyPairCheck(t *testing.T) {
691691
Providers: testAccProviders,
692692
CheckDestroy: testAccCheckInstanceDestroy,
693693
Steps: []resource.TestStep{
694-
resource.TestStep{
694+
{
695695
Config: testAccInstanceConfigKeyPair,
696696
Check: resource.ComposeTestCheckFunc(
697697
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -710,7 +710,7 @@ func TestAccAWSInstance_rootBlockDeviceMismatch(t *testing.T) {
710710
Providers: testAccProviders,
711711
CheckDestroy: testAccCheckInstanceDestroy,
712712
Steps: []resource.TestStep{
713-
resource.TestStep{
713+
{
714714
Config: testAccInstanceConfigRootBlockDeviceMismatch,
715715
Check: resource.ComposeTestCheckFunc(
716716
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -740,15 +740,15 @@ func TestAccAWSInstance_forceNewAndTagsDrift(t *testing.T) {
740740
Providers: testAccProviders,
741741
CheckDestroy: testAccCheckInstanceDestroy,
742742
Steps: []resource.TestStep{
743-
resource.TestStep{
743+
{
744744
Config: testAccInstanceConfigForceNewAndTagsDrift,
745745
Check: resource.ComposeTestCheckFunc(
746746
testAccCheckInstanceExists("aws_instance.foo", &v),
747747
driftTags(&v),
748748
),
749749
ExpectNonEmptyPlan: true,
750750
},
751-
resource.TestStep{
751+
{
752752
Config: testAccInstanceConfigForceNewAndTagsDrift_Update,
753753
Check: resource.ComposeTestCheckFunc(
754754
testAccCheckInstanceExists("aws_instance.foo", &v),
@@ -758,6 +758,43 @@ func TestAccAWSInstance_forceNewAndTagsDrift(t *testing.T) {
758758
})
759759
}
760760

761+
func TestAccAWSInstance_changeInstanceType(t *testing.T) {
762+
var before ec2.Instance
763+
var after ec2.Instance
764+
765+
resource.Test(t, resource.TestCase{
766+
PreCheck: func() { testAccPreCheck(t) },
767+
Providers: testAccProviders,
768+
CheckDestroy: testAccCheckInstanceDestroy,
769+
Steps: []resource.TestStep{
770+
{
771+
Config: testAccInstanceConfigWithSmallInstanceType,
772+
Check: resource.ComposeTestCheckFunc(
773+
testAccCheckInstanceExists("aws_instance.foo", &before),
774+
),
775+
},
776+
{
777+
Config: testAccInstanceConfigUpdateInstanceType,
778+
Check: resource.ComposeTestCheckFunc(
779+
testAccCheckInstanceExists("aws_instance.foo", &after),
780+
testAccCheckInstanceNotRecreated(
781+
t, &before, &after),
782+
),
783+
},
784+
},
785+
})
786+
}
787+
788+
func testAccCheckInstanceNotRecreated(t *testing.T,
789+
before, after *ec2.Instance) resource.TestCheckFunc {
790+
return func(s *terraform.State) error {
791+
if *before.InstanceId != *after.InstanceId {
792+
t.Fatalf("AWS Instance IDs have changed. Before %s. After %s", *before.InstanceId, *after.InstanceId)
793+
}
794+
return nil
795+
}
796+
}
797+
761798
func testAccCheckInstanceDestroy(s *terraform.State) error {
762799
return testAccCheckInstanceDestroyWithProvider(s, testAccProvider)
763800
}
@@ -873,7 +910,7 @@ func driftTags(instance *ec2.Instance) resource.TestCheckFunc {
873910
_, err := conn.CreateTags(&ec2.CreateTagsInput{
874911
Resources: []*string{instance.InstanceId},
875912
Tags: []*ec2.Tag{
876-
&ec2.Tag{
913+
{
877914
Key: aws.String("Drift"),
878915
Value: aws.String("Happens"),
879916
},
@@ -921,6 +958,34 @@ resource "aws_instance" "foo" {
921958
}
922959
`
923960

961+
const testAccInstanceConfigWithSmallInstanceType = `
962+
resource "aws_instance" "foo" {
963+
# us-west-2
964+
ami = "ami-55a7ea65"
965+
availability_zone = "us-west-2a"
966+
967+
instance_type = "m3.medium"
968+
969+
tags {
970+
Name = "tf-acctest"
971+
}
972+
}
973+
`
974+
975+
const testAccInstanceConfigUpdateInstanceType = `
976+
resource "aws_instance" "foo" {
977+
# us-west-2
978+
ami = "ami-55a7ea65"
979+
availability_zone = "us-west-2a"
980+
981+
instance_type = "m3.large"
982+
983+
tags {
984+
Name = "tf-acctest"
985+
}
986+
}
987+
`
988+
924989
const testAccInstanceGP2IopsDevice = `
925990
resource "aws_instance" "foo" {
926991
# us-west-2

0 commit comments

Comments
 (0)