Ansible looping over main playbook - ansible

I created a "main" playbook that create and deploy a complex application let's say an entire house.
The "main" looks like this :
- hosts: host1
roles:
- { role: role1 }
- hosts: host2
roles:
- { role: role2 }
- hosts: localhost
roles:
- { role: role3 }
- { role: role4 }
- { role: role5 }
- { role: role6 }
I would like now to be able to deploy multiple houses using a CSV as input, containing my variables.
I was expecting to just import that "main" playbook, and loop over my CSV so that I can create multiple houses.
Based on the documentation I'm not able to loop using import_playbook, so I'm a stuck on how I could use this "main" for multiple creations in series.
Has anybody been in that situation or has an idea on how I could resolve this ?

You can use the csvfile lookup to read data from CSV files.
Example CSV file roles.csv:
host1,role1
host2,role2
localhost,role3 role4 role5 role6
Create mock-up roles:
for i in {1,2,3,4,5,6}; do
mkdir -p roles/role$i/tasks &&
echo "- debug: msg=\"role$i\"" > roles/role$i/tasks/main.yaml
done
And in the playbook you use the include_role syntax instead of roles, because include_role can be used in a loop. By this you can loop over the array read from the CSV file.
---
- hosts: localhost
connection: local
tasks:
- name: Use role in loop
include_role:
name: '{{ roleinputvar }}'
loop: "{{ lookup('csvfile', inventory_hostname + ' file=roles.csv delimiter=,').split(' ') }}"
loop_control:
loop_var: roleinputvar
connection: local is just for this example.
When run the roles 3 to 6 are executed:
$ ansible-playbook roles.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the
implicit localhost does not match 'all'
PLAY [localhost] **********************************************************************
TASK [Gathering Facts] ****************************************************************
ok: [localhost]
TASK [Use role in loop] ***************************************************************
TASK [role3 : debug] ******************************************************************
ok: [localhost] => {
"msg": "role3"
}
TASK [role4 : debug] ******************************************************************
ok: [localhost] => {
"msg": "role4"
}
TASK [role5 : debug] ******************************************************************
ok: [localhost] => {
"msg": "role5"
}
TASK [role6 : debug] ******************************************************************
ok: [localhost] => {
"msg": "role6"
}
PLAY RECAP ****************************************************************************
localhost : ok=5 changed=0 unreachable=0 failed=0

Related

Access variable from one role in another role in an Ansible playbook with multiple hosts

I'm using the latest version of Ansible, and I am trying to use a default variable in role-one used on host one, in role-two, used on host two, but I can't get it to work.
Nothing I have found in the documentation or on StackOverflow has really helped. I'm not sure what I am doing wrong. Ideally I want to set the value of the variable once, and be able to use it in another role for any host in my playbook.
I've broken it down below.
In my inventory I have a hosts group called [test] which has two hosts aliased as one and two.
[test]
one ansible_host=10.0.1.10 ansible_connection=ssh ansible_user=centos ansible_ssh_private_key_file=<path_to_key>
two ansible_host=10.0.1.20 ansible_connection=ssh ansible_user=centos ansible_ssh_private_key_file=<path_to_key>
I have a single playbook with a play for each of these hosts and I supply the hosts: value as "{{ host_group }}[0]" for host one and "{{ host_group }}[1]" for host two.
The play for host one uses a role called role-one and the play for host two uses a role called role-two.
- name: Test Sharing Role Variables
hosts: "{{ host_group }}[0]"
roles:
- ../../ansible-roles/role-one
- name: Test Sharing Role Variables
hosts: "{{ host_group }}[1]"
roles:
- ../../ansible-roles/role-two
In role-one I have set a variable variable-one.
---
# defaults file for role-one
variable_one: Role One Variable
I want to use the value of variable_one in a template in role-two but I haven't had any luck. I'm using the below as a task in role-two to test and see if the variable is getting "picked-up".
---
# tasks file for role-two
- debug:
msg: "{{ variable_one }}"
When I run the playbook with ansible-playbook test.yml --extra-vars "host_group=test" I get the below failure.
TASK [../../ansible-roles/role-two : debug] ***********************************************************************************************************************************************************************************************
fatal: [two]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['test']\" is undefined\n\nThe error appears to be in 'ansible-roles/role-two/tasks/main.yml': line 3, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# tasks file for role-two\n- debug:\n ^ here\n"}
Variables declared in roles are scoped to the play. If you want to access a variable from role-one in role-two, they would both need to be in the same play. For example, you could write:
- name: Test Sharing Role Variables
hosts: "{{ host_group }}"
tasks:
- import_role:
name: role-one
when: inventory_hostname == "one"
- import_role:
name: role-two
when: inventory_hostname == "two"
Alternatively, you could restructure your roles so that the variables can be imported separately from your actions. That is, have a role_one_vars role that does nothing but define variables, and then you can import that in both role-one and role-two. That is, you would have a structure something like:
playbook.yml
hosts
roles/
role-one/
tasks/
main.yml
role-one-vars/
variables/
main.yml
role-two/
tasks/
main.yml
And role-one/tasks/main.yml would look like:
- import_role:
name: role-one-vars
- debug:
msg: "in role-one: {{ variable_one }}"
role-two/tasks/main.yml would look like:
---
- import_role:
name: role-one-vars
- debug:
msg: "in role-two: {{ variable_one }}"
And role-one-vars/vars/main.yml would look like:
---
variable_one: role one variable
Putting this all together, the output looks like:
PLAY [Test Sharing Role Variables] *****************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [one]
TASK [role-one : debug] ****************************************************************************************************************************************************
ok: [one] => {
"msg": "in role-one: role one variable"
}
PLAY [Test Sharing Role Variables] *****************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [two]
TASK [role-two : debug] ****************************************************************************************************************************************************
ok: [two] => {
"msg": "in role-two: role one variable"
}
PLAY RECAP *****************************************************************************************************************************************************************
one : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
two : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Q: "Access variable from one role in another role in an Ansible playbook with multiple hosts"
A: Short answer: Use set_fact and put the variable into the hostvars.
Details: Given the roles
shell> cat roles/role-one/defaults/main.yml
variable_one: Role One Variable
shell> cat roles/role-one/tasks/main.yml
- debug:
var: variable_one
shell> cat roles/role-two/tasks/main.yml
- debug:
var: variable_one
The playbook
- hosts: one
roles:
- role-one
tasks:
- debug:
var: variable_one
- hosts: two
roles:
- role-two
- hosts: one
tasks:
- debug:
var: variable_one
gives (abridged)
PLAY [one] ************************************************
TASK [role-one : debug] ****
ok: [one] =>
variable_one: Role One Variable
TASK [debug] ****
ok: [one] =>
variable_one: Role One Variable
PLAY [two] ************************************************
TASK [role-two : debug] ****
ok: [two] =>
variable_one: VARIABLE IS NOT DEFINED!
PLAY [one] ************************************************
TASK [debug] ****
ok: [one] =>
variable_one: VARIABLE IS NOT DEFINED!
As expected, the variable variable_one is visible to the tasks in the first play. But, there is no reason the variable should be visible to the host two in the second play. The variable is not visible also to the same host in the third play because it hasn't been stored in the hostvars aka "instantiated". The playbook below
- hosts: one
roles:
- role-one
tasks:
- debug:
var: variable_one
- set_fact:
variable_one: "{{ variable_one }}"
- hosts: two
roles:
- role-two
- hosts: one
tasks:
- debug:
var: variable_one
gives (abridged)
PLAY [one] ************************************************
TASK [role-one : debug] ****
ok: [one] =>
variable_one: Role One Variable
TASK [debug] ****
ok: [one] =>
variable_one: Role One Variable
TASK [set_fact] ****
ok: [one]
PLAY [two] ************************************************
TASK [role-two : debug] ****
ok: [two] =>
variable_one: VARIABLE IS NOT DEFINED!
PLAY [one] ************************************************
TASK [debug] ****
ok: [one] =>
variable_one: Role One Variable
Now, the variable is visible to the host one in the whole playbook and can be visible to other hosts using hostvars as well. For example, the playbook below
- hosts: one
roles:
- role-one
tasks:
- debug:
var: variable_one
- set_fact:
variable_one: "{{ variable_one }}"
- hosts: two
tasks:
- set_fact:
variable_one: "{{ hostvars.one.variable_one }}"
- include_role:
name: role-two
gives (abridged)
PLAY [one] ************************************************
TASK [role-one : debug] ****
ok: [one] =>
variable_one: Role One Variable
TASK [debug] ****
ok: [one] =>
variable_one: Role One Variable
TASK [set_fact] ****
ok: [one]
PLAY [two] ************************************************
TASK [set_fact] ****
ok: [two]
TASK [include_role : role-two] ****
TASK [role-two : debug] ****
ok: [two] =>
variable_one: Role One Variable
The problem with the above setting is that the host referencing hostvars is hardcoded. A better approach is to "instantiate" the variable in the first play for all hosts. For example, add a dummy task to the role
shell> cat roles/role-one/tasks/noop.yml
- meta: noop
Then, in the first play, include all hosts, run_once import the role, run the dummy task only, and "instantiate" the variable for all hosts. For example
- hosts: all
tasks:
- import_role:
name: role-one
tasks_from: noop.yml
run_once: true
- set_fact:
variable_one: "{{ variable_one }}"
run_once: true
- hosts: two
roles:
- role-two
- hosts: one
roles:
- role-two
gives (abridged)
PLAY [all] ************************************************
TASK [set_fact] ****
ok: [one]
PLAY [two] ************************************************
TASK [role-two : debug] ****
ok: [two] =>
variable_one: Role One Variable
PLAY [one] ************************************************
TASK [role-two : debug] ****
ok: [one] =>
variable_one: Role One Variable

