Ansible - play role even in case of previous failure - amazon-web-services

I am building an amazon AMI builder playbook. The idea is:
spawn up an EC2 instance
provision it
register an AMI
terminate the EC2 instance
I would like to terminate the EC2 instance in any case, even if a previous step failed.
My playbook currently looks like (the spawned EC2 instance is dynamically added to the ec2_servers group in the aws_spawn_ec2 role)):
---
- hosts: localhost
connection: local
gather_facts: False
roles:
- role: aws_spawn_ec2
vars:
ec2_host_group: ec2_servers
- hosts: ec2_servers
roles:
- role: provision_ec2
- hosts: localhost
connection: local
gather_facts: False
roles:
- role: aws_ami_register
- hosts: localhost
connection: local
gather_facts: False
roles:
-role: aws_terminate_ec2
I would like the last play to be run even if a previous play failed. Is there a (preferably clean) way of doing that?
[EDIT]
I tried #Z.Liu answer, I got the following error:
ERROR! 'delegate_to' is not a valid attribute for a IncludeRole
I then tried that:
- name: provision ec2
include_role:
name: provision_ec2
apply:
delegate_to: ec2_servers
But I now have that error:
TASK [provision ec2 : Check if reboot is required] **********************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'reboot_required.stat.exists' failed. The error was: error while evaluating conditional (reboot_required.stat.exists): 'dict object' has no attribute 'stat'"}
I have ansible 2.9.10
Thanks

ansible method
you can leverage ansible delegate_to and block always
delegate_to can let you run the playbook in another hosts
always will execute the task regardless of the previous task results.
- name: update AMI
hosts: localhost
tasks:
- name: spawn new ec2 instance
include_role:
name: aws_spawn_ec2
vars:
ec2_host_group: ec2_servers
- name: provision only spaw ec2 succeed
block:
- name: provision ec2
include_role:
name: provision_ec2
delegate_to: ec2_servers
- name: registe aws AMI
include_role:
name: aws_ami_register
always:
- name: terminate ec2 instance regardless of the ami registration results
include_role:
name: aws_terminate_ec2
You can also use packer, it is more easily to build the AMI in AWS.
https://www.packer.io/intro

Related

Ansible - ec2_eni reuse ENI

I have a pretty basic ansible playbook that creates an ENI:
---
- name: create ENIs
hosts: localhost
tasks:
- name: create eni 1
ec2_eni:
subnet_id: subnet-xxxxxxx
region: us-east-1
description: my-eni
state: present
What i am trying to do is when i rerun this playbook, it does not create the new ENI but verifies that the ENI that was created and exists.
I cannot pass Private IP address as I want to reuse it across multiple accounts we have.
Is it possible to do so?
This is the ENI Module I am using:
http://docs.ansible.com/ansible/ec2_eni_module.html
Assuming ENI description is unique (very important assumption):
tasks:
- ec2_eni_facts:
region: us-east-1
filters:
description: my-eni
register: eni_facts
- name: create eni 1 if not presemt
ec2_eni:
subnet_id: subnet-xxxxxxx
region: us-east-1
description: my-eni
state: present
when: not eni_facts.interfaces

Ansible use ec2 public ip of one play in another play

I have the following ansible playbook.
---
- name: Ansible playbook to create a new aws dev instance
hosts: localhost
roles:
- aws
- name: Set up the dev server
hosts:
roles:
- services
In the aws role, I am creating an ec2 instance and registering it as ec2_instance. How will I use the public IP of that newly created instance in the hosts of the second play.
Should I use something like hosts: ec2_instance.public_ip?
You may consider using add_host. Put this in your first play (after getting the ip of new vm):
- name: Adding a new host in inventory file.
add_host: name=someName ansible_ssh_host="{{your_ip}}" ansible_ssh_pass=*** groups=new_group
and then use this group in second play:
- name: Set up the dev server
hosts: new_group

How to run playbook after creating ec2 with ansible

