ansible vars_files and extra_vars to read input - ansible

looking to pass the dict to read a set of key value pairs based on the location. When values are hardcoded to the playbook, it works fine but calling through extra_vars giving an error message. Not sure even if it supports. appreciate, your thoughts and inputs.
ansible-playbook play3.yml -e '{"var1":"loc2"}' -vv
play3.yml
---
- name: testing
hosts: localhost
connection: local
gather_facts: no
vars_files:
- var_file.yml
tasks:
- debug:
msg: "{{ var1['first'] }}"
var_file.yml
---
loc1:
first: name1
last: name2
loc2:
first: python
last: perl
...

"Anything's possible in an animated cartoon." -Bugs Bunny
This playook:
---
- name: testing
hosts: localhost
connection: local
gather_facts: no
vars_files:
- var_file.yml
tasks:
- debug:
var: "{{ item }}.first"
with_items: "{{ var1 }}"
Gave me this output:
TASK [debug] **********************************************************************************************************************************
task path: /home/jack/Ansible/CANES/PLAYBOOKS/play3.yml:9
ok: [localhost] => (item=None) => {
"loc2.first": "python"
}

Related

Ansible: Retrieve Data from inventory

I need to retrieve the IP of bob_server from the inventory file. I am not clear as to what combination to use in filter, lookup, and when? Depending on the inventory filebob_server and alice_server names can change, but app_type won't change. My playbook logic is obviously wrong, Can someone guide me the correct way to fetch IP address when app_type = bob
My current Inventory file:
---
all:
hosts:
children:
bob_server:
hosts: 10.192.2.6
vars:
app_type: bob
alice_server:
hosts: 10.192.2.53
vars:
app_type: alice
My Playbook
---
- hosts: localhost
name: Retrive data
tasks:
- name: Set Ambari IP
set_fact:
ambariIP: "{{ lookup('hosts', children) }}"
when: "hostvars[app_type] == 'bob'"
Given the inventory
shell> cat hosts-01
---
all:
hosts:
children:
bob_server:
hosts: 10.192.2.6
vars:
app_type: bob
alice_server:
hosts: 10.192.2.53
vars:
app_type: alice
The simple option is using ansible-inventory, e.g.
- hosts: localhost
tasks:
- command: ansible-inventory -i hosts-01 --list
register: result
- set_fact:
my_inventory: "{{ result.stdout|from_yaml }}"
- debug:
var: my_inventory.bob_server.hosts
gives
my_inventory.bob_server.hosts:
- 10.192.2.6
If you want to parse the file on your own read it into a dictionary and flatten the paths, e.g. (install ansible.utils ansible-galaxy collection install ansible.utils)
- include_vars:
file: hosts-01
name: my_hosts
- set_fact:
my_paths: "{{ lookup('ansible.utils.to_paths', my_hosts) }}"
- debug:
var: my_paths
gives
my_paths:
all.children.alice_server.hosts: 10.192.2.53
all.children.alice_server.vars.app_type: alice
all.children.bob_server.hosts: 10.192.2.6
all.children.bob_server.vars.app_type: bob
all.hosts: null
Now select the keys ending bob_server.hosts
- set_fact:
bob_server_hosts: "{{ my_paths|
dict2items|
selectattr('key', 'match', '^.*bob_server\\.hosts$')|
items2dict }}"
gives
bob_server_hosts:
all.children.bob_server.hosts: 10.192.2.6
and select the IPs
- set_fact:
bob_server_ips: "{{ bob_server_hosts.values()|list }}"
gives
bob_server_ips:
- 10.192.2.6
The inventory is missing the concept of groups. See Inventory basics: formats, hosts, and groups. Usually, the value of children is a group of hosts. In this inventory, the value of children is the single host. This is conceptually wrong but still valid, .e.g
- hosts: bob_server
gather_facts: false
tasks:
- debug:
var: inventory_hostname
gives
shell> ansible-playbook -i hosts-01 playbook.ym
...
TASK [debug] ****************************************************
ok: [10.192.2.6] =>
inventory_hostname: 10.192.2.6

ansible regex_replace IP change

I would like to modify vars for drupal configuration file settings.php with ansible and regex_replace module. My initial var is an IP xxx.xxx.xxx.xxx and I want this as my new var xxx\.xxx\.xxx\.xxx
My playbook:
---
- hosts: localhost
remote_user: cal
become: yes
become_user: cal
tasks:
- set_fact:
ip_front: "10.11.12.13"
ip_front_back: "{{ ip_front | regex_replace('\\.', '\\.') }}"
- name: "show all var"
debug:
msg:
- "{{ ip_front }}"
- "{{ ip_front_ok }}"
Output:
ok: [localhost] => {
"msg": [
"10.11.12.13",
"10\\.11\\.12\\.13"
]
}
How can I use pattern to resolve it?

How to use variables defined through vars_prompt of one host in another host vars?

I am having 2 plays in a playbook. One of them prompts for input from user and I want to use that variable in another play. Please suggest me how to do that
---
- hosts: workers
gather_facts: false
sudo: true
vars_prompt:
- name: "server_ip"
prompt: "Enter the Server IP"
private: no
roles:
- client-setup-worker
- hosts: master
gather_facts: false
sudo: true
vars:
server: "{{ hostvars['workers']['server_ip'] }}"
roles:
- client-setup-master
In the above playbook I want to use server_ip defined in workers hosts to be used in master hosts.
I am facing the error "The error was: \"hostvars['workers']\" is undefined" while doing so
I am facing the error "The error was: \"hostvars['workers']\" is undefined" while doing so
That's because workers is evidently a group, and not a host, which is the only thing one will find declared in hostvars
You'll need to grab one of the hosts at random from the workers group, and then extract its fact; I believe this will do that:
update after seeing the mostly correct answer by #VladimirBotka
- hosts: workers
vars_prompt:
# as before ...
pre_tasks:
- name: re-export the vars_prompt for cross playbook visibility
set_fact:
server_ip: '{{ server_ip }}'
roles:
# as before
- hosts: masters
vars:
server: '{{ hostvars[(groups.workers|first)].server_ip }}'
The scope of variables declared in vars_prompt is the play.
Such variable may be put into the hostvars by set_facts "to use that variable in another play". For example the play below
- hosts: test_01
gather_facts: false
vars_prompt:
- name: "server_ip"
prompt: "Enter the Server IP"
private: no
tasks:
- set_fact:
stored_server_ip: "{{ server_ip }}"
- debug:
var: stored_server_ip
- hosts: test_02
gather_facts: false
vars:
server: "{{ hostvars.test_01.stored_server_ip }}"
tasks:
- debug:
var: server
gives (abridged):
ok: [test_01] => {
"stored_server_ip": "10.1.0.10"
}
ok: [test_02] => {
"server": "10.1.0.10"
}

Ansible Five random hosts from /etc/ansible/hosts

I have this playbook, it work using max_index but always takes the first 3 hosts from /etc/ansible/hosts , i need to take 3 random (and not repeated) hosts from that file.
playbook.yml
---
- hosts: ciscos
connection: local
gather_facts: false
tasks:
- group_by: key=limited_selection
when: play_hosts.index(inventory_hostname) < max_index | int
- hosts: limited_selection
gather_facts: no
/etc/ansible/hosts
[ciscos]
stagin ansible_host=10.xx.xx.1
stagin2 ansible_host=10.xx.xx.1
stagin3 ansible_host=10.xx.xx.1
stagin4 ansible_host=10.xx.xx.1
stagin5 ansible_host=10.xx.xx.1
Solution
You need to shuffle the elements of the group and choose three first. The Jinja2 expression for that is:
(groups['ciscos'] | shuffle)[0:3]
Implementation which should work, but has problems
You should be able to simply filter the group in the hosts declaration:
- hosts: "{{ (groups['ciscos'] | shuffle)[0:3] }}"
gather_facts: no
tasks:
- debug:
However the results are undeterministic - although the play shows as running against three randomly chosen hosts, the tasks are sometimes executed on 1, 2, 3, or 0:
PLAY [[u'stagin2', u'stagin4', u'stagin5']] *******************************************************************************
TASK [debug] **************************************************************************************************************
ok: [stagin2] => {
"msg": "Hello world!"
}
ok: [stagin5] => {
"msg": "Hello world!"
}
Workaround (implementation which works)
Use add_host module to create a filtered group:
- hosts: localhost
connection: local
gather_facts: no
tasks:
- add_host:
name: "{{ item }}"
groups: limited_selection
loop: "{{ (groups['ciscos'] | shuffle)[0:3] }}"
- hosts: limited_selection
gather_facts: no
tasks:
- debug:
What about something like this?
---
- hosts: ciscos
gather_facts: False
connection: local
tasks:
- name: Fact My Inventory
set_fact:
myinventory: "{{ ansible_play_batch | shuffle }}"
run_once: True
delegate_to: localhost
- name: Fact limited_selection
set_fact:
limited_selection: "{{ myinventory[0:max_index|int] }}"
run_once: True
delegate_to: localhost
- name: Create Inventory
add_host:
name: '{{ item }}'
groups: limited_selection
with_items: "{{ limited_selection }}"
delegate_to: localhost
- hosts: limited_selection
gather_facts: no
tasks:
- name: Debug
debug:
msg: "I'm in the limited selection group!"
Be careful with play_hosts as it is deprecated.
Note: I have kept the playbook with connection:ciscos instead of localhost for learning purposes and showing the ansible_play_batch and max_index variables. It is better to have a localhost play with groups instead of delegate_to:localhost

Rendering Ansible template into the fact variable

Is there a way to render Ansible template into the fact? I tried to find a solution but it looks like temp file is the the only way.
I think you might be just looking for the template lookup plugin:
- set_fact:
rendered_template: "{{ lookup('template', './template.j2') }}"
Usage example:
template.j2
Hello {{ value_for_template }}
playbook.yml
---
- hosts: localhost
gather_facts: no
connection: local
vars:
value_for_template: world
tasks:
- debug:
var: rendered_template
vars:
rendered_template: "{{ lookup('template', './template.j2') }}"
The result:
TASK [debug] *******************************************************************
ok: [localhost] => {
"rendered_template": "Hello world\n"
}

Resources