Repository: ansible/ansible

Issue:
cloudfront_invalidation doesn't work for the first invalidation ever for given distribution
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
Always add information AFTER of these html comments.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report

##### COMPONENT NAME
<!---
Insert below this comment the 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
-->
cloudfront_invalidation
##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.5.0
  config file = None
  configured module search path = [u'/Users/gennadii_aleksandrov/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/gennadii_aleksandrov/Library/Python/2.7/lib/python/site-packages/ansible
  executable location = /Users/Gennadii_Aleksandrov/Library/Python/2.7/bin/ansible
  python version = 2.7.14 (default, Mar  9 2018, 23:57:12) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)]
```

##### 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).
-->
DEFAULT_HOST_LIST(/Users/gennadii_aleksandrov/r/ansible-control-repo/ansible.cfg) = [u'/Users/gennadii_aleksandrov/r/ansible-control-repo/inventory/local']
DEFAULT_REMOTE_USER(/Users/gennadii_aleksandrov/r/ansible-control-repo/ansible.cfg) = ubuntu
HOST_KEY_CHECKING(/Users/gennadii_aleksandrov/r/ansible-control-repo/ansible.cfg) = False
RETRY_FILES_ENABLED(/Users/gennadii_aleksandrov/r/ansible-control-repo/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 -->
If distribution doesn't have any previous invalidations, boto3 `list_invalidations` returns empty dict. But `cloudfront_invalidation` attempts to read the list and fails with `KeyError`, see line 184
```
invalidations = paginator.paginate(DistributionId=distribution_id).build_full_result()['InvalidationList'].get('Items', [])
```
##### 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.
-->
Create CloudFront distribution. Then try to execute the playbook:
<!--- Paste example playbooks or commands between quotes below -->
```yaml
    - name: Invalidate CloudFront cache
      cloudfront_invalidation:
        alias: '{{ fqdn }}'
        target_paths: '/*'
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Invalidation created.
##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Module fails with this message (sanitized):
<!--- Paste verbatim command output between quotes below -->
```
fatal: [XXX]: FAILED! => {
    "changed": false,
    "module_stderr": "Shared connection to 1.2.3.4 closed.\r\n",
    "module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_7NNXVV/ansible_module__cloudfront_invalidation.py\", line 275, in <modul
e>\r\n    main()\r\n  File \"/tmp/ansible_7NNXVV/ansible_module__cloudfront_invalidation.py\", line 269, in main\r\n    result, changed = service_mgr.crea
te_invalidation(distribution_id, valid_pascal_target_paths)\r\n  File \"/tmp/ansible_7NNXVV/ansible_module__cloudfront_invalidation.py\", line 160, in cre
ate_invalidation\r\n    current_invalidation_response = self.get_invalidation(distribution_id, invalidation_batch['CallerReference'])\r\n  File \"/tmp/ans
ible_7NNXVV/ansible_module__cloudfront_invalidation.py\", line 184, in get_invalidation\r\n    invalidations = paginator.paginate(DistributionId=distribut
ion_id).build_full_result()['InvalidationList'].get('Items', [])\r\nKeyError: 'InvalidationList'\r\n",
    "msg": "MODULE FAILURE",
    "rc": 1
}
```



Discussion:

Resolving patch:
diff --git a/lib/ansible/modules/cloud/amazon/cloudfront_invalidation.py b/lib/ansible/modules/cloud/amazon/cloudfront_invalidation.py
--- a/lib/ansible/modules/cloud/amazon/cloudfront_invalidation.py
+++ b/lib/ansible/modules/cloud/amazon/cloudfront_invalidation.py
@@ -181,7 +181,7 @@ def get_invalidation(self, distribution_id, caller_reference):
         # find all invalidations for the distribution
         try:
             paginator = self.client.get_paginator('list_invalidations')
-            invalidations = paginator.paginate(DistributionId=distribution_id).build_full_result()['InvalidationList'].get('Items', [])
+            invalidations = paginator.paginate(DistributionId=distribution_id).build_full_result().get('InvalidationList', {}).get('Items', [])
             invalidation_ids = [inv['Id'] for inv in invalidations]
         except (BotoCoreError, ClientError) as e:
             self.module.fail_json_aws(e, msg="Error listing CloudFront invalidations.")


Test patch: