How to skip existing machines while running ansible playbook - ansible

I am running ansible playbook on a cluster to add new machine. I want this to be run on only to add new machine thinking that there are no old machines existing. I can limit playbook to one machine by using "--limit" but in this case I dont know machine name or ip before creating.
How can I skip existing machines on the cluster while adding new one by ansible?
Thanks

You could use a add_host module if you playbook create a new machine you need catch the public or private IP and relate this with a new group and then use this group in your next play.
Take a look on the next example:
- name: Create a sandbox instance
hosts: localhost
gather_facts: False
vars:
key_name: my_keypair
instance_type: m1.small
security_group: my_securitygroup
image: my_ami_id
region: us-east-1
tasks:
- name: Launch instance
ec2:
key_name: "{{ keypair }}"
group: "{{ security_group }}"
instance_type: "{{ instance_type }}"
image: "{{ image }}"
wait: true
region: "{{ region }}"
vpc_subnet_id: subnet-29e63245
assign_public_ip: yes
register: ec2
- name: Add new instance to host group
add_host: hostname={{ item.public_ip }} groupname=launched
with_items: ec2.instances
- name: Wait for SSH to come up
wait_for: host={{ item.public_dns_name }} port=22 delay=60 timeout=320 state=started
with_items: ec2.instances
- name: Configure instance(s)
hosts: launched
become: True
gather_facts: True
roles:
- my_awesome_role
- my_awesome_test

Related

Ansible Playbook with include_tasks