I have playbook to create ec2 like this
- name: Create an EC2 Instance
hosts: localmachine
connection: local
vars_files:
- vars/common.yml
roles:
- ec2
Now I also want that after the ec2 is created then I want to run another role inside that ec2 machine. I know how to wait for ec2 to be created but I don't know how to run role in newly created ec2.
This is how I wait for it
- name: Wait for instances to listen on port 22
wait_for:
state: started
host: "{{ ec2_info.instances[0].private_ip" }}"
port: 22
when: ec2_info|changed
but I want another task after that to run different roles inside that ec2
There is a detailed AWS guide with a section on provisioning. The short answer is that you should register the results of your provisioning into a variable (it looks like you've already chosen ec2_info for this) and then add those into another group:
- name: Add all instance public IPs to host group
add_host: hostname={{ item.public_ip }} groups=ec2hosts
with_items: ec2_info.instances
You can then assign roles to that group as you would normally.

start the stopped AWS instances using ansible playbook

I am trying to stop/start the particular group of instances listed in the hosts file under group [target].
following playbook works fine to stop the instances.
---
- hosts: target
remote_user: ubuntu
tasks:
- name: Gather facts
action: ec2_facts
- name: Stop Instances
local_action:
module: ec2
region: "{{region}}"
instance_ids: "{{ansible_ec2_instance_id}}"
state: stopped
But when I am trying to start these instances, it's not working as the ec2_facts is not able to ssh into the instances (since they are stopped now) and get the instance-ids
---
- hosts: target
remote_user: ubuntu
tasks:
- name: start instances
local_action:
module: ec2
region: "{{region}}"
instance_ids: "{{ansible_ec2_instance_id}}"
state: running
I have already seen the documentation which make use of dynamic inventory file for hosts and the way of hard-coding the instance-ids. I want to start the instances whose IPs are listed in the target group of hosts file.
Got the solution, Following is the ansible-task that worked for me.
---
- name: Start instances
hosts: localhost
gather_facts: false
connection: local
vars:
instance_ids:
- 'i-XXXXXXXX'
region: ap-southeast-1
tasks:
- name: Start the feature instances
ec2:
instance_ids: '{{ instance_ids }}'
region: '{{ region }}'
state: running
wait: True
Here is the Blog post on How to start/stop ec2 instances with ansible
You have 2 options:
Option 1
Use AWS CLI to query the instance-id of a stopped instance using its IP or name. For example, to query the instance id for a given instance name:
shell: aws ec2 describe-instances --filters 'Name=tag:Name,Values={{inst_name}}' --output text --query 'Reservations[*].Instances[*].InstanceId'
register: inst_id
Option 2
Upgrade Ansible to version 2.0 (Over the Hills and Far Away) and use the new ec2_remote_facts module
- ec2_remote_facts:
filters:
instance-state-name: stopped
You should add gather_facts: False to prevent Ansible from trying to SSH into the hosts since they're not running:
- hosts: target
remote_user: ubuntu
gather_facts: false
If you need to gather facts after the instances have started up then you can use the setup module to explicitly gather facts after they have booted up.
Edit: I just realized that the issue is that you're trying to access the ansible_ec2_instance_id fact that you can't get because the instance is down. You might want to take a look at this custom module called ec2_lookup that will let you search fetch AWS instance IDs even when the instances are down. Using this you can get a list of the instances you're interested in and then start them up.

Getting the IP address/attributes of the AWS instance created using Ansible

I know how to create an AWS instance using Ansible. Now what I want to achieve is to configure that instance as web server by installing nginx using the same playbook which created the instance.
The goal of the playbook will be:
Create an AWS instance.
Configure the instance as Web server by setting up the Nginx server.
Is it possible with ansible?
Read http://www.ansible.com/blog/ansible-ec2-tags It details how to spin up an ec2 instance (or multiple) and then run tasks against it (I.e install nginx).
I'f you want to jump straight to the example playbook https://github.com/chrismeyersfsu/playbook-ec2_properties/blob/master/new_group.yml
Bring up ec2 instance
Wait for ssh
add ec2 instance to Ansible dynamically created host group w/ associated ec2 pem file (so you can ssh to it)
Call an example play with a ping task to show everything works
Note: you would replace the ping task with your set of tasks to install nginx
#Bidyut How to reference ec2 ip address
look at Line 27 Note the use of register: ec2Then at Line 46 the ec2 ip address is "extracted" {{ ec2.results[item.0]['instances'][0]['public_ip'] }}. Note that the example calls register within a loop. If you are just creating one ec2 instance then the ec2 ip address reference would look like {{ ec2.results['instances'][0]['public_ip'] }}
Here is a working example that might help you.
---
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: Create the EC2 Instance
ec2:
region: us-east-1
group: sg-xxxxx # Replace your Security Group here
keypair: test-key # Replace Key here
instance_type: t2.mirco
image: ami-xxxxx # Replace AMI here
vpc_subnet_id: subnet-xxxxx # Replace Subnet here
assign_public_ip: yes
wait: yes
wait_timeout: 600
instance_tags:
Name: "My-EC2-Instance"
register: ec2
- name: Create SSH Group to login dynamically to EC2 Instance
add_host:
hostname: "{{ item.public_ip }}"
ansible_ssh_private_key_file: path/to/test-pair.pem
groupname: ec2_server
with_items: ec2.instances
- name: Wait for SSH to come up
wait_for:
host: "{{ item.public_ip }}"
port: 22
state: started
with_items: ec2.instances
- hosts: ec2_server
become: yes
# Use ec2_user if you are using CentOS/Amazon server
remote_user: ubuntu # for Ubuntu server
gather_facts: yes
roles:
- webserver
Yes, you can use a single playbook to launch an instance and install nginx. Use the ansible module add_host to add the ip of the just launched instance. Then write a play for the new host.
Launch an EC2 instance using ec2 module and register the instance
Use add_host module to add the new instance to the host inventory
Write a new play with host as the just registered host and call apt to install nginx
Try it and if you need code snippet, let me know.