Allocate EC2 through Ansible - amazon-ec2

When creating an EC2 instance through Ansible, how do you specify the security group (this is for a Amazon VPC environment that is not the account default)? In my case, I am attempting to assign a security group (that currently exists) to my webserver EC2 instance that restricts traffic to only the traffic coming from the ELB that sits in front of it. If I try the following:
- name: Create webserver instance
ec2:
key_name: "{{ project_name }}-{{ env }}-key"
image: "{{ image }}"
instance_type: "{{ instance_type }}"
instance_tags: '{"Name":"{{ project_name }}-{{ env }}-{{ webserver_name }}","Owner":"{{ project_name }}", "Type":"{{ webserver_name }}","Environment":"{{ env }}"}'
region: "{{ aws_region }}"
group: "{{ security_group_name }}"
wait: true
register: ec2
where {{ security_group_name }} is the 'Group Name' found in the AWS console, I receive the following error: 'Value () for parameter groupId is invalid. The value cannot be empty'
If I try the following:
- name: Create webserver instance
ec2:
key_name: "{{ project_name }}-{{ env }}-key"
image: "{{ image }}"
instance_type: "{{ instance_type }}"
instance_tags: '{"Name":"{{ project_name }}-{{ env }}-{{ webserver_name }}","Owner":"{{ project_name }}", "Type":"{{ webserver_name }}","Environment":"{{ env }}"}'
region: "{{ aws_region }}"
group_id: "{{ security_group_id }}"
wait: true
register: ec2
where {{ security_group_id }} is the 'Group Id' found in the AWS console (such as sg-xxxxxx), I receive the same error. The Ansible documentation stated that 'group' and 'group_id' are for the specification of the security group (http://docs.ansible.com/ansible/ec2_module.html).
The only thing I can think of is that AWS cannot find the security group because I am creating it and it does not know the VPC to place it in or it is placing it in my default VPC and cannot find the security group as it is in a different VPC.
So, maybe a better question is, how to I specify the VPC for a particular EC2 instance (when I have multiple VPCs in a region)?

I receive the following error: 'Value () for parameter groupId is invalid. The value cannot be empty'
It sounds like those variables aren't defined; where are you defining them? Does it work when you don't use a variable, but put in the value directly?
So, maybe a better question is, how to I specify the VPC for a particular EC2 instance (when I have multiple VPCs in a region)?
The VPC is implied by other values, notably group/group_id and vpc_subnet_id.
One of the main advantages of using group_id instead of group is that you'll get an error if you accidentally use a subnet for the wrong VPC, whereas if you have security groups with the same names in multiple VPCs, using group and an incorrect vpc_subnet_id will successfully launch a machine in the wrong place.

There is no way to specify the VPC ID in your playbook. Instead you specify the vpc_subnet_id. AWS can figure out the VPC based on subnet id. You are not specifying the subnet id, so AWS assumes that you want to launch it in EC2 Classic. Since the specified security group is not found in EC2 Classic, you are getting the not found or invalid error.
How to fix this? Find the id of the subnet where you want to launch the instance. Each VPC can have one more public and/or private subnets. From AWS dashboard, select VPC Service which will list the subnets and VPCs. Find the subnet you want to launch in, and specify its id in the playbook.
vpc_subnet_id: subnet-29e63245

Related

Provisioning multiple spot instances with instance_interruption_behavior using Ansible

I know it seems to relate to other questions asked in the past but I feel it's not.
You will be the judge of that.
I've been using Ansible for 1.5 years now and I'm aware it's not the best tool to provision infrastructure , Yet for my needs it suffice.
I'm using AWS as my cloud provider
Is there any way to cause Ansible to provision multiple spot instances of the same type( similar to the count attribute in the ec2 ansible module) with the instance_interruption_behavior set to stop(behavior) instead of the default terminate?
My Goal:
Set up multiple EC2 instances with different ec2_spot_requests to Amazon. ( spot request per instance)
But instead of using the default instance_interruption_behavior which is terminate, I wish to set it to stop(behavior )
What I've done so far:
I'm aware that Ansible has the following module to handle ec2 infrastructure .
Mainly the
ec2.
https://docs.ansible.com/ansible/latest/modules/ec2_module.html
Not to be confused with the
ec2_instance module.
https://docs.ansible.com/ansible/latest/modules/ec2_instance_module.html
I could use the ec2 module to set up spot instances , As I've done so far, as follows:
ec2:
key_name: mykey
region: us-west-1
instance_type: "{{ instance_type }}"
image: "{{ instance_ami }}"
wait: yes
wait_timeout: 100
spot_price: "{{ spot_bid }}"
spot_wait_timeout: 600
spot_type: persistent
group_id: "{{ created_sg.group_id }}"
instance_tags:
Name: "Name"
count: "{{ my_count }}"
vpc_subnet_id: " {{ subnet }}"
assign_public_ip: yes
monitoring: no
volumes:
- device_name: /dev/sda1
volume_type: gp2
volume_size: "{{ volume_size }}"
Pre Problem:
The above sample module is nice and clean and allow me to setup spot instance according to my requirements , by using the ec2 module and the count attribute.
Yet, It doesn't allow me to set the instance_interruption_behavior to stop( unless I'm worng), It just defaults to terminate.
Other modules:
To be released on Ansible version 2.8.0 ( Currently only available in develop) , There is a new module called: ec2_launch_template
https://docs.ansible.com/ansible/devel/modules/ec2_launch_template_module.html
This module gives you more attributes , which allows you ,with the combination of ec2_instance module to set the desired instance_interruption_behavior to stop(behavior).
This is what I did:
- hosts: 127.0.0.1
connection: local
gather_facts: True
vars_files:
- vars/main.yml
tasks:
- name: "create security group"
include_tasks: tasks/create_sg.yml
- name: "Create launch template to support interruption behavior 'STOP' for spot instances"
ec2_launch_template:
name: spot_launch_template
region: us-west-1
key_name: mykey
instance_type: "{{ instance_type }}"
image_id: "{{ instance_ami }}"
instance_market_options:
market_type: spot
spot_options:
instance_interruption_behavior: stop
max_price: "{{ spot_bid }}"
spot_instance_type: persistent
monitoring:
enabled: no
block_device_mappings:
- device_name: /dev/sda1
ebs:
volume_type: gp2
volume_size: "{{ manager_instance_volume_size }}"
register: my_template
- name: "setup up a single spot instance"
ec2_instance:
instance_type: "{{ instance_type }}"
tags:
Name: "My_Spot"
launch_template:
id: "{{ my_template.latest_template.launch_template_id }}"
security_groups:
- "{{ created_sg.group_id }}"
The main Problem:
As it shown from the above snippet code, the ec2_launch_template Ansible module does not support the count attribute and the ec2_instance module doesn't allow it either.
Is there any way cause ansible to provision multiple instances of the same type( similar to the count attribute in the ec2 ansible module)?
In general if you are managing lots of copies of EC2 instances at once you probably want to either use Auto-scaling groups or EC2 Fleets.
There is an ec2_asg module that allows you to manage auto-scaling groups via ansible. This would allow you to deploy multiple EC2 instances based on that launch template.
Another technique to solve this issue would be to use the cloudformation or terraform modules if AWS cloudformation templates or terraform plans support what you want to do. This would also let you use Jinja2 templating syntax to do some clever template generation before supplying the infrastructure templates if necessary.

