# Buggy code
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            key_name=dict(aliases=["keypair"]),
            id=dict(),
            group=dict(type="list", aliases=["groups"]),
            group_id=dict(type="list"),
            zone=dict(aliases=["aws_zone", "ec2_zone"]),
            instance_type=dict(aliases=["type"]),
            spot_price=dict(),
            spot_type=dict(default="one-time", choices=["one-time", "persistent"]),
            spot_launch_group=dict(),
            image=dict(),
            kernel=dict(),
            count=dict(type="int", default="1"),
            monitoring=dict(type="bool", default=False),
            ramdisk=dict(),
            wait=dict(type="bool", default=False),
            wait_timeout=dict(default=300),
            spot_wait_timeout=dict(default=600),
            placement_group=dict(),
            user_data=dict(),
            instance_tags=dict(type="dict"),
            vpc_subnet_id=dict(),
            assign_public_ip=dict(type="bool", default=False),
            private_ip=dict(),
            instance_profile_name=dict(),
            instance_ids=dict(type="list", aliases=["instance_id"]),
            source_dest_check=dict(type="bool", default=True),
            termination_protection=dict(type="bool", default=None),
            state=dict(
                default="present",
                choices=["present", "absent", "running", "restarted", "stopped"],
            ),
            instance_initiated_shutdown_behavior=dict(
                default=None, choices=["stop", "terminate"]
            ),
            exact_count=dict(type="int", default=None),
            count_tag=dict(),
            volumes=dict(type="list"),
            ebs_optimized=dict(type="bool", default=False),
            tenancy=dict(default="default"),
            network_interfaces=dict(type="list", aliases=["network_interface"]),
        )
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        mutually_exclusive=[
            ["group_name", "group_id"],
            ["exact_count", "count"],
            ["exact_count", "state"],
            ["exact_count", "instance_ids"],
            ["network_interfaces", "assign_public_ip"],
            ["network_interfaces", "group"],
            ["network_interfaces", "group_id"],
            ["network_interfaces", "private_ip"],
            ["network_interfaces", "vpc_subnet_id"],
        ],
    )

    if not HAS_BOTO:
        module.fail_json(msg="boto required for this module")

    try:
        _, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
        if module.params.get("region") or not module.params.get("ec2_url"):
            ec2 = ec2_connect(module)
        elif module.params.get("ec2_url"):
            ec2 = connect_ec2_endpoint(ec2_url, **aws_connect_kwargs)

        vpc = connect_vpc(**aws_connect_kwargs)
    except boto.exception.NoAuthHandlerFound as e:
        module.fail_json(
            msg="Failed to get connection: %s" % e.message,
            exception=traceback.format_exc(),
        )

    tagged_instances = []

    state = module.params["state"]

    if state == "absent":
        instance_ids = module.params["instance_ids"]
        if not instance_ids:
            module.fail_json(msg="instance_ids list is required for absent state")

        (changed, instance_dict_array, new_instance_ids) = terminate_instances(
            module, ec2, instance_ids
        )

    elif state in ("running", "stopped"):
        instance_ids = module.params.get("instance_ids")
        instance_tags = module.params.get("instance_tags")
        if not (isinstance(instance_ids, list) or isinstance(instance_tags, dict)):
            module.fail_json(
                msg="running list needs to be a list of instances or set of tags to run: %s"
                % instance_ids
            )

        (changed, instance_dict_array, new_instance_ids) = startstop_instances(
            module, ec2, instance_ids, state, instance_tags
        )

    elif state in ("restarted"):
        instance_ids = module.params.get("instance_ids")
        instance_tags = module.params.get("instance_tags")
        if not (isinstance(instance_ids, list) or isinstance(instance_tags, dict)):
            module.fail_json(
                msg="running list needs to be a list of instances or set of tags to run: %s"
                % instance_ids
            )

        (changed, instance_dict_array, new_instance_ids) = restart_instances(
            module, ec2, instance_ids, state, instance_tags
        )

    elif state == "present":
        # Changed is always set to true when provisioning new instances
        if not module.params.get("image"):
            module.fail_json(msg="image parameter is required for new instance")

        if module.params.get("exact_count") is None:
            (instance_dict_array, new_instance_ids, changed) = create_instances(
                module, ec2, vpc
            )
        else:
            (tagged_instances, instance_dict_array, new_instance_ids, changed) = (
                enforce_count(module, ec2, vpc)
            )

    module.exit_json(
        changed=changed,
        instance_ids=new_instance_ids,
        instances=instance_dict_array,
        tagged_instances=tagged_instances,
    )


# Traceback (boto.exception.EC2ResponseError)
Using module_utils file /Users/jmorgan/tmp/ansible/lib/ansible/module_utils/basic.py
Using module_utils file /Users/jmorgan/tmp/ansible/lib/ansible/module_utils/ec2.py
Using module_utils file /Users/jmorgan/tmp/ansible/lib/ansible/module_utils/six/__init__.py
Using module_utils file /Users/jmorgan/tmp/ansible/lib/ansible/module_utils/_text.py
Using module_utils file /Users/jmorgan/tmp/ansible/lib/ansible/module_utils/pycompat24.py
Using module_utils file /Users/jmorgan/tmp/ansible/lib/ansible/module_utils/cloud.py
Using module_utils file /Users/jmorgan/tmp/ansible/lib/ansible/module_utils/six/_six.py
Using module file /Users/jmorgan/tmp/ansible/lib/ansible/modules/cloud/amazon/ec2.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: jmorgan
<localhost> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo /tmp/ansible-$USER/tmp/ansible-tmp-1497405139.06-173735515787978 `" &amp;&amp; echo ansible-tmp-1497405139.06-173735515787978="` echo /tmp/ansible-$USER/tmp/ansible-tmp-1497405139.06-173735515787978 `" ) &amp;&amp; sleep 0'
<localhost> PUT /var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/tmp2mUYrZ TO /tmp/ansible-jmorgan/tmp/ansible-tmp-1497405139.06-173735515787978/ec2.py
<localhost> EXEC /bin/sh -c 'chmod u+x /tmp/ansible-jmorgan/tmp/ansible-tmp-1497405139.06-173735515787978/ /tmp/ansible-jmorgan/tmp/ansible-tmp-1497405139.06-173735515787978/ec2.py &amp;&amp; sleep 0'
<localhost> EXEC /bin/sh -c '/usr/local/opt/python/bin/python2.7 /tmp/ansible-jmorgan/tmp/ansible-tmp-1497405139.06-173735515787978/ec2.py; rm -rf "/tmp/ansible-jmorgan/tmp/ansible-tmp-1497405139.06-173735515787978/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
The full traceback is:
Traceback (most recent call last):
File "/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py", line 1675, in <module>
main()
File "/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py", line 1669, in main
(tagged_instances, instance_dict_array, new_instance_ids, changed) = enforce_count(module, ec2, vpc)
File "/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py", line 949, in enforce_count
= create_instances(module, ec2, vpc, override_count=to_create)
File "/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py", line 1034, in create_instances
vpc_id = vpc.get_all_subnets(subnet_ids=[vpc_subnet_id])[0].vpc_id
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/boto/vpc/__init__.py", line 1153, in get_all_subnets
return self.get_list('DescribeSubnets', params, [('item', Subnet)])
File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/boto/connection.py", line 1186, in get_list
raise self.ResponseError(response.status, response.reason, body)
boto.exception.EC2ResponseError: EC2ResponseError: 400 Bad Request
<?xml version="1.0" encoding="UTF-8"?>
<Response><Errors><Error><Code>InvalidSubnetID.NotFound</Code><Message>The subnet ID 'subnet-42c96f34' does not exist</Message></Error></Errors><RequestID>2e1f90ed-9c0d-4490-a4e8-e2005985a3b3</RequestID></Response>

fatal: [localhost -> localhost]: FAILED! => {
"changed": false,
"failed": true,
"module_stderr": "Traceback (most recent call last):\n  File \"/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py\", line 1675, in <module>\n    main()\n  File \"/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py\", line 1669, in main\n    (tagged_instances, instance_dict_array, new_instance_ids, changed) = enforce_count(module, ec2, vpc)\n  File \"/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py\", line 949, in enforce_count\n    = create_instances(module, ec2, vpc, override_count=to_create)\n  File \"/var/folders/yt/1w3x85v95qd3kt50624tzgww0000gn/T/ansible_Q79IEm/ansible_module_ec2.py\", line 1034, in create_instances\n    vpc_id = vpc.get_all_subnets(subnet_ids=[vpc_subnet_id])[0].vpc_id\n  File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/boto/vpc/__init__.py\", line 1153, in get_all_subnets\n    return self.get_list('DescribeSubnets', params, [('item', Subnet)])\n  File \"/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/boto/connection.py\", line 1186, in get_list\n    raise self.ResponseError(response.status, response.reason, body)\nboto.exception.EC2ResponseError: EC2ResponseError: 400 Bad Request\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response><Errors><Error><Code>InvalidSubnetID.NotFound</Code><Message>The subnet ID 'subnet-42c96f34' does not exist</Message></Error></Errors><RequestID>2e1f90ed-9c0d-4490-a4e8-e2005985a3b3</RequestID></Response>\n",
"module_stdout": "",
"msg": "MODULE FAILURE",
"rc": 0
}
to retry, use: --limit @/Users/jmorgan/git/sovereign/ansible/deploy.retry

PLAY RECAP **********************************************************************************************************************************************************************************************
localhost                  : ok=6    changed=1    unreachable=0    failed=1

# Fixed code
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            key_name=dict(aliases=["keypair"]),
            id=dict(),
            group=dict(type="list", aliases=["groups"]),
            group_id=dict(type="list"),
            zone=dict(aliases=["aws_zone", "ec2_zone"]),
            instance_type=dict(aliases=["type"]),
            spot_price=dict(),
            spot_type=dict(default="one-time", choices=["one-time", "persistent"]),
            spot_launch_group=dict(),
            image=dict(),
            kernel=dict(),
            count=dict(type="int", default="1"),
            monitoring=dict(type="bool", default=False),
            ramdisk=dict(),
            wait=dict(type="bool", default=False),
            wait_timeout=dict(default=300),
            spot_wait_timeout=dict(default=600),
            placement_group=dict(),
            user_data=dict(),
            instance_tags=dict(type="dict"),
            vpc_subnet_id=dict(),
            assign_public_ip=dict(type="bool", default=False),
            private_ip=dict(),
            instance_profile_name=dict(),
            instance_ids=dict(type="list", aliases=["instance_id"]),
            source_dest_check=dict(type="bool", default=True),
            termination_protection=dict(type="bool", default=None),
            state=dict(
                default="present",
                choices=["present", "absent", "running", "restarted", "stopped"],
            ),
            instance_initiated_shutdown_behavior=dict(
                default=None, choices=["stop", "terminate"]
            ),
            exact_count=dict(type="int", default=None),
            count_tag=dict(),
            volumes=dict(type="list"),
            ebs_optimized=dict(type="bool", default=False),
            tenancy=dict(default="default"),
            network_interfaces=dict(type="list", aliases=["network_interface"]),
        )
    )

    module = AnsibleModule(
        argument_spec=argument_spec,
        mutually_exclusive=[
            ["group_name", "group_id"],
            ["exact_count", "count"],
            ["exact_count", "state"],
            ["exact_count", "instance_ids"],
            ["network_interfaces", "assign_public_ip"],
            ["network_interfaces", "group"],
            ["network_interfaces", "group_id"],
            ["network_interfaces", "private_ip"],
            ["network_interfaces", "vpc_subnet_id"],
        ],
    )

    if not HAS_BOTO:
        module.fail_json(msg="boto required for this module")

    try:
        region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
        if module.params.get("region") or not module.params.get("ec2_url"):
            ec2 = ec2_connect(module)
        elif module.params.get("ec2_url"):
            ec2 = connect_ec2_endpoint(ec2_url, **aws_connect_kwargs)

        if "region" not in aws_connect_kwargs:
            aws_connect_kwargs["region"] = ec2.region

        vpc = connect_vpc(**aws_connect_kwargs)
    except boto.exception.NoAuthHandlerFound as e:
        module.fail_json(
            msg="Failed to get connection: %s" % e.message,
            exception=traceback.format_exc(),
        )

    tagged_instances = []

    state = module.params["state"]

    if state == "absent":
        instance_ids = module.params["instance_ids"]
        if not instance_ids:
            module.fail_json(msg="instance_ids list is required for absent state")

        (changed, instance_dict_array, new_instance_ids) = terminate_instances(
            module, ec2, instance_ids
        )

    elif state in ("running", "stopped"):
        instance_ids = module.params.get("instance_ids")
        instance_tags = module.params.get("instance_tags")
        if not (isinstance(instance_ids, list) or isinstance(instance_tags, dict)):
            module.fail_json(
                msg="running list needs to be a list of instances or set of tags to run: %s"
                % instance_ids
            )

        (changed, instance_dict_array, new_instance_ids) = startstop_instances(
            module, ec2, instance_ids, state, instance_tags
        )

    elif state in ("restarted"):
        instance_ids = module.params.get("instance_ids")
        instance_tags = module.params.get("instance_tags")
        if not (isinstance(instance_ids, list) or isinstance(instance_tags, dict)):
            module.fail_json(
                msg="running list needs to be a list of instances or set of tags to run: %s"
                % instance_ids
            )

        (changed, instance_dict_array, new_instance_ids) = restart_instances(
            module, ec2, instance_ids, state, instance_tags
        )

    elif state == "present":
        # Changed is always set to true when provisioning new instances
        if not module.params.get("image"):
            module.fail_json(msg="image parameter is required for new instance")

        if module.params.get("exact_count") is None:
            (instance_dict_array, new_instance_ids, changed) = create_instances(
                module, ec2, vpc
            )
        else:
            (tagged_instances, instance_dict_array, new_instance_ids, changed) = (
                enforce_count(module, ec2, vpc)
            )

    module.exit_json(
        changed=changed,
        instance_ids=new_instance_ids,
        instances=instance_dict_array,
        tagged_instances=tagged_instances,
    )