Add support for Launch Templates in Auto Scaling Groups (#3236)

* Add support for Launch Templates in Auto Scaling Groups

* Use named parameters, simplify parameter validation
This commit is contained in:
Kevin Frommelt 2020-08-26 09:15:07 -05:00 committed by GitHub
commit 55b02c6ee9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 774 additions and 42 deletions

View file

@ -17,6 +17,7 @@ from moto import (
mock_elb,
mock_autoscaling_deprecated,
mock_ec2,
mock_cloudformation,
)
from tests.helpers import requires_boto_gte
@ -164,7 +165,7 @@ def test_list_many_autoscaling_groups():
@mock_autoscaling
@mock_ec2
def test_list_many_autoscaling_groups():
def test_propogate_tags():
mocked_networking = setup_networking()
conn = boto3.client("autoscaling", region_name="us-east-1")
conn.create_launch_configuration(LaunchConfigurationName="TestLC")
@ -692,7 +693,7 @@ def test_detach_load_balancer():
def test_create_autoscaling_group_boto3():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration(
client.create_launch_configuration(
LaunchConfigurationName="test_launch_configuration"
)
response = client.create_auto_scaling_group(
@ -798,13 +799,171 @@ def test_create_autoscaling_group_from_invalid_instance_id():
@mock_autoscaling
def test_describe_autoscaling_groups_boto3():
@mock_ec2
def test_create_autoscaling_group_from_template():
mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template",
LaunchTemplateData={
"ImageId": "ami-0cc293023f983ed53",
"InstanceType": "t2.micro",
},
)["LaunchTemplate"]
client = boto3.client("autoscaling", region_name="us-east-1")
response = client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchTemplate={
"LaunchTemplateId": template["LaunchTemplateId"],
"Version": str(template["LatestVersionNumber"]),
},
MinSize=1,
MaxSize=3,
DesiredCapacity=2,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=False,
)
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
@mock_autoscaling
@mock_ec2
def test_create_autoscaling_group_no_template_ref():
mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template",
LaunchTemplateData={
"ImageId": "ami-0cc293023f983ed53",
"InstanceType": "t2.micro",
},
)["LaunchTemplate"]
client = boto3.client("autoscaling", region_name="us-east-1")
with assert_raises(ClientError) as ex:
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchTemplate={"Version": str(template["LatestVersionNumber"])},
MinSize=0,
MaxSize=20,
DesiredCapacity=5,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=False,
)
ex.exception.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.exception.response["Error"]["Code"].should.equal("ValidationError")
ex.exception.response["Error"]["Message"].should.equal(
"Valid requests must contain either launchTemplateId or LaunchTemplateName"
)
@mock_autoscaling
@mock_ec2
def test_create_autoscaling_group_multiple_template_ref():
mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template",
LaunchTemplateData={
"ImageId": "ami-0cc293023f983ed53",
"InstanceType": "t2.micro",
},
)["LaunchTemplate"]
client = boto3.client("autoscaling", region_name="us-east-1")
with assert_raises(ClientError) as ex:
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchTemplate={
"LaunchTemplateId": template["LaunchTemplateId"],
"LaunchTemplateName": template["LaunchTemplateName"],
"Version": str(template["LatestVersionNumber"]),
},
MinSize=0,
MaxSize=20,
DesiredCapacity=5,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=False,
)
ex.exception.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.exception.response["Error"]["Code"].should.equal("ValidationError")
ex.exception.response["Error"]["Message"].should.equal(
"Valid requests must contain either launchTemplateId or LaunchTemplateName"
)
@mock_autoscaling
def test_create_autoscaling_group_boto3_no_launch_configuration():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration(
with assert_raises(ClientError) as ex:
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
MinSize=0,
MaxSize=20,
DesiredCapacity=5,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=False,
)
ex.exception.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.exception.response["Error"]["Code"].should.equal("ValidationError")
ex.exception.response["Error"]["Message"].should.equal(
"Valid requests must contain either LaunchTemplate, LaunchConfigurationName, "
"InstanceId or MixedInstancesPolicy parameter."
)
@mock_autoscaling
@mock_ec2
def test_create_autoscaling_group_boto3_multiple_launch_configurations():
mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template",
LaunchTemplateData={
"ImageId": "ami-0cc293023f983ed53",
"InstanceType": "t2.micro",
},
)["LaunchTemplate"]
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration(
LaunchConfigurationName="test_launch_configuration"
)
_ = client.create_auto_scaling_group(
with assert_raises(ClientError) as ex:
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchConfigurationName="test_launch_configuration",
LaunchTemplate={
"LaunchTemplateId": template["LaunchTemplateId"],
"Version": str(template["LatestVersionNumber"]),
},
MinSize=0,
MaxSize=20,
DesiredCapacity=5,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=False,
)
ex.exception.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.exception.response["Error"]["Code"].should.equal("ValidationError")
ex.exception.response["Error"]["Message"].should.equal(
"Valid requests must contain either LaunchTemplate, LaunchConfigurationName, "
"InstanceId or MixedInstancesPolicy parameter."
)
@mock_autoscaling
def test_describe_autoscaling_groups_boto3_launch_config():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration(
LaunchConfigurationName="test_launch_configuration", InstanceType="t2.micro",
)
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchConfigurationName="test_launch_configuration",
MinSize=0,
@ -818,22 +977,72 @@ def test_describe_autoscaling_groups_boto3():
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
group = response["AutoScalingGroups"][0]
group["AutoScalingGroupName"].should.equal("test_asg")
group["LaunchConfigurationName"].should.equal("test_launch_configuration")
group.should_not.have.key("LaunchTemplate")
group["AvailabilityZones"].should.equal(["us-east-1a"])
group["VPCZoneIdentifier"].should.equal(mocked_networking["subnet1"])
group["NewInstancesProtectedFromScaleIn"].should.equal(True)
for instance in group["Instances"]:
instance["LaunchConfigurationName"].should.equal("test_launch_configuration")
instance.should_not.have.key("LaunchTemplate")
instance["AvailabilityZone"].should.equal("us-east-1a")
instance["ProtectedFromScaleIn"].should.equal(True)
instance["InstanceType"].should.equal("t2.micro")
@mock_autoscaling
def test_describe_autoscaling_instances_boto3():
@mock_ec2
def test_describe_autoscaling_groups_boto3_launch_template():
mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template",
LaunchTemplateData={
"ImageId": "ami-0cc293023f983ed53",
"InstanceType": "t2.micro",
},
)["LaunchTemplate"]
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchTemplate={"LaunchTemplateName": "test_launch_template", "Version": "1"},
MinSize=0,
MaxSize=20,
DesiredCapacity=5,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=True,
)
expected_launch_template = {
"LaunchTemplateId": template["LaunchTemplateId"],
"LaunchTemplateName": "test_launch_template",
"Version": "1",
}
response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"])
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
group = response["AutoScalingGroups"][0]
group["AutoScalingGroupName"].should.equal("test_asg")
group["LaunchTemplate"].should.equal(expected_launch_template)
group.should_not.have.key("LaunchConfigurationName")
group["AvailabilityZones"].should.equal(["us-east-1a"])
group["VPCZoneIdentifier"].should.equal(mocked_networking["subnet1"])
group["NewInstancesProtectedFromScaleIn"].should.equal(True)
for instance in group["Instances"]:
instance["LaunchTemplate"].should.equal(expected_launch_template)
instance.should_not.have.key("LaunchConfigurationName")
instance["AvailabilityZone"].should.equal("us-east-1a")
instance["ProtectedFromScaleIn"].should.equal(True)
instance["InstanceType"].should.equal("t2.micro")
@mock_autoscaling
def test_describe_autoscaling_instances_boto3_launch_config():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration(
LaunchConfigurationName="test_launch_configuration"
client.create_launch_configuration(
LaunchConfigurationName="test_launch_configuration", InstanceType="t2.micro",
)
_ = client.create_auto_scaling_group(
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchConfigurationName="test_launch_configuration",
MinSize=0,
@ -846,9 +1055,51 @@ def test_describe_autoscaling_instances_boto3():
response = client.describe_auto_scaling_instances()
len(response["AutoScalingInstances"]).should.equal(5)
for instance in response["AutoScalingInstances"]:
instance["LaunchConfigurationName"].should.equal("test_launch_configuration")
instance.should_not.have.key("LaunchTemplate")
instance["AutoScalingGroupName"].should.equal("test_asg")
instance["AvailabilityZone"].should.equal("us-east-1a")
instance["ProtectedFromScaleIn"].should.equal(True)
instance["InstanceType"].should.equal("t2.micro")
@mock_autoscaling
@mock_ec2
def test_describe_autoscaling_instances_boto3_launch_template():
mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template",
LaunchTemplateData={
"ImageId": "ami-0cc293023f983ed53",
"InstanceType": "t2.micro",
},
)["LaunchTemplate"]
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchTemplate={"LaunchTemplateName": "test_launch_template", "Version": "1"},
MinSize=0,
MaxSize=20,
DesiredCapacity=5,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=True,
)
expected_launch_template = {
"LaunchTemplateId": template["LaunchTemplateId"],
"LaunchTemplateName": "test_launch_template",
"Version": "1",
}
response = client.describe_auto_scaling_instances()
len(response["AutoScalingInstances"]).should.equal(5)
for instance in response["AutoScalingInstances"]:
instance["LaunchTemplate"].should.equal(expected_launch_template)
instance.should_not.have.key("LaunchConfigurationName")
instance["AutoScalingGroupName"].should.equal("test_asg")
instance["AvailabilityZone"].should.equal("us-east-1a")
instance["ProtectedFromScaleIn"].should.equal(True)
instance["InstanceType"].should.equal("t2.micro")
@mock_autoscaling
@ -885,13 +1136,16 @@ def test_describe_autoscaling_instances_instanceid_filter():
@mock_autoscaling
def test_update_autoscaling_group_boto3():
def test_update_autoscaling_group_boto3_launch_config():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration(
client.create_launch_configuration(
LaunchConfigurationName="test_launch_configuration"
)
_ = client.create_auto_scaling_group(
client.create_launch_configuration(
LaunchConfigurationName="test_launch_configuration_new"
)
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchConfigurationName="test_launch_configuration",
MinSize=0,
@ -901,8 +1155,9 @@ def test_update_autoscaling_group_boto3():
NewInstancesProtectedFromScaleIn=True,
)
_ = client.update_auto_scaling_group(
client.update_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchConfigurationName="test_launch_configuration_new",
MinSize=1,
VPCZoneIdentifier="{subnet1},{subnet2}".format(
subnet1=mocked_networking["subnet1"], subnet2=mocked_networking["subnet2"]
@ -912,6 +1167,64 @@ def test_update_autoscaling_group_boto3():
response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"])
group = response["AutoScalingGroups"][0]
group["LaunchConfigurationName"].should.equal("test_launch_configuration_new")
group["MinSize"].should.equal(1)
set(group["AvailabilityZones"]).should.equal({"us-east-1a", "us-east-1b"})
group["NewInstancesProtectedFromScaleIn"].should.equal(False)
@mock_autoscaling
@mock_ec2
def test_update_autoscaling_group_boto3_launch_template():
mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1")
ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template",
LaunchTemplateData={
"ImageId": "ami-0cc293023f983ed53",
"InstanceType": "t2.micro",
},
)
template = ec2_client.create_launch_template(
LaunchTemplateName="test_launch_template_new",
LaunchTemplateData={
"ImageId": "ami-1ea5b10a3d8867db4",
"InstanceType": "t2.micro",
},
)["LaunchTemplate"]
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchTemplate={"LaunchTemplateName": "test_launch_template", "Version": "1"},
MinSize=0,
MaxSize=20,
DesiredCapacity=5,
VPCZoneIdentifier=mocked_networking["subnet1"],
NewInstancesProtectedFromScaleIn=True,
)
client.update_auto_scaling_group(
AutoScalingGroupName="test_asg",
LaunchTemplate={
"LaunchTemplateName": "test_launch_template_new",
"Version": "1",
},
MinSize=1,
VPCZoneIdentifier="{subnet1},{subnet2}".format(
subnet1=mocked_networking["subnet1"], subnet2=mocked_networking["subnet2"]
),
NewInstancesProtectedFromScaleIn=False,
)
expected_launch_template = {
"LaunchTemplateId": template["LaunchTemplateId"],
"LaunchTemplateName": "test_launch_template_new",
"Version": "1",
}
response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"])
group = response["AutoScalingGroups"][0]
group["LaunchTemplate"].should.equal(expected_launch_template)
group["MinSize"].should.equal(1)
set(group["AvailabilityZones"]).should.equal({"us-east-1a", "us-east-1b"})
group["NewInstancesProtectedFromScaleIn"].should.equal(False)
@ -966,7 +1279,7 @@ def test_update_autoscaling_group_max_size_desired_capacity_change():
@mock_autoscaling
def test_autoscaling_taqs_update_boto3():
def test_autoscaling_tags_update_boto3():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration(