Repository: ansible/ansible-modules-core

Issue:
cloudformation module fails with 
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE
- Bug Report
##### COMPONENT NAME

cloudformation
##### ANSIBLE VERSION

```
ansible 2.2.0
```
##### CONFIGURATION

N/A
##### OS / ENVIRONMENT

N/A
##### SUMMARY

After a successful stack operation the module always fails when calling `exit_json(**results)` due to a bad result variable type.  The cloudformation module tries to include stack events in module output.  The stack events are an `itertools.imap` iterator which ansible doesn't know how to deal with when calling `exit_json()` and fails with a `Value of unknown type: <type 'itertools.imap'>`.  The fix here can be as simple as wrapping the stack events variable in a call to `list()`.  The more general fix would be to make ansible's `remove_values()` function accept `itertools.imap` objects.
##### STEPS TO REPRODUCE

<!---
For bugs, show exactly how to reproduce the problem.
For new features, show how the feature would be used.
-->

**ansible-cfn-bug.yml**

``` yaml

---
- hosts: localhost
  tasks:
    - name: deploy stack
      cloudformation:
        stack_name: ansible-cfn-bug
        state: present
        template: stack.json
```

**stack.json**

``` json
{
  "Resources": {
    "S3B3QFCX": {
      "Type": "AWS::S3::Bucket",
      "Properties": {}
    }
  }
}
```

``` bash
ansible-playbook -vvvv -c local ansible-cfn-bug.yml
```
##### EXPECTED RESULTS

Stack should be deployed.  Deploy task should successfully complete.
##### ACTUAL RESULTS

Deploy task fails for reasons listed above.

```
TASK [deploy stack] ************************************************************
task path: [redacted]/ansible-cfn-bug.yml:4
Using module file [redacted]/venv/local/lib/python2.7/site-packages/ansible/modules/core/cloud/amazon/cloudformation.py
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: [redacted]
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1473951676.35-213586073691975 `" && echo ansible-tmp-1473951676.35-213586073691975="` echo $HOME/.ansible/tmp/ansible-tmp-1473951676.35-213586073691975 `" ) && sleep 0'
<127.0.0.1> PUT /tmp/tmpGPzHre TO [redacted]/.ansible/tmp/ansible-tmp-1473951676.35-213586073691975/cloudformation.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x [redacted]/.ansible/tmp/ansible-tmp-1473951676.35-213586073691975/ [redacted]/.ansible/tmp/ansible-tmp-1473951676.35-213586073691975/cloudformation.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '[redacted]/venv/bin/python2 [redacted]/.ansible/tmp/ansible-tmp-1473951676.35-213586073691975/cloudformation.py; rm -rf "[redacted]/.ansible/tmp/ansible-tmp-1473951676.35-213586073691975/" > /dev/null 2>&1 && sleep 0'
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_rX9aA1/ansible_module_cloudformation.py", line 402, in <module>
    main()
  File "/tmp/ansible_rX9aA1/ansible_module_cloudformation.py", line 395, in main
    module.exit_json(**result)
  File "/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py", line 1798, in exit_json
  File "/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py", line 387, in remove_values
  File "/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py", line 387, in <genexpr>
  File "/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py", line 398, in remove_values
TypeError: Value of unknown type: <type 'itertools.imap'>, <itertools.imap object at 0x7f300e408950>

fatal: [localhost]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "invocation": {
        "module_name": "cloudformation"
    }, 
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_rX9aA1/ansible_module_cloudformation.py\", line 402, in <module>\n    main()\n  File \"/tmp/ansible_rX9aA1/ansible_module_cloudformation.py\", line 395, in main\n    module.exit_json(**result)\n  File \"/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py\", line 1798, in exit_json\n  File \"/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py\", line 387, in remove_values\n  File \"/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py\", line 387, in <genexpr>\n  File \"/tmp/ansible_rX9aA1/ansible_modlib.zip/ansible/module_utils/basic.py\", line 398, in remove_values\nTypeError: Value of unknown type: <type 'itertools.imap'>, <itertools.imap object at 0x7f300e408950>\n", 
```



Discussion:
<!-- @mzizzi: Thanks for filing this bug report! -->

@jsmartin ping, this issue is waiting for your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_bug_new --->


Resolving patch:
diff --git a/cloud/amazon/cloudformation.py b/cloud/amazon/cloudformation.py
--- a/cloud/amazon/cloudformation.py
+++ b/cloud/amazon/cloudformation.py
@@ -193,28 +193,28 @@ def stack_operation(cfn, stack_name, operation):
             if 'yes' in existed:
                 result = dict(changed=True,
                               output='Stack Deleted',
-                              events=map(str, list(stack.describe_events())))
+                              events=list(map(str, list(stack.describe_events()))))
             else:
                 result = dict(changed= True, output='Stack Not Found')
             break
         if '%s_COMPLETE' % operation == stack.stack_status:
             result = dict(changed=True,
-                          events = map(str, list(stack.describe_events())),
+                          events = list(map(str, list(stack.describe_events()))),
                           output = 'Stack %s complete' % operation)
             break
         if  'ROLLBACK_COMPLETE' == stack.stack_status or '%s_ROLLBACK_COMPLETE' % operation == stack.stack_status:
             result = dict(changed=True, failed=True,
-                          events = map(str, list(stack.describe_events())),
+                          events = list(map(str, list(stack.describe_events()))),
                           output = 'Problem with %s. Rollback complete' % operation)
             break
         elif '%s_FAILED' % operation == stack.stack_status:
             result = dict(changed=True, failed=True,
-                          events = map(str, list(stack.describe_events())),
+                          events = list(map(str, list(stack.describe_events()))),
                           output = 'Stack %s failed' % operation)
             break
         elif '%s_ROLLBACK_FAILED' % operation == stack.stack_status:
             result = dict(changed=True, failed=True,
-                          events = map(str, list(stack.describe_events())),
+                          events = list(map(str, list(stack.describe_events()))),
                           output = 'Stack %s rollback failed' % operation)
             break
         else:


Test patch: