-
Notifications
You must be signed in to change notification settings - Fork 46
Ansible module to restart ec2 instances #6905
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
Open
AmitPhulera
wants to merge
26
commits into
master
Choose a base branch
from
ap/restart-ans-mod
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,127
−0
Open
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
ba1b46a
add basic setup for the ansible module
AmitPhulera a432ff3
get region and init ec2 client
AmitPhulera 1cc0e41
have a lightweight context class to bundle ansible and boto clients, …
AmitPhulera 2be5cf9
add basic structure for all the commands that module will support
AmitPhulera 8c3e9b1
allow test ansible module to capture warnings as well
AmitPhulera 6e7ea8f
add basic tests for module's basic calling checks
AmitPhulera 29991c2
have an Instance class to represent the instance state
AmitPhulera 1002e41
add FakeEC2Instance class to be used in the tests
AmitPhulera d2f78e7
describe instances
AmitPhulera 5b26467
start instances
AmitPhulera ea6ed5f
implement stop
AmitPhulera 036229a
implement stop_and_start
AmitPhulera 974a90e
lint
AmitPhulera 813a7d5
don't update library path to call ansible module, it is being taken c…
AmitPhulera 6d3d240
remove redundant list casting
AmitPhulera 69749cb
fail with module.fail_json if client is not available
AmitPhulera 88b69ed
rename property name to be same as variable name
AmitPhulera 10e8703
remove docstrings that are less helpful
AmitPhulera 46189a2
nits from review
AmitPhulera f65f251
fix tests
AmitPhulera 02e4d10
refactor: from review
AmitPhulera 9e12be6
use f strings everywhere in tests
AmitPhulera 616ad06
move module functions to InstanceManager to remove _Ctx class
AmitPhulera 111910c
fix failing test - this failed because the start_and_stop was relying…
AmitPhulera 64231cc
Merge remote-tracking branch 'origin/master' into ap/restart-ans-mod
AmitPhulera cf25fe2
remove return statements that were added to safeguard that tests retu…
AmitPhulera File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
141 changes: 141 additions & 0 deletions
141
src/commcare_cloud/ansible/library/ec2_instance_state.py
This file contains hidden or 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,141 @@ | ||||||||||
| #! /usr/bin/env python3 | ||||||||||
| """Custom Ansible module to start/stop/stop_and_start/describe EC2 instances.""" | ||||||||||
| import re | ||||||||||
| from enum import Enum | ||||||||||
|
|
||||||||||
| from ansible.module_utils.basic import AnsibleModule | ||||||||||
|
|
||||||||||
| DOCUMENTATION = """ | ||||||||||
| --- | ||||||||||
| module: ec2_instance_state | ||||||||||
|
|
||||||||||
| short_description: Start, stop, stop_and_start, or describe EC2 instances by ID. | ||||||||||
|
|
||||||||||
| description: | ||||||||||
| - Manages the running state of EC2 instances given an explicit list of | ||||||||||
| instance IDs. Supports four commands - describe, start, stop, stop_and_start, | ||||||||||
| and is idempotent (no API call is made if the instance is already in the requested state). | ||||||||||
| - Designed to run with delegate_to localhost. AWS credentials and the target region are picked up from the standard boto3 credential chain; in the commcare-cloud workflow the AWS_PROFILE and AWS_REGION environment variables are exported automatically before ansible runs. | ||||||||||
|
|
||||||||||
| version_added: "1.0.0" | ||||||||||
|
|
||||||||||
| options: | ||||||||||
| instance_ids: | ||||||||||
| description: List of EC2 instance IDs to act on. | ||||||||||
| required: true | ||||||||||
| type: list | ||||||||||
| elements: str | ||||||||||
| command: | ||||||||||
| description: Command to execute. | ||||||||||
| required: true | ||||||||||
| type: str | ||||||||||
| choices: [describe, start, stop, stop_and_start] | ||||||||||
| region: | ||||||||||
| description: > | ||||||||||
| AWS region. Falls back to the AWS_REGION environment variable | ||||||||||
| when omitted. Module fails if neither is set. | ||||||||||
| required: false | ||||||||||
| type: str | ||||||||||
| wait: | ||||||||||
| description: > | ||||||||||
| Block until the final target state (running/stopped) is reached. | ||||||||||
| Ignored for describe. Transition preconditions are always waited | ||||||||||
| for regardless of this setting: a 'stopping' instance is awaited to | ||||||||||
| 'stopped' before it is started, and a 'pending' instance is awaited | ||||||||||
| to 'running' before it is stopped. For stop_and_start the stop | ||||||||||
| phase always waits; this setting governs only the final start phase. | ||||||||||
| required: false | ||||||||||
| default: true | ||||||||||
| type: bool | ||||||||||
|
|
||||||||||
| author: | ||||||||||
| - Amit Phulera | ||||||||||
| """ | ||||||||||
|
|
||||||||||
| EXAMPLES = """ | ||||||||||
| - name: Stop and start a single host (region picked up from AWS_REGION env var) | ||||||||||
| ec2_instance_state: | ||||||||||
| instance_ids: | ||||||||||
| - "{{ hostvars['10.201.11.133'].ec2_instance_id }}" | ||||||||||
| command: stop_and_start | ||||||||||
| delegate_to: localhost | ||||||||||
|
|
||||||||||
| - name: Stop all webworkers in batch | ||||||||||
| ec2_instance_state: | ||||||||||
| instance_ids: >- | ||||||||||
| {{ groups['webworkers'] | ||||||||||
| | map('extract', hostvars, 'ec2_instance_id') | ||||||||||
| | list }} | ||||||||||
| command: stop | ||||||||||
| delegate_to: localhost | ||||||||||
|
|
||||||||||
| - name: Describe instances in a non-default region | ||||||||||
| ec2_instance_state: | ||||||||||
| instance_ids: ["i-0123456789abcdef0"] | ||||||||||
| command: describe | ||||||||||
| region: us-west-2 | ||||||||||
| delegate_to: localhost | ||||||||||
| """ | ||||||||||
|
|
||||||||||
| RETURN = """ | ||||||||||
| changed: | ||||||||||
| description: True if this run mutated AWS state. | ||||||||||
| type: bool | ||||||||||
| command: | ||||||||||
| description: The requested command, echoed back. | ||||||||||
| type: str | ||||||||||
| instances: | ||||||||||
| description: One entry per requested instance, in input order. | ||||||||||
| type: list | ||||||||||
| elements: dict | ||||||||||
| unchanged_instance_ids: | ||||||||||
| description: IDs that needed no action because they were already in the target state. | ||||||||||
| type: list | ||||||||||
| elements: str | ||||||||||
| diff: | ||||||||||
| description: Per-instance state map before/after this run. | ||||||||||
| type: dict | ||||||||||
| """ | ||||||||||
|
|
||||||||||
|
|
||||||||||
| class InstanceCommand(str, Enum): | ||||||||||
| DESCRIBE = 'describe' | ||||||||||
| START = 'start' | ||||||||||
| STOP = 'stop' | ||||||||||
| STOP_AND_START = 'stop_and_start' | ||||||||||
|
|
||||||||||
| INSTANCE_ID_RE = re.compile(r'^i-([0-9a-f]{8}|[0-9a-f]{17})$') | ||||||||||
|
|
||||||||||
| # EC2 instance lifecycle states as returned by DescribeInstances (State.Name). | ||||||||||
| class InstanceState(str, Enum): | ||||||||||
| PENDING = 'pending' | ||||||||||
| RUNNING = 'running' | ||||||||||
| STOPPING = 'stopping' | ||||||||||
| STOPPED = 'stopped' | ||||||||||
| SHUTTING_DOWN = 'shutting-down' | ||||||||||
| TERMINATED = 'terminated' | ||||||||||
|
|
||||||||||
| TERMINATED_STATES = {InstanceState.TERMINATED, InstanceState.SHUTTING_DOWN} | ||||||||||
|
|
||||||||||
| def main(): | ||||||||||
| module_args = { | ||||||||||
| 'instance_ids': {'type': 'list', 'elements': 'str', 'required': True}, | ||||||||||
| 'command': {'type': 'str', 'required': True, 'choices': [c.value for c in InstanceCommand]}, | ||||||||||
| 'region': {'type': 'str', 'required': False, 'default': None}, | ||||||||||
| 'wait': {'type': 'bool', 'required': False, 'default': True}, | ||||||||||
| } | ||||||||||
| module = AnsibleModule(argument_spec=module_args, supports_check_mode=True) | ||||||||||
| params = module.params | ||||||||||
|
|
||||||||||
| instance_ids = params['instance_ids'] | ||||||||||
| if not instance_ids: | ||||||||||
| module.fail_json(msg="'instance_ids' must be a non-empty list.") | ||||||||||
|
|
||||||||||
| bad = [i for i in instance_ids if not INSTANCE_ID_RE.match(i)] | ||||||||||
| if bad: | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||
| module.fail_json(msg=f"Malformed instance IDs: {bad!r}") | ||||||||||
| module.exit_json() | ||||||||||
|
|
||||||||||
|
|
||||||||||
| 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.
I'm just not too familiar with this. Do you mind elaborating on the "delete_to localhost" workflow?
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.
It is
delegate_to localhost. This is the command that we want to run locally on the host from where the command was run instead of running it on the target machine.For this case the AWS credentials will be on our local system so we want to run the module from our local systems.