From 02ee352951867401c65424a886464abb4fac2f16 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 28 Apr 2016 17:35:37 -0400 Subject: [PATCH] fixes and refactoring of s3_bucket policy should now accept and handle correctly both data structures or JSON strings removed unused tag_set var refactored code to make conditions clearer rebased to allow for ceph changes, left ceph update on todo list --- .../modules/extras/cloud/amazon/s3_bucket.py | 153 ++++++++---------- 1 file changed, 70 insertions(+), 83 deletions(-) diff --git a/lib/ansible/modules/extras/cloud/amazon/s3_bucket.py b/lib/ansible/modules/extras/cloud/amazon/s3_bucket.py index 6e5466c1f6d..7464f76f0a7 100644 --- a/lib/ansible/modules/extras/cloud/amazon/s3_bucket.py +++ b/lib/ansible/modules/extras/cloud/amazon/s3_bucket.py @@ -107,9 +107,10 @@ EXAMPLES = ''' tags: example: tag1 another: tag2 - + ''' +import os import xml.etree.ElementTree as ET import urlparse @@ -126,16 +127,13 @@ except ImportError: HAS_BOTO = False def get_request_payment_status(bucket): - + response = bucket.get_request_payment() root = ET.fromstring(response) for message in root.findall('.//{http://s3.amazonaws.com/doc/2006-03-01/}Payer'): payer = message.text - - if payer == "BucketOwner": - return False - else: - return True + + return (payer != "BucketOwner") def create_tags_container(tags): @@ -147,7 +145,7 @@ def create_tags_container(tags): tags_obj.add_tag_set(tag_set) return tags_obj -def _create_bucket(connection, module, location): +def _create_or_update_bucket(connection, module, location): policy = module.params.get("policy") name = module.params.get("name") @@ -155,7 +153,7 @@ def _create_bucket(connection, module, location): tags = module.params.get("tags") versioning = module.params.get("versioning") changed = False - + try: bucket = connection.get_bucket(name) except S3ResponseError as e: @@ -164,42 +162,38 @@ def _create_bucket(connection, module, location): changed = True except S3CreateError as e: module.fail_json(msg=e.message) - + # Versioning versioning_status = bucket.get_versioning_status() - if not versioning_status and versioning: - try: - bucket.configure_versioning(versioning) - changed = True - versioning_status = bucket.get_versioning_status() - except S3ResponseError as e: - module.fail_json(msg=e.message) - elif not versioning_status and not versioning: - # do nothing - pass - else: - if versioning_status['Versioning'] == "Enabled" and not versioning: - bucket.configure_versioning(versioning) - changed = True - versioning_status = bucket.get_versioning_status() - elif ( (versioning_status['Versioning'] == "Disabled" and versioning) or (versioning_status['Versioning'] == "Suspended" and versioning) ): - bucket.configure_versioning(versioning) - changed = True - versioning_status = bucket.get_versioning_status() - + if not versioning_status: + if versioning: + try: + bucket.configure_versioning(versioning) + changed = True + versioning_status = bucket.get_versioning_status() + except S3ResponseError as e: + module.fail_json(msg=e.message) + elif versioning_status['Versioning'] == "Enabled" and not versioning: + bucket.configure_versioning(versioning) + changed = True + versioning_status = bucket.get_versioning_status() + elif ( (versioning_status['Versioning'] == "Disabled" and versioning) or (versioning_status['Versioning'] == "Suspended" and versioning) ): + bucket.configure_versioning(versioning) + changed = True + versioning_status = bucket.get_versioning_status() + # Requester pays requester_pays_status = get_request_payment_status(bucket) if requester_pays_status != requester_pays: if requester_pays: - bucket.set_request_payment(payer='Requester') - changed = True - requester_pays_status = get_request_payment_status(bucket) + payer='Requester' else: - bucket.set_request_payment(payer='BucketOwner') - changed = True - requester_pays_status = get_request_payment_status(bucket) + payer='BucketOwner' + bucket.set_request_payment(payer=payer) + changed = True + requester_pays_status = get_request_payment_status(bucket) - # Policy + # Policy try: current_policy = bucket.get_policy() except S3ResponseError as e: @@ -207,30 +201,25 @@ def _create_bucket(connection, module, location): current_policy = None else: module.fail_json(msg=e.message) - - if current_policy is not None and policy is not None: - if policy is not None: - policy = json.dumps(policy) - - if json.loads(current_policy) != json.loads(policy): + + if policy is not None: + # Deal with policy if either JSON formatted string or just data structure + if isinstance(policy, basestring): + compare_policy = json.dumps(policy) + load_policy = policy + else: + compare_policy = policy + load_policy = json.loads(policy) + + if current_policy is None or json.loads(current_policy) != compare_policy: try: - bucket.set_policy(policy) + bucket.set_policy(load_policy) changed = True current_policy = bucket.get_policy() except S3ResponseError as e: module.fail_json(msg=e.message) + elif current_policy is not None: - elif current_policy is None and policy is not None: - policy = json.dumps(policy) - - try: - bucket.set_policy(policy) - changed = True - current_policy = bucket.get_policy() - except S3ResponseError as e: - module.fail_json(msg=e.message) - - elif current_policy is not None and policy is None: try: bucket.delete_policy() changed = True @@ -240,23 +229,17 @@ def _create_bucket(connection, module, location): current_policy = None else: module.fail_json(msg=e.message) - - #### - ## Fix up json of policy so it's not escaped - #### - # Tags try: current_tags = bucket.get_tags() - tag_set = TagSet() except S3ResponseError as e: if e.error_code == "NoSuchTagSet": current_tags = None else: module.fail_json(msg=e.message) - + if current_tags is not None or tags is not None: - + if current_tags is None: current_tags_dict = {} else: @@ -274,13 +257,13 @@ def _create_bucket(connection, module, location): module.fail_json(msg=e.message) module.exit_json(changed=changed, name=bucket.name, versioning=versioning_status, requester_pays=requester_pays_status, policy=current_policy, tags=current_tags_dict) - + def _destroy_bucket(connection, module): - + force = module.params.get("force") name = module.params.get("name") changed = False - + try: bucket = connection.get_bucket(name) except S3ResponseError as e: @@ -289,25 +272,26 @@ def _destroy_bucket(connection, module): else: # Bucket already absent module.exit_json(changed=changed) - + if force: try: # Empty the bucket for key in bucket.list(): key.delete() - + except BotoServerError as e: module.fail_json(msg=e.message) - + try: bucket = connection.delete_bucket(name) changed = True except S3ResponseError as e: module.fail_json(msg=e.message) - + module.exit_json(changed=changed) -def _create_bucket_ceph(connection, module, location): +def _create_or_update_bucket_ceph(connection, module, location): + #TODO: add update name = module.params.get("name") @@ -322,17 +306,20 @@ def _create_bucket_ceph(connection, module, location): except S3CreateError as e: module.fail_json(msg=e.message) - module.exit_json(changed=changed) + if bucket: + module.exit_json(changed=changed) + else: + module.fail_json(msg='Unable to create bucket, no error from the API') def _destroy_bucket_ceph(connection, module): _destroy_bucket(connection, module) -def create_bucket(connection, module, location, flavour='aws'): +def create_or_update_bucket(connection, module, location, flavour='aws'): if flavour == 'ceph': - _create_bucket_ceph(connection, module, location) + _create_or_update_bucket_ceph(connection, module, location) else: - _create_bucket(connection, module, location) + _create_or_update_bucket(connection, module, location) def destroy_bucket(connection, module, flavour='aws'): if flavour == 'ceph': @@ -358,27 +345,27 @@ def is_walrus(s3_url): return False def main(): - + argument_spec = ec2_argument_spec() argument_spec.update( dict( force = dict(required=False, default='no', type='bool'), - policy = dict(required=False, default=None), - name = dict(required=True), + policy = dict(required=False), + name = dict(required=True, type='str'), requester_pays = dict(default='no', type='bool'), - s3_url = dict(aliases=['S3_URL']), - state = dict(default='present', choices=['present', 'absent']), + s3_url = dict(aliases=['S3_URL'], type='str'), + state = dict(default='present', type='str', choices=['present', 'absent']), tags = dict(required=None, default={}, type='dict'), versioning = dict(default='no', type='bool'), ceph = dict(default='no', type='bool') ) ) - + module = AnsibleModule(argument_spec=argument_spec) if not HAS_BOTO: module.fail_json(msg='boto required for this module') - + region, ec2_url, aws_connect_params = get_aws_connection_info(module) if region in ('us-east-1', '', None): @@ -444,7 +431,7 @@ def main(): state = module.params.get("state") if state == 'present': - create_bucket(connection, module, location, flavour=flavour) + create_or_update_bucket(connection, module, location) elif state == 'absent': destroy_bucket(connection, module, flavour=flavour)