-
Notifications
You must be signed in to change notification settings - Fork 23.7k
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
Module to create and delete EC2 Placement Groups. #33139
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
17fe700
Added modules to create, delete, and describe EC2 Placement Groups.
bradmacpherson f8d567d
Remove unnecessary print statement
bradmacpherson 1bfe398
Update to use boto3.
bradmacpherson 3f9fa1e
De-linting
bradmacpherson 0c3f013
Remove facts from this PR
bradmacpherson b85abf0
Update to newer method of handling Boto3 connections and exceptions.
bradmacpherson 47f05fd
Futzing around with imports and HAS_BOTO3
bradmacpherson 34d1925
Fix up exception imports.
bradmacpherson 9902d4b
Remove redundant default.
bradmacpherson c5ff3d8
Handle DryRunOperation errors appropriately.
bradmacpherson 00cee43
Remove redundant BOTO3 check.
bradmacpherson b2c089f
Use shorter licence declaration.
bradmacpherson f66648b
Remove redundant HAS_BOTO3 import.
bradmacpherson 1debf6c
Add AWSRetry decorators to API calls.
bradmacpherson 6078ab0
Add new 'strategy' parameter to allow for cluster and spread PGs.
bradmacpherson File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
216 changes: 216 additions & 0 deletions
216
lib/ansible/modules/cloud/amazon/ec2_placement_group.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
#!/usr/bin/python | ||
# Copyright (c) 2017 Ansible Project | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
ANSIBLE_METADATA = {'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'community'} | ||
|
||
|
||
DOCUMENTATION = ''' | ||
--- | ||
module: ec2_placement_group | ||
short_description: Create or delete an EC2 Placement Group | ||
description: | ||
- Create an EC2 Placement Group; if the placement group already exists, | ||
nothing is done. Or, delete an existing placement group. If the placement | ||
group is absent, do nothing. See also | ||
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/placement-groups.html | ||
version_added: "2.5" | ||
author: "Brad Macpherson (@iiibrad)" | ||
options: | ||
name: | ||
description: | ||
- The name for the placement group. | ||
required: true | ||
state: | ||
description: | ||
- Create or delete placement group. | ||
required: false | ||
default: present | ||
choices: [ 'present', 'absent' ] | ||
strategy: | ||
description: | ||
- Placement group strategy. Cluster will cluster instances into a | ||
low-latency group in a single Availability Zone, while Spread spreads | ||
instances across underlying hardware. | ||
required: false | ||
default: cluster | ||
choices: [ 'cluster', 'spread' ] | ||
extends_documentation_fragment: | ||
- aws | ||
- ec2 | ||
''' | ||
|
||
EXAMPLES = ''' | ||
# Note: These examples do not set authentication details, see the AWS Guide | ||
# for details. | ||
|
||
# Create a placement group. | ||
- ec2_placement_group: | ||
name: my-cluster | ||
state: present | ||
|
||
# Create a Spread placement group. | ||
- ec2_placement_group: | ||
name: my-cluster | ||
state: present | ||
strategy: spread | ||
|
||
# Delete a placement group. | ||
- ec2_placement_group: | ||
name: my-cluster | ||
state: absent | ||
|
||
''' | ||
|
||
|
||
RETURN = ''' | ||
placement_group: | ||
description: Placement group attributes | ||
returned: when state != absent | ||
type: complex | ||
contains: | ||
name: | ||
description: PG name | ||
type: string | ||
sample: my-cluster | ||
state: | ||
description: PG state | ||
type: string | ||
sample: "available" | ||
strategy: | ||
description: PG strategy | ||
type: string | ||
sample: "cluster" | ||
|
||
''' | ||
|
||
from ansible.module_utils.aws.core import AnsibleAWSModule | ||
from ansible.module_utils.ec2 import (AWSRetry, | ||
boto3_conn, | ||
ec2_argument_spec, | ||
get_aws_connection_info) | ||
try: | ||
from botocore.exceptions import (BotoCoreError, ClientError) | ||
except ImportError: | ||
pass # caught by AnsibleAWSModule | ||
|
||
|
||
@AWSRetry.exponential_backoff() | ||
def get_placement_group_details(connection, module): | ||
name = module.params.get("name") | ||
try: | ||
response = connection.describe_placement_groups( | ||
Filters=[{ | ||
"Name": "group-name", | ||
"Values": [name] | ||
}]) | ||
except (BotoCoreError, ClientError) as e: | ||
module.fail_json_aws( | ||
e, | ||
msg="Couldn't find placement group named [%s]" % name) | ||
|
||
if len(response['PlacementGroups']) != 1: | ||
return None | ||
else: | ||
placement_group = response['PlacementGroups'][0] | ||
return { | ||
"name": placement_group['GroupName'], | ||
"state": placement_group['State'], | ||
"strategy": placement_group['Strategy'], | ||
} | ||
|
||
|
||
@AWSRetry.exponential_backoff() | ||
def create_placement_group(connection, module): | ||
name = module.params.get("name") | ||
strategy = module.params.get("strategy") | ||
|
||
try: | ||
connection.create_placement_group( | ||
GroupName=name, Strategy=strategy, DryRun=module.check_mode) | ||
except (BotoCoreError, ClientError) as e: | ||
if e.response['Error']['Code'] == "DryRunOperation": | ||
module.exit_json(changed=True, placement_group={ | ||
"name": name, | ||
"state": 'DryRun', | ||
"strategy": strategy, | ||
}) | ||
module.fail_json_aws( | ||
e, | ||
msg="Couldn't create placement group [%s]" % name) | ||
|
||
module.exit_json(changed=True, | ||
placement_group=get_placement_group_details( | ||
connection, module | ||
)) | ||
|
||
|
||
@AWSRetry.exponential_backoff() | ||
def delete_placement_group(connection, module): | ||
name = module.params.get("name") | ||
|
||
try: | ||
connection.delete_placement_group( | ||
GroupName=name, DryRun=module.check_mode) | ||
except (BotoCoreError, ClientError) as e: | ||
module.fail_json_aws( | ||
e, | ||
msg="Couldn't delete placement group [%s]" % name) | ||
|
||
module.exit_json(changed=True) | ||
|
||
|
||
def main(): | ||
argument_spec = ec2_argument_spec() | ||
argument_spec.update( | ||
dict( | ||
name=dict(type='str'), | ||
state=dict(default='present', choices=['present', 'absent']), | ||
strategy=dict(default='cluster', choices=['cluster', 'spread']) | ||
) | ||
) | ||
|
||
module = AnsibleAWSModule( | ||
argument_spec=argument_spec, | ||
supports_check_mode=True | ||
) | ||
|
||
region, ec2_url, aws_connect_params = get_aws_connection_info( | ||
module, boto3=True) | ||
|
||
connection = boto3_conn(module, | ||
resource='ec2', conn_type='client', | ||
region=region, **aws_connect_params) | ||
|
||
state = module.params.get("state") | ||
|
||
if state == 'present': | ||
placement_group = get_placement_group_details(connection, module) | ||
if placement_group is None: | ||
create_placement_group(connection, module) | ||
else: | ||
strategy = module.params.get("strategy") | ||
if placement_group['strategy'] == strategy: | ||
module.exit_json( | ||
changed=False, placement_group=placement_group) | ||
else: | ||
name = module.params.get("name") | ||
module.fail_json( | ||
msg=("Placement group '{}' exists, can't change strategy" + | ||
" from '{}' to '{}'").format( | ||
name, | ||
placement_group['strategy'], | ||
strategy)) | ||
|
||
elif state == 'absent': | ||
placement_group = get_placement_group_details(connection, module) | ||
if placement_group is None: | ||
module.exit_json(changed=False) | ||
else: | ||
delete_placement_group(connection, module) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason you don't have a parameter to set the strategy? Seems like it'd be easy to add (and default to
cluster
).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simply that it isn't (or wasn't, until a day or so ago) an option as such. There was only one value.
Now that spread placement groups are available, that will have to change :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added parameter 'strategy'; attempting to provision a placement group with a different strategy to the existing one will fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hah - life with AWS: "oh, that's a parameter too now"