From 980f660bb6825833b1759e5d9f42666bbe0b56c5 Mon Sep 17 00:00:00 2001 From: Matthew Davis <7035647+mdavis-xyz@users.noreply.github.com> Date: Thu, 12 Jan 2023 00:00:20 +1100 Subject: [PATCH] make s3_lifecycle not call put_lifecycle_configuration if there is no change to put (#1629) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make s3_lifecycle not call put_lifecycle_configuration if there is no… SUMMARY Fixes #1624 ISSUE TYPE Bugfix Pull Request COMPONENT NAME s3_lifecycle ADDITIONAL INFORMATION I have not written integration tests for this. My MWE in #1624 used multiple hosts (all localhost). I don't know how to add that here. Reviewed-by: Markus Bergholz Reviewed-by: Alina Buzachis (cherry picked from commit 5aa3ff17c24feb9facc327bff9f68482210c024d) --- .../1624-s3-lifecycle-idempotent.yml | 2 + plugins/modules/s3_lifecycle.py | 129 +++++++++--------- 2 files changed, 69 insertions(+), 62 deletions(-) create mode 100644 changelogs/fragments/1624-s3-lifecycle-idempotent.yml diff --git a/changelogs/fragments/1624-s3-lifecycle-idempotent.yml b/changelogs/fragments/1624-s3-lifecycle-idempotent.yml new file mode 100644 index 00000000000..3307819894d --- /dev/null +++ b/changelogs/fragments/1624-s3-lifecycle-idempotent.yml @@ -0,0 +1,2 @@ +bugfixes: +- s3_lifecycle - Module no longer calls `put_lifecycle_configuration` if there is no change. (https://github.com/ansible-collections/community.aws/issues/1624) diff --git a/plugins/modules/s3_lifecycle.py b/plugins/modules/s3_lifecycle.py index 9a2ea51e92f..3d876d0c3e1 100644 --- a/plugins/modules/s3_lifecycle.py +++ b/plugins/modules/s3_lifecycle.py @@ -466,38 +466,40 @@ def create_lifecycle_rule(client, module): (changed, lifecycle_configuration) = compare_and_update_configuration(client, module, old_lifecycle_rules, new_rule) - - # Write lifecycle to bucket - try: - client.put_bucket_lifecycle_configuration( - aws_retry=True, - Bucket=name, - LifecycleConfiguration=lifecycle_configuration) - except is_boto3_error_message('At least one action needs to be specified in a rule'): - # Amazon interpretted this as not changing anything - changed = False - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except - module.fail_json_aws(e, lifecycle_configuration=lifecycle_configuration, name=name, old_lifecycle_rules=old_lifecycle_rules) - - _changed = changed - _retries = 10 - _not_changed_cnt = 6 - while wait and _changed and _retries and _not_changed_cnt: - # We've seen examples where get_bucket_lifecycle_configuration returns - # the updated rules, then the old rules, then the updated rules again and - # again couple of times. - # Thus try to read the rule few times in a row to check if it has changed. - time.sleep(5) - _retries -= 1 - new_rules = fetch_rules(client, module, name) - (_changed, lifecycle_configuration) = compare_and_update_configuration(client, module, - new_rules, - new_rule) - if not _changed: - _not_changed_cnt -= 1 - _changed = True - else: - _not_changed_cnt = 6 + if changed: + # Write lifecycle to bucket + try: + client.put_bucket_lifecycle_configuration( + aws_retry=True, + Bucket=name, + LifecycleConfiguration=lifecycle_configuration) + except is_boto3_error_message('At least one action needs to be specified in a rule'): + # Amazon interpretted this as not changing anything + changed = False + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except + module.fail_json_aws(e, lifecycle_configuration=lifecycle_configuration, name=name, old_lifecycle_rules=old_lifecycle_rules) + + _changed = changed + _retries = 10 + _not_changed_cnt = 6 + while wait and _changed and _retries and _not_changed_cnt: + # We've seen examples where get_bucket_lifecycle_configuration returns + # the updated rules, then the old rules, then the updated rules again and + # again couple of times. + # Thus try to read the rule few times in a row to check if it has changed. + time.sleep(5) + _retries -= 1 + new_rules = fetch_rules(client, module, name) + (_changed, lifecycle_configuration) = compare_and_update_configuration(client, module, + new_rules, + new_rule) + if not _changed: + _not_changed_cnt -= 1 + _changed = True + else: + _not_changed_cnt = 6 + else: + _retries = 0 new_rules = fetch_rules(client, module, name) @@ -520,36 +522,39 @@ def destroy_lifecycle_rule(client, module): current_lifecycle_rules = fetch_rules(client, module, name) changed, lifecycle_obj = compare_and_remove_rule(current_lifecycle_rules, rule_id, prefix) - # Write lifecycle to bucket or, if there no rules left, delete lifecycle configuration - try: - if lifecycle_obj['Rules']: - client.put_bucket_lifecycle_configuration( - aws_retry=True, - Bucket=name, - LifecycleConfiguration=lifecycle_obj) - elif current_lifecycle_rules: - changed = True - client.delete_bucket_lifecycle(aws_retry=True, Bucket=name) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e) - - _changed = changed - _retries = 10 - _not_changed_cnt = 6 - while wait and _changed and _retries and _not_changed_cnt: - # We've seen examples where get_bucket_lifecycle_configuration returns - # the updated rules, then the old rules, then the updated rules again and - # again couple of times. - # Thus try to read the rule few times in a row to check if it has changed. - time.sleep(5) - _retries -= 1 - new_rules = fetch_rules(client, module, name) - (_changed, lifecycle_configuration) = compare_and_remove_rule(new_rules, rule_id, prefix) - if not _changed: - _not_changed_cnt -= 1 - _changed = True - else: - _not_changed_cnt = 6 + if changed: + # Write lifecycle to bucket or, if there no rules left, delete lifecycle configuration + try: + if lifecycle_obj['Rules']: + client.put_bucket_lifecycle_configuration( + aws_retry=True, + Bucket=name, + LifecycleConfiguration=lifecycle_obj) + elif current_lifecycle_rules: + changed = True + client.delete_bucket_lifecycle(aws_retry=True, Bucket=name) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e) + + _changed = changed + _retries = 10 + _not_changed_cnt = 6 + while wait and _changed and _retries and _not_changed_cnt: + # We've seen examples where get_bucket_lifecycle_configuration returns + # the updated rules, then the old rules, then the updated rules again and + # again couple of times. + # Thus try to read the rule few times in a row to check if it has changed. + time.sleep(5) + _retries -= 1 + new_rules = fetch_rules(client, module, name) + (_changed, lifecycle_configuration) = compare_and_remove_rule(new_rules, rule_id, prefix) + if not _changed: + _not_changed_cnt -= 1 + _changed = True + else: + _not_changed_cnt = 6 + else: + _retries = 0 new_rules = fetch_rules(client, module, name)