Implement enter_standby, exit_standby and terminate_instance_in_auto_scaling_group
This commit is contained in:
		
							parent
							
								
									755a08e137
								
							
						
					
					
						commit
						d745dfd3d2
					
				| @ -267,6 +267,9 @@ class FakeAutoScalingGroup(BaseModel): | ||||
|         self.tags = tags if tags else [] | ||||
|         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): | ||||
|         # for updates, if only AZs are provided, they must not clash with | ||||
|         # the AZs of existing VPCs | ||||
| @ -413,9 +416,11 @@ class FakeAutoScalingGroup(BaseModel): | ||||
|         else: | ||||
|             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: | ||||
|             self.autoscaling_backend.update_attached_elbs(self.name) | ||||
|             self.autoscaling_backend.update_attached_target_groups(self.name) | ||||
|             return | ||||
| 
 | ||||
|         if self.desired_capacity > curr_instance_count: | ||||
| @ -442,6 +447,8 @@ class FakeAutoScalingGroup(BaseModel): | ||||
|                 self.instance_states = list( | ||||
|                     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): | ||||
|         propagated_tags = {} | ||||
| @ -703,7 +710,7 @@ class AutoScalingBackend(BaseBackend): | ||||
| 
 | ||||
|     def detach_instances(self, group_name, instance_ids, should_decrement): | ||||
|         group = self.autoscaling_groups[group_name] | ||||
|         original_size = len(group.instance_states) | ||||
|         original_size = group.desired_capacity | ||||
| 
 | ||||
|         detached_instances = [ | ||||
|             x for x in group.instance_states if x.instance.id in instance_ids | ||||
| @ -720,13 +727,8 @@ class AutoScalingBackend(BaseBackend): | ||||
| 
 | ||||
|         if should_decrement: | ||||
|             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 | ||||
| 
 | ||||
|     def set_desired_capacity(self, group_name, desired_capacity): | ||||
| @ -791,7 +793,9 @@ class AutoScalingBackend(BaseBackend): | ||||
| 
 | ||||
|     def update_attached_elbs(self, 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 | ||||
|         # otherwise elb_backend.describe_load_balancers returns all available load balancers | ||||
| @ -908,15 +912,15 @@ class AutoScalingBackend(BaseBackend): | ||||
|             autoscaling_group_name, | ||||
|             autoscaling_group, | ||||
|         ) 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( | ||||
|                 filter( | ||||
|                     lambda i_state: i_state.instance.id not in instance_ids, | ||||
|                     autoscaling_group.instance_states, | ||||
|                 ) | ||||
|             ) | ||||
|             difference = original_instance_count - len( | ||||
|                 autoscaling_group.instance_states | ||||
|             difference = original_active_instance_count - len( | ||||
|                 autoscaling_group.active_instances() | ||||
|             ) | ||||
|             if difference > 0: | ||||
|                 autoscaling_group.replace_autoscaling_group_instances( | ||||
| @ -924,6 +928,45 @@ class AutoScalingBackend(BaseBackend): | ||||
|                 ) | ||||
|                 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 = {} | ||||
| for region, ec2_backend in ec2_backends.items(): | ||||
|  | ||||
| @ -1,7 +1,12 @@ | ||||
| from __future__ import unicode_literals | ||||
| import datetime | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| 
 | ||||
| @ -291,6 +296,50 @@ class AutoScalingResponse(BaseResponse): | ||||
|         template = self.response_template(DETACH_LOAD_BALANCERS_TEMPLATE) | ||||
|         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): | ||||
|         autoscaling_group_name = self._get_param("AutoScalingGroupName") | ||||
|         scaling_processes = self._get_multi_param("ScalingProcesses.member") | ||||
| @ -310,6 +359,29 @@ class AutoScalingResponse(BaseResponse): | ||||
|         template = self.response_template(SET_INSTANCE_PROTECTION_TEMPLATE) | ||||
|         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/"> | ||||
| <ResponseMetadata> | ||||
| @ -707,3 +779,73 @@ SET_INSTANCE_PROTECTION_TEMPLATE = """<SetInstanceProtectionResponse xmlns="http | ||||
| <RequestId></RequestId> | ||||
| </ResponseMetadata> | ||||
| </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") | ||||
| 
 | ||||
|     response = ec2_client.describe_instances(InstanceIds=[instance_to_detach]) | ||||
| 
 | ||||
|     response = client.detach_instances( | ||||
|         AutoScalingGroupName="test_asg", | ||||
|         InstanceIds=[instance_to_detach], | ||||
| @ -1156,8 +1154,6 @@ def test_detach_one_instance(): | ||||
| 
 | ||||
|     ec2_client = boto3.client("ec2", region_name="us-east-1") | ||||
| 
 | ||||
|     response = ec2_client.describe_instances(InstanceIds=[instance_to_detach]) | ||||
| 
 | ||||
|     response = client.detach_instances( | ||||
|         AutoScalingGroupName="test_asg", | ||||
|         InstanceIds=[instance_to_detach], | ||||
| @ -1178,6 +1174,516 @@ def test_detach_one_instance(): | ||||
|     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_ec2 | ||||
| def test_attach_one_instance(): | ||||
| @ -1411,7 +1917,7 @@ def test_set_desired_capacity_down_boto3(): | ||||
| 
 | ||||
| @mock_autoscaling | ||||
| @mock_ec2 | ||||
| def test_terminate_instance_in_autoscaling_group(): | ||||
| def test_terminate_instance_via_ec2_in_autoscaling_group(): | ||||
|     mocked_networking = setup_networking() | ||||
|     client = boto3.client("autoscaling", region_name="us-east-1") | ||||
|     _ = client.create_launch_configuration( | ||||
| @ -1440,3 +1946,71 @@ def test_terminate_instance_in_autoscaling_group(): | ||||
|         for instance in response["AutoScalingGroups"][0]["Instances"] | ||||
|     ) | ||||
|     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