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

Add new manage_ec2_instance role #123

Merged
merged 39 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
fa4b064
add initial functionality to create instance from basic parameters
mandar242 Nov 18, 2024
207bde0
add functionality to associate EIP to instance
mandar242 Nov 19, 2024
683bcb9
rename role, ansible-lint fixes
mandar242 Nov 19, 2024
700a3d5
add functionality to create and associate sg
mandar242 Nov 20, 2024
1089e6c
add functionality to create attach igw
mandar242 Nov 20, 2024
ff7ae4c
update readme and arg spec
mandar242 Nov 20, 2024
0ac2b46
modified based on feedback
mandar242 Nov 20, 2024
7de1d20
change ec2_instance_create_external_sg_rules to list of dicts
mandar242 Nov 20, 2024
8ec3319
minor fixes
mandar242 Nov 20, 2024
75ce1da
add integration tests
mandar242 Nov 21, 2024
6e0574c
minor fix
mandar242 Nov 21, 2024
4e755c6
minor fixes
mandar242 Nov 21, 2024
2a23755
minor update
mandar242 Nov 21, 2024
dfe5a4a
minor fixes
mandar242 Nov 21, 2024
40c4fd2
add functionality to associate existing sg with instane during creation
mandar242 Nov 21, 2024
5c73f9d
update param name
mandar242 Nov 21, 2024
99f0aae
update arg spec and readme
mandar242 Nov 21, 2024
f94d901
linter fix, newline at eof
mandar242 Nov 21, 2024
a000a37
add check for instance name
mandar242 Nov 22, 2024
d2fc194
add functionality to delete role resources
mandar242 Nov 22, 2024
01000a6
update readme
mandar242 Nov 22, 2024
cc30d69
update readme
mandar242 Nov 22, 2024
57006fe
minor fixes
mandar242 Nov 22, 2024
cf5f50c
linter fixes
mandar242 Nov 22, 2024
1f90b4f
linter fixes
mandar242 Nov 22, 2024
561d533
create key pair if does not exist
mandar242 Nov 22, 2024
e6a8db8
minor fixes
mandar242 Nov 22, 2024
0418042
fix terminate task
mandar242 Nov 25, 2024
d48f6e2
update logic to handle security group association
mandar242 Nov 25, 2024
63fd294
update readme
mandar242 Nov 25, 2024
8732293
minor updates
mandar242 Nov 25, 2024
c975b91
sanity fix
mandar242 Nov 25, 2024
7324fd6
modified based on feedback
mandar242 Dec 1, 2024
076eade
Updates to ec2_instance_create_delete role
hakbailey Dec 5, 2024
6a16f82
Fix linting error
hakbailey Dec 5, 2024
c8956bc
Add optional deletion of key pair
hakbailey Dec 5, 2024
79e661d
Rename role to manage_ec2_instance
hakbailey Dec 6, 2024
9957fae
Remove unneeded option
hakbailey Dec 9, 2024
5a7d83b
Update result var names
hakbailey Dec 9, 2024
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
153 changes: 153 additions & 0 deletions roles/manage_ec2_instance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# manage_ec2_instance

A role to create or delete an EC2 instance in AWS.

Users can specify various parameters for instance configuration, including instance type, AMI ID, key pair, tags, VPC/subnet configuration, and whether to associate an EIP. You can choose to wait for the EC2 instance to finish booting/terminating before continuing.

