I'm trying to create an AWS EC2 ansible playbook that:
1) first allocates one VPC each on three Regions which are: us-west-1, ap-northeast-1 and eu-west-1.
2) Finds the latest ubuntu AMI for each region (ec2_ami_search),
3) then using the discovered results from 1) and 2), create one EC2 instance per region with the latest ubuntu AMI (for the region) with Availibility Zones us-west-1a, ap-northeast-1a and eu-west-1a, respectively.
With Ansible, I had no problem with step 1) and 2) which was simply:
>
tasks:
- name: create a vpc
ec2_vpc:
state: present
region: "{{ item.region }}"
internet_gateway: True
resource_tags: { env: production}
cidr_block: 10.0.0.0/16
subnets:
- cidr: 10.0.0.0/24
az: "{{ item.az }}"
resource_tags:
env: production
tier: public
route_tables:
- subnets:
- 10.0.0.0/24
routes:
- dest: 0.0.0.0/0
gw: igw
with_items:
- region: us-west-1
az: us-west-1a
- region: ap-northeast-1
az: ap-northeast-1a
- region: eu-west-1
az: eu-west-1a
...
- name: Get the ubuntu trusty AMI
ec2_ami_search: distro=ubuntu release=trusty virt=hvm region={{ item }}
with_items:
- us-west-1
- ap-northeast-1
- eu-west-1
register: ubuntu_image
...
>
and the outputted for the ubuntu_image variable with debug module:
TASK: [print out ubuntu images] ***********************************************
ok: [localhost] => {
"ubuntu_image": {
"changed": false,
"msg": "All items completed",
"results": [
{
"aki": null,
"ami": "ami-b33dccf7",
"ari": null,
"changed": false,
"invocation": {
"module_args": "distro=ubuntu release=trusty virt=hvm region=us-west-1",
"module_name": "ec2_ami_search"
},
"item": "us-west-1",
"serial": "20150629",
"tag": "release"
},
{
"aki": null,
"ami": "ami-9e5cff9e",
"ari": null,
"changed": false,
"invocation": {
"module_args": "distro=ubuntu release=trusty virt=hvm region=ap-northeast-1",
"module_name": "ec2_ami_search"
},
"item": "ap-northeast-1",
"serial": "20150629",
"tag": "release"
},
{
"aki": null,
"ami": "ami-7c4b0a0b",
"ari": null,
"changed": false,
"invocation": {
"module_args": "distro=ubuntu release=trusty virt=hvm region=eu-west-1",
"module_name": "ec2_ami_search"
},
"item": "eu-west-1",
"serial": "20150629",
"tag": "release"
}
]
}
}
However, I couldn't figure out how to make step 3) take the result from the ubuntu_image register variable and then determine which of the 3 AMIs and Subnets the given EC2 instance belonged. See below where as a workaround I manually hardcoded the ami and subnet value which I simply got from the printout from the above ubuntu_image printout:
- name: start the instances
ec2:
image: "{{ item.ami }}" # MANUALLY HARDCODED
region: "{{ item.region }}"
instance_type: "{{ instance_type }}"
assign_public_ip: True
key_name: "{{ item.name }}"
group: ["http deployment", "ssh deployment", "outbound deployment"]
instance_tags: { Name: "{{ item.name }}", type: ss, env: production}
exact_count: "{{ count }}"
count_tag: { Name: "{{ item.name }}" }
vpc_subnet_id: "{{ item.subnet }}" #MANUALLY HARDCODED
wait: yes
register: ec2
with_items:
- region: us-west-1
name: ss12
ami: ami-b33dccf7 # MANUALLY HARDCODED
subnet: subnet-35a22550 # MANUALLY HARDCODED
- region: ap-northeast-1
name: ss21
ami: ami-9e5cff9e # MANUALLY HARDCODED
subnet: subnet-88c47dff # MANUALLY HARDCODED
- region: eu-west-1
name: ss32
ami: ami-7c4b0a0b # MANUALLY HARDCODED
subnet: subnet-23f59554 # MANUALLY HARDCODED
While hardcoding ami/subnet works, can you think of a solution for me to avoid this hardcoding of the ami/subnet? I tried messing with set_fact to no avail as I couldn't get it to become a dictionary of "region to ami" value mappings
Q: How many instances can I run in Amazon EC2? You are limited to running On-Demand Instances per your vCPU-based On-Demand Instance limit, purchasing 20 Reserved Instances, and requesting Spot Instances per your dynamic Spot limit per region.
Moving an EC2 Instance to a Different Availability Zone And if you need to change the zone, here's how to do so: Shutdown / stop the instance. Right-click the instance and select Create Image to make an AMI from the instance. Go to the AMI page, right-click on the new AMI and select Launch Instance.
Install BOTO Once all the tools and packages have been installed successfully, we can create Ansible playbooks to initialize an EC2 instance.
Keep in mind that Ansible
is a "plugable" system, so it's really easy to customize it for your self. Sometimes it's even easier and faster than trying to find a workaround by using "native" modules.
In your case you can easily write your own custom lookup_plugin
that would search for a correct subnet
.
For example:
lookup_plugins
in your main folder.ansible.cfg
[defaults] lookup_plugins = lookup_plugins
Create a file in lookup_plugins
called subnets.py
import boto.vpc
class LookupModule(object):
def __init__(self, basedir=None, **kwargs):
self.basedir = basedir
self.plugin_name = 'subnets'
def run(self, regions, variable=None, **kwargs):
if not isinstance(regions, list):
regions = [regions]
for region in regions:
return [boto.vpc.connect_to_region(region).get_all_subnets()[0].id]
The above simple code would look for a subnet in a given region. Of course you can customize it however you want.
Then in your playbook reference this plugin to find correct subnet:
Example:
- hosts: localhost
gather_facts: no
tasks:
- name: Start instance
debug: msg="Starting instance {{ item.ami }} in {{ item.region }} in {{ item.subnet }}"
with_items:
- region: us-west-1
name: ss12
ami: ami-b33dccf7
subnet: "{{ lookup('subnets', 'us-west-1') }}"
- region: ap-northeast-1
name: ss21
ami: ami-9e5cff9e
subnet: "{{ lookup('subnets', 'ap-northeast-1') }}"
- region: eu-west-1
name: ss32
ami: ami-7c4b0a0b
subnet: "{{ lookup('subnets', 'ap-northeast-1') }}"
In your case you would probably need to reference the correct AMI
and associated Region
.
if you still want to do this without help from another module you can calculate the modulo '%' of the servers and the subnets length:
"{{subnets[item.0 | int % subnets | length | int].aws_ec2_subnets}}"
example code
vars:
subnets:
- {zone: "us-east-1a", aws_ec2_subnets: 'subnet-123'}
- {zone: "us-east-1b", aws_ec2_subnets: 'subnet-456'}
- {zone: "us-east-1d", aws_ec2_subnets: 'subnet-789'}
server_list:
- server1
- server2
- server3
task:
- name: Create new ec2 instance
ec2:
profile: "{{aws_profile}}"
key_name: "{{aws_key_name}}"
group_id: "{{aws_security_group}}"
instance_type: "{{aws_instance_type}}"
image: "{{aws_ami}}"
region: "{{region}}"
exact_count: "1"
#instance_profile_name: none
wait: yes
wait_timeout: 500
volumes: "{{volumes}}"
monitoring: no
vpc_subnet_id: "{{subnets[item.0 | int % subnets | length | int].aws_ec2_subnets}}"
assign_public_ip: no
tenancy: default
termination_protection: yes
instance_tags:
App: "{{app_name}}"
Environment: "{{environment_type}}"
Platform: "{{platform_name}}"
Name: "{{item.1}}"
count_tag:
App: "{{app_name}}"
Environment: "{{environment_type}}"
Platform: "{{platform_name}}"
Name: "{{item.1}}"
register: ec2_new_instance
with_indexed_items:
- "{{server_list}}"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With