Repository: getmoto/moto

Issue:
Implement suspend_processes in AutoScaling service
I am using moto `1.1.25` and when I try and mock `client.suspend_processes()` I get:

```
NotImplementedError: The suspend_processes action has not been implemented
```

I searched issues for `suspend_processes` and had no hits so assuming this feature hasn't been requested yet?



Discussion:
Can I get a simple test case for this, then I'll go and add it
Sure, here would be an example test case:
```
@mock_autoscaling
def test_asg():
    client = boto3.client('autoscaling')
    client.create_launch_configuration(
        LaunchConfigurationName='lc',
    )
    client.create_auto_scaling_group(
        LaunchConfigurationName='lc',
        AutoScalingGroupName='test-asg',
        MinSize=1,
        MaxSize=1,
    )

    # Testing something that calls the below...
    client.suspend_processes(
        AutoScalingGroupName='test-asg',
        ScalingProcesses=['Launch']
    )

    res = client.describe_auto_scaling_groups(
        AutoScalingGroupNames=['test-asg']
    )
    launch_suspended = False
    for proc in res['AutoScalingGroups'][0]['SuspendedProcesses']:
        if proc.get('ProcessName') == 'Launch':
            launch_suspended = True

    assert launch_suspended is True
```

Resolving patch:
diff --git a/moto/autoscaling/models.py b/moto/autoscaling/models.py
--- a/moto/autoscaling/models.py
+++ b/moto/autoscaling/models.py
@@ -179,6 +179,7 @@ def __init__(self, name, availability_zones, desired_capacity, max_size,
         self.placement_group = placement_group
         self.termination_policies = termination_policies
 
+        self.suspended_processes = []
         self.instance_states = []
         self.tags = tags if tags else []
         self.set_desired_capacity(desired_capacity)
@@ -621,6 +622,10 @@ def detach_load_balancer_target_groups(self, group_name, target_group_arns):
             asg_targets = [{'id': x.instance.id} for x in group.instance_states]
             self.elbv2_backend.deregister_targets(target_group, (asg_targets))
 
+    def suspend_processes(self, group_name, scaling_processes):
+        group = self.autoscaling_groups[group_name]
+        group.suspended_processes = scaling_processes or []
+
 
 autoscaling_backends = {}
 for region, ec2_backend in ec2_backends.items():
diff --git a/moto/autoscaling/responses.py b/moto/autoscaling/responses.py
--- a/moto/autoscaling/responses.py
+++ b/moto/autoscaling/responses.py
@@ -283,6 +283,13 @@ def detach_load_balancers(self):
         template = self.response_template(DETACH_LOAD_BALANCERS_TEMPLATE)
         return template.render()
 
+    def suspend_processes(self):
+        autoscaling_group_name = self._get_param('AutoScalingGroupName')
+        scaling_processes = self._get_multi_param('ScalingProcesses.member')
+        self.autoscaling_backend.suspend_processes(autoscaling_group_name, scaling_processes)
+        template = self.response_template(SUSPEND_PROCESSES_TEMPLATE)
+        return template.render()
+
 
 CREATE_LAUNCH_CONFIGURATION_TEMPLATE = """<CreateLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
 <ResponseMetadata>
@@ -463,7 +470,14 @@ def detach_load_balancers(self):
           </member>
           {% endfor %}
         </Tags>
-        <SuspendedProcesses/>
+        <SuspendedProcesses>
+          {% for suspended_process in group.suspended_processes %}
+          <member>
+            <ProcessName>{{suspended_process}}</ProcessName>
+            <SuspensionReason></SuspensionReason>
+          </member>
+          {% endfor %}
+        </SuspendedProcesses>
         <AutoScalingGroupName>{{ group.name }}</AutoScalingGroupName>
         <HealthCheckType>{{ group.health_check_type }}</HealthCheckType>
         <CreatedTime>2013-05-06T17:47:15.107Z</CreatedTime>
@@ -644,6 +658,12 @@ def detach_load_balancers(self):
 </ResponseMetadata>
 </DetachLoadBalancersResponse>"""
 
+SUSPEND_PROCESSES_TEMPLATE = """<SuspendProcessesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+<ResponseMetadata>
+   <RequestId>7c6e177f-f082-11e1-ac58-3714bEXAMPLE</RequestId>
+</ResponseMetadata>
+</SuspendProcessesResponse>"""
+
 SET_INSTANCE_HEALTH_TEMPLATE = """<SetInstanceHealthResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
 <SetInstanceHealthResponse></SetInstanceHealthResponse>
 <ResponseMetadata>


Test patch:
diff --git a/tests/test_autoscaling/test_autoscaling.py b/tests/test_autoscaling/test_autoscaling.py
--- a/tests/test_autoscaling/test_autoscaling.py
+++ b/tests/test_autoscaling/test_autoscaling.py
@@ -1067,3 +1067,36 @@ def test_set_instance_health():
 
     instance1 = response['AutoScalingGroups'][0]['Instances'][0]
     instance1['HealthStatus'].should.equal('Unhealthy')
+
+@mock_autoscaling
+def test_suspend_processes():
+    mocked_networking = setup_networking()
+    client = boto3.client('autoscaling', region_name='us-east-1')
+    client.create_launch_configuration(
+        LaunchConfigurationName='lc',
+    )
+    client.create_auto_scaling_group(
+        LaunchConfigurationName='lc',
+        AutoScalingGroupName='test-asg',
+        MinSize=1,
+        MaxSize=1,
+        VPCZoneIdentifier=mocked_networking['subnet1'],
+    )
+
+    # When we suspend the 'Launch' process on the ASG client
+    client.suspend_processes(
+        AutoScalingGroupName='test-asg',
+        ScalingProcesses=['Launch']
+    )
+
+    res = client.describe_auto_scaling_groups(
+        AutoScalingGroupNames=['test-asg']
+    )
+
+    # The 'Launch' process should, in fact, be suspended
+    launch_suspended = False
+    for proc in res['AutoScalingGroups'][0]['SuspendedProcesses']:
+        if proc.get('ProcessName') == 'Launch':
+            launch_suspended = True
+
+    assert launch_suspended is True