Repository: ansible/ansible

Issue:
AWS ec2 copy ami fails with wait enabled (Waiter ImageAvailable failed: Max attempts exceeded)
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report

##### COMPONENT NAME
<!---
Name of the module, plugin, task or feature
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->
ec2_ami_copy

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/rajass/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Sep 15 2016, 22:37:39) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)]

```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
HOST_KEY_CHECKING(/etc/ansible/ansible.cfg) = False

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
N/A

##### SUMMARY
<!--- Explain the problem briefly -->
The ec2_ami_copy module fails with WaiterError if wait parameter is enabled and if the ami takes more than 10mins to get into available state.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
Code that fails 
<!--- Paste example playbooks or commands between quotes below -->
```yaml
      ec2_ami_copy:
        source_region: "us-east-1"
        region: "us-west-2"
        source_image_id: "ami-93fc00hh"
        name: "test_ami"
        wait: yes
        encrypted: no

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
The task should complete without any error and return the ami id.
##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_8b2dUL/ansible_module_ec2_ami_copy.py", line 176, in copy_image
    ec2.get_waiter('image_available').wait(ImageIds=[image_id])
  File "/usr/lib/python2.7/site-packages/botocore/waiter.py", line 53, in wait
    Waiter.wait(self, **kwargs)
  File "/usr/lib/python2.7/site-packages/botocore/waiter.py", line 329, in wait
    last_response=response
WaiterError: Waiter ImageAvailable failed: Max attempts exceeded

fatal: [localhost]: FAILED! => {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "aws_access_key": null,
            "aws_secret_key": null,
            "description": "",
            "ec2_url": null,
            "encrypted": false,
            "kms_key_id": null,
            "name": "test_ami",
            "profile": null,
            "region": "us-west-2",
            "security_token": null,
            "source_image_id": "ami-93fc00hh",
            "source_region": "us-east-1",
            "validate_certs": true,
            "wait": true,
            "wait_timeout": "1200"
        }
    },
    "msg": "An error occurred waiting for the image to become available. (Waiter ImageAvailable failed: Max attempts exceeded)"
}
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/cloud/amazon/ec2_ami_copy.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/amazon/ec2_ami_copy.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @amir343 @defunctio @willthames
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/amazon/ec2_ami_copy.py b/lib/ansible/modules/cloud/amazon/ec2_ami_copy.py
--- a/lib/ansible/modules/cloud/amazon/ec2_ami_copy.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_ami_copy.py
@@ -58,8 +58,10 @@
     default: 'no'
   wait_timeout:
     description:
-      - How long before wait gives up, in seconds. (As of 2.3 this option is deprecated. See boto3 Waiters)
-    default: 1200
+      - How long before wait gives up, in seconds. Prior to 2.3 the default was 1200.
+      - From 2.3-2.5 this option was deprecated in favor of boto3 waiter defaults.
+        This was reenabled in 2.6 to allow timeouts greater than 10 minutes.
+    default: 600
   tags:
     description:
       - A hash/dictionary of tags to add to the new copied AMI; '{"key":"value"}' and '{"key":"value","key":"value"}'
@@ -84,6 +86,7 @@
     region: eu-west-1
     source_image_id: ami-xxxxxxx
     wait: yes
+    wait_timeout: 1200  # Default timeout is 600
   register: image_id
 
 # Named AMI copy
@@ -159,7 +162,12 @@ def copy_image(module, ec2):
     try:
         image_id = ec2.copy_image(**params)['ImageId']
         if module.params.get('wait'):
-            ec2.get_waiter('image_available').wait(ImageIds=[image_id])
+            delay = 15
+            max_attempts = module.params.get('wait_timeout') // delay
+            ec2.get_waiter('image_available').wait(
+                ImageIds=[image_id],
+                WaiterConfig={'Delay': delay, 'MaxAttempts': max_attempts}
+            )
         if module.params.get('tags'):
             ec2.create_tags(
                 Resources=[image_id],
@@ -187,7 +195,7 @@ def main():
         encrypted=dict(type='bool', default=False, required=False),
         kms_key_id=dict(type='str', required=False),
         wait=dict(type='bool', default=False),
-        wait_timeout=dict(default=1200),
+        wait_timeout=dict(type='int', default=600),
         tags=dict(type='dict')))
 
     module = AnsibleModule(argument_spec=argument_spec)


Test patch: