diff --git a/.changelog/45005.txt b/.changelog/45005.txt new file mode 100644 index 000000000000..4181799fd537 --- /dev/null +++ b/.changelog/45005.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_instance: Add option to preserve state after attribute changes which require EC2 start/stop +``` diff --git a/internal/service/ec2/ec2_instance.go b/internal/service/ec2/ec2_instance.go index 0589bbd1a25e..d16f62be361e 100644 --- a/internal/service/ec2/ec2_instance.go +++ b/internal/service/ec2/ec2_instance.go @@ -491,6 +491,12 @@ func resourceInstance() *schema.Resource { Optional: true, AtLeastOneOf: []string{names.AttrInstanceType, names.AttrLaunchTemplate}, }, + "preserve_powerstate": { + Type: schema.TypeBool, + Computed: false, + Optional: true, + Default: false, + }, "ipv6_address_count": { Type: schema.TypeInt, Optional: true, @@ -1552,6 +1558,8 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta an } } + preservePowerstate := d.Get("preserve_powerstate").(bool) + // See also CustomizeDiff. if d.HasChanges(names.AttrInstanceType, "user_data", "user_data_base64") && !d.IsNewResource() { // For each argument change, we start and stop the instance @@ -1568,7 +1576,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta an }, } - if err := modifyInstanceAttributeWithStopStart(ctx, conn, &input, fmt.Sprintf("InstanceType (%s)", instanceType)); err != nil { + if err := modifyInstanceAttributeWithStopStart(ctx, conn, &input, fmt.Sprintf("InstanceType (%s)", instanceType), preservePowerstate); err != nil { return sdkdiag.AppendErrorf(diags, "updating EC2 Instance (%s) type: %s", d.Id(), err) } } @@ -1593,7 +1601,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta an }, } - if err := modifyInstanceAttributeWithStopStart(ctx, conn, &input, "UserData"); err != nil { + if err := modifyInstanceAttributeWithStopStart(ctx, conn, &input, "UserData", preservePowerstate); err != nil { return sdkdiag.AppendErrorf(diags, "updating EC2 Instance (%s) user data: %s", d.Id(), err) } } @@ -1613,7 +1621,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta an }, } - if err := modifyInstanceAttributeWithStopStart(ctx, conn, &input, "UserData (base64)"); err != nil { + if err := modifyInstanceAttributeWithStopStart(ctx, conn, &input, "UserData (base64)", preservePowerstate); err != nil { return sdkdiag.AppendErrorf(diags, "updating EC2 Instance (%s) user data base64: %s", d.Id(), err) } } @@ -2003,9 +2011,15 @@ func disableInstanceAPITermination(ctx context.Context, conn *ec2.Client, id str // as input by first stopping the EC2 instance before the modification // and then starting up the EC2 instance after modification. // Reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Stop_Start.html -func modifyInstanceAttributeWithStopStart(ctx context.Context, conn *ec2.Client, input *ec2.ModifyInstanceAttributeInput, attrName string) error { +func modifyInstanceAttributeWithStopStart(ctx context.Context, conn *ec2.Client, input *ec2.ModifyInstanceAttributeInput, attrName string, preservePowerstate bool) error { id := aws.ToString(input.InstanceId) + _, state, err := statusInstance(ctx, conn, id)() + + if err != nil { + return err + } + if err := stopInstance(ctx, conn, id, false, instanceStopTimeout); err != nil { return err } @@ -2014,8 +2028,10 @@ func modifyInstanceAttributeWithStopStart(ctx context.Context, conn *ec2.Client, return fmt.Errorf("modifying EC2 Instance (%s) %s attribute: %w", id, attrName, err) } - if err := startInstance(ctx, conn, id, true, instanceStartTimeout); err != nil { - return err + if !preservePowerstate || (strings.ToLower(state) != "stopped" && strings.ToLower(state) != "stopping") { + if err := startInstance(ctx, conn, id, true, instanceStartTimeout); err != nil { + return err + } } return nil