AutoScaling: create_auto_scaling_group() now supports the MixedInstancesPolicy-parameter (#5433)

This commit is contained in:
Bert Blommers 2022-08-30 10:04:12 +00:00 committed by GitHub
parent bd051f4f32
commit 2c98b7574b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 199 additions and 25 deletions

View File

@ -368,6 +368,8 @@ class FakeAutoScalingGroup(CloudFormationModel):
autoscaling_backend,
ec2_backend,
tags,
mixed_instance_policy,
capacity_rebalance,
new_instances_protected_from_scale_in=False,
):
self.autoscaling_backend = autoscaling_backend
@ -376,6 +378,7 @@ class FakeAutoScalingGroup(CloudFormationModel):
self._id = str(uuid4())
self.region = self.autoscaling_backend.region_name
self.account_id = self.autoscaling_backend.account_id
self.service_linked_role = f"arn:aws:iam::{self.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"
self._set_azs_and_vpcs(availability_zones, vpc_zone_identifier)
@ -385,7 +388,10 @@ class FakeAutoScalingGroup(CloudFormationModel):
self.launch_template = None
self.launch_config = None
self._set_launch_configuration(launch_config_name, launch_template)
self._set_launch_configuration(
launch_config_name, launch_template, mixed_instance_policy
)
self.mixed_instance_policy = mixed_instance_policy
self.default_cooldown = (
default_cooldown if default_cooldown else DEFAULT_COOLDOWN
@ -395,6 +401,7 @@ class FakeAutoScalingGroup(CloudFormationModel):
self.load_balancers = load_balancers
self.target_group_arns = target_group_arns
self.placement_group = placement_group
self.capacity_rebalance = capacity_rebalance
self.termination_policies = termination_policies or ["Default"]
self.new_instances_protected_from_scale_in = (
new_instances_protected_from_scale_in
@ -458,16 +465,29 @@ class FakeAutoScalingGroup(CloudFormationModel):
self.availability_zones = availability_zones
self.vpc_zone_identifier = vpc_zone_identifier
def _set_launch_configuration(self, launch_config_name, launch_template):
def _set_launch_configuration(
self, launch_config_name, launch_template, mixed_instance_policy
):
if launch_config_name:
self.launch_config = self.autoscaling_backend.launch_configurations[
launch_config_name
]
self.launch_config_name = launch_config_name
if launch_template:
launch_template_id = launch_template.get("launch_template_id")
launch_template_name = launch_template.get("launch_template_name")
if launch_template or mixed_instance_policy:
if launch_template:
launch_template_id = launch_template.get("launch_template_id")
launch_template_name = launch_template.get("launch_template_name")
self.launch_template_version = (
launch_template.get("version") or "$Default"
)
else:
spec = mixed_instance_policy["LaunchTemplate"][
"LaunchTemplateSpecification"
]
launch_template_id = spec.get("LaunchTemplateId")
launch_template_name = spec.get("LaunchTemplateName")
self.launch_template_version = spec.get("Version") or "$Default"
if not (launch_template_id or launch_template_name) or (
launch_template_id and launch_template_name
@ -484,7 +504,6 @@ class FakeAutoScalingGroup(CloudFormationModel):
self.launch_template = self.ec2_backend.get_launch_template_by_name(
launch_template_name
)
self.launch_template_version = launch_template.get("version") or "$Default"
@staticmethod
def __set_string_propagate_at_launch_booleans_on_tags(tags):
@ -637,7 +656,9 @@ class FakeAutoScalingGroup(CloudFormationModel):
if max_size is not None and max_size < len(self.instance_states):
desired_capacity = max_size
self._set_launch_configuration(launch_config_name, launch_template)
self._set_launch_configuration(
launch_config_name, launch_template, mixed_instance_policy=None
)
if health_check_period is not None:
self.health_check_period = health_check_period
@ -909,8 +930,10 @@ class AutoScalingBackend(BaseBackend):
placement_group,
termination_policies,
tags,
capacity_rebalance=False,
new_instances_protected_from_scale_in=False,
instance_id=None,
mixed_instance_policy=None,
):
max_size = self.make_int(max_size)
min_size = self.make_int(min_size)
@ -921,9 +944,13 @@ class AutoScalingBackend(BaseBackend):
else:
health_check_period = self.make_int(health_check_period)
# TODO: Add MixedInstancesPolicy once implemented.
# Verify only a single launch config-like parameter is provided.
params = [launch_config_name, launch_template, instance_id]
params = [
launch_config_name,
launch_template,
instance_id,
mixed_instance_policy,
]
num_params = sum([1 for param in params if param])
if num_params != 1:
@ -962,6 +989,8 @@ class AutoScalingBackend(BaseBackend):
ec2_backend=self.ec2_backend,
tags=tags,
new_instances_protected_from_scale_in=new_instances_protected_from_scale_in,
mixed_instance_policy=mixed_instance_policy,
capacity_rebalance=capacity_rebalance,
)
self.autoscaling_groups[name] = group

View File

@ -80,6 +80,7 @@ class AutoScalingResponse(BaseResponse):
return template.render()
def create_auto_scaling_group(self):
params = self._get_params()
self.autoscaling_backend.create_auto_scaling_group(
name=self._get_param("AutoScalingGroupName"),
availability_zones=self._get_multi_param("AvailabilityZones.member"),
@ -89,6 +90,7 @@ class AutoScalingResponse(BaseResponse):
instance_id=self._get_param("InstanceId"),
launch_config_name=self._get_param("LaunchConfigurationName"),
launch_template=self._get_dict_param("LaunchTemplate."),
mixed_instance_policy=params.get("MixedInstancesPolicy"),
vpc_zone_identifier=self._get_param("VPCZoneIdentifier"),
default_cooldown=self._get_int_param("DefaultCooldown"),
health_check_period=self._get_int_param("HealthCheckGracePeriod"),
@ -98,6 +100,7 @@ class AutoScalingResponse(BaseResponse):
placement_group=self._get_param("PlacementGroup"),
termination_policies=self._get_multi_param("TerminationPolicies.member"),
tags=self._get_list_prefix("Tags.member"),
capacity_rebalance=self._get_bool_param("CapacityRebalance"),
new_instances_protected_from_scale_in=self._get_bool_param(
"NewInstancesProtectedFromScaleIn", False
),
@ -748,6 +751,30 @@ DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE = """<DescribeAutoScalingGroupsResponse xml
<CreatedTime>2013-05-06T17:47:15.107Z</CreatedTime>
{% if group.launch_config_name %}
<LaunchConfigurationName>{{ group.launch_config_name }}</LaunchConfigurationName>
{% elif group.mixed_instance_policy %}
<MixedInstancesPolicy>
<LaunchTemplate>
<LaunchTemplateSpecification>
<LaunchTemplateId>{{ group.launch_template.id }}</LaunchTemplateId>
<Version>{{ group.launch_template_version }}</Version>
<LaunchTemplateName>{{ group.launch_template.name }}</LaunchTemplateName>
</LaunchTemplateSpecification>
{% if group.mixed_instance_policy.get("LaunchTemplate", {}).get("Overrides", []) %}
<Overrides>
{% for member in group.mixed_instance_policy.get("LaunchTemplate", {}).get("Overrides", []) %}
<member>
{% if member.get("InstanceType") %}
<InstanceType>{{ member.get("InstanceType") }}</InstanceType>
{% endif %}
{% if member.get("WeightedCapacity") %}
<WeightedCapacity>{{ member.get("WeightedCapacity") }}</WeightedCapacity>
{% endif %}
</member>
{% endfor %}
</Overrides>
{% endif %}
</LaunchTemplate>
</MixedInstancesPolicy>
{% elif group.launch_template %}
<LaunchTemplate>
<LaunchTemplateId>{{ group.launch_template.id }}</LaunchTemplateId>
@ -777,6 +804,7 @@ DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE = """<DescribeAutoScalingGroupsResponse xml
{% endfor %}
</Instances>
<DesiredCapacity>{{ group.desired_capacity }}</DesiredCapacity>
<CapacityRebalance>{{ 'true' if group.capacity_rebalance else 'false' }}</CapacityRebalance>
<AvailabilityZones>
{% for availability_zone in group.availability_zones %}
<member>{{ availability_zone }}</member>
@ -833,6 +861,7 @@ DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE = """<DescribeAutoScalingGroupsResponse xml
{% endfor %}
</EnabledMetrics>
{% endif %}
<ServiceLinkedRoleARN>{{ group.service_linked_role }}</ServiceLinkedRoleARN>
</member>
{% endfor %}
</AutoScalingGroups>

View File

@ -11,6 +11,14 @@ autoscaling:
- TestAccAutoScalingAttachment
- TestAccAutoScalingGroupDataSource
- TestAccAutoScalingGroupTag
- TestAccAutoScalingGroup_basic
- TestAccAutoScalingGroup_disappears
- TestAccAutoScalingGroup_nameGenerated
- TestAccAutoScalingGroup_namePrefix
- TestAccAutoScalingGroup_enablingMetrics
- TestAccAutoScalingGroup_suspendingProcesses
- TestAccAutoScalingGroup_mixedInstancesPolicy
- TestAccAutoScalingGroup_MixedInstancesPolicy_capacityRebalance
- TestAccAutoScalingLaunchConfigurationDataSource
- TestAccAutoScalingLaunchConfiguration_
batch:

View File

@ -61,22 +61,6 @@ def test_create_autoscaling_group_from_instance():
MinSize=1,
MaxSize=3,
DesiredCapacity=2,
Tags=[
{
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "propogated-tag-key",
"Value": "propagate-tag-value",
"PropagateAtLaunch": True,
},
{
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "not-propogated-tag-key",
"Value": "not-propagate-tag-value",
"PropagateAtLaunch": False,
},
],
VPCZoneIdentifier=mocked_instance_with_networking["subnet1"],
NewInstancesProtectedFromScaleIn=False,
)
@ -874,6 +858,116 @@ def test_create_autoscaling_policy_with_predictive_scaling_config():
)
@mock_autoscaling
@mock_ec2
def test_create_auto_scaling_group_with_mixed_instances_policy():
mocked_networking = setup_networking(region_name="eu-west-1")
client = boto3.client("autoscaling", region_name="eu-west-1")
ec2_client = boto3.client("ec2", region_name="eu-west-1")
asg_name = "asg_test"
lt = ec2_client.create_launch_template(
LaunchTemplateName="launchie",
LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID},
)["LaunchTemplate"]
client.create_auto_scaling_group(
MixedInstancesPolicy={
"LaunchTemplate": {
"LaunchTemplateSpecification": {
"LaunchTemplateName": "launchie",
"Version": "$DEFAULT",
}
}
},
AutoScalingGroupName=asg_name,
MinSize=2,
MaxSize=2,
VPCZoneIdentifier=mocked_networking["subnet1"],
)
# Assert we can describe MixedInstancesPolicy
response = client.describe_auto_scaling_groups(AutoScalingGroupNames=[asg_name])
group = response["AutoScalingGroups"][0]
group.should.have.key("MixedInstancesPolicy").equals(
{
"LaunchTemplate": {
"LaunchTemplateSpecification": {
"LaunchTemplateId": lt["LaunchTemplateId"],
"LaunchTemplateName": "launchie",
"Version": "$DEFAULT",
}
}
}
)
# Assert the LaunchTemplate is known for the resulting instances
response = client.describe_auto_scaling_instances()
len(response["AutoScalingInstances"]).should.equal(2)
for instance in response["AutoScalingInstances"]:
instance["LaunchTemplate"].should.equal(
{
"LaunchTemplateId": lt["LaunchTemplateId"],
"LaunchTemplateName": "launchie",
"Version": "$DEFAULT",
}
)
@mock_autoscaling
@mock_ec2
def test_create_auto_scaling_group_with_mixed_instances_policy_overrides():
mocked_networking = setup_networking(region_name="eu-west-1")
client = boto3.client("autoscaling", region_name="eu-west-1")
ec2_client = boto3.client("ec2", region_name="eu-west-1")
asg_name = "asg_test"
lt = ec2_client.create_launch_template(
LaunchTemplateName="launchie",
LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID},
)["LaunchTemplate"]
client.create_auto_scaling_group(
MixedInstancesPolicy={
"LaunchTemplate": {
"LaunchTemplateSpecification": {
"LaunchTemplateName": "launchie",
"Version": "$DEFAULT",
},
"Overrides": [
{
"InstanceType": "t2.medium",
"WeightedCapacity": "50",
}
],
}
},
AutoScalingGroupName=asg_name,
MinSize=2,
MaxSize=2,
VPCZoneIdentifier=mocked_networking["subnet1"],
)
# Assert we can describe MixedInstancesPolicy
response = client.describe_auto_scaling_groups(AutoScalingGroupNames=[asg_name])
group = response["AutoScalingGroups"][0]
group.should.have.key("MixedInstancesPolicy").equals(
{
"LaunchTemplate": {
"LaunchTemplateSpecification": {
"LaunchTemplateId": lt["LaunchTemplateId"],
"LaunchTemplateName": "launchie",
"Version": "$DEFAULT",
},
"Overrides": [
{
"InstanceType": "t2.medium",
"WeightedCapacity": "50",
}
],
}
}
)
@mock_autoscaling
def test_set_instance_protection():
mocked_networking = setup_networking()

View File

@ -44,6 +44,20 @@ class TestAutoScalingGroup(TestCase):
group["TerminationPolicies"].should.equal(["Default"])
group["Tags"].should.equal([])
def test_create_autoscaling_group__additional_params(self):
self.as_client.create_auto_scaling_group(
AutoScalingGroupName="tester_group",
MinSize=1,
MaxSize=2,
LaunchConfigurationName=self.lc_name,
CapacityRebalance=True,
VPCZoneIdentifier=self.mocked_networking["subnet1"],
)
group = self.as_client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
group["AutoScalingGroupName"].should.equal("tester_group")
group["CapacityRebalance"].should.equal(True)
def test_list_many_autoscaling_groups(self):
for i in range(51):