diff --git a/changelogs/fragments/1633-backup-selection-conditions.yml b/changelogs/fragments/1633-backup-selection-conditions.yml new file mode 100644 index 00000000000..8fac9ef4ce3 --- /dev/null +++ b/changelogs/fragments/1633-backup-selection-conditions.yml @@ -0,0 +1,5 @@ +minor_changes: +- backup_selection - add validation and documentation for all conditions suboptions (https://github.com/ansible-collections/amazon.aws/pull/1633). + +bugfixes: +- module_utils.backup - get_selection_details fix empty list returned when multiple backup selections exist (https://github.com/ansible-collections/amazon.aws/pull/1633). diff --git a/plugins/module_utils/backup.py b/plugins/module_utils/backup.py index b456ab970cc..a9e3e6ed01b 100644 --- a/plugins/module_utils/backup.py +++ b/plugins/module_utils/backup.py @@ -144,7 +144,7 @@ def get_selection_details(module, client, plan_name: str, selection_name: Union[ if selection["SelectionName"] == selection_name: selection_id = selection["SelectionId"] result.append(_get_backup_selection(client, module, plan_id, selection_id)) - break + break else: for selection in selection_list: selection_id = selection["SelectionId"] diff --git a/plugins/modules/backup_selection.py b/plugins/modules/backup_selection.py index e6edc251a31..6dd7454e0ee 100644 --- a/plugins/modules/backup_selection.py +++ b/plugins/modules/backup_selection.py @@ -43,13 +43,14 @@ description: - A list of conditions that you define to assign resources to your backup plans using tags. - Condition operators are case sensitive. + - When you specify more than one condition in I(list_of_tags), you assign all resources that match AT LEAST ONE condition (using OR logic). type: list elements: dict suboptions: condition_type: description: - An operation applied to a key-value pair used to assign resources to your backup plan. - - Condition only supports C(StringEquals). + - Condition only supports C(string_equals). type: str condition_key: description: @@ -69,8 +70,71 @@ conditions: description: - A list of conditions (expressed as a dict) that you define to assign resources to your backup plans using tags. - - I(conditions) supports C(StringEquals), C(StringLike), C(StringNotEquals), and C(StringNotLike). I(list_of_tags) only supports C(StringEquals). + - When you specify more than one condition in I(conditions), you only assign the resources that match ALL conditions (using AND logic). + - I(conditions) supports C(string_equals), C(string_like), C(string_not_equals), and C(string_not_like). I(list_of_tags) only supports C(string_equals). type: dict + suboptions: + string_equals: + description: + - Filters the values of your tagged resources for only those resources that you tagged with the same value. + type: list + default: [] + elements: dict + suboptions: + condition_key: + description: + - The key in a key-value pair. + - I(condition_key) in the I(conditions) option must use the AWS resource tag prefix, e.g. 'aws:ResourceTag/key-name' + type: str + condition_value: + description: The value in a key-value pair. + type: str + string_like: + description: + - Filters the values of your tagged resources for matching tag values with the use of a wildcard character (*) anywhere in the string. + For example, "prod*" or "*rod*" matches the tag value "production". + type: list + default: [] + elements: dict + suboptions: + condition_key: + description: + - The key in a key-value pair. + - I(condition_key) in the I(conditions) option must use the AWS resource tag prefix, e.g. 'aws:ResourceTag/key-name' + type: str + condition_value: + description: The value in a key-value pair. + type: str + string_not_equals: + description: + - Filters the values of your tagged resources for only those resources that you tagged that do not have the same value. + type: list + default: [] + elements: dict + suboptions: + condition_key: + description: + - The key in a key-value pair. + - I(condition_key) in the I(conditions) option must use the AWS resource tag prefix, e.g. 'aws:ResourceTag/key-name' + type: str + condition_value: + description: The value in a key-value pair. + type: str + string_not_like: + description: + - Filters the values of your tagged resources for non-matching tag values with the use of a wildcard character (*) anywhere in the string. + type: list + default: [] + elements: dict + suboptions: + condition_key: + description: + - The key in a key-value pair. + - I(condition_key) in the I(conditions) option must use the AWS resource tag prefix, e.g. 'aws:ResourceTag/key-name' + type: str + condition_value: + description: The value in a key-value pair. + type: str state: description: - Create, delete a backup selection. @@ -220,7 +284,47 @@ def main(): backup_plan_name=dict(type="str", required=True, aliases=["plan_name"]), iam_role_arn=dict(type="str"), resources=dict(type="list", elements="str"), - conditions=dict(type="dict"), + conditions=dict( + type="dict", + options=dict( + string_equals=dict( + type="list", + default=[], + elements="dict", + options=dict( + condition_key=dict(type="str", no_log=False), + condition_value=dict(type="str"), + ), + ), + string_like=dict( + type="list", + default=[], + elements="dict", + options=dict( + condition_key=dict(type="str", no_log=False), + condition_value=dict(type="str"), + ), + ), + string_not_equals=dict( + type="list", + default=[], + elements="dict", + options=dict( + condition_key=dict(type="str", no_log=False), + condition_value=dict(type="str"), + ), + ), + string_not_like=dict( + type="list", + default=[], + elements="dict", + options=dict( + condition_key=dict(type="str", no_log=False), + condition_value=dict(type="str"), + ), + ), + ), + ), not_resources=dict(type="list", elements="str"), list_of_tags=dict( type="list", @@ -271,8 +375,7 @@ def main(): if current_selection: results["exists"] = True - update_needed |= check_for_update(current_selection, backup_selection_data, iam_role_arn) - + update_needed = check_for_update(current_selection, backup_selection_data, iam_role_arn) if update_needed: if module.check_mode: results["changed"] = True diff --git a/tests/integration/targets/backup_selection/tasks/main.yml b/tests/integration/targets/backup_selection/tasks/main.yml index c29d738b3c3..aba34a2ba36 100644 --- a/tests/integration/targets/backup_selection/tasks/main.yml +++ b/tests/integration/targets/backup_selection/tasks/main.yml @@ -18,60 +18,36 @@ wait: true register: iam_role - # Wait for the role to be created - - pause: - seconds: 5 + - name: Wait for the role to be created + ansible.builtin.pause: + seconds: 8 - name: Create an AWS Backup vault for the plan to target amazon.aws.backup_vault: backup_vault_name: "{{ backup_vault_name }}" - register: _resutl_create_backup_vault + register: _result_create_backup_vault - name: Verify result ansible.builtin.assert: that: - - _resutl_create_backup_vault.changed - - # - name: Create an AWS Backup plan - # amazon.aws.backup_plan: - # backup_plan_name: "{{ backup_plan_name }}" - # rules: - # - RuleName: DailyBackups - # TargetBackupVaultName: "{{ backup_vault_name }}" - # ScheduleExpression: "cron(0 5 ? * * *)" - # StartWindowMinutes: 60 - # CompletionWindowMinutes: 1440 - # tags: - # environment: test - # register: _resutl_create_backup_plan - - # - name: Verify result - # ansible.builtin.assert: - # that: - # - _resutl_create_backup_plan.changed - - # - name: Get detailed information about the AWS Backup plan - # amazon.aws.backup_plan_info: - # backup_plan_names: - # - "{{ backup_plan_name }}" - # register: _result_backup_plan_info - - # - name: Verify result - # ansible.builtin.assert: - # that: - # - _result_backup_plan_info.backup_plans | length == 1 - - - name: Create an AWS Backup plan - command: aws backup create-backup-plan --backup-plan "{\"BackupPlanName\":\"{{ backup_plan_name }}\",\"Rules\":[{\"RuleName\":\"DailyBackups\",\"ScheduleExpression\":\"cron(0 5 ? * * *)\",\"StartWindowMinutes\":60,\"TargetBackupVaultName\":\"{{ backup_vault_name }}\",\"CompletionWindowMinutes\":1440,\"Lifecycle\":{\"DeleteAfterDays\":35}}]}" - environment: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - AWS_SESSION_TOKEN: "{{ security_token | default('') }}" - AWS_DEFAULT_REGION: "{{ aws_region }}" + - _result_create_backup_vault.changed + + - name: Create an AWS Backup plan for the selection to target + amazon.aws.backup_plan: + backup_plan_name: "{{ backup_plan_name }}" + rules: + - rule_name: DailyBackups + target_backup_vault_name: "{{ backup_vault_name }}" + schedule_expression: "cron(0 5 ? * * *)" + start_window_minutes: 60 + completion_window_minutes: 1440 + tags: + environment: test register: _result_create_backup_plan - - set_fact: - backup_plan_id: "{{ (_result_create_backup_plan.stdout | from_json).BackupPlanId }}" + - name: Set backup plan ID + ansible.builtin.set_fact: + backup_plan_id: "{{ _result_create_backup_plan.backup_plan_id }}" - name: Create an AWS Backup selection (check_mode) amazon.aws.backup_selection: @@ -82,6 +58,10 @@ - condition_type: "STRINGEQUALS" condition_key: "backup" condition_value: "daily" + conditions: + string_like: + - condition_key: "aws:ResourceTag/environment" + condition_value: "prod*" check_mode: true register: _create_result_backup_selection @@ -99,6 +79,10 @@ - condition_type: "STRINGEQUALS" condition_key: "backup" condition_value: "daily" + conditions: + string_like: + - condition_key: "aws:ResourceTag/environment" + condition_value: "prod*" register: _create_result_backup_selection - name: Verify result @@ -118,6 +102,10 @@ - condition_type: "STRINGEQUALS" condition_key: "backup" condition_value: "daily" + conditions: + string_like: + - condition_key: "aws:ResourceTag/environment" + condition_value: "prod*" register: _create_result_backup_selection - name: Verify result @@ -155,6 +143,10 @@ - condition_type: "STRINGEQUALS" condition_key: "backup" condition_value: "weekly" + conditions: + string_not_equals: + - condition_key: "aws:ResourceTag/environment" + condition_value: "dev" check_mode: true register: _modify_result_backup_selection @@ -172,6 +164,10 @@ - condition_type: "STRINGEQUALS" condition_key: "backup" condition_value: "weekly" + conditions: + string_not_equals: + - condition_key: "aws:ResourceTag/environment" + condition_value: "dev" register: _modify_result_backup_selection - name: Verify result @@ -191,6 +187,10 @@ - condition_type: "STRINGEQUALS" condition_key: "backup" condition_value: "weekly" + conditions: + string_not_equals: + - condition_key: "aws:ResourceTag/environment" + condition_value: "dev" register: _modify_result_backup_selection - name: Verify result @@ -260,19 +260,10 @@ state: absent ignore_errors: true - # - name: Delete AWS Backup plan created during this test - # amazon.aws.backup_plan: - # backup_plan_name: "{{ backup_plan_name }}" - # state: absent - # ignore_errors: true - - name: Delete AWS Backup plan created during this test - command: aws backup delete-backup-plan --backup-plan-id "{{ backup_plan_id }}" - environment: - AWS_ACCESS_KEY_ID: "{{ aws_access_key }}" - AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}" - AWS_SESSION_TOKEN: "{{ security_token | default('') }}" - AWS_DEFAULT_REGION: "{{ aws_region }}" + amazon.aws.backup_plan: + backup_plan_name: "{{ backup_plan_name }}" + state: absent ignore_errors: true - name: Delete AWS Backup vault created during this test @@ -280,3 +271,9 @@ backup_vault_name: "{{ backup_vault_name }}" state: absent ignore_errors: true + + - name: Delete IAM role created during this test + community.aws.iam_role: + name: "{{ backup_iam_role_name }}" + state: absent + ignore_errors: true