Skip to content

Commit

Permalink
Document and validate backup_selection conditions suboptions (#1633)
Browse files Browse the repository at this point in the history
Document and validate backup_selection conditions suboptions

SUMMARY
Adds documentation and validation for all conditions suboptions in backup_selection module. Fixes #1613
Additionally fixes a bug in module_utils.backup that caused an empty list to be returned from get_selection_details() when multiple backup selections exist for a given backup plan.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
backup_selection
module_utils.backup
ADDITIONAL INFORMATION
See #1613 for detailed description of related issue.

Reviewed-by: Jill R
Reviewed-by: Alina Buzachis
  • Loading branch information
hakbailey committed Jul 4, 2023
1 parent bfea52d commit cfeffe6
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 62 deletions.
5 changes: 5 additions & 0 deletions changelogs/fragments/1633-backup-selection-conditions.yml
Original file line number Diff line number Diff line change
@@ -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).
2 changes: 1 addition & 1 deletion plugins/module_utils/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
113 changes: 108 additions & 5 deletions plugins/modules/backup_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand Down
109 changes: 53 additions & 56 deletions tests/integration/targets/backup_selection/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -260,23 +260,20 @@
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
amazon.aws.backup_vault:
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

0 comments on commit cfeffe6

Please sign in to comment.