Implement AutoScaling resume_processes and correct behavior of suspend_processes (#4133)

* Implement AutoScaling resume_processes and correct behavior of suspend_processes
This commit is contained in:
Ray Myers 2021-08-04 00:57:21 -05:00 committed by GitHub
parent 1b7e015e19
commit 4ae9b0e253
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 180 additions and 2 deletions

View File

@ -945,7 +945,7 @@
- [ ] put_scheduled_update_group_action
- [ ] put_warm_pool
- [ ] record_lifecycle_action_heartbeat
- [ ] resume_processes
- [X] resume_processes
- [X] set_desired_capacity
- [X] set_instance_health
- [X] set_instance_protection

View File

@ -1040,8 +1040,31 @@ class AutoScalingBackend(BaseBackend):
self.elbv2_backend.deregister_targets(target_group, (asg_targets))
def suspend_processes(self, group_name, scaling_processes):
all_proc_names = [
"Launch",
"Terminate",
"AddToLoadBalancer",
"AlarmNotification",
"AZRebalance",
"HealthCheck",
"InstanceRefresh",
"ReplaceUnhealthy",
"ScheduledActions",
]
group = self.autoscaling_groups[group_name]
group.suspended_processes = scaling_processes or []
set_to_add = set(scaling_processes or all_proc_names)
group.suspended_processes = list(
set(group.suspended_processes).union(set_to_add)
)
def resume_processes(self, group_name, scaling_processes):
group = self.autoscaling_groups[group_name]
if scaling_processes:
group.suspended_processes = list(
set(group.suspended_processes).difference(set(scaling_processes))
)
else:
group.suspended_processes = []
def set_instance_protection(
self, group_name, instance_ids, protected_from_scale_in

View File

@ -359,6 +359,15 @@ class AutoScalingResponse(BaseResponse):
template = self.response_template(SUSPEND_PROCESSES_TEMPLATE)
return template.render()
def resume_processes(self):
autoscaling_group_name = self._get_param("AutoScalingGroupName")
scaling_processes = self._get_multi_param("ScalingProcesses.member")
self.autoscaling_backend.resume_processes(
autoscaling_group_name, scaling_processes
)
template = self.response_template(RESUME_PROCESSES_TEMPLATE)
return template.render()
def set_instance_protection(self):
group_name = self._get_param("AutoScalingGroupName")
instance_ids = self._get_multi_param("InstanceIds.member")
@ -802,6 +811,12 @@ SUSPEND_PROCESSES_TEMPLATE = """<SuspendProcessesResponse xmlns="http://autoscal
</ResponseMetadata>
</SuspendProcessesResponse>"""
RESUME_PROCESSES_TEMPLATE = """<ResumeProcessesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
<ResponseMetadata>
<RequestId></RequestId>
</ResponseMetadata>
</ResumeProcessesResponse>"""
SET_INSTANCE_HEALTH_TEMPLATE = """<SetInstanceHealthResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
<SetInstanceHealthResponse></SetInstanceHealthResponse>
<ResponseMetadata>

View File

@ -2391,6 +2391,146 @@ def test_suspend_processes():
assert launch_suspended is True
@mock_autoscaling
def test_suspend_processes_all_by_default():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration(
LaunchConfigurationName="lc", ImageId=EXAMPLE_AMI_ID, InstanceType="t2.medium"
)
client.create_auto_scaling_group(
LaunchConfigurationName="lc",
AutoScalingGroupName="test-asg",
MinSize=1,
MaxSize=1,
VPCZoneIdentifier=mocked_networking["subnet1"],
)
# When we suspend with no processes specified
client.suspend_processes(AutoScalingGroupName="test-asg")
res = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test-asg"])
# All processes should be suspended
all_proc_names = [
"Launch",
"Terminate",
"AddToLoadBalancer",
"AlarmNotification",
"AZRebalance",
"HealthCheck",
"InstanceRefresh",
"ReplaceUnhealthy",
"ScheduledActions",
]
suspended_proc_names = [
proc["ProcessName"]
for proc in res["AutoScalingGroups"][0]["SuspendedProcesses"]
]
set(suspended_proc_names).should.equal(set(all_proc_names))
@mock_autoscaling
def test_suspend_additional_processes():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration(
LaunchConfigurationName="lc", ImageId=EXAMPLE_AMI_ID, InstanceType="t2.medium"
)
client.create_auto_scaling_group(
LaunchConfigurationName="lc",
AutoScalingGroupName="test-asg",
MinSize=1,
MaxSize=1,
VPCZoneIdentifier=mocked_networking["subnet1"],
)
# When we suspend the 'Launch' and 'Terminate' processes in separate calls
client.suspend_processes(
AutoScalingGroupName="test-asg", ScalingProcesses=["Launch"]
)
client.suspend_processes(
AutoScalingGroupName="test-asg", ScalingProcesses=["Terminate"]
)
res = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test-asg"])
# Both 'Launch' and 'Terminate' should be suspended
launch_suspended = False
terminate_suspended = False
for proc in res["AutoScalingGroups"][0]["SuspendedProcesses"]:
if proc.get("ProcessName") == "Launch":
launch_suspended = True
if proc.get("ProcessName") == "Terminate":
terminate_suspended = True
assert launch_suspended is True
assert terminate_suspended is True
@mock_autoscaling
def test_resume_processes():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration(
LaunchConfigurationName="lc", ImageId=EXAMPLE_AMI_ID, InstanceType="t2.medium"
)
client.create_auto_scaling_group(
LaunchConfigurationName="lc",
AutoScalingGroupName="test-asg",
MinSize=1,
MaxSize=1,
VPCZoneIdentifier=mocked_networking["subnet1"],
)
# When we suspect 'Launch' and 'Termiate' process then resume 'Launch'
client.suspend_processes(
AutoScalingGroupName="test-asg", ScalingProcesses=["Launch", "Terminate"]
)
client.resume_processes(
AutoScalingGroupName="test-asg", ScalingProcesses=["Launch"]
)
res = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test-asg"])
# Only 'Terminate' should be suspended
expected_suspended_processes = [
{"ProcessName": "Terminate", "SuspensionReason": ""}
]
res["AutoScalingGroups"][0]["SuspendedProcesses"].should.equal(
expected_suspended_processes
)
@mock_autoscaling
def test_resume_processes_all_by_default():
mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration(
LaunchConfigurationName="lc", ImageId=EXAMPLE_AMI_ID, InstanceType="t2.medium"
)
client.create_auto_scaling_group(
LaunchConfigurationName="lc",
AutoScalingGroupName="test-asg",
MinSize=1,
MaxSize=1,
VPCZoneIdentifier=mocked_networking["subnet1"],
)
# When we suspend two processes then resume with no process argument
client.suspend_processes(
AutoScalingGroupName="test-asg", ScalingProcesses=["Launch", "Terminate"]
)
client.resume_processes(AutoScalingGroupName="test-asg")
res = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test-asg"])
# No processes should be suspended
res["AutoScalingGroups"][0]["SuspendedProcesses"].should.equal([])
@mock_autoscaling
def test_set_instance_protection():
mocked_networking = setup_networking()