aws-cloudformation / cloudformation-coverage-roadmap

The AWS CloudFormation Public Coverage Roadmap
https://aws.amazon.com/cloudformation/
Creative Commons Attribution Share Alike 4.0 International
1.1k stars 53 forks source link

Rollback of AWS::EC2::LaunchTemplate does not remove new version of launch template #1912

Open isuftin opened 6 months ago

isuftin commented 6 months ago

Name of the resource

AWS::EC2::LaunchTemplate

Resource Name

No response

Issue Description

Sample CFN with one ASG and one LT:

AWSTemplateFormatVersion: '2010-09-09'
Description: Sample CFN
Resources:
  ControllerAutoscalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      DesiredCapacity: '1'
      HealthCheckGracePeriod: 1200
      HealthCheckType: EC2
      TargetGroupARNs:
        - !Ref SomeTargetGroupElsewhereInTheTemplate
      LaunchTemplate:
        LaunchTemplateId: !Ref ControllerLaunchTemplate
        Version: !GetAtt ControllerLaunchTemplate.LatestVersionNumber
      MetricsCollection:
        - Granularity: 1Minute
      MaxSize: '5'
      MinSize: '1'
      VPCZoneIdentifier:
        - !Sub '{{resolve:ssm:/subnets/a}}'
        - !Sub '{{resolve:ssm:/subnets/b}}'
        - !Sub '{{resolve:ssm:/subnets/c}}'
    CreationPolicy:
      ResourceSignal:
        Timeout: PT120M
        Count: '1'
    UpdatePolicy:
      AutoScalingReplacingUpdate:
        WillReplace: true
      AutoScalingRollingUpdate:
        MaxBatchSize: 1
        MinInstancesInService: 1
        MinSuccessfulInstancesPercent: 1
        PauseTime: PT1H
        WaitOnResourceSignals: true
      AutoScalingScheduledAction:
        IgnoreUnmodifiedGroupSizeProperties: true
  ControllerLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateData:
        BlockDeviceMappings:
          - DeviceName: /dev/sda1
            Ebs:
              Encrypted: true
              DeleteOnTermination: true
              VolumeSize: 256
        EbsOptimized: true
        IamInstanceProfile:
          Name: !Sub '{{resolve:ssm:/iam/role}}'
        ImageId: !Sub '{{resolve:ssm:/ami/redhat8:11}}'
        Monitoring:
          Enabled: true
        InstanceType: m4.2xlarge
        KeyName: my-shh-key
        SecurityGroupIds:
          - !Sub '{{resolve:ssm:/some_security_group}}'
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash -xe

            PATH="/usr/local/bin:${!PATH}";
            REGION="${AWS::Region}";
            STACK_NAME="${AWS::StackName}";
            ASG_NAME="ControllerAutoscalingGroup";
            TEMPLATE_NAME="ControllerLaunchTemplate";

            aws configure set default.region ${AWS::Region};

            function error_exit {
              /usr/bin/cfn-signal --region $REGION --exit-code 1 --reason '$1' --stack $STACK_NAME --resource $ASG_NAME;
              exit 1;
            }

            /usr/bin/cfn-init -v --region $REGION --stack $STACK_NAME --resource $TEMPLATE_NAME --configsets ascending || error_exit 'Failed to run cfn-init.';
            /usr/bin/cfn-hup || error_exit 'Failed to start cfn-hup';
            /usr/bin/cfn-signal --region $REGION --success true --stack $STACK_NAME --resource $ASG_NAME;
    Metadata:
      AWS::CloudFormation::Init:
        configSets:
          ascending:
            - '01-config'
            - '02-setup'
        01-config:
          files:
            /etc/cfn/cfn-hup.conf:
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
                verbose=true
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.ControllerLaunchTemplate.Metadata.AWS::CloudFormation::Init
                action=/usr/bin/cfn-init -v --stack ${AWS::StackName} --resource ControllerLaunchTemplate --configsets ascending --region ${AWS::Region}
                runas=root
          services:
            sysvinit:
              cfn-hup:
                enabled: 'true'
                ensureRunning: 'true'
                files:
                  - /etc/cfn/cfn-hup.conf
                  - /etc/cfn/hooks.d/cfn-auto-reloader.conf
        02-setup:
          files:
            /root/setup.sh:
              content: |
                #!/bin/bash -ex

                some amazing things here that may fail
              mode: '000774'
              owner: root
              group: root
          commands:
            00-install-executor:
              command: /root/setup.sh

So let's say previous to launch I have 1 version of the launch template resource. After the launch, a new launch template resource gets created. Now let's say CloudFormation rolls back due to some error hit in the ASG. My expectation is that the launch template that was created during the deployment is deleted on rollback.

Now the latest version of the launch template after rollback is version 2.

I find this to be a gotcha if you have a CloudFormation template where you might manage multiple ASGs and LTs or if you want to revert the code for your LT to what you expect is currently deployed so your next update doesn't try to replace your ASG but instead your ASG will attempt to be replaced.

Expected Behavior

During rollback I expect the new launch template to be deleted and the latest version to be the version which was latest previous to deployment

Observed Behavior

Latest launch template does not get deleted by CloudFormation upon rollback

Test Cases

Launch a very simple cloudformation template with a dead simple launch template and asg. Let that succeed. Now update the launch template such that CFN will create a new one (say with a new valid AMI) and also update the ASG to ensure the cfn stack fails (add "exit 1" in the userdata somewhere). Upon rollback your launch template's latest version should be 1. It will instead be 2.

Other Details

No response