Ansible playbook to get all private Ip of my AWS environments

I'm running a scan against all the instances on my AWS using Ansible pLaybook . I need to get their Private IP and list them
I have tried to use json query to filter the Json format. The format output look like this..............
ok: [localhost] => {
"msg": [
{
"private_dns_name": "ip-10.89.3.12.ec2.internal",
"private_ip_address": "10.89.3.12",
"public_dns_name": "",
"public_ip_address": null,
},
- hosts: localhost
connection: local
gather_facts: yes
tasks:
- name: Gather EC2 remote facts.
ec2_remote_facts:
region: "{{ region | default('us-east-1') }}"
filters:
instance-state-name: running
register: ec2_remote_facts
- set_fact:
msg: "{{ ec2_remote_facts | json_query('results[*].instances[*].private_ip_address') }} "
- debug: var=msg
I expect the output to be list of private_IP only
I tried with "ec2_instance_facts" as below :
- hosts: localhost
connection: local
gather_facts: yes
tasks:
- name: Gather EC2 remote facts.
ec2_instance_facts:
filters:
availability-zone: ap-south-1b
register: ec2_instance_facts
- set_fact:
msg: "{{ ec2_instance_facts | json_query('instances[*].private_ip_address') }} "
- debug: var=msg
and below is the output :
PLAY [localhost] **************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Gather EC2 remote facts.] ***********************************************************************************************************************************************************************************
ok: [localhost]
TASK [set_fact] ***************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"172.31.6.87"
]
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Which is correct as per EC2 instance I had created.

How to pass vars in nested Ansible playbook?

I have a nested ansible playbook (master) file and I want to call included playbook (slave) with their own JSON vars.
Master.yaml
- name: this is a play at the top level of a file
hosts: local
connection: local
tasks:
- debug: msg=hello
- include: slave_first.yaml
- include: slave_second.yaml
slave_first.yaml should make use of "vars/slave_first_vars.json" file and slave_second.yaml should make use of "vars/slave_second_vars.json" file.
When including playbooks you can only override variables with vars statement, like:
- include: slave_first.yaml
vars:
myvar: foo
- include: slave_second.yaml
vars:
myvar: foo
There are no other options for PlaybookInclude.
If you need to load variables from files, you have to use vars_files or include_vars inside your slave playbooks.
In your scenario, I'll use like this, master.yml:
- hosts: localhost
connection: local
tasks:
- include: slave_first.yml
vars:
VAR_FILE: "slave_first_vars"
- include: slave_second.yml
vars:
VAR_FILE: "slave_second_vars"
While slave_first.yml and slave_second.yml are like this, in my case both are same but you get an idea that how you can use them:
slave_first.yml:
---
- include_vars: "{{ VAR_FILE }}.yml"
- debug:
msg: "{{ DOMAIN_NAME }}"
slave_second.yml:
---
- include_vars: "{{ VAR_FILE }}.yml"
- debug:
msg: "{{ DOMAIN_NAME }}"
Now come to the different variable part:
slave_first_vars.yml: in your case it will be json
---
DOMAIN_NAME: "first.com"
slave_second_vars.yml:
---
DOMAIN_NAME: "second.com"
Then you can run and verify that if work as expected:
➤ansible-playbook -i localhost, master.yml
PLAY [localhost] **********************************************************************************
TASK [Gathering Facts] **********************************************************************************
ok: [localhost]
TASK [include_vars] **********************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "first.com"
}
TASK [include_vars] **********************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "second.com"
}
PLAY RECAP **********************************************************************************
localhost : ok=5 changed=0 unreachable=0 failed=0
Hope that might help you!

Ansible hostvars undefined

