How to run playbook after creating ec2 with ansible - amazon-web-services

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.

Related

Using Ansible, how can I start a GCP VM instance which is currently stopped?

I have a GCP Compute Engine VM instance that is in a stopped state. How can I start it up, specifically using Ansible?
Please note that this must be in its own Ansible playbook, as opposed to the playbook that created the VM.
Ansible cannot connect to your device (or machine) if your SSHD process is off.
so How can Ansible connect to your device (or machine) if not only SSHD process is off, but also the whole machine is off ?
Ansible connects on yourbehalf to your machine and makes sure that your desired state meets the actual state.
However, you have solution as your are dealing with IaaS.
In this case, you need to target your localhost and call the module gcp_compute_instance with status: RUNNING
- name: create a instance
gcp_compute_instance:
name: test_object
machine_type: n1-standard-1
#. ...
status: RUNNING # <-- this is what u need
Please make sure you have ansible 2.8 or above otherwise there is no param called status in the previous versions.
Thanks #abdennour-toumi.
Correct, status: RUNNING works well.
Be sure to set the deletion_protection parameter, else the playbook fails.
---
- name: Start a GCP instance which is currently stopped
hosts: to_start_up
gather_facts: false
tasks:
- name: Start a GCP VM instance which is currently stopped
gcp_compute_instance:
name: "{{ inventory_hostname_short }}"
deletion_protection: no
machine_type: "{{ gcp_ce_machine_type }}"
zone: "{{ gcp_ce_zone }}"
project: "{{ gcp_ce_project_name }}"
auth_kind: serviceaccount
service_account_file: "{{ gcp_ce_service_account_keyfile }}"
status: RUNNING
delegate_to: localhost

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

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.

Best way to launch aws ec2 instances with ansible

I'm trying to create an small webapp infrastructure with ansible on Amazon AWS and I want to do all the process: launch instance, configure services, etc. but I can't find a proper tool or module to deal with that from ansible. Mainly EC2 Launch.
Thanks a lot.
This is the short answer of your question, if you want detail and fully automated role, please let me know. Thanks
Prerequisite:
Ansible
Python boto library
Set up the AWS access and secret keys in the environment settings
(best is inside the ~./boto)
To Create the EC2 Instance(s):
In order to create the EC2 Instance, please modified these parameters that you can find inside the "ec2_launch.yml" file under "vars":
region # where is want to launch the instance(s), USA, Australia, Ireland etc
count # Number of instance(s), you want to create
Once, you have mentioned these parameter, please run the following command:
ansible-playbook -i hosts ec2_launch.yml
Contents of hosts file:
[local]
localhost
[webserver]
Contents of ec2_launch.yml file:
---
- name: Provision an EC2 Instance
hosts: local
connection: local
gather_facts: False
tags: provisioning
# Necessary Variables for creating/provisioning the EC2 Instance
vars:
instance_type: t1.micro
security_group: webserver # Change the security group name here
image: ami-98aa1cf0 # Change the AMI, from which you want to launch the server
region: us-east-1 # Change the Region
keypair: ansible # Change the keypair name
count: 1
# Task that will be used to Launch/Create an EC2 Instance
tasks:
- name: Create a security group
local_action:
module: ec2_group
name: "{{ security_group }}"
description: Security Group for webserver Servers
region: "{{ region }}"
rules:
- proto: tcp
type: ssh
from_port: 22
to_port: 22
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: 0.0.0.0/0
rules_egress:
- proto: all
type: all
cidr_ip: 0.0.0.0/0
- name: Launch the new EC2 Instance
local_action: ec2
group={{ security_group }}
instance_type={{ instance_type}}
image={{ image }}
wait=true
region={{ region }}
keypair={{ keypair }}
count={{count}}
register: ec2
- name: Add the newly created EC2 instance(s) to the local host group (located inside the directory)
local_action: lineinfile
dest="./hosts"
regexp={{ item.public_ip }}
insertafter="[webserver]" line={{ item.public_ip }}
with_items: "{{ ec2.instances }}"
- name: Wait for SSH to come up
local_action: wait_for
host={{ item.public_ip }}
port=22
state=started
with_items: "{{ ec2.instances }}"
- name: Add tag to Instance(s)
local_action: ec2_tag resource={{ item.id }} region={{ region }} state=present
with_items: "{{ ec2.instances }}"
args:
tags:
Name: webserver
As others have said, the cloud module contains just about all the AWS provisioning support you'd need. That said, Ansible's paradigm makes most sense once there's an existing SSH:able machine to target and connect to. The instantiation phase, by comparison, essentially asks you to target your local machine and calls AWS API endpoints from there.
Like you, I wanted a single-shot command with a graceful transition from EC2 instantiation into its configuration. There's suggestions on how to accomplish something like this in the documentation, but it relies on the the add_host module to tweak Ansible's idea of current host inventory, and even then I couldn't find a solution that didn't feel like i was working against rather than with the system.
In the end I opted for two distinct playbooks: a provision.yml that uses the ec2, ec2_group, ec2_vol, ec2_eip and route53 modules to ensure I have the "hardware" in place, and then configure.yml, more like a traditional Ansible site.yml, which is able to treat host inventory (static in my case, but dynamic will work well) as a given and do all that good declarative state transitioning.
Both playbooks are idempotent, but it's configure.yml that's meant to be rerun over and over in the long run.
The EC2 module was designed precisely for creating and destroying instances.
If you want the "best" way, it's hard to beat CloudFormation, which can be launched from Ansible.