how to launch multiple instances with different subnet ids using ansible

I'm trying to use Ansible to create two instances, each instance must have different subnet ids. I'm using exact_count with tag Name to keep track of instances. The main issue is that I am not able to understand how to provide two different subnet ids in the same playbook.
This task can be used in order to create the multiple ec2 instances with different subnets
- name: 7. Create EC2 server
ec2:
image: "{{ image }}"
wait: true
instance_type: t2.micro
group_id: "{{ security_group.group_id }}"
vpc_subnet_id: "{{ item }}"
key_name: "{{ key_name }}"
count: 1
region: us-east-1
with_items:
- "{{ subnet1.subnet.id }}"
- "{{ subnet2.subnet.id }}"
register: ec2

resize type of ec2 with ansible

I want to resize a ec2 type from ansible.
This is my code:
- name: resize the instance
ec2:
aws_access_key: "{{ aws_access_key_var }}"
aws_secret_key: "{{ aws_secret_key_var }}"
region: "{{ region }}"
instance_ids:
- "{{ instance_id }}"
instance_type: "{\"Value\": \"t2.small\"}"
wait: True
register: ec2_result_file
But I get this error:
fatal: [localhost]: FAILED! => {"changed": false, "msg": "image parameter is required for new instance"}
I try with command line all good
aws ec2 modify-instance-attribute --region reg --instance-id i-xx --instance-type "{\"Value\": \"t2.small\"}
Regards,
How to arrive at the solution:
Ansible tells you it wants to create "a new instance", but you already provided an existing instance ID.
Go to the docs for the ec2 module and check the argument in which you provided the ID of the current instance:
instance_ids list of instance ids, currently used for states: absent, running, stopped
Check what state you specified - you did not, so it's the default.
Check the same docs what is the default for state argument: it is present.
present is not listed in the instance_ids description, so the instance_ids is completely ignored.
Ansible thinks you really wanted to create a new instance.
Solution:
Add state: running to the ec2 module arguments.

