From 6ae4e50e4740dc17791747c0ef29ad90b73f2347 Mon Sep 17 00:00:00 2001 From: Ryan Brown Date: Fri, 9 Sep 2016 19:38:05 -0400 Subject: [PATCH] Fix failure when powering on/off EC2 instances by tag only. (#4767) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you apply `wait=yes` and use `instance_tags` as your filter for stopping/starting EC2 instances, this stack trace happens: ``` An exception occurred during task execution. The full traceback is: │~ Traceback (most recent call last): │~ File "/tmp/ryansb/ansible_FwE8VR/ansible_module_ec2.py", line 1540, in │~ main() │~ File "/tmp/ryansb/ansible_FwE8VR/ansible_module_ec2.py", line 1514, in main │~ (changed, instance_dict_array, new_instance_ids) = startstop_instances(module, ec2, instance_ids, state, instance_tags) │~ File "/tmp/ryansb/ansible_FwE8VR/ansible_module_ec2.py", line 1343, in startstop_instances │~ if len(matched_instances) < len(instance_ids): │~ TypeError: object of type 'NoneType' has no len() │~ │~ fatal: [localhost -> localhost]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_name": "ec2"}, "module_stderr": "Traceb│~ ack (most recent call last):\n File \"/tmp/ryansb/ansible_FwE8VR/ansible_module_ec2.py\", line 1540, in \n main()\n File \"/tmp/│~ ryansb/ansible_FwE8VR/ansible_module_ec2.py\", line 1514, in main\n (changed, instance_dict_array, new_instance_ids) = startstop_instances│~ (module, ec2, instance_ids, state, instance_tags)\n File \"/tmp/ryansb/ansible_FwE8VR/ansible_module_ec2.py\", line 1343, in startstop_insta│~ nces\n if len(matched_instances) < len(instance_ids):\nTypeError: object of type 'NoneType' has no len()\n", "module_stdout": "", "msg": "│~ MODULE FAILURE", "parsed": false} ``` That's because the `instance_ids` variable is None if not supplied in the task. That means the instances that result from the instance_tags query aren't going to be included in the wait loop. To fix this, a list needs to be kept of instances with matching tags and that list needs to be added to `instance_ids` before the wait loop. --- lib/ansible/modules/cloud/amazon/ec2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ansible/modules/cloud/amazon/ec2.py b/lib/ansible/modules/cloud/amazon/ec2.py index 7c26b84bc1..57bf07ca5a 100755 --- a/lib/ansible/modules/cloud/amazon/ec2.py +++ b/lib/ansible/modules/cloud/amazon/ec2.py @@ -1302,7 +1302,7 @@ def startstop_instances(module, ec2, instance_ids, state, instance_tags): # Check that our instances are not in the state we want to take # Check (and eventually change) instances attributes and instances state - running_instances_array = [] + existing_instances_array = [] for res in ec2.get_all_instances(instance_ids, filters=filters): for inst in res.instances: @@ -1327,7 +1327,9 @@ def startstop_instances(module, ec2, instance_ids, state, instance_tags): except EC2ResponseError as e: module.fail_json(msg='Unable to change state for instance {0}, error: {1}'.format(inst.id, e)) changed = True + existing_instances_array.append(inst.id) + instance_ids = list(set(existing_instances_array + (instance_ids or []))) ## Wait for all the instances to finish starting or stopping wait_timeout = time.time() + wait_timeout while wait and wait_timeout > time.time():