481 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			481 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import boto3
 | |
| import sure  # noqa # pylint: disable=unused-import
 | |
| import json
 | |
| 
 | |
| from moto import mock_autoscaling, mock_cloudformation, mock_ec2, mock_elb
 | |
| 
 | |
| from .utils import setup_networking
 | |
| from tests import EXAMPLE_AMI_ID
 | |
| 
 | |
| 
 | |
| @mock_autoscaling
 | |
| @mock_cloudformation
 | |
| 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]
 | |
|     stack["Outputs"][0]["OutputValue"].should.be.equal("test_launch_configuration")
 | |
| 
 | |
|     lc = client.describe_launch_configurations()["LaunchConfigurations"][0]
 | |
|     lc["LaunchConfigurationName"].should.be.equal("test_launch_configuration")
 | |
|     lc["ImageId"].should.be.equal(EXAMPLE_AMI_ID)
 | |
|     lc["InstanceType"].should.be.equal("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]
 | |
|     stack["Outputs"][0]["OutputValue"].should.be.equal("test_launch_configuration")
 | |
| 
 | |
|     lc = client.describe_launch_configurations()["LaunchConfigurations"][0]
 | |
|     lc["LaunchConfigurationName"].should.be.equal("test_launch_configuration")
 | |
|     lc["ImageId"].should.be.equal(EXAMPLE_AMI_ID)
 | |
|     lc["InstanceType"].should.be.equal("m5.large")
 | |
| 
 | |
| 
 | |
| @mock_autoscaling
 | |
| @mock_cloudformation
 | |
| 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]
 | |
|     stack["Outputs"][0]["OutputValue"].should.be.equal("test_auto_scaling_group")
 | |
| 
 | |
|     asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
 | |
|     asg["AutoScalingGroupName"].should.be.equal("test_auto_scaling_group")
 | |
|     asg["MinSize"].should.be.equal(1)
 | |
|     asg["MaxSize"].should.be.equal(5)
 | |
|     asg["LaunchConfigurationName"].should.be.equal("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]
 | |
|     stack["Outputs"][0]["OutputValue"].should.be.equal("test_auto_scaling_group")
 | |
| 
 | |
|     asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
 | |
|     asg["AutoScalingGroupName"].should.be.equal("test_auto_scaling_group")
 | |
|     asg["MinSize"].should.be.equal(2)
 | |
|     asg["MaxSize"].should.be.equal(6)
 | |
|     asg["LaunchConfigurationName"].should.be.equal("test_launch_configuration_new")
 | |
| 
 | |
| 
 | |
| @mock_autoscaling
 | |
| @mock_cloudformation
 | |
| @mock_ec2
 | |
| 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]
 | |
|     stack["Outputs"][0]["OutputValue"].should.be.equal("test_auto_scaling_group")
 | |
| 
 | |
|     asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
 | |
|     asg["AutoScalingGroupName"].should.be.equal("test_auto_scaling_group")
 | |
|     asg["MinSize"].should.be.equal(1)
 | |
|     asg["MaxSize"].should.be.equal(5)
 | |
|     lt = asg["LaunchTemplate"]
 | |
|     lt["LaunchTemplateId"].should.be.equal(launch_template_id)
 | |
|     lt["LaunchTemplateName"].should.be.equal("test_launch_template")
 | |
|     lt["Version"].should.be.equal("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]
 | |
|     stack["Outputs"][0]["OutputValue"].should.be.equal("test_auto_scaling_group")
 | |
| 
 | |
|     asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
 | |
|     asg["AutoScalingGroupName"].should.be.equal("test_auto_scaling_group")
 | |
|     asg["MinSize"].should.be.equal(2)
 | |
|     asg["MaxSize"].should.be.equal(6)
 | |
|     lt = asg["LaunchTemplate"]
 | |
|     lt["LaunchTemplateId"].should.be.equal(launch_template_id)
 | |
|     lt["LaunchTemplateName"].should.be.equal("test_launch_template_new")
 | |
|     lt["Version"].should.be.equal("1")
 | |
| 
 | |
| 
 | |
| @mock_autoscaling
 | |
| @mock_elb
 | |
| @mock_cloudformation
 | |
| @mock_ec2
 | |
| 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",
 | |
|                 },
 | |
|             },
 | |
|             "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]
 | |
|     autoscale_group["LaunchConfigurationName"].should.contain("my-launch-config")
 | |
|     autoscale_group["LoadBalancerNames"].should.equal(["my-elb"])
 | |
| 
 | |
|     # Confirm the Launch config was actually created
 | |
|     client.describe_launch_configurations()[
 | |
|         "LaunchConfigurations"
 | |
|     ].should.have.length_of(1)
 | |
| 
 | |
|     # Confirm the ELB was actually created
 | |
|     elb.describe_load_balancers()["LoadBalancerDescriptions"].should.have.length_of(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]
 | |
|     as_group_resource["PhysicalResourceId"].should.contain("my-as-group")
 | |
| 
 | |
|     launch_config_resource = [
 | |
|         resource
 | |
|         for resource in resources
 | |
|         if resource["ResourceType"] == "AWS::AutoScaling::LaunchConfiguration"
 | |
|     ][0]
 | |
|     launch_config_resource["PhysicalResourceId"].should.contain("my-launch-config")
 | |
| 
 | |
|     elb_resource = [
 | |
|         resource
 | |
|         for resource in resources
 | |
|         if resource["ResourceType"] == "AWS::ElasticLoadBalancing::LoadBalancer"
 | |
|     ][0]
 | |
|     elb_resource["PhysicalResourceId"].should.contain("my-elb")
 | |
| 
 | |
|     # confirm the instances were created with the right tags
 | |
|     reservations = ec2.describe_instances()["Reservations"]
 | |
| 
 | |
|     reservations.should.have.length_of(1)
 | |
|     reservations[0]["Instances"].should.have.length_of(2)
 | |
|     for instance in reservations[0]["Instances"]:
 | |
|         tag_keys = [t["Key"] for t in instance["Tags"]]
 | |
|         tag_keys.should.contain("propagated-test-tag")
 | |
|         tag_keys.should_not.contain("not-propagated-test-tag")
 | |
| 
 | |
|     # confirm scheduled scaling action was created
 | |
|     response = client.describe_scheduled_actions(
 | |
|         AutoScalingGroupName="test-scaling-group"
 | |
|     )["ScheduledUpdateGroupActions"]
 | |
|     response.should.have.length_of(1)
 | |
| 
 | |
| 
 | |
| @mock_autoscaling
 | |
| @mock_cloudformation
 | |
| @mock_ec2
 | |
| 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]
 | |
|     asg["MinSize"].should.equal(2)
 | |
|     asg["MaxSize"].should.equal(2)
 | |
|     asg["DesiredCapacity"].should.equal(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]
 | |
|     asg["MinSize"].should.equal(2)
 | |
|     asg["MaxSize"].should.equal(3)
 | |
|     asg["DesiredCapacity"].should.equal(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
 | |
|                 instance["Tags"].should.contain(
 | |
|                     {"Key": "propagated-test-tag", "Value": "propagated-test-tag-value"}
 | |
|                 )
 | |
|                 tag_keys = [t["Key"] for t in instance["Tags"]]
 | |
|                 tag_keys.should_not.contain("not-propagated-test-tag")
 | |
|     running_instance_count.should.equal(2)
 |