forked from ansible/ansible
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New module: manage Amazon CloudFront origin access identities (cloud/…
…amazon/cloudfront_origin_access_identity) (ansible#35540)
- Loading branch information
Showing
2 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
284 changes: 284 additions & 0 deletions
284
lib/ansible/modules/cloud/amazon/cloudfront_origin_access_identity.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
#!/usr/bin/python | ||
# Copyright (c) 2017 Ansible Project | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
ANSIBLE_METADATA = {'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'community'} | ||
|
||
DOCUMENTATION = ''' | ||
--- | ||
|
||
module: cloudfront_origin_access_identity | ||
|
||
short_description: create, update and delete origin access identities for a | ||
cloudfront distribution. | ||
|
||
description: | ||
- Allows for easy creation, updating and deletion of origin access | ||
identities. | ||
|
||
requirements: | ||
- boto3 >= 1.0.0 | ||
- python >= 2.6 | ||
|
||
version_added: "2.5" | ||
|
||
author: Willem van Ketwich (@wilvk) | ||
|
||
extends_documentation_fragment: | ||
- aws | ||
- ec2 | ||
|
||
options: | ||
state: | ||
description: If the named resource should exist. | ||
choices: | ||
- present | ||
- absent | ||
default: update_origin_access_identity | ||
origin_access_identity_id: | ||
description: | ||
- The origin_access_identity_id of the cloudfront distribution. | ||
required: false | ||
comment: | ||
description: | ||
- A comment to describe the cloudfront origin access identity. | ||
required: false | ||
caller_reference: | ||
description: | ||
- A unique identifier to reference the origin access identity by. | ||
required: false | ||
|
||
notes: | ||
- does not support check mode | ||
|
||
''' | ||
|
||
EXAMPLES = ''' | ||
|
||
- name: create an origin access identity | ||
cloudfront_origin_access_identity: | ||
state: present | ||
caller_reference: this is an example reference | ||
comment: this is an example comment | ||
|
||
- name: update an existing origin access identity using caller_reference as an identifier | ||
cloudfront_origin_access_identity: | ||
origin_access_identity_id: E17DRN9XUOAHZX | ||
caller_reference: this is an example reference | ||
comment: this is a new comment | ||
|
||
- name: delete an existing origin access identity using caller_reference as an identifier | ||
cloudfront_origin_access_identity: | ||
state: absent | ||
caller_reference: this is an example reference | ||
comment: this is a new comment | ||
|
||
''' | ||
|
||
RETURN = ''' | ||
cloud_front_origin_access_identity: | ||
description: The origin access identity's information. | ||
returned: always | ||
type: complex | ||
contains: | ||
cloud_front_origin_access_identity_config: | ||
description: describes a url specifying the origin access identity. | ||
returned: always | ||
type: complex | ||
contains: | ||
caller_reference: | ||
description: a caller reference for the oai | ||
returned: always | ||
type: string | ||
comment: | ||
description: a comment describing the oai | ||
returned: always | ||
type: string | ||
id: | ||
description: a unique identifier of the oai | ||
returned: always | ||
type: string | ||
s3_canonical_user_id: | ||
description: the cannonical user id of the user who created the oai | ||
returned: always | ||
type: string | ||
e_tag: | ||
description: The current version of the origin access identity created. | ||
returned: always | ||
type: string | ||
location: | ||
description: The fully qualified URI of the new origin access identity just created. | ||
returned: when initially created | ||
type: string | ||
|
||
''' | ||
|
||
from ansible.module_utils.ec2 import get_aws_connection_info, ec2_argument_spec | ||
from ansible.module_utils.ec2 import boto3_conn | ||
from ansible.module_utils.aws.cloudfront_facts import CloudFrontFactsServiceManager | ||
from ansible.module_utils.ec2 import camel_dict_to_snake_dict | ||
from ansible.module_utils.aws.core import AnsibleAWSModule | ||
import datetime | ||
from functools import partial | ||
import json | ||
import traceback | ||
|
||
try: | ||
import botocore | ||
from botocore.signers import CloudFrontSigner | ||
from botocore.exceptions import ClientError, BotoCoreError | ||
except ImportError: | ||
pass # caught by imported AnsibleAWSModule | ||
|
||
|
||
class CloudFrontOriginAccessIdentityServiceManager(object): | ||
""" | ||
Handles cloudfront origin access identity service calls to aws | ||
""" | ||
|
||
def __init__(self, module): | ||
self.module = module | ||
self.create_client('cloudfront') | ||
|
||
def create_client(self, resource): | ||
try: | ||
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(self.module, boto3=True) | ||
self.client = boto3_conn(self.module, conn_type='client', resource=resource, region=region, endpoint=ec2_url, **aws_connect_kwargs) | ||
except (ClientError, BotoCoreError) as e: | ||
self.module.fail_json_aws(e, msg="Unable to establish connection.") | ||
|
||
def create_origin_access_identity(self, caller_reference, comment): | ||
try: | ||
return self.client.create_cloud_front_origin_access_identity( | ||
CloudFrontOriginAccessIdentityConfig={ | ||
'CallerReference': caller_reference, | ||
'Comment': comment | ||
} | ||
) | ||
except (ClientError, BotoCoreError) as e: | ||
self.module.fail_json_aws(e, msg="Error creating cloud front origin access identity.") | ||
|
||
def delete_origin_access_identity(self, origin_access_identity_id, e_tag): | ||
try: | ||
return self.client.delete_cloud_front_origin_access_identity(Id=origin_access_identity_id, IfMatch=e_tag) | ||
except (ClientError, BotoCoreError) as e: | ||
self.module.fail_json_aws(e, msg="Error updating Origin Access Identity.") | ||
|
||
def update_origin_access_identity(self, caller_reference, comment, origin_access_identity_id, e_tag): | ||
changed = False | ||
new_config = { | ||
'CallerReference': caller_reference, | ||
'Comment': comment | ||
} | ||
|
||
try: | ||
current_config = self.client.get_cloud_front_origin_access_identity_config( | ||
Id=origin_access_identity_id)['CloudFrontOriginAccessIdentityConfig'] | ||
except (ClientError, BotoCoreError) as e: | ||
self.module.fail_json_aws(e, msg="Error getting Origin Access Identity config.") | ||
|
||
if new_config != current_config: | ||
changed = True | ||
|
||
try: | ||
# If the CallerReference is a value already sent in a previous identity request | ||
# the returned value is that of the original request | ||
result = self.client.update_cloud_front_origin_access_identity( | ||
CloudFrontOriginAccessIdentityConfig=new_config, | ||
Id=origin_access_identity_id, | ||
IfMatch=e_tag, | ||
) | ||
except (ClientError, BotoCoreError) as e: | ||
self.module.fail_json_aws(e, msg="Error updating Origin Access Identity.") | ||
|
||
return result, changed | ||
|
||
|
||
class CloudFrontOriginAccessIdentityValidationManager(object): | ||
""" | ||
Manages Cloudfront Origin Access Identities | ||
""" | ||
|
||
def __init__(self, module): | ||
self.module = module | ||
self.__cloudfront_facts_mgr = CloudFrontFactsServiceManager(module) | ||
|
||
def validate_etag_from_origin_access_identity_id(self, origin_access_identity_id): | ||
try: | ||
if origin_access_identity_id is None: | ||
return | ||
oai = self.__cloudfront_facts_mgr.get_origin_access_identity(origin_access_identity_id) | ||
if oai is not None: | ||
return oai.get('ETag') | ||
except (ClientError, BotoCoreError) as e: | ||
self.module.fail_json_aws(e, msg="Error getting etag from origin_access_identity.") | ||
|
||
def validate_origin_access_identity_id_from_caller_reference( | ||
self, caller_reference): | ||
try: | ||
origin_access_identities = self.__cloudfront_facts_mgr.list_origin_access_identities() | ||
origin_origin_access_identity_ids = [oai.get('Id') for oai in origin_access_identities] | ||
for origin_access_identity_id in origin_origin_access_identity_ids: | ||
oai_config = (self.__cloudfront_facts_mgr.get_origin_access_identity_config(origin_access_identity_id)) | ||
temp_caller_reference = oai_config.get('CloudFrontOriginAccessIdentityConfig').get('CallerReference') | ||
if temp_caller_reference == caller_reference: | ||
return origin_access_identity_id | ||
except (ClientError, BotoCoreError) as e: | ||
self.module.fail_json_aws(e, msg="Error getting Origin Access Identity from caller_reference.") | ||
|
||
def validate_comment(self, comment): | ||
if comment is None: | ||
return "origin access identity created by Ansible with datetime " + datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') | ||
return comment | ||
|
||
|
||
def main(): | ||
argument_spec = ec2_argument_spec() | ||
|
||
argument_spec.update(dict( | ||
state=dict(choices=['present', 'absent'], default='present'), | ||
origin_access_identity_id=dict(), | ||
caller_reference=dict(), | ||
comment=dict(), | ||
)) | ||
|
||
result = {} | ||
e_tag = None | ||
changed = False | ||
|
||
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=False) | ||
service_mgr = CloudFrontOriginAccessIdentityServiceManager(module) | ||
validation_mgr = CloudFrontOriginAccessIdentityValidationManager(module) | ||
|
||
state = module.params.get('state') | ||
caller_reference = module.params.get('caller_reference') | ||
|
||
comment = module.params.get('comment') | ||
origin_access_identity_id = module.params.get('origin_access_identity_id') | ||
|
||
if origin_access_identity_id is None and caller_reference is not None: | ||
origin_access_identity_id = validation_mgr.validate_origin_access_identity_id_from_caller_reference(caller_reference) | ||
|
||
e_tag = validation_mgr.validate_etag_from_origin_access_identity_id(origin_access_identity_id) | ||
comment = validation_mgr.validate_comment(comment) | ||
|
||
if state == 'present': | ||
if origin_access_identity_id is not None and e_tag is not None: | ||
result, changed = service_mgr.update_origin_access_identity(caller_reference, comment, origin_access_identity_id, e_tag) | ||
else: | ||
result = service_mgr.create_origin_access_identity(caller_reference, comment) | ||
changed = True | ||
elif(state == 'absent' and origin_access_identity_id is not None and | ||
e_tag is not None): | ||
result = service_mgr.delete_origin_access_identity(origin_access_identity_id, e_tag) | ||
changed = True | ||
|
||
result.pop('ResponseMetadata', None) | ||
|
||
module.exit_json(changed=changed, **camel_dict_to_snake_dict(result)) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |