import json import boto3 from moto import mock_aws from tests import EXAMPLE_AMI_ID from .utils import setup_networking @mock_aws def test_launch_configuration(): cf_client = boto3.client("cloudformation", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1") stack_name = "test-launch-configuration" cf_template = """ Resources: LaunchConfiguration: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: {0} InstanceType: t2.micro LaunchConfigurationName: test_launch_configuration Outputs: LaunchConfigurationName: Value: !Ref LaunchConfiguration """.strip().format( EXAMPLE_AMI_ID ) cf_client.create_stack(StackName=stack_name, TemplateBody=cf_template) stack = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] assert stack["Outputs"][0]["OutputValue"] == "test_launch_configuration" lc = client.describe_launch_configurations()["LaunchConfigurations"][0] assert lc["LaunchConfigurationName"] == "test_launch_configuration" assert lc["ImageId"] == EXAMPLE_AMI_ID assert lc["InstanceType"] == "t2.micro" cf_template = """ Resources: LaunchConfiguration: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: {0} InstanceType: m5.large LaunchConfigurationName: test_launch_configuration Outputs: LaunchConfigurationName: Value: !Ref LaunchConfiguration """.strip().format( EXAMPLE_AMI_ID ) cf_client.update_stack(StackName=stack_name, TemplateBody=cf_template) stack = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] assert stack["Outputs"][0]["OutputValue"] == "test_launch_configuration" lc = client.describe_launch_configurations()["LaunchConfigurations"][0] assert lc["LaunchConfigurationName"] == "test_launch_configuration" assert lc["ImageId"] == EXAMPLE_AMI_ID assert lc["InstanceType"] == "m5.large" @mock_aws def test_autoscaling_group_from_launch_config(): subnet_id = setup_networking()["subnet1"] cf_client = boto3.client("cloudformation", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1") client.create_launch_configuration( LaunchConfigurationName="test_launch_configuration", InstanceType="t2.micro", ImageId=EXAMPLE_AMI_ID, ) stack_name = "test-auto-scaling-group" cf_template = """ Parameters: SubnetId: Type: AWS::EC2::Subnet::Id Resources: AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: test_auto_scaling_group AvailabilityZones: - us-east-1a LaunchConfigurationName: test_launch_configuration MaxSize: "5" MinSize: "1" VPCZoneIdentifier: - !Ref SubnetId Outputs: AutoScalingGroupName: Value: !Ref AutoScalingGroup """.strip() cf_client.create_stack( StackName=stack_name, TemplateBody=cf_template, Parameters=[{"ParameterKey": "SubnetId", "ParameterValue": subnet_id}], ) stack = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] assert stack["Outputs"][0]["OutputValue"] == "test_auto_scaling_group" asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0] assert asg["AutoScalingGroupName"] == "test_auto_scaling_group" assert asg["MinSize"] == 1 assert asg["MaxSize"] == 5 assert asg["LaunchConfigurationName"] == "test_launch_configuration" client.create_launch_configuration( LaunchConfigurationName="test_launch_configuration_new", InstanceType="t2.micro", ImageId=EXAMPLE_AMI_ID, ) cf_template = """ Parameters: SubnetId: Type: AWS::EC2::Subnet::Id Resources: AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: test_auto_scaling_group AvailabilityZones: - us-east-1a LaunchConfigurationName: test_launch_configuration_new MaxSize: "6" MinSize: "2" VPCZoneIdentifier: - !Ref SubnetId Outputs: AutoScalingGroupName: Value: !Ref AutoScalingGroup """.strip() cf_client.update_stack( StackName=stack_name, TemplateBody=cf_template, Parameters=[{"ParameterKey": "SubnetId", "ParameterValue": subnet_id}], ) stack = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] assert stack["Outputs"][0]["OutputValue"] == "test_auto_scaling_group" asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0] assert asg["AutoScalingGroupName"] == "test_auto_scaling_group" assert asg["MinSize"] == 2 assert asg["MaxSize"] == 6 assert asg["LaunchConfigurationName"] == "test_launch_configuration_new" @mock_aws def test_autoscaling_group_from_launch_template(): subnet_id = setup_networking()["subnet1"] cf_client = boto3.client("cloudformation", region_name="us-east-1") ec2_client = boto3.client("ec2", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1") template_response = ec2_client.create_launch_template( LaunchTemplateName="test_launch_template", LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID, "InstanceType": "t2.micro"}, ) launch_template_id = template_response["LaunchTemplate"]["LaunchTemplateId"] stack_name = "test-auto-scaling-group" cf_template = """ Parameters: SubnetId: Type: AWS::EC2::Subnet::Id LaunchTemplateId: Type: String Resources: AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: test_auto_scaling_group AvailabilityZones: - us-east-1a LaunchTemplate: LaunchTemplateId: !Ref LaunchTemplateId Version: "1" MaxSize: "5" MinSize: "1" VPCZoneIdentifier: - !Ref SubnetId Outputs: AutoScalingGroupName: Value: !Ref AutoScalingGroup """.strip() cf_client.create_stack( StackName=stack_name, TemplateBody=cf_template, Parameters=[ {"ParameterKey": "SubnetId", "ParameterValue": subnet_id}, {"ParameterKey": "LaunchTemplateId", "ParameterValue": launch_template_id}, ], ) stack = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] assert stack["Outputs"][0]["OutputValue"] == "test_auto_scaling_group" asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0] assert asg["AutoScalingGroupName"] == "test_auto_scaling_group" assert asg["MinSize"] == 1 assert asg["MaxSize"] == 5 lt = asg["LaunchTemplate"] assert lt["LaunchTemplateId"] == launch_template_id assert lt["LaunchTemplateName"] == "test_launch_template" assert lt["Version"] == "1" template_response = ec2_client.create_launch_template( LaunchTemplateName="test_launch_template_new", LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID, "InstanceType": "m5.large"}, ) launch_template_id = template_response["LaunchTemplate"]["LaunchTemplateId"] cf_template = """ Parameters: SubnetId: Type: AWS::EC2::Subnet::Id LaunchTemplateId: Type: String Resources: AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: test_auto_scaling_group AvailabilityZones: - us-east-1a LaunchTemplate: LaunchTemplateId: !Ref LaunchTemplateId Version: "1" MaxSize: "6" MinSize: "2" VPCZoneIdentifier: - !Ref SubnetId Outputs: AutoScalingGroupName: Value: !Ref AutoScalingGroup """.strip() cf_client.update_stack( StackName=stack_name, TemplateBody=cf_template, Parameters=[ {"ParameterKey": "SubnetId", "ParameterValue": subnet_id}, {"ParameterKey": "LaunchTemplateId", "ParameterValue": launch_template_id}, ], ) stack = cf_client.describe_stacks(StackName=stack_name)["Stacks"][0] assert stack["Outputs"][0]["OutputValue"] == "test_auto_scaling_group" asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0] assert asg["AutoScalingGroupName"] == "test_auto_scaling_group" assert asg["MinSize"] == 2 assert asg["MaxSize"] == 6 lt = asg["LaunchTemplate"] assert lt["LaunchTemplateId"] == launch_template_id assert lt["LaunchTemplateName"] == "test_launch_template_new" assert lt["Version"] == "1" @mock_aws def test_autoscaling_group_with_elb(): web_setup_template = { "AWSTemplateFormatVersion": "2010-09-09", "Resources": { "my-as-group": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "AvailabilityZones": ["us-east-1a"], "LaunchConfigurationName": {"Ref": "my-launch-config"}, "MinSize": "2", "MaxSize": "2", "DesiredCapacity": "2", "LoadBalancerNames": [{"Ref": "my-elb"}], "Tags": [ { "Key": "propagated-test-tag", "Value": "propagated-test-tag-value", "PropagateAtLaunch": True, }, { "Key": "not-propagated-test-tag", "Value": "not-propagated-test-tag-value", "PropagateAtLaunch": False, }, ], }, }, "ScheduledAction": { "Type": "AWS::AutoScaling::ScheduledAction", "Properties": { "AutoScalingGroupName": "test-scaling-group", "DesiredCapacity": 10, "EndTime": "2022-08-01T00:00:00Z", "MaxSize": 15, "MinSize": 5, "Recurrence": "* * * * *", "StartTime": "2022-07-01T00:00:00Z", "TimeZone": "Etc/UTC", }, }, "my-launch-config": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": EXAMPLE_AMI_ID, "InstanceType": "t2.medium", "UserData": "some user data", }, }, "my-elb": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "AvailabilityZones": ["us-east-1a"], "Listeners": [ { "LoadBalancerPort": "80", "InstancePort": "80", "Protocol": "HTTP", } ], "LoadBalancerName": "my-elb", "HealthCheck": { "Target": "HTTP:80", "HealthyThreshold": "3", "UnhealthyThreshold": "5", "Interval": "30", "Timeout": "5", }, }, }, }, } web_setup_template_json = json.dumps(web_setup_template) cf = boto3.client("cloudformation", region_name="us-east-1") ec2 = boto3.client("ec2", region_name="us-east-1") elb = boto3.client("elb", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1") cf.create_stack(StackName="web_stack", TemplateBody=web_setup_template_json) autoscale_group = client.describe_auto_scaling_groups()["AutoScalingGroups"][0] asg_name = autoscale_group["AutoScalingGroupName"] assert "my-launch-config" in autoscale_group["LaunchConfigurationName"] assert autoscale_group["LoadBalancerNames"] == ["my-elb"] assert len(autoscale_group["Tags"]) == 2 assert { "ResourceId": asg_name, "ResourceType": "auto-scaling-group", "Key": "propagated-test-tag", "Value": "propagated-test-tag-value", "PropagateAtLaunch": True, } in autoscale_group["Tags"] assert { "ResourceId": asg_name, "ResourceType": "auto-scaling-group", "Key": "not-propagated-test-tag", "Value": "not-propagated-test-tag-value", "PropagateAtLaunch": False, } in autoscale_group["Tags"] tags = client.describe_tags( Filters=[{"Name": "auto-scaling-group", "Values": [asg_name]}] )["Tags"] assert tags == autoscale_group["Tags"] # Confirm the Launch config was actually created assert len(client.describe_launch_configurations()["LaunchConfigurations"]) == 1 # Confirm the ELB was actually created assert len(elb.describe_load_balancers()["LoadBalancerDescriptions"]) == 1 resources = cf.list_stack_resources(StackName="web_stack")["StackResourceSummaries"] as_group_resource = [ resource for resource in resources if resource["ResourceType"] == "AWS::AutoScaling::AutoScalingGroup" ][0] assert "my-as-group" in as_group_resource["PhysicalResourceId"] launch_config_resource = [ resource for resource in resources if resource["ResourceType"] == "AWS::AutoScaling::LaunchConfiguration" ][0] assert "my-launch-config" in launch_config_resource["PhysicalResourceId"] elb_resource = [ resource for resource in resources if resource["ResourceType"] == "AWS::ElasticLoadBalancing::LoadBalancer" ][0] assert "my-elb" in elb_resource["PhysicalResourceId"] # confirm the instances were created with the right tags reservations = ec2.describe_instances()["Reservations"] assert len(reservations) == 1 assert len(reservations[0]["Instances"]) == 2 for instance in reservations[0]["Instances"]: tag_keys = [t["Key"] for t in instance["Tags"]] assert "propagated-test-tag" in tag_keys assert "not-propagated-test-tag" not in tag_keys # confirm scheduled scaling action was created response = client.describe_scheduled_actions( AutoScalingGroupName="test-scaling-group" )["ScheduledUpdateGroupActions"] assert len(response) == 1 @mock_aws def test_autoscaling_group_update(): asg_template = { "AWSTemplateFormatVersion": "2010-09-09", "Resources": { "my-as-group": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "AvailabilityZones": ["us-west-1a"], "LaunchConfigurationName": {"Ref": "my-launch-config"}, "MinSize": "2", "MaxSize": "2", "DesiredCapacity": "2", }, }, "my-launch-config": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": EXAMPLE_AMI_ID, "InstanceType": "t2.medium", "UserData": "some user data", }, }, }, } asg_template_json = json.dumps(asg_template) cf = boto3.client("cloudformation", region_name="us-west-1") ec2 = boto3.client("ec2", region_name="us-west-1") client = boto3.client("autoscaling", region_name="us-west-1") cf.create_stack(StackName="asg_stack", TemplateBody=asg_template_json) asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0] assert asg["MinSize"] == 2 assert asg["MaxSize"] == 2 assert asg["DesiredCapacity"] == 2 asg_template["Resources"]["my-as-group"]["Properties"]["MaxSize"] = 3 asg_template["Resources"]["my-as-group"]["Properties"]["Tags"] = [ { "Key": "propagated-test-tag", "Value": "propagated-test-tag-value", "PropagateAtLaunch": True, }, { "Key": "not-propagated-test-tag", "Value": "not-propagated-test-tag-value", "PropagateAtLaunch": False, }, ] asg_template_json = json.dumps(asg_template) cf.update_stack(StackName="asg_stack", TemplateBody=asg_template_json) asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0] assert asg["MinSize"] == 2 assert asg["MaxSize"] == 3 assert asg["DesiredCapacity"] == 2 # confirm the instances were created with the right tags reservations = ec2.describe_instances()["Reservations"] running_instance_count = 0 for res in reservations: for instance in res["Instances"]: if instance["State"]["Name"] == "running": running_instance_count += 1 assert { "Key": "propagated-test-tag", "Value": "propagated-test-tag-value", } in instance["Tags"] tag_keys = [t["Key"] for t in instance["Tags"]] assert "not-propagated-test-tag" not in tag_keys assert running_instance_count == 2