diff --git a/changelogs/fragments/20240613_ec2_placement_group_tags.yml b/changelogs/fragments/20240613_ec2_placement_group_tags.yml new file mode 100644 index 00000000000..2121536cc29 --- /dev/null +++ b/changelogs/fragments/20240613_ec2_placement_group_tags.yml @@ -0,0 +1,2 @@ +minor_changes: + - ec2_placement_group - Added support for creating with ``tags`` diff --git a/plugins/modules/ec2_placement_group.py b/plugins/modules/ec2_placement_group.py index 3cdb5be219e..88a083fd77e 100644 --- a/plugins/modules/ec2_placement_group.py +++ b/plugins/modules/ec2_placement_group.py @@ -43,6 +43,11 @@ default: cluster choices: [ 'cluster', 'spread', 'partition' ] type: str + tags: + description: + - A dict of key value pairs to associate with the placement group + type: dict + version_added: 9.0.0 extends_documentation_fragment: - amazon.aws.common.modules - amazon.aws.region.modules @@ -95,6 +100,14 @@ description: PG strategy type: str sample: "cluster" + tags: + description: Tags associated with the placement group + type: dict + sample: + tags: + version_added: 9.0.0 + some: value1 + other: value2 """ try: @@ -104,6 +117,8 @@ from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry +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 boto3_tag_specifications from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule @@ -127,6 +142,7 @@ def search_placement_group(connection, module): "name": placement_group["GroupName"], "state": placement_group["State"], "strategy": placement_group["Strategy"], + "tags": boto3_tag_list_to_ansible_dict(placement_group.get("Tags")), } @@ -141,6 +157,7 @@ def get_placement_group_information(connection, name): "name": placement_group["GroupName"], "state": placement_group["State"], "strategy": placement_group["Strategy"], + "tags": boto3_tag_list_to_ansible_dict(placement_group.get("Tags")), } @@ -148,6 +165,7 @@ def get_placement_group_information(connection, name): def create_placement_group(connection, module): name = module.params.get("name") strategy = module.params.get("strategy") + tags = module.params.get("tags") partition_count = module.params.get("partition_count") if strategy != "partition" and partition_count: @@ -156,6 +174,8 @@ def create_placement_group(connection, module): params = {} params["GroupName"] = name params["Strategy"] = strategy + if tags: + params["TagSpecifications"] = boto3_tag_specifications(tags, types=["placement-group"]) if partition_count: params["PartitionCount"] = partition_count params["DryRun"] = module.check_mode @@ -169,6 +189,7 @@ def create_placement_group(connection, module): "name": name, "state": "DryRun", "strategy": strategy, + "tags": tags, }, ) except ( @@ -198,6 +219,7 @@ def main(): partition_count=dict(type="int"), state=dict(default="present", choices=["present", "absent"]), strategy=dict(default="cluster", choices=["cluster", "spread", "partition"]), + tags=dict(type="dict"), ) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) diff --git a/plugins/modules/ec2_placement_group_info.py b/plugins/modules/ec2_placement_group_info.py index 05b37488cfe..f89ffc0d02d 100644 --- a/plugins/modules/ec2_placement_group_info.py +++ b/plugins/modules/ec2_placement_group_info.py @@ -75,6 +75,7 @@ except ImportError: pass # caught by AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule @@ -102,6 +103,7 @@ def get_placement_groups_details(connection, module): "name": placement_group["GroupName"], "state": placement_group["State"], "strategy": placement_group["Strategy"], + "tags": boto3_tag_list_to_ansible_dict(placement_group.get("Tags")), } ) return results diff --git a/tests/integration/targets/ec2_placement_group/tasks/main.yml b/tests/integration/targets/ec2_placement_group/tasks/main.yml index 10695571ebf..eec1b168ef0 100644 --- a/tests/integration/targets/ec2_placement_group/tasks/main.yml +++ b/tests/integration/targets/ec2_placement_group/tasks/main.yml @@ -241,6 +241,105 @@ - pg_3_create_check_mode_idem.placement_group.state == "available" - '"ec2:CreatePlacementGroup" not in pg_3_create_check_mode_idem.resource_actions' + - name: Create a placement group 4 with tags - check_mode + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: present + strategy: cluster + tags: + foo: test1 + bar: test2 + check_mode: true + register: pg_4_create_check_mode + + - assert: + that: + - pg_4_create_check_mode is changed + - pg_4_create_check_mode.placement_group.name == resource_prefix ~ '-pg4' + - pg_4_create_check_mode.placement_group.state == "DryRun" + - pg_4_create_check_mode.placement_group.tags.foo == "test1" + - pg_4_create_check_mode.placement_group.tags.bar == "test2" + - '"ec2:CreatePlacementGroup" in pg_4_create_check_mode.resource_actions' + + - name: Create a placement group 4 with tags + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: present + strategy: cluster + tags: + foo: test1 + bar: test2 + register: pg_4_create + + - assert: + that: + - pg_4_create is changed + - pg_4_create.placement_group.name == resource_prefix ~ '-pg4' + - pg_4_create.placement_group.state == "available" + - pg_4_create.placement_group.tags.foo == "test1" + - pg_4_create.placement_group.tags.bar == "test2" + - '"ec2:CreatePlacementGroup" in pg_4_create.resource_actions' + + - set_fact: + placement_group_names: "{{ placement_group_names + [pg_4_create.placement_group.name] }}" + + - name: Gather information about placement group 4 + community.aws.ec2_placement_group_info: + names: + - '{{ resource_prefix }}-pg4' + register: pg_4_info_result + + - assert: + that: + - pg_4_info_result is not changed + - pg_4_info_result.placement_groups[0].name == resource_prefix ~ '-pg4' + - pg_4_info_result.placement_groups[0].state == "available" + - pg_4_info_result.placement_groups[0].strategy == "cluster" + - pg_4_info_result.placement_groups[0].tags.foo == "test1" + - pg_4_info_result.placement_groups[0].tags.bar == "test2" + - '"ec2:DescribePlacementGroups" in pg_4_info_result.resource_actions' + + - name: Create a placement group 4 with tags - Idempotency + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: present + strategy: cluster + tags: + foo: test1 + bar: test2 + register: pg_4_create + + - assert: + that: + - pg_4_create is not changed + - pg_4_create.placement_group.name == resource_prefix ~ '-pg4' + - pg_4_create.placement_group.state == "available" + - pg_4_create.placement_group.strategy == "cluster" + - pg_4_create.placement_group.tags.foo == "test1" + - pg_4_create.placement_group.tags.bar == "test2" + - '"ec2:CreatePlacementGroup" not in pg_4_create.resource_actions' + + - name: Create a placement group 4 with tags - check_mode Idempotency + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: present + strategy: cluster + tags: + foo: test1 + bar: test2 + check_mode: true + register: pg_4_create_check_mode_idem + + - assert: + that: + - pg_4_create_check_mode_idem is not changed + - pg_4_create_check_mode_idem.placement_group.name == resource_prefix ~ '-pg4' + - pg_4_create_check_mode_idem.placement_group.state == "available" + - pg_4_create_check_mode_idem.placement_group.strategy == "cluster" + - pg_4_create_check_mode_idem.placement_group.tags.foo == "test1" + - pg_4_create_check_mode_idem.placement_group.tags.bar == "test2" + - '"ec2:CreatePlacementGroup" not in pg_4_create_check_mode_idem.resource_actions' + - name: List all placement groups. community.aws.ec2_placement_group_info: register: all_ec2_placement_groups @@ -397,6 +496,56 @@ - pg_3_delete_check_mode_idem is not changed - '"ec2:DeletePlacementGroup" not in pg_3_delete_check_mode_idem.resource_actions' + - name: Delete a placement group 4 - check_mode + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: absent + check_mode: true + register: pg_4_delete_check_mode + ignore_errors: true + + - assert: + that: + - pg_4_delete_check_mode is not changed + - pg_4_delete_check_mode.error.code == 'DryRunOperation' + - '"ec2:DeletePlacementGroup" in pg_4_delete_check_mode.resource_actions' + + + - name: Delete a placement group 4 + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: absent + register: pg_4_delete + + - assert: + that: + - pg_4_delete is changed + - '"ec2:DeletePlacementGroup" in pg_4_delete.resource_actions' + + - name: Delete a placement group 4 - Idempotency + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: absent + register: pg_4_delete + + - assert: + that: + - pg_4_delete is not changed + - '"ec2:DeletePlacementGroup" not in pg_4_delete.resource_actions' + + - name: Delete a placement group 4 - check_mode Idempotency + community.aws.ec2_placement_group: + name: '{{ resource_prefix }}-pg4' + state: absent + check_mode: true + register: pg_4_delete_check_mode_idem + ignore_errors: true + + - assert: + that: + - pg_4_delete_check_mode_idem is not changed + - '"ec2:DeletePlacementGroup" not in pg_4_delete_check_mode_idem.resource_actions' + always: - name: Make sure placement groups created during test are deleted