I have an Ansible playbook called main.yml that builds a Windows VM using an OVF template. It then configures the VM using variables that I pass. Typical Ansible stuff.
What I would like to do is have another task inside the main.yml run at the end that configures a couple things on the VM (configureserver.yml). I pass "{{ vmName }}" as a variable in the main.yml, and want the 2nd playbook (configureserver.yml) to run against that `"{{ vmName }}" variable.
Main.yml (removed some of the customization to shorten this post)
- name: Deploy Virtual Machine from an OVF template in content library
community.vmware.vmware_content_deploy_ovf_template:
name: "{{ vmName }}"
hostname: "{{ vcenterName }}"
username: "{{ vmwareUser }}"
password: "{{ vmwarePassword }}"
template: "{{ templateName }}"
- name: Configure the VM
community.vmware.vmware_guest:
name: "{{ vmName }}"
hostname: "{{ vcenterName }}"
username: "{{ vmwareUser }}"
password: "{{ vmwarePassword }}"
datacenter: "{{ datacenterName }}"
cluster: "{{ clusterName }}"
datastore: "{{ datastoreclusterName }}"
# THIS IS WHAT I WANT TO ADD
- name: Configure the D Drive
include_tasks:
file: configureserver.yml
configureserver.yml
- hosts: "{{ vmName }}"
gather_facts: no
become: yes
vars_files:
- passwords.yml
- vars.test.yml
vars:
- ansible_connection: ssh
- ansible_shell_type: cmd
- ansible_become_method: runas
- ansible_become_user: System
In the code above, I want to run a separate task in a separate yml that will configure the server. I want to run the configureserver.yml playbook against the "{{ vmName }}" variable as the inventory or host.
Glad to provide more details if needed.
I figured it out. I changed the include_tasks to include_playbook and that did the trick

How to extract individual ips of ec2 instances launch using ansible when count is more than 1

I am launching aws ec2 2 instances using ansible using count:2 please check below playbook
- name: Create an EC2 instance
ec2:
aws_access_key: "{{ access_key }}"
aws_secret_key: "{{ key }}"
key_name: "{{ keypair }}"
region: "{{ region }}"
group: "{{ security_group }}"
instance_type: "{{ instance_type }}"
image: "{{ image }}"
wait: yes
count: 2
vpc_subnet_id: "{{ vpc_subnet_id }}"
assign_public_ip: "{{ assign_public_ip }}"
register: ec2
- name: Add the newly created 1 EC2 instance(s) to webserver group
lineinfile: dest=inventory
insertafter='^\[webserver\]$'
line="{{ item.private_ip }} {{hoststring}}"
state=present
with_items: "{{ ec2.instances }}"
- name: add newly created remaining ec2 instance to db group
lineinfile: dest=inventory
insertafter='^\[db-server\]$'
line="{{ item.private_ip }} {{hoststring}}"
state=present
with_items: "{{ ec2.instances }}"
Here i want to add one ip to webserver host group & remaining to db host group but its not working with above playbook please help me to achieve same?
i dont wnt to use add_host here.
Since you are using AWS, have you considered using the aws_ec2 plugin for dynamic inventory?
As long as you are tagging your instances correctly, and you set up the yaml file, it would do what you want it.
Otherwise, your register: ec2 has two elements in it. The way (if it worked) you are looping through ec2 would add both to each group. You would need to add a when condition to match the something like the tag/subnet/cidr to know which server to add to which group.
One way to help see what the return is would be do print out the ec2 variable:
- debug: var=ec2

ansible dynamic hosts refuse to use custom interpreter

I'm trying to provision new machines on AWS with ec2 module
and to update my hosts file locally so that the next tasks would already use the hosts file.
So, provisioning isn't and issue and even the creation of the local host file:
- name: Provision a set of instances
ec2:
key_name: AWS
region: eu-west-1
group: default
instance_type: t2.micro
image: ami-6f587e1c # For Ubuntu 14.04 LTS use ami-b9b394ca # For Ubuntu 16.04 LTS use ami-6f587e1c
wait: yes
volumes:
- device_name: /dev/xvda
volume_type: gp2
volume_size: 50
wait: true
count: 2
vpc_subnet_id: subnet-xxxxxxxx
assign_public_ip: yes
instance_tags:
Name: Ansible
register: ec2
- name: Add all instance private IPs to host group
add_host:
hostname: "{{ item.private_ip }}"
ansible_ssh_user: ubuntu
groups: aws
with_items: "{{ ec2.instances }}"
- local_action: file path=./hosts state=absent
ignore_errors: yes
- local_action: file path=./hosts state=touch
- local_action: lineinfile line="[all]" insertafter=EOF dest=./hosts
- local_action: lineinfile line="{{ item.private_ip }} ansible_python_interpreter=/usr/bin/python3" insertafter=EOF dest=./hosts
with_items: "{{ ec2.instances }}"
- name: Wait for SSH to come up
wait_for:
host: "{{ item.private_ip }}"
port: 22
delay: 60
timeout: 600
state: started
with_items: "{{ ec2.instances }}"
- name: refreshing inventory cache
meta: refresh_inventory
- hosts: all
gather_facts: False
tasks:
- command: hostname -i
However the next task which is a simple print of hostname -i (just for the test)
fails because it can't find on Ubuntu 16.04 LTS Python 2.7 (there is python3)
For that, in my dynamic host file I add the following line:
ansible_python_interpreter=/usr/bin/python3
But it seems that ansible ignore it and goes straight to python 2.7 which is missing.
I've tried to reload the inventory file
meta: refresh_inventory
but that didn't helped either.
What am I doing wrong ?
I'm not sure why the refresh did not work but I suggest setting it in the add_host section, it takes any variable.
- name: Add all instance private IPs to host group
add_host:
hostname: "{{ item.private_ip }}"
ansible_ssh_user: ubuntu
groups: aws
ansible_python_interpreter: "/usr/bin/python3"
with_items: "{{ ec2.instances }}"
Also i find it useful to debug with this task
- debug: var=hostvars[inventory_hostname]

How to stop old instance from ELB in ansible?

I have playbook which creates and add instance to Load balancer, what is the way I can remove/stop old instance already assigned to ELB, I want to make sure that we stop the old instance first and then new 1s are added or vice verse.
I am using AWS ELB and EC2 instance
I hope that might help you. Once you have the instance id then you can do whatever you want, I am just removing it from the ELB but you can use the ec2 module to remove it.
---
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: Get the facts about the ELB
ec2_elb_facts:
names: rbgeek-dev-web-elb
region: "eu-west-1"
register: elb_facts
- name: Instance(s) ID that are currently register to the ELB
debug:
msg: "{{ elb_facts.elbs.0.instances }}"
- name: Tag the Old instances as zombie
ec2_tag:
resource: "{{ item }}"
region: "eu-west-1"
state: present
tags:
Instance_Status: "zombie"
with_items: "{{ elb_facts.elbs.0.instances }}"
- name: Refresh the ec2.py cache
shell: ./inventory/ec2.py --refresh-cache
changed_when: no
- name: Refresh inventory
meta: refresh_inventory
# must check this step with ec2_remote_facts_module.html ##http://docs.ansible.com/ansible/ec2_remote_facts_module.html
- hosts: tag_Instance_Status_zombie
gather_facts: no
tasks:
- name: Get the facts about the zombie instances
ec2_facts:
- name: remove instance by instance id
ec2:
state: absent
region: "eu-west-1"
instance_ids: "{{ ansible_ec2_instance_id }}"
wait: true
delegate_to: localhost

Ansible - How to loop and get attributes of new EC2 instances

I'm creating a set of new EC2 instances using this play
- hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Provision a set of instances
ec2:
assign_public_ip: yes
aws_access_key: XXXXXXXXXX
aws_secret_key: XXXXXXXXXX
group_id: XXXXXXXXXX
instance_type: t2.micro
image: ami-32a85152
vpc_subnet_id: XXXXXXXXXX
region: XXXXXXXXXX
user_data: "{{ lookup('file', '/SOME_PATH/cloud-config.yaml') }}"
wait: true
exact_count: 1
count_tag:
Name: Demo
instance_tags:
Name: Demo
register: ec2
- name: Add new CoreOS machines to coreos-launched group
add_host: hostname="{{ item.public_ip }}" groups=coreos-launched
with_items: "{{ ec2.instances }}"
- name: Wait for SSH to come up
wait_for: host="{{ item.public_dns_name }}" port=22 delay=60 timeout=320
with_items: "{{ ec2.instances }}"
Now, I need to create an SSL/TLS certificate for every of those new machines. To do so, I require their private IP. Yet, I don't know how to access the "{{ ec2.instances }}" I registered in the previous play.
I tried something, in the same playbook, to do something like this
- hosts: coreos-launched
gather_facts: False
tasks:
- name: Find the current machine IP addresse
command: echo "{{ item.private_ip }}" > /tmp/private_ip
with_items: "{{ ec2.instances }}"
sudo: yes
But without any success. Is there a way to use the "{{ ec2.instances }}" items inside a same playbook but in a different play?
-- EDIT --
Following Theo advices, I manage to get the instances attributes using
- name: Gather current facts
action: ec2_facts
register: ec2_facts
- name: Use the current facts
command: echo "{{ ec2_facts.ansible_facts.ansible_ec2_local_ipv4 }}"
with_items: "{{ ec2_facts }}"
The best way to learn about a return structure (short of the documentation) is to wrap it in a debug task.
- name: Debug ec2 variable
debug: var=ec2.instances
From there, follow the structure to get the variable you seek.
Also (following the idempotence model), you can use the ec2_remote_facts module to get the facts from the instances and call them in future plays/tasks as well.
See Variables -- Ansible Documentation for more info about calling registered variables.

Resources