How to change an existing AWS VPC resource with Ansible?

I have just created a vpc on AWS with ansible like so:
- name: Ensure VPC is present
ec2_vpc:
state: present
region: "{{ ec2_region }}"
cidr_block: "{{ ec2_subnet }}"
subnets:
- cidr: "{{ ec2_subnet }}"
route_tables:
- subnets:
- "{{ ec2_subnet }}"
routes:
- dest: 0.0.0.0/0
gw: igw
internet_gateway: yes # we want our instances to connect internet
wait: yes # wait for the VPC to be in state 'available' before returning
resource_tags: { Name: "my_project", environment: "production", tier: "DB" } # we tag this VPC so it will be easier for us to find it later
Note that this task is called from another playbook that takes care of filling the variables.
Also note that I am aware the ec2_vpc module is deprecated and I should update this piece of code soon.
But I think those points are not relevant to the question.
So you can notice in the resource_tags I have a name for that project. When I first ran this playbook, I did not have a name.
The VPC got created successfully the first time but then I wanted to add a name to it. So I tried adding it in the play, without knowing exactly how Ansible would know I want to update the existing VPC.
Indeed Ansible created a new VPC and did not update the existing one.
So the question is, how do I update the already existing one instead of creating a new resource?
After a conversation on the ansible irc (can't remember the usernames, sorry) it appears this specific module is not good at updating resources.
It looks like the answer lies in the new ec2_vpc_net module, specifically with the option multi_ok which by default won't duplicate VPCs with the same name and CIDR blocks.
docs: http://docs.ansible.com/ansible/ec2_vpc_net_module.html#ec2-vpc-net

Login to created Windows instance using Ansible

I am creating a Windows instance using Ansible. Once the instance got created I need to install IIS on that created instance automatically.
How to login to the newly created instance automatically?
What are the parameters I need to mention in the host (inventory) file to login?
To connect to ec2 instances you will first need to retrieve the password using the ec2_win_password module
Example:
- ec2_win_password:
instance_id: i-xxxxxxx
region: us-west-2
key_file: "/.ssh/yourPEM.pem"
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key}}"
security_token: "{{ session_token }}"
key_passphrase: "1122355"
register: result
- debug : msg="{{ result }}"
The result can be used as your ansible_password

Resources