I have a very simple play which saves vars and looks them up in hostvars.
- name: Set hostvars
hosts: localhost
vars:
var_one: "I am a"
var_two: "test"
tasks:
- debug: var=hostvars['localhost']['var_one']
- debug: var=hostvars['localhost']['var_two']
However, when I run this play the vars aren't defined:
PLAY [Set hostvars] ************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"hostvars['localhost']['var_one']": "VARIABLE IS NOT DEFINED!"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"hostvars['localhost']['var_two']": "VARIABLE IS NOT DEFINED!"
}
How can I save these vars in hostvars?
You can set host facts runtime using set_fact module:
---
- name: Set hostvars
hosts: localhost
tasks:
- set_fact: var_one="I am a"
- set_fact: var_two="test"
- debug: var=hostvars['localhost']['var_one']
- debug: var=hostvars['localhost']['var_two']
Quoting the documentation:
These variables will survive between plays during an Ansible run, but will not be saved across executions even if you use a fact cache.
This is where the difference between facts (variables bound to Ansible target hosts) and regular variables can be seen.
Variables are internally stored in vars structure, so you can access them with:
tasks:
- debug: var=vars['var_one']
- debug: var=vars['var_two']
Facts, on the other hand are stored in hostvars.
In either case, unless you were referring to a variable name with a dynamic name, or a fact bound to another host than the one executing the task, you can simply use the variable/fact name by using its name:
tasks:
- debug: var=var_one
- debug: var=var_two
Try using
msg=
instead of var=. As per help of debug module
var - A variable name to debug. Mutually exclusive with the 'msg' option.
- name: Set hostvars
hosts: localhost
vars:
var_one: I am a
var_two: est
tasks:
- debug: msg=hostvars['localhost']['var_one']
- debug: msg=hostvars['localhost']['var_two']
...
PLAY [Set hostvars] ************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "hostvars['localhost']['var_one']"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "hostvars['localhost']['var_two']"
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0

Ansible How to read and manipulate settings based on an acronym

What strategy you use to control custom settings? Using ini files or save files in yaml format ?!
For example I have settings for acronym of my establishment.
How do I access from my playbook these variables or custom data?
I want to read the settings conditionally. Based on the referenced acronym.
Like that:
ansible-playbook -i hosts myplaybooy.yml my_acronym
Example structure where CAX, BAC and SIN are acronyms:
CAX
IP_SERVER = 200.253.167.1
IP_DB_MASTER = 200.253.167.20
IP_DB_SLAVE = 200.253.167.21
IP_MIRROR = 200.253.167.13
BAC
IP_SERVER = 200.253.168.1
IP_DB_MASTER = 200.253.168.20
IP_DB_SLAVE = 200.253.168.21
IP_MIRROR = 200.253.168.13
SIN
IP_SERVER = 200.253.169.1
IP_DB_MASTER = 200.253.169.20
IP_DB_SLAVE = 200.253.169.21
IP_MIRROR = 200.253.169.13
The reason for this change is to adapt my playbook for the ansible-pull. In ansible-pull conditional tests like these not work.
- name: Download pub key acesso
fetch:
src=~acesso/.ssh/id_rsa.pub
dest="{{role_path}}/../appserver/files/pub_keys/appservers/csa{{groupvar.server.acronym}}am/acesso.pub" flat=yes
sudo: yes
delegate_to: "{{hostvars['csa'+groupvar.server.acronym+'am'].ansible_ssh_host}}"
when: inventory_hostname in groups['pdv'+groupvar.server.acronym]
run_once: True
ignore_errors: yes
I think this is due to the fact that ansible-pull look at inventory subsets.
I think this will work for you. If you can post more from the playbook you're using, I can help you make this work for the actual tasks you're running.
This is the command-line syntax I used:
ansible-playbook -i hosts playbook.yml --extra-vars "ACRONYM=SIN"
playbook.yml:
---
- name: show vars
hosts: localhost
vars_files:
- var_file.yml
tasks:
- debug:
msg: IP_SERVER = {{Acronyms[ACRONYM].IP_SERVER}}
- debug:
msg: IP_DB_MASTER = {{Acronyms[ACRONYM].IP_DB_MASTER}}
- debug:
msg: IP_DB_SLAVE = {{Acronyms[ACRONYM].IP_DB_SLAVE}}
- debug:
msg: IP_MIRROR = {{Acronyms[ACRONYM].IP_MIRROR}}
var_file.yml:
Acronyms: {
CAX:
{ IP_SERVER: 200.253.167.1,
IP_DB_MASTER: 200.253.167.20,
IP_DB_SLAVE: 200.253.167.21,
IP_MIRROR: 200.253.167.13
},
BAC:
{ IP_SERVER: 200.253.168.1,
IP_DB_MASTER: 200.253.168.20,
IP_DB_SLAVE: 200.253.168.21,
IP_MIRROR: 200.253.168.13
},
SIN:
{ IP_SERVER: 200.253.169.1,
IP_DB_MASTER: 200.253.169.20,
IP_DB_SLAVE: 200.253.169.21,
IP_MIRROR: 200.253.169.13
}
}
This is my terminal output:
PLAY [show vars] ***************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "IP_SERVER = 200.253.169.1"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "IP_DB_MASTER = 200.253.169.20"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "IP_DB_SLAVE = 200.253.169.21"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "IP_MIRROR = 200.253.169.13"
}
PLAY RECAP *********************************************************************
localhost : ok=5 changed=0 unreachable=0 failed=0

Resources