Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare ec2_placement_group* module for promotion #2167

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
abikouo marked this conversation as resolved.
Show resolved Hide resolved
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
Loading