Skip to content

Commit

Permalink
Prepare ec2_placement_group* module for promotion (#2167)
Browse files Browse the repository at this point in the history
SUMMARY
This PR refactors ec2_placement_group*.
Depends-On: ansible-collections/amazon.aws#2322
Refer: https://issues.redhat.com/browse/ACA-1886


ISSUE TYPE


Bugfix Pull Request
Docs Pull Request
Feature Pull Request
New Module Pull Request

COMPONENT NAME

ADDITIONAL INFORMATION

Reviewed-by: Bikouo Aubin
Reviewed-by: GomathiselviS <[email protected]>
Reviewed-by: Alina Buzachis
  • Loading branch information
GomathiselviS authored Oct 16, 2024
1 parent d2403ab commit 290e89a
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 190 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/refactor_ec2_placement_group.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ec2_placement_group - Refactor module to use shared code from ``amazon.aws.plugins.module_utils.ec2`` and update ``RETURN`` block (https://github.com/ansible-collections/community.aws/pull/2167).
125 changes: 59 additions & 66 deletions plugins/modules/ec2_placement_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
partition_count:
description:
- The number of partitions.
- Valid only when I(Strategy) is set to C(partition).
- Must be a value between C(1) and C(7).
- Valid only when O(strategy) is set to V(partition).
- Must be a value between V(1) and V(7).
type: int
version_added: 3.1.0
state:
Expand Down Expand Up @@ -86,83 +86,88 @@
placement_group:
description: Placement group attributes
returned: when state != absent
type: complex
type: dict
contains:
group_arn:
description: Placement Group ARN.
type: str
returned: always
sample: "arn:aws:ec2:us-east-1:123456789012:placement-group"
group_id:
description: Placement Group Id.
type: str
returned: always
sample: "pg-123456789012"
name:
description: PG name
description: Placement Group name.
type: str
returned: always
sample: "my-cluster"
partition_count:
description: Partition Count.
type: str
sample: my-cluster
returned: If applicable
sample: "my-cluster"
state:
description: PG state
description: Placement Groupt state.
type: str
returned: If applicable
sample: "available"
strategy:
description: PG strategy
description: Placement Group strategy.
type: str
returned: If applicable
sample: "cluster"
tags:
description: Tags associated with the placement group
description: Tags associated with the placement group.
type: dict
returned: If applicable
version_added: 8.1.0
sample:
tags:
some: value1
other: value2
"""

try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
from typing import Any
from typing import Dict

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.module_utils.common.dict_transformations import camel_dict_to_snake_dict

from ansible_collections.amazon.aws.plugins.module_utils.ec2 import create_ec2_placement_group
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import delete_ec2_placement_group
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_ec2_placement_groups
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


@AWSRetry.exponential_backoff()
def search_placement_group(connection, module):
def search_placement_group(connection, name: str) -> Dict[str, Any]:
"""
Check if a placement group exists.
"""
name = module.params.get("name")
try:
response = connection.describe_placement_groups(Filters=[{"Name": "group-name", "Values": [name]}])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg=f"Couldn't find placement group named [{name}]")
response = describe_ec2_placement_groups(connection, Filters=[{"Name": "group-name", "Values": [name]}])

if len(response["PlacementGroups"]) != 1:
if len(response) != 1:
return None
else:
placement_group = response["PlacementGroups"][0]
return {
"name": placement_group["GroupName"],
"state": placement_group["State"],
"strategy": placement_group["Strategy"],
"tags": boto3_tag_list_to_ansible_dict(placement_group.get("Tags")),
}
return format_placement_group_information(response[0])


@AWSRetry.exponential_backoff(catch_extra_error_codes=["InvalidPlacementGroup.Unknown"])
def get_placement_group_information(connection, name):
def format_placement_group_information(response: Dict[str, Any]) -> Dict[str, Any]:
"""
Retrieve information about a placement group.
Format placement group information
"""
response = connection.describe_placement_groups(GroupNames=[name])
placement_group = response["PlacementGroups"][0]
return {
"name": placement_group["GroupName"],
"state": placement_group["State"],
"strategy": placement_group["Strategy"],
"tags": boto3_tag_list_to_ansible_dict(placement_group.get("Tags")),
}


@AWSRetry.exponential_backoff()
def create_placement_group(connection, module):

response = camel_dict_to_snake_dict(response, ignore_list=["Tags"])
if "tags" in response:
response["tags"] = boto3_tag_list_to_ansible_dict(response.get("tags", []))
response["name"] = response["group_name"]
return response


def create_placement_group(connection, module: AnsibleAWSModule) -> None:
name = module.params.get("name")
strategy = module.params.get("strategy")
tags = module.params.get("tags")
Expand All @@ -178,38 +183,26 @@ def create_placement_group(connection, module):
params["TagSpecifications"] = boto3_tag_specifications(tags, types=["placement-group"])
if partition_count:
params["PartitionCount"] = partition_count
params["DryRun"] = module.check_mode

try:
connection.create_placement_group(**params)
except is_boto3_error_code("DryRunOperation"):
if module.check_mode:
module.exit_json(
changed=True,
placement_group={
"name": name,
"state": "DryRun",
"strategy": strategy,
"tags": tags,
},
msg="EC2 placement group would be created if not in check mode",
)
except (
botocore.exceptions.ClientError,
botocore.exceptions.BotoCoreError,
) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg=f"Couldn't create placement group [{name}]")

module.exit_json(changed=True, placement_group=get_placement_group_information(connection, name))
response = create_ec2_placement_group(connection, **params)
module.exit_json(changed=True, placement_group=format_placement_group_information(response))


@AWSRetry.exponential_backoff()
def delete_placement_group(connection, module):
def delete_placement_group(connection, module: AnsibleAWSModule) -> None:
if module.check_mode:
module.exit_json(changed=True, msg="VPC would be deleted if not in check mode")
name = module.params.get("name")

try:
connection.delete_placement_group(GroupName=name, DryRun=module.check_mode)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg=f"Couldn't delete placement group [{name}]")

delete_ec2_placement_group(connection, name)
module.exit_json(changed=True)


Expand All @@ -227,9 +220,10 @@ def main():
connection = module.client("ec2")

state = module.params.get("state")
name = module.params.get("name")
placement_group = search_placement_group(connection, name)

if state == "present":
placement_group = search_placement_group(connection, module)
if placement_group is None:
create_placement_group(connection, module)
else:
Expand All @@ -243,7 +237,6 @@ def main():
)

elif state == "absent":
placement_group = search_placement_group(connection, module)
if placement_group is None:
module.exit_json(changed=False)
else:
Expand Down
45 changes: 19 additions & 26 deletions plugins/modules/ec2_placement_group_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
name:
description: PG name
type: str
sample: my-cluster
sample: "my-cluster"
state:
description: PG state
type: str
Expand All @@ -77,36 +77,28 @@
other: value2
"""

try:
from botocore.exceptions import BotoCoreError
from botocore.exceptions import ClientError
except ImportError:
pass # caught by AnsibleAWSModule
from typing import Any
from typing import Dict
from typing import List

from ansible_collections.amazon.aws.plugins.module_utils.ec2 import describe_ec2_placement_groups
from ansible_collections.amazon.aws.plugins.module_utils.modules import 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


def get_placement_groups_details(connection, module):
names = module.params.get("names")
try:
if len(names) > 0:
response = connection.describe_placement_groups(
Filters=[
{
"Name": "group-name",
"Values": names,
}
]
)
else:
response = connection.describe_placement_groups()
except (BotoCoreError, ClientError) as e:
module.fail_json_aws(e, msg=f"Couldn't find placement groups named [{names}]")
def get_placement_groups_details(connection, names: List) -> Dict[str, Any]:
params = {}
if len(names) > 0:
params["Filters"] = [
{
"Name": "group-name",
"Values": names,
}
]
response = describe_ec2_placement_groups(connection, **params)

results = []
for placement_group in response["PlacementGroups"]:
for placement_group in response:
results.append(
{
"name": placement_group["GroupName"],
Expand All @@ -129,8 +121,9 @@ def main():
)

connection = module.client("ec2")
names = module.params.get("names")

placement_groups = get_placement_groups_details(connection, module)
placement_groups = get_placement_groups_details(connection, names)
module.exit_json(changed=False, placement_groups=placement_groups)


Expand Down
34 changes: 17 additions & 17 deletions tests/integration/targets/ec2_placement_group/tasks/env_cleanup.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
- name: remove any instances in the test VPC
ec2_instance:
- name: Remove any instances in the test VPC
amazon.aws.ec2_instance:
filters:
vpc_id: "{{ testing_vpc.vpc.id }}"
state: absent
Expand All @@ -9,22 +9,22 @@
retries: 10

- name: Get ENIs
ec2_eni_info:
amazon.aws.ec2_eni_info:
filters:
vpc-id: "{{ testing_vpc.vpc.id }}"
register: enis

- name: delete all ENIs
ec2_eni:
- name: Delete all ENIs
amazon.aws.ec2_eni:
eni_id: "{{ item.id }}"
state: absent
until: removed is not failed
with_items: "{{ enis.network_interfaces }}"
ignore_errors: yes
retries: 10

- name: remove the security group
ec2_security_group:
- name: Remove the security group
amazon.aws.ec2_security_group:
name: "{{ resource_prefix }}-sg"
description: a security group for ansible tests
vpc_id: "{{ testing_vpc.vpc.id }}"
Expand All @@ -34,8 +34,8 @@
ignore_errors: yes
retries: 10

- name: remove routing rules
ec2_vpc_route_table:
- name: Remove routing rules
amazon.aws.ec2_vpc_route_table:
state: absent
vpc_id: "{{ testing_vpc.vpc.id }}"
tags:
Expand All @@ -51,17 +51,17 @@
ignore_errors: yes
retries: 10

- name: remove internet gateway
ec2_vpc_igw:
- name: Remove internet gateway
amazon.aws.ec2_vpc_igw:
vpc_id: "{{ testing_vpc.vpc.id }}"
state: absent
register: removed
until: removed is not failed
ignore_errors: yes
retries: 10

- name: remove subnet A
ec2_vpc_subnet:
- name: Remove subnet A
amazon.aws.ec2_vpc_subnet:
state: absent
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.22.32.0/24
Expand All @@ -70,8 +70,8 @@
ignore_errors: yes
retries: 10

- name: remove subnet B
ec2_vpc_subnet:
- name: Remove subnet B
amazon.aws.ec2_vpc_subnet:
state: absent
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.22.33.0/24
Expand All @@ -80,8 +80,8 @@
ignore_errors: yes
retries: 10

- name: remove the VPC
ec2_vpc_net:
- name: Remove the VPC
amazon.aws.ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
cidr_block: 10.22.32.0/23
state: absent
Expand Down
Loading

0 comments on commit 290e89a

Please sign in to comment.