From 841b063d1222e3325fec51064fd045a769201f59 Mon Sep 17 00:00:00 2001 From: Guy Templeton Date: Wed, 18 Jul 2018 13:49:01 +0100 Subject: [PATCH] =?UTF-8?q?Fixes=20#37752=20Delete=20all=20versions=20and?= =?UTF-8?q?=20deletemarkers=20in=20S3=5FBucket=20when=20force=20paramet?= =?UTF-8?q?=E2=80=A6=20(#39781)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Delete all versions and deletemarkers in S3_Bucket when force parameter is passed * Fix PEP8 style conformance * Clarify explanation of force parameter --- lib/ansible/modules/cloud/amazon/s3_bucket.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/ansible/modules/cloud/amazon/s3_bucket.py b/lib/ansible/modules/cloud/amazon/s3_bucket.py index 3effbfe7a26..4b18d88a37b 100644 --- a/lib/ansible/modules/cloud/amazon/s3_bucket.py +++ b/lib/ansible/modules/cloud/amazon/s3_bucket.py @@ -30,7 +30,8 @@ author: "Rob White (@wimnat)" options: force: description: - - When trying to delete a bucket, delete all keys in the bucket first (an s3 bucket must be empty for a successful deletion) + - When trying to delete a bucket, delete all keys (including versions and delete markers) + in the bucket first (an s3 bucket must be empty for a successful deletion) type: bool default: 'no' name: @@ -417,6 +418,13 @@ def paginated_list(s3_client, **pagination_params): yield [data['Key'] for data in page.get('Contents', [])] +def paginated_versions_list(s3_client, **pagination_params): + pg = s3_client.get_paginator('list_object_versions') + for page in pg.paginate(**pagination_params): + # We have to merge the Versions and DeleteMarker lists here, as DeleteMarkers can still prevent a bucket deletion + yield [(data['Key'], data['VersionId']) for data in (page.get('Versions', []) + page.get('DeleteMarkers', []))] + + def destroy_bucket(s3_client, module): force = module.params.get("force") @@ -432,10 +440,10 @@ def destroy_bucket(s3_client, module): module.exit_json(changed=False) if force: - # if there are contents then we need to delete them before we can delete the bucket + # if there are contents then we need to delete them (including versions) before we can delete the bucket try: - for keys in paginated_list(s3_client, Bucket=name): - formatted_keys = [{'Key': key} for key in keys] + for key_version_pairs in paginated_versions_list(s3_client, Bucket=name): + formatted_keys = [{'Key': key, 'VersionId': version} for key, version in key_version_pairs] if formatted_keys: s3_client.delete_objects(Bucket=name, Delete={'Objects': formatted_keys}) except (BotoCoreError, ClientError) as e: