Merge pull request #2891 from DenverJ/enhancement/autoscaling-standby-terminate
Implement enter_standby, exit_standby and terminate_instance_in_auto_scaling_group
This commit is contained in:
		
						commit
						d0c60ecaac
					
				| @ -267,6 +267,9 @@ class FakeAutoScalingGroup(BaseModel): | |||||||
|         self.tags = tags if tags else [] |         self.tags = tags if tags else [] | ||||||
|         self.set_desired_capacity(desired_capacity) |         self.set_desired_capacity(desired_capacity) | ||||||
| 
 | 
 | ||||||
|  |     def active_instances(self): | ||||||
|  |         return [x for x in self.instance_states if x.lifecycle_state == "InService"] | ||||||
|  | 
 | ||||||
|     def _set_azs_and_vpcs(self, availability_zones, vpc_zone_identifier, update=False): |     def _set_azs_and_vpcs(self, availability_zones, vpc_zone_identifier, update=False): | ||||||
|         # for updates, if only AZs are provided, they must not clash with |         # for updates, if only AZs are provided, they must not clash with | ||||||
|         # the AZs of existing VPCs |         # the AZs of existing VPCs | ||||||
| @ -413,9 +416,11 @@ class FakeAutoScalingGroup(BaseModel): | |||||||
|         else: |         else: | ||||||
|             self.desired_capacity = new_capacity |             self.desired_capacity = new_capacity | ||||||
| 
 | 
 | ||||||
|         curr_instance_count = len(self.instance_states) |         curr_instance_count = len(self.active_instances()) | ||||||
| 
 | 
 | ||||||
|         if self.desired_capacity == curr_instance_count: |         if self.desired_capacity == curr_instance_count: | ||||||
|  |             self.autoscaling_backend.update_attached_elbs(self.name) | ||||||
|  |             self.autoscaling_backend.update_attached_target_groups(self.name) | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         if self.desired_capacity > curr_instance_count: |         if self.desired_capacity > curr_instance_count: | ||||||
| @ -442,6 +447,8 @@ class FakeAutoScalingGroup(BaseModel): | |||||||
|                 self.instance_states = list( |                 self.instance_states = list( | ||||||
|                     set(self.instance_states) - set(instances_to_remove) |                     set(self.instance_states) - set(instances_to_remove) | ||||||
|                 ) |                 ) | ||||||
|  |             self.autoscaling_backend.update_attached_elbs(self.name) | ||||||
|  |             self.autoscaling_backend.update_attached_target_groups(self.name) | ||||||
| 
 | 
 | ||||||
|     def get_propagated_tags(self): |     def get_propagated_tags(self): | ||||||
|         propagated_tags = {} |         propagated_tags = {} | ||||||
| @ -703,7 +710,7 @@ class AutoScalingBackend(BaseBackend): | |||||||
| 
 | 
 | ||||||
|     def detach_instances(self, group_name, instance_ids, should_decrement): |     def detach_instances(self, group_name, instance_ids, should_decrement): | ||||||
|         group = self.autoscaling_groups[group_name] |         group = self.autoscaling_groups[group_name] | ||||||
|         original_size = len(group.instance_states) |         original_size = group.desired_capacity | ||||||
| 
 | 
 | ||||||
|         detached_instances = [ |         detached_instances = [ | ||||||
|             x for x in group.instance_states if x.instance.id in instance_ids |             x for x in group.instance_states if x.instance.id in instance_ids | ||||||
| @ -720,13 +727,8 @@ class AutoScalingBackend(BaseBackend): | |||||||
| 
 | 
 | ||||||
|         if should_decrement: |         if should_decrement: | ||||||
|             group.desired_capacity = original_size - len(instance_ids) |             group.desired_capacity = original_size - len(instance_ids) | ||||||
|         else: |  | ||||||
|             count_needed = len(instance_ids) |  | ||||||
|             group.replace_autoscaling_group_instances( |  | ||||||
|                 count_needed, group.get_propagated_tags() |  | ||||||
|             ) |  | ||||||
| 
 | 
 | ||||||
|         self.update_attached_elbs(group_name) |         group.set_desired_capacity(group.desired_capacity) | ||||||
|         return detached_instances |         return detached_instances | ||||||
| 
 | 
 | ||||||
|     def set_desired_capacity(self, group_name, desired_capacity): |     def set_desired_capacity(self, group_name, desired_capacity): | ||||||
| @ -791,7 +793,9 @@ class AutoScalingBackend(BaseBackend): | |||||||
| 
 | 
 | ||||||
|     def update_attached_elbs(self, group_name): |     def update_attached_elbs(self, group_name): | ||||||
|         group = self.autoscaling_groups[group_name] |         group = self.autoscaling_groups[group_name] | ||||||
|         group_instance_ids = set(state.instance.id for state in group.instance_states) |         group_instance_ids = set( | ||||||
|  |             state.instance.id for state in group.active_instances() | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
|         # skip this if group.load_balancers is empty |         # skip this if group.load_balancers is empty | ||||||
|         # otherwise elb_backend.describe_load_balancers returns all available load balancers |         # otherwise elb_backend.describe_load_balancers returns all available load balancers | ||||||
| @ -908,15 +912,15 @@ class AutoScalingBackend(BaseBackend): | |||||||
|             autoscaling_group_name, |             autoscaling_group_name, | ||||||
|             autoscaling_group, |             autoscaling_group, | ||||||
|         ) in self.autoscaling_groups.items(): |         ) in self.autoscaling_groups.items(): | ||||||
|             original_instance_count = len(autoscaling_group.instance_states) |             original_active_instance_count = len(autoscaling_group.active_instances()) | ||||||
|             autoscaling_group.instance_states = list( |             autoscaling_group.instance_states = list( | ||||||
|                 filter( |                 filter( | ||||||
|                     lambda i_state: i_state.instance.id not in instance_ids, |                     lambda i_state: i_state.instance.id not in instance_ids, | ||||||
|                     autoscaling_group.instance_states, |                     autoscaling_group.instance_states, | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
|             difference = original_instance_count - len( |             difference = original_active_instance_count - len( | ||||||
|                 autoscaling_group.instance_states |                 autoscaling_group.active_instances() | ||||||
|             ) |             ) | ||||||
|             if difference > 0: |             if difference > 0: | ||||||
|                 autoscaling_group.replace_autoscaling_group_instances( |                 autoscaling_group.replace_autoscaling_group_instances( | ||||||
| @ -924,6 +928,45 @@ class AutoScalingBackend(BaseBackend): | |||||||
|                 ) |                 ) | ||||||
|                 self.update_attached_elbs(autoscaling_group_name) |                 self.update_attached_elbs(autoscaling_group_name) | ||||||
| 
 | 
 | ||||||
|  |     def enter_standby_instances(self, group_name, instance_ids, should_decrement): | ||||||
|  |         group = self.autoscaling_groups[group_name] | ||||||
|  |         original_size = group.desired_capacity | ||||||
|  |         standby_instances = [] | ||||||
|  |         for instance_state in group.instance_states: | ||||||
|  |             if instance_state.instance.id in instance_ids: | ||||||
|  |                 instance_state.lifecycle_state = "Standby" | ||||||
|  |                 standby_instances.append(instance_state) | ||||||
|  |         if should_decrement: | ||||||
|  |             group.desired_capacity = group.desired_capacity - len(instance_ids) | ||||||
|  |         else: | ||||||
|  |             group.set_desired_capacity(group.desired_capacity) | ||||||
|  |         return standby_instances, original_size, group.desired_capacity | ||||||
|  | 
 | ||||||
|  |     def exit_standby_instances(self, group_name, instance_ids): | ||||||
|  |         group = self.autoscaling_groups[group_name] | ||||||
|  |         original_size = group.desired_capacity | ||||||
|  |         standby_instances = [] | ||||||
|  |         for instance_state in group.instance_states: | ||||||
|  |             if instance_state.instance.id in instance_ids: | ||||||
|  |                 instance_state.lifecycle_state = "InService" | ||||||
|  |                 standby_instances.append(instance_state) | ||||||
|  |         group.desired_capacity = group.desired_capacity + len(instance_ids) | ||||||
|  |         return standby_instances, original_size, group.desired_capacity | ||||||
|  | 
 | ||||||
|  |     def terminate_instance(self, instance_id, should_decrement): | ||||||
|  |         instance = self.ec2_backend.get_instance(instance_id) | ||||||
|  |         instance_state = next( | ||||||
|  |             instance_state | ||||||
|  |             for group in self.autoscaling_groups.values() | ||||||
|  |             for instance_state in group.instance_states | ||||||
|  |             if instance_state.instance.id == instance.id | ||||||
|  |         ) | ||||||
|  |         group = instance.autoscaling_group | ||||||
|  |         original_size = group.desired_capacity | ||||||
|  |         self.detach_instances(group.name, [instance.id], should_decrement) | ||||||
|  |         self.ec2_backend.terminate_instances([instance.id]) | ||||||
|  |         return instance_state, original_size, group.desired_capacity | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| autoscaling_backends = {} | autoscaling_backends = {} | ||||||
| for region, ec2_backend in ec2_backends.items(): | for region, ec2_backend in ec2_backends.items(): | ||||||
|  | |||||||
| @ -1,7 +1,12 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  | import datetime | ||||||
| 
 | 
 | ||||||
| from moto.core.responses import BaseResponse | from moto.core.responses import BaseResponse | ||||||
| from moto.core.utils import amz_crc32, amzn_request_id | from moto.core.utils import ( | ||||||
|  |     amz_crc32, | ||||||
|  |     amzn_request_id, | ||||||
|  |     iso_8601_datetime_with_milliseconds, | ||||||
|  | ) | ||||||
| from .models import autoscaling_backends | from .models import autoscaling_backends | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -291,6 +296,50 @@ class AutoScalingResponse(BaseResponse): | |||||||
|         template = self.response_template(DETACH_LOAD_BALANCERS_TEMPLATE) |         template = self.response_template(DETACH_LOAD_BALANCERS_TEMPLATE) | ||||||
|         return template.render() |         return template.render() | ||||||
| 
 | 
 | ||||||
|  |     @amz_crc32 | ||||||
|  |     @amzn_request_id | ||||||
|  |     def enter_standby(self): | ||||||
|  |         group_name = self._get_param("AutoScalingGroupName") | ||||||
|  |         instance_ids = self._get_multi_param("InstanceIds.member") | ||||||
|  |         should_decrement_string = self._get_param("ShouldDecrementDesiredCapacity") | ||||||
|  |         if should_decrement_string == "true": | ||||||
|  |             should_decrement = True | ||||||
|  |         else: | ||||||
|  |             should_decrement = False | ||||||
|  |         ( | ||||||
|  |             standby_instances, | ||||||
|  |             original_size, | ||||||
|  |             desired_capacity, | ||||||
|  |         ) = self.autoscaling_backend.enter_standby_instances( | ||||||
|  |             group_name, instance_ids, should_decrement | ||||||
|  |         ) | ||||||
|  |         template = self.response_template(ENTER_STANDBY_TEMPLATE) | ||||||
|  |         return template.render( | ||||||
|  |             standby_instances=standby_instances, | ||||||
|  |             should_decrement=should_decrement, | ||||||
|  |             original_size=original_size, | ||||||
|  |             desired_capacity=desired_capacity, | ||||||
|  |             timestamp=iso_8601_datetime_with_milliseconds(datetime.datetime.utcnow()), | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     @amz_crc32 | ||||||
|  |     @amzn_request_id | ||||||
|  |     def exit_standby(self): | ||||||
|  |         group_name = self._get_param("AutoScalingGroupName") | ||||||
|  |         instance_ids = self._get_multi_param("InstanceIds.member") | ||||||
|  |         ( | ||||||
|  |             standby_instances, | ||||||
|  |             original_size, | ||||||
|  |             desired_capacity, | ||||||
|  |         ) = self.autoscaling_backend.exit_standby_instances(group_name, instance_ids) | ||||||
|  |         template = self.response_template(EXIT_STANDBY_TEMPLATE) | ||||||
|  |         return template.render( | ||||||
|  |             standby_instances=standby_instances, | ||||||
|  |             original_size=original_size, | ||||||
|  |             desired_capacity=desired_capacity, | ||||||
|  |             timestamp=iso_8601_datetime_with_milliseconds(datetime.datetime.utcnow()), | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|     def suspend_processes(self): |     def suspend_processes(self): | ||||||
|         autoscaling_group_name = self._get_param("AutoScalingGroupName") |         autoscaling_group_name = self._get_param("AutoScalingGroupName") | ||||||
|         scaling_processes = self._get_multi_param("ScalingProcesses.member") |         scaling_processes = self._get_multi_param("ScalingProcesses.member") | ||||||
| @ -310,6 +359,29 @@ class AutoScalingResponse(BaseResponse): | |||||||
|         template = self.response_template(SET_INSTANCE_PROTECTION_TEMPLATE) |         template = self.response_template(SET_INSTANCE_PROTECTION_TEMPLATE) | ||||||
|         return template.render() |         return template.render() | ||||||
| 
 | 
 | ||||||
|  |     @amz_crc32 | ||||||
|  |     @amzn_request_id | ||||||
|  |     def terminate_instance_in_auto_scaling_group(self): | ||||||
|  |         instance_id = self._get_param("InstanceId") | ||||||
|  |         should_decrement_string = self._get_param("ShouldDecrementDesiredCapacity") | ||||||
|  |         if should_decrement_string == "true": | ||||||
|  |             should_decrement = True | ||||||
|  |         else: | ||||||
|  |             should_decrement = False | ||||||
|  |         ( | ||||||
|  |             instance, | ||||||
|  |             original_size, | ||||||
|  |             desired_capacity, | ||||||
|  |         ) = self.autoscaling_backend.terminate_instance(instance_id, should_decrement) | ||||||
|  |         template = self.response_template(TERMINATE_INSTANCES_TEMPLATE) | ||||||
|  |         return template.render( | ||||||
|  |             instance=instance, | ||||||
|  |             should_decrement=should_decrement, | ||||||
|  |             original_size=original_size, | ||||||
|  |             desired_capacity=desired_capacity, | ||||||
|  |             timestamp=iso_8601_datetime_with_milliseconds(datetime.datetime.utcnow()), | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| CREATE_LAUNCH_CONFIGURATION_TEMPLATE = """<CreateLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/"> | CREATE_LAUNCH_CONFIGURATION_TEMPLATE = """<CreateLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/"> | ||||||
| <ResponseMetadata> | <ResponseMetadata> | ||||||
| @ -707,3 +779,73 @@ SET_INSTANCE_PROTECTION_TEMPLATE = """<SetInstanceProtectionResponse xmlns="http | |||||||
| <RequestId></RequestId> | <RequestId></RequestId> | ||||||
| </ResponseMetadata> | </ResponseMetadata> | ||||||
| </SetInstanceProtectionResponse>""" | </SetInstanceProtectionResponse>""" | ||||||
|  | 
 | ||||||
|  | ENTER_STANDBY_TEMPLATE = """<EnterStandbyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/"> | ||||||
|  |   <EnterStandbyResult> | ||||||
|  |     <Activities> | ||||||
|  |       {% for instance in standby_instances %} | ||||||
|  |       <member> | ||||||
|  |         <ActivityId>12345678-1234-1234-1234-123456789012</ActivityId> | ||||||
|  |         <AutoScalingGroupName>{{ group_name }}</AutoScalingGroupName> | ||||||
|  |         {% if should_decrement %} | ||||||
|  |         <Cause>At {{ timestamp }} instance {{ instance.instance.id }} was moved to standby in response to a user request, shrinking the capacity from {{ original_size }} to {{ desired_capacity }}.</Cause> | ||||||
|  |         {% else %} | ||||||
|  |         <Cause>At {{ timestamp }} instance {{ instance.instance.id }} was moved to standby in response to a user request.</Cause> | ||||||
|  |         {% endif %} | ||||||
|  |         <Description>Moving EC2 instance to Standby: {{ instance.instance.id }}</Description> | ||||||
|  |         <Progress>50</Progress> | ||||||
|  |         <StartTime>{{ timestamp }}</StartTime> | ||||||
|  |         <Details>{"Subnet ID":"??","Availability Zone":"{{ instance.instance.placement }}"}</Details> | ||||||
|  |         <StatusCode>InProgress</StatusCode> | ||||||
|  |       </member> | ||||||
|  |       {% endfor %} | ||||||
|  |     </Activities> | ||||||
|  |   </EnterStandbyResult> | ||||||
|  |   <ResponseMetadata> | ||||||
|  |     <RequestId>7c6e177f-f082-11e1-ac58-3714bEXAMPLE</RequestId> | ||||||
|  |   </ResponseMetadata> | ||||||
|  | </EnterStandbyResponse>""" | ||||||
|  | 
 | ||||||
|  | EXIT_STANDBY_TEMPLATE = """<ExitStandbyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/"> | ||||||
|  |   <ExitStandbyResult> | ||||||
|  |     <Activities> | ||||||
|  |       {% for instance in standby_instances %} | ||||||
|  |       <member> | ||||||
|  |         <ActivityId>12345678-1234-1234-1234-123456789012</ActivityId> | ||||||
|  |         <AutoScalingGroupName>{{ group_name }}</AutoScalingGroupName> | ||||||
|  |         <Description>Moving EC2 instance out of Standby: {{ instance.instance.id }}</Description> | ||||||
|  |         <Progress>30</Progress> | ||||||
|  |         <Cause>At {{ timestamp }} instance {{ instance.instance.id }} was moved out of standby in response to a user request, increasing the capacity from {{ original_size }} to {{ desired_capacity }}.</Cause> | ||||||
|  |         <StartTime>{{ timestamp }}</StartTime> | ||||||
|  |         <Details>{"Subnet ID":"??","Availability Zone":"{{ instance.instance.placement }}"}</Details> | ||||||
|  |         <StatusCode>PreInService</StatusCode> | ||||||
|  |       </member> | ||||||
|  |       {% endfor %} | ||||||
|  |     </Activities> | ||||||
|  |   </ExitStandbyResult> | ||||||
|  |   <ResponseMetadata> | ||||||
|  |     <RequestId>7c6e177f-f082-11e1-ac58-3714bEXAMPLE</RequestId> | ||||||
|  |   </ResponseMetadata> | ||||||
|  | </ExitStandbyResponse>""" | ||||||
|  | 
 | ||||||
|  | TERMINATE_INSTANCES_TEMPLATE = """<TerminateInstanceInAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/"> | ||||||
|  |   <TerminateInstanceInAutoScalingGroupResult> | ||||||
|  |     <Activity> | ||||||
|  |       <ActivityId>35b5c464-0b63-2fc7-1611-467d4a7f2497EXAMPLE</ActivityId> | ||||||
|  |       <AutoScalingGroupName>{{ group_name }}</AutoScalingGroupName> | ||||||
|  |       {% if should_decrement %} | ||||||
|  |       <Cause>At {{ timestamp }} instance {{ instance.instance.id }} was taken out of service in response to a user request, shrinking the capacity from {{ original_size }} to {{ desired_capacity }}.</Cause> | ||||||
|  |       {% else %} | ||||||
|  |       <Cause>At {{ timestamp }} instance {{ instance.instance.id }} was taken out of service in response to a user request.</Cause> | ||||||
|  |       {% endif %} | ||||||
|  |       <Description>Terminating EC2 instance: {{ instance.instance.id }}</Description> | ||||||
|  |       <Progress>0</Progress> | ||||||
|  |       <StartTime>{{ timestamp }}</StartTime> | ||||||
|  |       <Details>{"Subnet ID":"??","Availability Zone":"{{ instance.instance.placement }}"}</Details> | ||||||
|  |       <StatusCode>InProgress</StatusCode> | ||||||
|  |     </Activity> | ||||||
|  |   </TerminateInstanceInAutoScalingGroupResult> | ||||||
|  |   <ResponseMetadata> | ||||||
|  |     <RequestId>a1ba8fb9-31d6-4d9a-ace1-a7f76749df11EXAMPLE</RequestId> | ||||||
|  |   </ResponseMetadata> | ||||||
|  | </TerminateInstanceInAutoScalingGroupResponse>""" | ||||||
|  | |||||||
| @ -1102,8 +1102,6 @@ def test_detach_one_instance_decrement(): | |||||||
| 
 | 
 | ||||||
|     ec2_client = boto3.client("ec2", region_name="us-east-1") |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
| 
 | 
 | ||||||
|     response = ec2_client.describe_instances(InstanceIds=[instance_to_detach]) |  | ||||||
| 
 |  | ||||||
|     response = client.detach_instances( |     response = client.detach_instances( | ||||||
|         AutoScalingGroupName="test_asg", |         AutoScalingGroupName="test_asg", | ||||||
|         InstanceIds=[instance_to_detach], |         InstanceIds=[instance_to_detach], | ||||||
| @ -1156,8 +1154,6 @@ def test_detach_one_instance(): | |||||||
| 
 | 
 | ||||||
|     ec2_client = boto3.client("ec2", region_name="us-east-1") |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
| 
 | 
 | ||||||
|     response = ec2_client.describe_instances(InstanceIds=[instance_to_detach]) |  | ||||||
| 
 |  | ||||||
|     response = client.detach_instances( |     response = client.detach_instances( | ||||||
|         AutoScalingGroupName="test_asg", |         AutoScalingGroupName="test_asg", | ||||||
|         InstanceIds=[instance_to_detach], |         InstanceIds=[instance_to_detach], | ||||||
| @ -1178,6 +1174,516 @@ def test_detach_one_instance(): | |||||||
|     tags.should.have.length_of(2) |     tags.should.have.length_of(2) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_one_instance_decrement(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=2, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby = response["AutoScalingGroups"][0]["Instances"][0]["InstanceId"] | ||||||
|  |     instance_to_keep = response["AutoScalingGroups"][0]["Instances"][1]["InstanceId"] | ||||||
|  | 
 | ||||||
|  |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby], | ||||||
|  |         ShouldDecrementDesiredCapacity=True, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(2) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(1) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances(InstanceIds=[instance_to_standby]) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     # test to ensure tag has been retained (standby instance is still part of the ASG) | ||||||
|  |     response = ec2_client.describe_instances() | ||||||
|  |     for reservation in response["Reservations"]: | ||||||
|  |         for instance in reservation["Instances"]: | ||||||
|  |             tags = instance["Tags"] | ||||||
|  |             tags.should.have.length_of(2) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_one_instance(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=2, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby = response["AutoScalingGroups"][0]["Instances"][0]["InstanceId"] | ||||||
|  |     instance_to_keep = response["AutoScalingGroups"][0]["Instances"][1]["InstanceId"] | ||||||
|  | 
 | ||||||
|  |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(3) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances(InstanceIds=[instance_to_standby]) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     # test to ensure tag has been retained (standby instance is still part of the ASG) | ||||||
|  |     response = ec2_client.describe_instances() | ||||||
|  |     for reservation in response["Reservations"]: | ||||||
|  |         for instance in reservation["Instances"]: | ||||||
|  |             tags = instance["Tags"] | ||||||
|  |             tags.should.have.length_of(2) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_elb | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_elb_update(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=2, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     elb_client = boto3.client("elb", region_name="us-east-1") | ||||||
|  |     elb_client.create_load_balancer( | ||||||
|  |         LoadBalancerName="my-lb", | ||||||
|  |         Listeners=[{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}], | ||||||
|  |         AvailabilityZones=["us-east-1a", "us-east-1b"], | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.attach_load_balancers( | ||||||
|  |         AutoScalingGroupName="test_asg", LoadBalancerNames=["my-lb"] | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby = response["AutoScalingGroups"][0]["Instances"][0]["InstanceId"] | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(3) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances(InstanceIds=[instance_to_standby]) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     response = elb_client.describe_load_balancers(LoadBalancerNames=["my-lb"]) | ||||||
|  |     list(response["LoadBalancerDescriptions"][0]["Instances"]).should.have.length_of(2) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_terminate_instance_decrement(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=3, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby_terminate = response["AutoScalingGroups"][0]["Instances"][0][ | ||||||
|  |         "InstanceId" | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby_terminate], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(3) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_terminate] | ||||||
|  |     ) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     response = client.terminate_instance_in_auto_scaling_group( | ||||||
|  |         InstanceId=instance_to_standby_terminate, ShouldDecrementDesiredCapacity=True | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     # AWS still decrements desired capacity ASG if requested, even if the terminated instance is in standby | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(1) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"][0]["InstanceId"].should_not.equal( | ||||||
|  |         instance_to_standby_terminate | ||||||
|  |     ) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(1) | ||||||
|  | 
 | ||||||
|  |     response = ec2_client.describe_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_terminate] | ||||||
|  |     ) | ||||||
|  |     response["Reservations"][0]["Instances"][0]["State"]["Name"].should.equal( | ||||||
|  |         "terminated" | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_terminate_instance_no_decrement(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=3, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby_terminate = response["AutoScalingGroups"][0]["Instances"][0][ | ||||||
|  |         "InstanceId" | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby_terminate], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(3) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_terminate] | ||||||
|  |     ) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     response = client.terminate_instance_in_auto_scaling_group( | ||||||
|  |         InstanceId=instance_to_standby_terminate, ShouldDecrementDesiredCapacity=False | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     group = response["AutoScalingGroups"][0] | ||||||
|  |     group["Instances"].should.have.length_of(2) | ||||||
|  |     instance_to_standby_terminate.shouldnt.be.within( | ||||||
|  |         [x["InstanceId"] for x in group["Instances"]] | ||||||
|  |     ) | ||||||
|  |     group["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = ec2_client.describe_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_terminate] | ||||||
|  |     ) | ||||||
|  |     response["Reservations"][0]["Instances"][0]["State"]["Name"].should.equal( | ||||||
|  |         "terminated" | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_detach_instance_decrement(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=3, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby_detach = response["AutoScalingGroups"][0]["Instances"][0][ | ||||||
|  |         "InstanceId" | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby_detach], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(3) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_detach] | ||||||
|  |     ) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     response = client.detach_instances( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby_detach], | ||||||
|  |         ShouldDecrementDesiredCapacity=True, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     # AWS still decrements desired capacity ASG if requested, even if the detached instance was in standby | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(1) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"][0]["InstanceId"].should_not.equal( | ||||||
|  |         instance_to_standby_detach | ||||||
|  |     ) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(1) | ||||||
|  | 
 | ||||||
|  |     response = ec2_client.describe_instances(InstanceIds=[instance_to_standby_detach]) | ||||||
|  |     response["Reservations"][0]["Instances"][0]["State"]["Name"].should.equal("running") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_detach_instance_no_decrement(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=3, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby_detach = response["AutoScalingGroups"][0]["Instances"][0][ | ||||||
|  |         "InstanceId" | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby_detach], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(3) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_detach] | ||||||
|  |     ) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     response = client.detach_instances( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby_detach], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     group = response["AutoScalingGroups"][0] | ||||||
|  |     group["Instances"].should.have.length_of(2) | ||||||
|  |     instance_to_standby_detach.shouldnt.be.within( | ||||||
|  |         [x["InstanceId"] for x in group["Instances"]] | ||||||
|  |     ) | ||||||
|  |     group["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = ec2_client.describe_instances(InstanceIds=[instance_to_standby_detach]) | ||||||
|  |     response["Reservations"][0]["Instances"][0]["State"]["Name"].should.equal("running") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_standby_exit_standby(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         MaxSize=3, | ||||||
|  |         DesiredCapacity=2, | ||||||
|  |         Tags=[ | ||||||
|  |             { | ||||||
|  |                 "ResourceId": "test_asg", | ||||||
|  |                 "ResourceType": "auto-scaling-group", | ||||||
|  |                 "Key": "propogated-tag-key", | ||||||
|  |                 "Value": "propagate-tag-value", | ||||||
|  |                 "PropagateAtLaunch": True, | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     instance_to_standby_exit_standby = response["AutoScalingGroups"][0]["Instances"][0][ | ||||||
|  |         "InstanceId" | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||||
|  | 
 | ||||||
|  |     response = client.enter_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         InstanceIds=[instance_to_standby_exit_standby], | ||||||
|  |         ShouldDecrementDesiredCapacity=False, | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.have.length_of(3) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(2) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_exit_standby] | ||||||
|  |     ) | ||||||
|  |     response["AutoScalingInstances"][0]["LifecycleState"].should.equal("Standby") | ||||||
|  | 
 | ||||||
|  |     response = client.exit_standby( | ||||||
|  |         AutoScalingGroupName="test_asg", InstanceIds=[instance_to_standby_exit_standby], | ||||||
|  |     ) | ||||||
|  |     response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     group = response["AutoScalingGroups"][0] | ||||||
|  |     group["Instances"].should.have.length_of(3) | ||||||
|  |     instance_to_standby_exit_standby.should.be.within( | ||||||
|  |         [x["InstanceId"] for x in group["Instances"]] | ||||||
|  |     ) | ||||||
|  |     group["DesiredCapacity"].should.equal(3) | ||||||
|  | 
 | ||||||
|  |     response = ec2_client.describe_instances( | ||||||
|  |         InstanceIds=[instance_to_standby_exit_standby] | ||||||
|  |     ) | ||||||
|  |     response["Reservations"][0]["Instances"][0]["State"]["Name"].should.equal("running") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @mock_autoscaling | @mock_autoscaling | ||||||
| @mock_ec2 | @mock_ec2 | ||||||
| def test_attach_one_instance(): | def test_attach_one_instance(): | ||||||
| @ -1411,7 +1917,7 @@ def test_set_desired_capacity_down_boto3(): | |||||||
| 
 | 
 | ||||||
| @mock_autoscaling | @mock_autoscaling | ||||||
| @mock_ec2 | @mock_ec2 | ||||||
| def test_terminate_instance_in_autoscaling_group(): | def test_terminate_instance_via_ec2_in_autoscaling_group(): | ||||||
|     mocked_networking = setup_networking() |     mocked_networking = setup_networking() | ||||||
|     client = boto3.client("autoscaling", region_name="us-east-1") |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|     _ = client.create_launch_configuration( |     _ = client.create_launch_configuration( | ||||||
| @ -1440,3 +1946,71 @@ def test_terminate_instance_in_autoscaling_group(): | |||||||
|         for instance in response["AutoScalingGroups"][0]["Instances"] |         for instance in response["AutoScalingGroups"][0]["Instances"] | ||||||
|     ) |     ) | ||||||
|     replaced_instance_id.should_not.equal(original_instance_id) |     replaced_instance_id.should_not.equal(original_instance_id) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_terminate_instance_in_auto_scaling_group_decrement(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     _ = client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         DesiredCapacity=1, | ||||||
|  |         MaxSize=2, | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |         NewInstancesProtectedFromScaleIn=False, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     original_instance_id = next( | ||||||
|  |         instance["InstanceId"] | ||||||
|  |         for instance in response["AutoScalingGroups"][0]["Instances"] | ||||||
|  |     ) | ||||||
|  |     client.terminate_instance_in_auto_scaling_group( | ||||||
|  |         InstanceId=original_instance_id, ShouldDecrementDesiredCapacity=True | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     response["AutoScalingGroups"][0]["Instances"].should.equal([]) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(0) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_autoscaling | ||||||
|  | @mock_ec2 | ||||||
|  | def test_terminate_instance_in_auto_scaling_group_no_decrement(): | ||||||
|  |     mocked_networking = setup_networking() | ||||||
|  |     client = boto3.client("autoscaling", region_name="us-east-1") | ||||||
|  |     _ = client.create_launch_configuration( | ||||||
|  |         LaunchConfigurationName="test_launch_configuration" | ||||||
|  |     ) | ||||||
|  |     _ = client.create_auto_scaling_group( | ||||||
|  |         AutoScalingGroupName="test_asg", | ||||||
|  |         LaunchConfigurationName="test_launch_configuration", | ||||||
|  |         MinSize=0, | ||||||
|  |         DesiredCapacity=1, | ||||||
|  |         MaxSize=2, | ||||||
|  |         VPCZoneIdentifier=mocked_networking["subnet1"], | ||||||
|  |         NewInstancesProtectedFromScaleIn=False, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     original_instance_id = next( | ||||||
|  |         instance["InstanceId"] | ||||||
|  |         for instance in response["AutoScalingGroups"][0]["Instances"] | ||||||
|  |     ) | ||||||
|  |     client.terminate_instance_in_auto_scaling_group( | ||||||
|  |         InstanceId=original_instance_id, ShouldDecrementDesiredCapacity=False | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     response = client.describe_auto_scaling_groups(AutoScalingGroupNames=["test_asg"]) | ||||||
|  |     replaced_instance_id = next( | ||||||
|  |         instance["InstanceId"] | ||||||
|  |         for instance in response["AutoScalingGroups"][0]["Instances"] | ||||||
|  |     ) | ||||||
|  |     replaced_instance_id.should_not.equal(original_instance_id) | ||||||
|  |     response["AutoScalingGroups"][0]["DesiredCapacity"].should.equal(1) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user