This role can be combined with the [cloud.aws_ops.ec2_networking_resources role](../ec2_networking_resources/README.md) to create/delete networking resources for the instance, see [examples](#examples).

## Requirements

An AWS account with the following permissions:

* ec2:AllocateAddress
* ec2:AssociateAddress
* ec2:CreateKeyPair
* ec2:DeleteKeyPair
* ec2:DescribeAddresses
* ec2:DescribeInstanceAttribute
* ec2:DescribeInstances
* ec2:DescribeInstanceStatus
* ec2:DescribeKeyPairs
* ec2:DescribeSecurityGroups
* ec2:DescribeSubnets
* ec2:DescribeVpcs
* ec2:DisassociateAddress
* ec2:ModifyInstanceAttribute
* ec2:ReleaseAddress
* ec2:RunInstances
* ec2:TerminateInstances

## Role Variables

The following variables can be set in the role to customize EC2 instance creation and networking configurations:

* **manage_ec2_instance_operation**: (Optional)
Target operation for the ec2 instance role. Choices are ["create", "delete"]. Defaults to "create".

* **manage_ec2_instance_instance_name**: (Required)
The name of the EC2 instance to be created/deleted.

* **manage_ec2_instance_instance_type**: (Optional)
The instance type for the EC2 instance (e.g., `t2.micro`, `m5.large`). Required when `manage_ec2_instance_operation` is `create`

* **manage_ec2_instance_ami_id**: (Optional)
The AMI ID for the EC2 instance. Required when `manage_ec2_instance_operation` is `create`

* **manage_ec2_instance_key_name**: (Optional)
The name of the key pair to use for SSH access to the EC2 instance.
If the key does not exist, a key pair will be created with the name.
If not provided, instance will not be accessible via SSH.
If provided when `manage_ec2_instance_operation` is `delete`, the keypair will also be deleted.

* **manage_ec2_instance_vpc_subnet_id**: (Optional)
The ID of the VPC subnet in which the instance will be launched.
If not provided, instance will be created in the default subnet for the default VPC in the AWS region if present.

* **manage_ec2_instance_tags**: (Optional)
A dictionary of tags to assign to the EC2 instance.

* **manage_ec2_instance_wait_for_state**: (Optional)
Whether to wait for the EC2 instance to be in the "running" (if creating an instance) or "terminated" (if deleting an instance) state before continuing. Default is `true`.

* **manage_ec2_instance_associate_security_groups**: (Optional)
List of security group IDs to associate with the EC2 instance.

* **manage_ec2_instance_associate_eip**: (Optional)
Whether to create an Elastic IP (EIP) and associate it with the EC2 instance. Default is `false`.
If true, EC2 instance must be launched in a VPC with an Internet Gateway (IGW) attached, otherwise this will fail. Use [cloud.aws_ops.ec2_networking_resources role](../ec2_networking_resources/README.md) to create the necessary networking resources.

* **manage_ec2_instance_eip_tags**: (Optional)
Tags to assign to the elastic IP.

## Dependencies

- role: [aws_setup_credentials](../aws_setup_credentials/README.md)

## Examples

Using the role on its own in a playbook:

```yaml
---
- name: Create EC2 instance
hosts: localhost
gather_facts: false
roles:
- role: cloud.aws_ops.manage_ec2_instance
vars:
manage_ec2_instance_operation: create
manage_ec2_instance_aws_region: us-west-2
manage_ec2_instance_instance_name: my-test-instance
manage_ec2_instance_instance_type: t2.micro
manage_ec2_instance_ami_id: ami-066a7fbaa12345678
manage_ec2_instance_vpc_subnet_id: subnet-071443aa123456789
manage_ec2_instance_tags:
Component: my-test-instance
Environment: Testing
manage_ec2_instance_wait_for_state: true
```

Combining the role with [cloud.aws_ops.ec2_networking_resources](../ec2_networking_resources/README.md):

```yaml
---
- name: Create EC2 networking resources and EC2 instance
hosts: localhost
gather_facts: false
roles:
- role: cloud.aws_ops.ec2_networking_resources:
vars:
ec2_networking_resources_vpc_name: my-vpc
ec2_networking_resources_vpc_cidr_block: 10.0.0.0/24
ec2_networking_resources_subnet_cidr_block: 10.0.0.0/25
ec2_networking_resources_sg_internal_name: my-internal-sg
ec2_networking_resources_sg_external_name: my-external-sg
ec2_networking_resources_create_igw: true
- role: cloud.aws_ops.manage_ec2_instance
vars:
manage_ec2_instance_operation: present
manage_ec2_instance_instance_name: my-test-instance
manage_ec2_instance_instance_type: t2.micro
manage_ec2_instance_ami_id: ami-066a7fbaa12345678
manage_ec2_instance_vpc_subnet_id: "{{ ec2_networking_resources_subnet_result.subnet.id }}"
manage_ec2_instance_associate_security_groups:
- my-internal-sg
- my-external-sg
manage_ec2_instance_associate_eip: true
```

Deleting an EC2 instance:

```yaml
---
- name: Delete EC2 instance
hosts: localhost
gather_facts: false
roles:
- role: cloud.aws_ops.manage_ec2_instance
vars:
manage_ec2_instance_operation: delete
manage_ec2_instance_instance_name: my-test-instance
manage_ec2_instance_wait_for_state: true
```

## License

GNU General Public License v3.0 or later

See [LICENSE](../../LICENSE) to see the full text.

## Author Information

- Ansible Cloud Content Team
4 changes: 4 additions & 0 deletions roles/manage_ec2_instance/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
manage_ec2_instance_operation: create
manage_ec2_instance_wait_for_state: true
manage_ec2_instance_associate_eip: false
69 changes: 69 additions & 0 deletions roles/manage_ec2_instance/meta/argument_specs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
argument_specs:
main:
short_description: A role to create or delete an EC2 instance with optional networking resources.
description:
- A role to create or delete an EC2 instance.
- Can optionally attach security groups and associate an Elastic IP with the instance.
- Supports custom configurations for instance settings including instance type, AMI, key pair, tags, VPC/subnet, and networking configurations.
options:
manage_ec2_instance_operation:
description:
- Whether to create or delete resources using the role.
required: false
type: str
default: create
choices: [create, delete]
manage_ec2_instance_instance_name:
description:
- The name of the EC2 instance to be created.
required: true
type: str
manage_ec2_instance_instance_type:
description:
- The instance type for the EC2 instance. Required when `manage_ec2_instance_operation` is `create`.
required: false
type: str
manage_ec2_instance_ami_id:
description:
- The AMI ID for the EC2 instance. Required when `manage_ec2_instance_operation` is `create`.
required: false
type: str
manage_ec2_instance_key_name:
description:
- The name of the key pair to use for SSH access to the EC2 instance. If the key does not exist, a key pair will be created with the name. If not provided, instance will not be accessible via SSH. If provided when `manage_ec2_instance_operation` is `delete`, the keypair will also be deleted.
required: false
type: str
manage_ec2_instance_vpc_subnet_id:
description:
- The ID of the VPC subnet in which the instance will be launched. If not provided, instance will be created in the default subnet for the default VPC in the AWS region, if present.
required: false
type: str
manage_ec2_instance_tags:
description:
- A dictionary of tags to assign to the EC2 instance.
required: false
type: dict
manage_ec2_instance_wait_for_state:
description:
- Whether to wait for the EC2 instance to be in the running/terminated state before continuing.
required: false
default: true
type: bool
manage_ec2_instance_associate_security_groups:
description:
- List of security group names or IDs to associate with the EC2 instance.
required: false
type: list
elements: str
manage_ec2_instance_associate_eip:
description:
- Whether to create and associate an Elastic IP (EIP) with the EC2 instance.
required: false
default: false
type: bool
manage_ec2_instance_eip_tags:
description:
- Tags to assign to the Elastic IP.
required: false
type: dict
3 changes: 3 additions & 0 deletions roles/manage_ec2_instance/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
dependencies:
- role: cloud.aws_ops.aws_setup_credentials
66 changes: 66 additions & 0 deletions roles/manage_ec2_instance/tasks/ec2_instance_create_operations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
- name: Verify that an instance with same name does not exist
block:
- name: Get instance info with provided name
amazon.aws.ec2_instance_info:
filters:
tag:Name: "{{ manage_ec2_instance_instance_name }}"
instance-state-name: ["pending", "running", "stopping", "stopped"]
register: ec2_info_result

- name: Print warning and exit if instance exists
ansible.builtin.fail:
msg: "Instance with name {{ manage_ec2_instance_instance_name }} already exists in {{ aws_region }}. Please provide a different name to avoid updating the existing instance."
when: ec2_info_result.instances | length > 0

- name: Create a key pair if required
when: manage_ec2_instance_key_name is defined and manage_ec2_instance_key_name | length > 0
block:
- name: Get key pair info
amazon.aws.ec2_key_info:
names:
- "{{ manage_ec2_instance_key_name }}"
register: key_info_result

- name: Create new key pair
amazon.aws.ec2_key:
name: "{{ manage_ec2_instance_key_name }}"
state: present
when: key_info_result.keypairs | length == 0
register: new_key_pair_result

- name: Create EC2 instance with provided configuration
amazon.aws.ec2_instance:
state: running
name: "{{ manage_ec2_instance_instance_name }}"
instance_type: "{{ manage_ec2_instance_instance_type }}"
image_id: "{{ manage_ec2_instance_ami_id }}"
key_name: "{{ manage_ec2_instance_key_name | default(omit) }}"
security_groups: "{{ manage_ec2_instance_associate_security_groups | default(omit, true) }}"
vpc_subnet_id: "{{ manage_ec2_instance_vpc_subnet_id | default(omit) }}"
tags: "{{ manage_ec2_instance_tags | default(omit) }}"
wait: "{{ manage_ec2_instance_wait_for_state }}"
register: ec2_instance

- name: Allocate and associate Elastic IP if enabled
when: manage_ec2_instance_associate_eip is true
amazon.aws.ec2_eip:
device_id: "{{ ec2_instance.instance_ids[0] }}"
state: present
register: instance_eip

- name: Get EC2 instance info
amazon.aws.ec2_instance_info:
instance_ids: "{{ ec2_instance.instance_ids[0] }}"
register: _ec2_instance

- name: Output details of the created EC2 instance
ansible.builtin.debug:
msg:
- "EC2 instance {{ ec2_instance.instance_ids[0] }} created successfully"
- "Instance details: {{ _ec2_instance.instances[0] }}"

- name: Output private key if a new keypair was created
when: new_key_pair_result.key is defined
ansible.builtin.debug:
msg: "A new key pair was created for ssh access to the instance. Please save this private key for reference, it will not be accessible again: {{ new_key_pair_result.key.private_key }}"
abikouo marked this conversation as resolved.
Show resolved Hide resolved
29 changes: 29 additions & 0 deletions roles/manage_ec2_instance/tasks/ec2_instance_delete_operations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
- name: Get instance info with provided name
amazon.aws.ec2_instance_info:
filters:
tag:Name: "{{ manage_ec2_instance_instance_name }}"
instance-state-name: ["pending", "running", "stopping", "stopped"]
register: ec2_info_result

- name: Disassociate and release EIP if present
when: ec2_info_result.instances | length > 0
# and ec2_info_result.instances[0].network_interfaces.association.public_ip is defined
amazon.aws.ec2_eip:
device_id: "{{ ec2_info_result.instances[0].instance_id }}"
state: absent
release_on_disassociation: true

- name: Terminate EC2 Instance if present
when: ec2_info_result.instances | length > 0
amazon.aws.ec2_instance:
state: terminated
wait: "{{ manage_ec2_instance_wait_for_state }}"
instance_ids:
- "{{ ec2_info_result.instances[0].instance_id }}"

- name: Delete keypair if provided
when: manage_ec2_instance_key_name is defined and manage_ec2_instance_key_name | length > 0
amazon.aws.ec2_key:
name: "{{ manage_ec2_instance_key_name }}"
state: absent
12 changes: 12 additions & 0 deletions roles/manage_ec2_instance/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
- name: EC2 Instance creation or deletion based on operation
module_defaults:
group/aws: "{{ aws_setup_credentials__output }}"
block:
- name: Include create operations
ansible.builtin.include_tasks: ec2_instance_create_operations.yml
when: manage_ec2_instance_operation == 'create'

- name: Include delete operations
ansible.builtin.include_tasks: ec2_instance_delete_operations.yml
when: manage_ec2_instance_operation == 'delete'
2 changes: 2 additions & 0 deletions tests/integration/targets/test_manage_ec2_instance/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cloud/aws
role/manage_ec2_instance
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
aws_security_token: "{{ security_token | default(omit) }}"

# Network Configuration
test_vpc_name: "{{ resource_prefix }}-vpc"
test_vpc_cidr: '101.{{ 255 | random(seed=resource_prefix) }}.0.0/16'
test_subnet_cidr: '101.{{ 255 | random(seed=resource_prefix) }}.0.0/24'
test_security_group_name: "{{ resource_prefix }}-sg"

# EC2 Instance Configuration
test_ec2_instance_name: "{{ resource_prefix }}-ec2-instance"
test_ec2_instance_type: t2.micro
test_ec2_key_name: "{{ resource_prefix }}-ec2-key"
21 changes: 21 additions & 0 deletions tests/integration/targets/test_manage_ec2_instance/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
- name: Integration tests for manage_ec2_instance role
module_defaults:
group/aws:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
- name: Create resources required for test
ansible.builtin.include_tasks: setup.yml

- name: Run tests for case 1 - EC2 instance with required options only
ansible.builtin.include_tasks: tasks/test_ec2_required_options.yml

- name: Run tests for case 2 - EC2 instance with all options
ansible.builtin.include_tasks: tasks/test_ec2_all_options.yml

always:
- name: Delete any leftover resources used in tests
ansible.builtin.include_tasks: teardown.yml
Loading
Loading