diff --git a/changelogs/fragments/1574-ssm-parameter-support-for-tags.yml b/changelogs/fragments/1574-ssm-parameter-support-for-tags.yml new file mode 100644 index 00000000000..6340f821972 --- /dev/null +++ b/changelogs/fragments/1574-ssm-parameter-support-for-tags.yml @@ -0,0 +1,2 @@ +minor_changes: + - ssm_parameter - add support for tags in ssm parameters (https://github.com/ansible-collections/community.aws/issues/1573). \ No newline at end of file diff --git a/plugins/modules/ssm_parameter.py b/plugins/modules/ssm_parameter.py index b7544d4a569..c435305c244 100644 --- a/plugins/modules/ssm_parameter.py +++ b/plugins/modules/ssm_parameter.py @@ -90,6 +90,11 @@ - amazon.aws.aws - amazon.aws.ec2 - amazon.aws.boto3 + - amazon.aws.tags + +notes: + - Support for I(tags) and I(purge_tags) was added in release 5.3.0. + ''' EXAMPLES = ''' @@ -137,6 +142,29 @@ - name: recommend to use with aws_ssm lookup plugin ansible.builtin.debug: msg: "{{ lookup('amazon.aws.aws_ssm', 'Hello') }}" + +- name: Create or update key/value pair in AWS SSM parameter store w/ tags + community.aws.ssm_parameter: + name: "Hello" + description: "This is your first key" + value: "World" + tags: + Environment: "dev" + Version: "1.0" + Confidentiality: "low" + Tag With Space: "foo bar" + +- name: Add or update a tag on an existing parameter w/o removing existing tags + community.aws.ssm_parameter: + name: "Hello" + purge_tags: false + tags: + Contact: "person1" + +- name: Delete all tags on an existing parameter + community.aws.ssm_parameter: + name: "Hello" + tags: {} ''' RETURN = ''' @@ -208,12 +236,19 @@ description: Parameter version number example: 3 returned: success + tags: + description: A dictionary representing the tags associated with the parameter. + type: dict + returned: when the parameter has tags + example: {'MyTagName': 'Some Value'} + version_added: 5.3.0 ''' import time try: import botocore + from botocore.exceptions import BotoCoreError, ClientError except ImportError: pass # Handled by AnsibleAWSModule @@ -223,6 +258,9 @@ from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory +from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list +from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict +from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags class ParameterWaiterFactory(BaseWaiterFactory): @@ -301,6 +339,58 @@ def _wait_deleted(client, module, name): module.fail_json_aws(e, msg="Failed to describe parameter while waiting for deletion") +def tag_parameter(client, module, parameter_name, tags): + try: + return client.add_tags_to_resource(aws_retry=True, ResourceType='Parameter', + ResourceId=parameter_name, Tags=tags) + except (BotoCoreError, ClientError) as e: + module.fail_json_aws(e, msg="Failed to add tag(s) to parameter") + + +def untag_parameter(client, module, parameter_name, tag_keys): + try: + return client.remove_tags_from_resource(aws_retry=True, ResourceType='Parameter', + ResourceId=parameter_name, TagKeys=tag_keys) + except (BotoCoreError, ClientError) as e: + module.fail_json_aws(e, msg="Failed to remove tag(s) from parameter") + + +def get_parameter_tags(client, module, parameter_name): + try: + tags = client.list_tags_for_resource(aws_retry=True, ResourceType='Parameter', + ResourceId=parameter_name)['TagList'] + tags_dict = boto3_tag_list_to_ansible_dict(tags) + return tags_dict + except (BotoCoreError, ClientError) as e: + module.fail_json_aws(e, msg="Unable to retrieve parameter tags") + + +def update_parameter_tags(client, module, parameter_name, supplied_tags): + changed = False + response = {} + + if supplied_tags is None: + return False, response + + current_tags = get_parameter_tags(client, module, parameter_name) + tags_to_add, tags_to_remove = compare_aws_tags(current_tags, supplied_tags, + module.params.get('purge_tags')) + + if tags_to_add: + if module.check_mode: + return True, response + response = tag_parameter(client, module, parameter_name, + ansible_dict_to_boto3_tag_list(tags_to_add)) + changed = True + if tags_to_remove: + if module.check_mode: + return True, response + response = untag_parameter(client, module, parameter_name, tags_to_remove) + changed = True + + return changed, response + + def update_parameter(client, module, **args): changed = False response = {} @@ -310,8 +400,8 @@ def update_parameter(client, module, **args): try: response = client.put_parameter(aws_retry=True, **args) changed = True - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg="setting parameter") + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as exc: + module.fail_json_aws(exc, msg="setting parameter") return changed, response @@ -324,6 +414,9 @@ def describe_parameter(client, module, **args): if not existing_parameter['Parameters']: return None + tags_dict = get_parameter_tags(client, module, module.params.get('name')) + existing_parameter['Parameters'][0]['tags'] = tags_dict + return existing_parameter['Parameters'][0] @@ -387,7 +480,25 @@ def create_update_parameter(client, module): (changed, response) = update_parameter(client, module, **args) if changed: _wait_updated(client, module, module.params.get('name'), original_version) + + # Handle tag updates for existing parameters + if module.params.get('overwrite_value') != 'never': + tags_changed, tags_response = update_parameter_tags( + client, module, existing_parameter['Parameter']['Name'], + module.params.get('tags')) + + changed = changed or tags_changed + + if tags_response: + response['tag_updates'] = tags_response + else: + # Add tags in initial creation request + if module.params.get('tags'): + args.update(Tags=ansible_dict_to_boto3_tag_list(module.params.get('tags'))) + # Overwrite=True conflicts with tags and is not needed for new param + args.update(Overwrite=False) + (changed, response) = update_parameter(client, module, **args) _wait_exists(client, module, module.params.get('name')) @@ -444,6 +555,8 @@ def setup_module_object(): key_id=dict(default="alias/aws/ssm"), overwrite_value=dict(default='changed', choices=['never', 'changed', 'always']), tier=dict(default='Standard', choices=['Standard', 'Advanced', 'Intelligent-Tiering']), + tags=dict(type='dict', aliases=['resource_tags']), + purge_tags=dict(type='bool', default=True), ) return AnsibleAWSModule( @@ -474,7 +587,8 @@ def main(): except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="to describe parameter") if parameter_metadata: - result['parameter_metadata'] = camel_dict_to_snake_dict(parameter_metadata) + result['parameter_metadata'] = camel_dict_to_snake_dict(parameter_metadata, + ignore_list=['tags']) module.exit_json(changed=changed, **result) diff --git a/tests/integration/targets/ssm_parameter/tasks/main.yml b/tests/integration/targets/ssm_parameter/tasks/main.yml index 3d4fb643b30..ac461392a96 100644 --- a/tests/integration/targets/ssm_parameter/tasks/main.yml +++ b/tests/integration/targets/ssm_parameter/tasks/main.yml @@ -23,6 +23,64 @@ simple_value: 'A simple VALue' updated_description: 'This is an updated example' updated_value: 'A simple VALue **UPDATED**' + simple_tag_param_name: '/{{ ssm_key_prefix }}/SimpleWithTags' + simple_tag_param_description: 'This is a simple example with tags' + simple_tag_param_updated_description: 'This is a simple example with tags (updated description)' + simple_tag_param_value: 'A simple VALue (w/ tags)' + single_tag: + Contact: "non-existent@ansible.com" + simple_tags_orig: + Contact: "non-existent@ansible.com" + Environment: "dev" + Version: "1.0" + Confidentiality: "low" + Tag With Space: "tag value with spaces" + simple_tags_add_owner: + Contact: "non-existent@ansible.com" + Environment: "dev" + Version: "1.0" + Confidentiality: "low" + Tag With Space: "foo" + Owner: "AWS" + simple_tags_change_environment: + Contact: "non-existent@ansible.com" + Environment: "test" + Version: "1.0" + Confidentiality: "low" + Tag With Space: "foo" + simple_tags_delete_version: + Contact: "non-existent@ansible.com" + Environment: "dev" + Confidentiality: "low" + Tag With Space: "foo" + simple_tags_delete_tag_with_space: + Contact: "non-existent@ansible.com" + Environment: "dev" + Version: "1.0" + Confidentiality: "low" + simple_tags_add_delete_change: + Contact: "non-existent@ansible.com" + Environment: "test" + Confidentiality: "low" + Tag With Space: "foo" + Owner: "AWS" + simple_tags_delete_all_tags: {} + simple_tags_purge_false_add_owner: + Owner: "AWS" + simple_tags_purge_false_add_multiple: + Contact1: "person1" + Contact2: "person2" + Contact3: "person3" + simple_tags_purge_false_change_environment: + Environment: "test" + simple_tags_purge_false_change_multiple: + Environment: "test" + Version: "2.0" + Confidentiality: "med" + Tag With Space: "tag value even more spaces" + simple_tags_purge_false_add_and_change: + Owner: "AWS" + Environment: "test" block: # ============================================================ @@ -439,6 +497,1094 @@ - '"description" in result.parameter_metadata' - result.parameter_metadata.description == simple_description + # ============================================================ + # Test tags - Create parameter with tags case + + - name: Create parameter with tags case - Create parameter (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Create parameter with tags case - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Create parameter with tags case - Ensure tags is correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_orig['{{ item.key }}'] + loop: "{{ simple_tags_orig | dict2items }}" + + - name: Create parameter with tags case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_orig | length + + - name: Create parameter with tags case - Ensure only tags have changed + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + # ============================================================ + # Test tags - Update description only case + + - name: Update description only case - Update parameter (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_updated_description }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Update description only case - Update parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_updated_description }}' + register: result + + - name: Update description only case - Ensure expected tags is correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_orig['{{ item.key }}'] + loop: "{{ simple_tags_orig | dict2items }}" + + - name: Update description only case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_orig | length + + - name: Update description only case - Ensure only description changed + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_updated_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + # ============================================================ + # Test tags - Add tag to existing parameter case + + - name: Add tag to existing parameter case - Update parameter (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_add_owner }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Add tag to existing parameter case - Update parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_add_owner }}' + register: result + + - name: Add tag to existing parameter case - Ensure tags correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_add_owner['{{ item.key }}'] + loop: "{{ simple_tags_add_owner | dict2items }}" + + - name: Add tag to existing parameter case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_add_owner | length + + - name: Add tag to existing parameter case - Ensure only tags changed + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_updated_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Add tag to existing parameter case - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - update tags only - change tag + + - name: Change single tag case - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Change single tag case - Update tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_change_environment }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Change single tag case - Update tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_change_environment }}' + register: result + + - name: Change single tag case - Ensure expected tags is correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_change_environment['{{ item.key }}'] + loop: "{{ simple_tags_change_environment | dict2items }}" + + - name: Change single tag case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_change_environment | length + + - name: Change single tag case - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Change single tag case - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - delete tag case + + - name: Delete single tag case - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Delete single tag case - Update tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_delete_version }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Delete single tag case - Update tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_delete_version }}' + register: result + + - name: Delete single tag case - Ensure expected tags is correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_delete_version['{{ item.key }}'] + loop: "{{ simple_tags_delete_version | dict2items }}" + + - name: Delete single tag case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_delete_version | length + + - name: Delete single tag case - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Delete single tag case - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - delete tag w/ spaces case + + - name: Delete single tag w/ spaces case - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Delete single tag w/ spaces case - Update tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_delete_tag_with_space }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Delete single tag w/ spaces case - Update tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_delete_tag_with_space }}' + register: result + + - name: Delete single tag w/ spaces case - Ensure expected tags is correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_delete_tag_with_space['{{ item.key }}'] + loop: "{{ simple_tags_delete_tag_with_space | dict2items }}" + + - name: Delete single tag w/ spaces case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_delete_tag_with_space | length + + - name: Delete single tag w/ spaces case - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Delete single tag w/ spaces case - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Add/delete/change tags case + + - name: Add/delete/change tags case - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Add/delete/change tags case - Update tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_add_delete_change }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Add/delete/change tags case - Update tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_add_delete_change }}' + register: result + + - name: Add/delete/change tags case - Ensure expected tags is correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_add_delete_change['{{ item.key }}'] + loop: "{{ simple_tags_add_delete_change | dict2items }}" + + - name: Add/delete/change tags case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_add_delete_change | length + + - name: Add/delete/change tags case - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Add/delete/change tags case - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Delete all tags case + + - name: Delete all tags case - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Delete all tags case - Update tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_delete_all_tags }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Delete all tags case - Update tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_delete_all_tags }}' + register: result + + - name: Delete all tags case - Ensure expected tags is correct + assert: + that: + - result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_delete_all_tags['{{ item.key }}'] + loop: "{{ simple_tags_delete_all_tags | dict2items }}" + + - name: Delete all tags case - Ensure no missing or additional tags + assert: + that: + - result.parameter_metadata.tags | length == simple_tags_delete_all_tags | length + + - name: Delete all tags case - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Delete all tags case - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Add tag case (purge_tags=false) + + - name: Add tag case (purge_tags=false) - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Add tag case (purge_tags=false) - Add tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_add_owner }}' + purge_tags: False + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Add tag case (purge_tags=false) - Add tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_add_owner }}' + purge_tags: False + register: result + + - name: Add tag case (purge_tags=false) - Ensure expected tags is correct + assert: + that: + - > + result.parameter_metadata.tags['{{ item.key }}'] == + (simple_tags_orig | combine(simple_tags_purge_false_add_owner))['{{ item.key }}'] + loop: > + {{ simple_tags_orig | combine(simple_tags_purge_false_add_owner) | dict2items }} + + - name: Add tag case (purge_tags=false) - Ensure no missing or additional tags + assert: + that: + - > + result.parameter_metadata.tags | length == {{ simple_tags_orig | + combine(simple_tags_purge_false_add_owner) | dict2items }} | length + + - name: Add tag case (purge_tags=false) - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Add tag case (purge_tags=false) - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Add multiple tags case (purge_tags=false) + + - name: Add multiple tags case (purge_tags=false) - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Add multiple tags case (purge_tags=false) - Add tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_add_multiple }}' + purge_tags: False + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Add multiple tags case (purge_tags=false) - Add tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_add_multiple }}' + purge_tags: False + register: result + + - name: Add multiple tags case (purge_tags=false) - Ensure expected tags is correct + assert: + that: + - > + result.parameter_metadata.tags['{{ item.key }}'] == + (simple_tags_orig | combine(simple_tags_purge_false_add_multiple))['{{ item.key }}'] + loop: > + {{ simple_tags_orig | combine(simple_tags_purge_false_add_multiple) | dict2items }} + + - name: Add multiple tags case (purge_tags=false) - Ensure no missing or additional tags + assert: + that: + - > + result.parameter_metadata.tags | length == {{ simple_tags_orig | + combine(simple_tags_purge_false_add_multiple) | dict2items }} | length + + - name: Add multiple tags case (purge_tags=false) - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Add multiple tags case (purge_tags=false) - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Change tag case (purge_tags=false) + + - name: Change tag case (purge_tags=false) - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Change tag case (purge_tags=false) - Change tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_change_environment}}' + purge_tags: False + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Change tag case (purge_tags=false) - Change tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_change_environment }}' + purge_tags: False + register: result + + - name: Change tag case (purge_tags=false) - Ensure expected tags is correct + assert: + that: + - > + result.parameter_metadata.tags['{{ item.key }}'] == + (simple_tags_orig | combine(simple_tags_purge_false_change_environment))['{{ item.key }}'] + loop: > + {{ simple_tags_orig | combine(simple_tags_purge_false_change_environment) | dict2items }} + loop_control: + extended: yes + + + - name: Change tag case (purge_tags=false) - Ensure no missing or additional tags + assert: + that: + - > + result.parameter_metadata.tags | length == {{ simple_tags_orig | + combine(simple_tags_purge_false_change_environment) | dict2items }} | length + + - name: Change tag case (purge_tags=false) - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Change tag case (purge_tags=false) - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Change multiple tags case (purge_tags=false) + + - name: Change multiple tags (purge_tags=false) - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Change multiple tags (purge_tags=false) - Change tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_change_multiple}}' + purge_tags: False + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Change multiple tags (purge_tags=false) - Change tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_change_multiple }}' + purge_tags: False + register: result + + - name: Change multiple tags (purge_tags=false) - Ensure expected tags is correct + assert: + that: + - > + result.parameter_metadata.tags['{{ item.key }}'] == + (simple_tags_orig | combine(simple_tags_purge_false_change_multiple))['{{ item.key }}'] + loop: > + {{ simple_tags_orig | combine(simple_tags_purge_false_change_multiple) | dict2items }} + loop_control: + extended: yes + + + - name: Change multiple tags (purge_tags=false) - Ensure no missing or additional tags + assert: + that: + - > + result.parameter_metadata.tags | length == {{ simple_tags_orig | + combine(simple_tags_purge_false_change_multiple) | dict2items }} | length + + - name: Change multiple tags (purge_tags=false) - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Change multiple tags (purge_tags=false) - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Add/Change multiple tags case (purge_tags=false) + + - name: Add/Change multiple tags (purge_tags=false) - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Add/Change multiple tags (purge_tags=false) - Change tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_add_and_change}}' + purge_tags: False + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: Add/Change multiple tags (purge_tags=false) - Change tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: '{{ simple_tags_purge_false_add_and_change }}' + purge_tags: False + register: result + + - name: Add/Change multiple tags (purge_tags=false) - Ensure expected tags is correct + assert: + that: + - > + result.parameter_metadata.tags['{{ item.key }}'] == + (simple_tags_orig | combine(simple_tags_purge_false_add_and_change))['{{ item.key }}'] + loop: > + {{ simple_tags_orig | combine(simple_tags_purge_false_add_and_change) | dict2items }} + loop_control: + extended: yes + + + - name: Add/Change multiple tags (purge_tags=false) - Ensure no missing or additional tags + assert: + that: + - > + result.parameter_metadata.tags | length == {{ simple_tags_orig | + combine(simple_tags_purge_false_add_and_change) | dict2items }} | length + + - name: Add/Change multiple tags (purge_tags=false) - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Add/Change multiple tags (purge_tags=false) - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - Empty tags dict case (purge_tags=false) # should be no change + + - name: Empty tags dict (purge_tags=false) - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: Empty tags dict (purge_tags=false) - Change tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: {} + purge_tags: False + register: result + check_mode: True + - assert: + that: + - result != 'changed' + + - name: Empty tags dict (purge_tags=false) - Change tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + tags: {} + purge_tags: False + register: result + + - name: Empty tags dict (purge_tags=false) - Ensure expected tags is correct + assert: + that: + - > + result.parameter_metadata.tags['{{ item.key }}'] == simple_tags_orig['{{ item.key }}'] + loop: > + {{ simple_tags_orig | dict2items }} + loop_control: + extended: yes + + - name: Empty tags dict (purge_tags=false) - Ensure no missing or additional tags + assert: + that: + - > + result.parameter_metadata.tags | length + == {{ simple_tags_orig | dict2items }} | length + + - name: Empty tags dict (purge_tags=false) - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result != 'changed' + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: Empty tags dict (purge_tags=false) - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: True + with_items: + - '{{ simple_tag_param_name }}' + + # ============================================================ + # Test tags - No tags parameter (purge_tags=true) case # should be no change + + - name: No tags parameter (purge_tags=true) - Create parameter + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_description }}' + value: '{{ simple_tag_param_value }}' + tags: '{{ simple_tags_orig }}' + register: result + + - name: No tags parameter (purge_tags=true) - Change tag (CHECK) + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_updated_description }}' + register: result + check_mode: True + - assert: + that: + - result is changed + + - name: No tags parameter (purge_tags=true) - Change tag + aws_ssm_parameter_store: + name: '{{ simple_tag_param_name }}' + description: '{{ simple_tag_param_updated_description }}' + register: result + + - name: No tags parameter (purge_tags=true) - Ensure expected tags is correct + assert: + that: + - > + result.parameter_metadata.tags['{{ item.key }}'] + == simple_tags_orig['{{ item.key }}'] + loop: > + {{ simple_tags_orig | dict2items }} + loop_control: + extended: true + + - name: No tags parameter (purge_tags=true) - Ensure no missing or additional tags + assert: + that: + - > + result.parameter_metadata.tags | length + == {{ simple_tags_orig | dict2items }} | length + + - name: No tags parameter (purge_tags=true) - Lookup a tagged parameter + set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', simple_tag_param_name, **connection_args) }}" + - assert: + that: + - result is changed + - lookup_value == simple_tag_param_value + - '"parameter_metadata" in result' + - '"data_type" in result.parameter_metadata' + - '"description" in result.parameter_metadata' + - '"last_modified_date" in result.parameter_metadata' + - '"last_modified_user" in result.parameter_metadata' + - '"name" in result.parameter_metadata' + - '"policies" in result.parameter_metadata' + - '"tier" in result.parameter_metadata' + - '"type" in result.parameter_metadata' + - '"version" in result.parameter_metadata' + - '"tags" in result.parameter_metadata' + - result.parameter_metadata.data_type == 'text' + - result.parameter_metadata.description == simple_tag_param_updated_description + - result.parameter_metadata.name == simple_tag_param_name + - result.parameter_metadata.policies | length == 0 + - result.parameter_metadata.tier == 'Standard' + - result.parameter_metadata.type == 'String' + + - name: No tags parameter (purge_tags=true) - Delete parameter + aws_ssm_parameter_store: + name: "{{item}}" + state: absent + ignore_errors: true + with_items: + - '{{ simple_tag_param_name }}' + always: # ============================================================ - name: Delete remaining key/value pairs in aws parameter store @@ -448,3 +1594,4 @@ ignore_errors: True with_items: - '{{ simple_name }}' + - '{{ simple_tag_param_name }}'