From ddb39e08c14a5de55f29dd14b92fcdbeff7453a5 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:15:21 +0000 Subject: [PATCH] backup_plan - fix idempotency issue with botocore >= 1.31.36 (#1961) (#1962) [PR #1961/c8064d5c backport][stable-7] backup_plan - fix idempotency issue with botocore >= 1.31.36 This is a backport of PR #1961 as merged into main (c8064d5). SUMMARY Fixes #1952 backup_plan - fix idempotency issue with botocore >= 1.31.36 ISSUE TYPE Bugfix Pull Request Feature Pull Request Reviewed-by: Alina Buzachis --- .../20240202-backup_plan-idempotency.yml | 6 ++ plugins/modules/backup_plan.py | 84 +++++++++++++++++++ .../targets/backup_plan/meta/main.yml | 5 ++ .../targets/backup_plan/tasks/main.yml | 39 +++++++++ 4 files changed, 134 insertions(+) create mode 100644 changelogs/fragments/20240202-backup_plan-idempotency.yml create mode 100644 tests/integration/targets/backup_plan/meta/main.yml diff --git a/changelogs/fragments/20240202-backup_plan-idempotency.yml b/changelogs/fragments/20240202-backup_plan-idempotency.yml new file mode 100644 index 00000000000..d98974cb2d6 --- /dev/null +++ b/changelogs/fragments/20240202-backup_plan-idempotency.yml @@ -0,0 +1,6 @@ +bugfixes: + - backup_plan - Fix idempotency issue when using botocore >= 1.31.36 (https://github.com/ansible-collections/amazon.aws/issues/1952). + +minor_changes: + - backup_plan - Let user to set ``schedule_expression_timezone`` for + backup plan rules when when using botocore >= 1.31.36 (https://github.com/ansible-collections/amazon.aws/issues/1952). diff --git a/plugins/modules/backup_plan.py b/plugins/modules/backup_plan.py index c8e7db92f7a..4fab240c762 100644 --- a/plugins/modules/backup_plan.py +++ b/plugins/modules/backup_plan.py @@ -125,6 +125,15 @@ - AWS default if not supplied is false. type: bool default: false + schedule_expression_timezone: + description: + - This is the timezone in which the schedule expression is set. + - By default, ScheduleExpressions are in UTC. You can modify this to a specified timezone. + - This option requires botocore >= 1.31.36. + type: str + default: "Etc/UTC" + required: false + version_added: 7.3.0 advanced_backup_settings: description: - Specifies a list of advanced backup settings for each resource type. @@ -233,6 +242,70 @@ returned: always type: list elements: dict + contains: + rule_name: + description: A display name for a backup rule. + returned: always + type: str + sample: "daily" + target_backup_vault_name: + description: The name of a logical container where backups are stored. + returned: always + type: str + sample: 09da67966fd5-backup-vault" + schedule_expression: + description: A cron expression in UTC specifying when Backup initiates a backup job. + returned: always + type: str + sample: "cron(0 5 ? * * *)" + start_window_minutes: + description: + - A value in minutes after a backup is scheduled before a job will be canceled if it + doesn't start successfully. + type: int + sample: 480 + completion_window_minutes: + description: + - A value in minutes after a backup job is successfully started before it must be + completed or it will be canceled by Backup. + type: int + sample: 10080 + lifecycle: + description: + - The lifecycle defines when a protected resource is transitioned to cold storage and when + it expires. + type: dict + sample: {} + recovery_point_tags: + description: + - An array of key-value pair strings that are assigned to resources that are associated with + this rule when restored from backup. + type: dict + sample: {} + rule_id: + description: + - Uniquely identifies a rule that is used to schedule the backup of a selection of resources. + type: str + returned: always + sample: "973621ef-d863-41ef-b5c3-9e943a64ad0c" + copy_actions: + description: An array of CopyAction objects, which contains the details of the copy operation. + type: list + returned: always + sample: [] + enable_continous_backup: + description: Specifies whether Backup creates continuous backups. + type: bool + returned: always + sample: false + schedule_expression_timezone: + description: + - This is the timezone in which the schedule expression is set. + - This information is returned for botocore versions >= 1.31.36. + type: str + returned: when botocore >= 1.31.36 + sample: "Etc/UTC" + version_added: 7.3.0 advanced_backup_settings: description: Advanced backup settings of the backup plan. returned: when configured @@ -281,6 +354,7 @@ schedule_expression=dict(type="str", default="cron(0 5 ? * * *)"), start_window_minutes=dict(type="int", default=480), completion_window_minutes=dict(type="int", default=10080), + schedule_expression_timezone=dict(type="str", default="Etc/UTC"), lifecycle=dict( type="dict", options=dict( @@ -542,6 +616,7 @@ def main(): client = module.client("backup") state = module.params["state"] plan_name = module.params["backup_plan_name"] + plan = { "backup_plan_name": module.params["backup_plan_name"], "rules": [scrub_none_parameters(rule) for rule in module.params["rules"] or []], @@ -549,6 +624,15 @@ def main(): scrub_none_parameters(setting) for setting in module.params["advanced_backup_settings"] or [] ], } + + if module.params["rules"]: + for each in plan["rules"]: + if not module.botocore_at_least("1.31.36"): + module.warn( + "schedule_expression_timezone requires botocore >= 1.31.36. schedule_expression_timezone will be ignored." + ) + each.pop("schedule_expression_timezone") + tags = module.params["tags"] # Get existing backup plan details and ID if present diff --git a/tests/integration/targets/backup_plan/meta/main.yml b/tests/integration/targets/backup_plan/meta/main.yml new file mode 100644 index 00000000000..afaa9f42b5d --- /dev/null +++ b/tests/integration/targets/backup_plan/meta/main.yml @@ -0,0 +1,5 @@ +--- +dependencies: + - role: setup_botocore_pip + vars: + botocore_version: "1.31.36" diff --git a/tests/integration/targets/backup_plan/tasks/main.yml b/tests/integration/targets/backup_plan/tasks/main.yml index ea95eacb8ed..ee8f62ec9a5 100644 --- a/tests/integration/targets/backup_plan/tasks/main.yml +++ b/tests/integration/targets/backup_plan/tasks/main.yml @@ -305,6 +305,45 @@ - backup_plan_delete_result.backup_plan_arn == backup_plan_info.backup_plans[0].backup_plan_arn - backup_plan_delete_result.deletion_date is defined + - name: Create a backup plan using specific botocore version + amazon.aws.backup_plan: + backup_plan_name: "{{ backup_plan_name }}" + rules: + - rule_name: daily + target_backup_vault_name: "{{ backup_vault_name }}" + tags: + Environment: Test + register: backup_plan_create_result + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - name: Verify backup plan create result + ansible.builtin.assert: + that: + - backup_plan_create_result.exists is true + - backup_plan_create_result.changed is true + - backup_plan_create_result.backup_plan_name == backup_plan_name + - backup_plan_create_result.backup_plan.rules != [] + - "backup_plan_create_result.backup_plan.rules | selectattr('schedule_expression_timezone', 'match', 'Etc/UTC') | list" + + - name: Create a backup plan using specific botocore version (idempotency) + amazon.aws.backup_plan: + backup_plan_name: "{{ backup_plan_name }}" + rules: + - rule_name: daily + target_backup_vault_name: "{{ backup_vault_name }}" + tags: + Environment: Test + register: backup_plan_create_result + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - name: Verify backup plan create result + ansible.builtin.assert: + that: + - backup_plan_create_result.exists is true + - backup_plan_create_result.changed is false + always: - name: Delete AWS Backup plan created during this test amazon.aws.backup_plan: