Ansible separating hosts, group_vars and host_vars - ansible

I need to change some files in YAML format from one "big" yml to several smaller files. Unfortunately, I do not know which part belongs where. For example, I have the following .yml:
all:
hosts:
station01:
dns_name: localhost
ansible_host: localhost
work01:
dns_name: X.X.X.X
ansible_host: Y.Y.Y.Y
vars:
yum_proxy: false
zabbix_proxy_ip: A.A.A.A
yum_proxy_ip:
dns_servers:
- B.B.B.B
- C.C.C.C
timezone: XXX
ntp_servers:
- D.D.D.D
disable_firewall_tasks: true
children:
deploy:
hosts:
station01:
linux:
hosts:
work01:
work_users:
hosts:
work01:
vars:
users:
- john: user
- mike: user
I believe that hosts file should looke like this:
all:
hosts:
station01
work01
children:
deploy:
hosts:
station01:
linux:
hosts:
work01:
work_users:
hosts:
work01:
The group_vars "all.yml" looks like this, I guess:
---
all:
yum_proxy: false
zabbix_proxy_ip: A.A.A.A
yum_proxy_ip:
dns_servers:
- B.B.B.B
- C.C.C.C
timezone: XXX
ntp_servers:
- D.D.D.D
disable_firewall_tasks: true
And this is where the problem begins. I do not know where to put the "users:". Should it be in host_vars "work01.yml" assigned to one host, like this:
---
work01:
dns_name: X.X.X.X
ansible_host: Y.Y.Y.Y
users:
- john: user
- mike: user
Or should it be contained in the group_vars file named "work_users.yml"?
---
users:
- john: user
- mike: user
What the files host_vars and group_vars should look like? Any kind of help would be appreciated.

Q: "What the files host_vars and group_vars should look like?"
A: There are more options of how to name and organize the directories and files. See Organizing host and group variables.
Files named after the corresponding groups and hostnames
Below is an example of putting the variables into the files named after the corresponding groups and hostnames
shell> cat group_vars/all.yml
---
yum_proxy: false
zabbix_proxy_ip: A.A.A.A
yum_proxy_ip:
dns_servers:
- B.B.B.B
- C.C.C.C
timezone: XXX
ntp_servers:
- D.D.D.D
disable_firewall_tasks: true
shell> cat group_vars/work_users.yml
---
users:
- john: user
- mike: user
shell> cat host_vars/work01.yml
---
dns_name: X.X.X.X
ansible_host: Y.Y.Y.Y
shell> cat host_vars/station01.yml
---
dns_name: localhost
ansible_host: localhost
Files inside the directories named after the corresponding groups and hostnames
The next option is putting the variables into the files inside the directories named after the corresponding groups and hostnames
shell> cat group_vars/all/network.yml
---
yum_proxy: false
zabbix_proxy_ip: A.A.A.A
yum_proxy_ip:
dns_servers:
- B.B.B.B
- C.C.C.C
timezone: XXX
ntp_servers:
- D.D.D.D
disable_firewall_tasks: true
shell> cat group_vars/work_users/users.yml
---
users:
- john: user
- mike: user
shell> cat host_vars/work01/network.yml
---
dns_name: X.X.X.X
ansible_host: Y.Y.Y.Y
shell> cat host_vars/station01/network.yml
---
dns_name: localhost
ansible_host: localhost

Related

How to use host_vars in Ansible?

I created a variable in group_vars
group_vars/all
---
hostname: name1
I want to set name2 to the real host(10.20.30.40), so I created a file and set the hostname again there
host_vars/10.20.30.40
---
hostname: name2
When I run the playbook, it returned name1 but not name2:
roles/os/tasks/main.yml
- name: Print hostname
ansible.builtin.debug:
msg: "{{ hostname }}"
Result:
TASK [server : Print hostname] *************************************
ok: [web_server] => {
"msg": "name1"
}
I want to set the variable in each host that I want to update, isn't it the right usage?
And, if I name the host file this way under the host_vars folder, does it work?
web_server
The inventory:
[web_server]
10.20.30.40
playbook:
---
- hosts: web_server
become: true
vars_files:
- group_vars/all
roles:
- os
Q: "When I run the playbook, it returned name1 but not name2."
shell> cat hosts
[web_server]
10.20.30.40
shell> cat group_vars/all
---
hostname: name1
shell> cat host_vars/10.20.30.40
---
hostname: name2
shell> cat playbook.yml
---
- hosts: web_server
vars_files:
- group_vars/all
tasks:
- debug:
var: hostname
A: Don't include group_vars/all in a playbook.
The playbook's group_vars/all are included by the playbook automatically at precedence 5. See Understanding variable precedence. If you put group_vars/all into the vars_files (precedence 14) you override the host_vars (precedence 10).
Example. Given the inventory
shell> cat hosts
[web_server]
10.20.30.40
10.20.30.41
the playbook
shell> cat playbook.yml
---
- hosts: web_server
gather_facts: false
tasks:
- debug:
var: hostname
gives as expected
shell> ansible-playbook -i hosts playbook.yml
PLAY [web_server] *********************************************************
TASK [debug] **************************************************************
ok: [10.20.30.40] =>
hostname: name2
ok: [10.20.30.41] =>
hostname: name1
The variable in host_vars/10.20.30.40 override the variable in group_vars/all

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 how to set_fact with condition or var base on condition

I have 3 types of servers: dev, qa and prod. I need to send files to server specific home directories, i.e:
Dev Home Directory: /dev/home
QA Home Directory:/qa/home
PROD Home Directory: /prod/home
I have var set as boolean to determine the server type and think of using set_fact with condition to assign home directories for the servers. My playbook looks like this:
---
- hosts: localhost
var:
dev: "{{ True if <hostname matches dev> | else False }}"
qa: "{{ True if <hostname matches qa> | else False }}"
prod: "{{ True if <hostname matches prod> | else False }}"
tasks:
- set_facts:
home_dir: "{{'/dev/home/' if dev | '/qa/home' if qa | default('prod')}}"
However, then I ran the playbook, I was getting error about 'template expected token 'name', got string> Anyone know what I did wrong? Thanks!
Use match test. For example, the playbook
shell> cat pb.yml
- hosts: localhost
vars:
dev_pattern: '^dev_.+$'
qa_pattern: '^qa_.+$'
prod_pattern: '^prod_.+$'
dev: "{{ hostname is match(dev_pattern) }}"
qa: "{{ hostname is match(qa_pattern) }}"
prod: "{{ hostname is match(prod_pattern) }}"
tasks:
- set_fact:
home_dir: /prod/home
- set_fact:
home_dir: /dev/home
when: dev|bool
- set_fact:
home_dir: /qa/home
when: qa|bool
- debug:
var: home_dir
gives (abridged)
shell> ansible-playbook pb.yml -e hostname=dev_007
home_dir: /dev/home
Notes:
The variable prod is not used because /prod/home is default.
prod/home is assigned to home_dir first because it's the default. Next tasks can conditionally overwrite home_dirs.
Without the variable hostname defined the playbook will crash.
A simpler solution that gives the same result is creating a dictionary of 'pattern: home_dir'. For example
- hosts: localhost
vars:
home_dirs:
dev_: /dev/home
qa_: /qa/home
prod_: /prod/home
tasks:
- set_fact:
home_dir: "{{ home_dirs|
dict2items|
selectattr('key', 'in' , hostname)|
map(attribute='value')|
list|
first|default('/prod/home') }}"
- debug:
var: home_dir
Adding an alternative method to achieve this. This kind of extends the group_vars suggestion given by #mdaniel in his comment.
Ansible has a ready-made mechanism to build the variables based on the inventory hosts and groups. If you organize your inventory, you can avoid a lot of complication in trying to match host patterns.
Below is a simplified example, please go through the link above for more options.
Consider an inventory file /home/user/ansible/hosts:
[dev]
srv01.dev.example
srv02.dev.example
[qa]
srv01.qa.example
srv02.qa.example
[prod]
srv01.prod.example
srv02.prod.example
Using group_vars:
Then you can have below group_var files in /home/user/ansible/group_vars/ (matching inventory group names):
dev.yml
qa.yml
prod.yml
In dev.yml:
home_dir: "/dev/home"
In qa.yml:
home_dir: "/qa/home"
In prod.yml:
home_dir: "/prod/home"
Using host_vars:
Or you can have variables specific to hosts in host_vars directory /home/user/ansible/host_vars/:
srv01.dev.example.yml
srv01.prod.example.yml
# and so on
In srv01.dev.example.yml:
home_dir: "/dev/home"
In srv01.prod.example.yml:
home_dir: "/prod/home"
These variables will be picked based on which hosts you run the playbook, for example the below playbook:
---
- hosts: dev
tasks:
- debug:
var: home_dir
# will be "/dev/home"
- hosts: prod
tasks:
- debug:
var: home_dir
# will be "/prod/home"
- hosts: srv01.dev.example
tasks:
- debug:
var: home_dir
# will be "/dev/home"
- hosts: srv01.prod.example
tasks:
- debug:
var: home_dir
# will be "/prod/home"

ansible cisco modifying multiple object-groups with single playbook lines

I have following playbook to modify ASA object-group:
---
- hosts: us_asa
connection: local
gather_facts: false
tasks:
- name: change config
asa_config:
auth_pass: "{{ ansible_ssh_password }}"
username: "{{ ansible_ssh_user }}"
password: "{{ ansible_ssh_password }}"
authorize: yes
timeout: 45
lines:
- network-object host 1.2.3.4
- network-object host 2.3.2.3
parents: ['object-group network BAD_IPs']
This works fine for single group.
Any suggestion how to modify multiple groups with same connection? If I add another object-group after parents: ['object-group network BAD_IPs'] example:
---
- hosts: us_asa
connection: local
gather_facts: false
tasks:
- name: change config
asa_config:
auth_pass: "{{ ansible_ssh_password }}"
username: "{{ ansible_ssh_user }}"
password: "{{ ansible_ssh_password }}"
authorize: yes
timeout: 45
lines:
- network-object host 1.2.3.4
- network-object host 2.3.2.3
parents: ['object-group network BAD_IPs']
- network-object host 4.4.4.4
parents: ['object-group network Good_IPs']
This fails
The offending line appears to be:
parents: ['object-group network BAD_IPs']
- network-object host 4.4.4.4
^ here
Any recommendation on syntax I should use?
Thank you in advance!
You just have a basic YAML syntax error there. A YAML dictionary key with a list value looks either like this:
key: [item1, item2, item3]
Or like this:
key:
- item1
- item2
- item3
You have some weird combination of the two:
parents: ['object-group network BAD_IPs']
- network-object host 4.4.4.4
I don't know exactly what structure you want, but what you have there is simply invalid.

iterate over the hostname stored in var_files

I have two type of server host names added in the ansible main.yml var file:
main.yml file:
foo_server1: 10.10.1.1
foo_server2: 10.10.1.2
bar_server1: 192.168.1.3
bar_server2: 192.168.1.4
bar_server3: 192.168.1.5
I am having an ansible playbook which essentially runs on foo_server1 and initializes/formats all other servers in the list one at a time - starting with foo_server2 then bar_server1, bar_server2 and so on...
---
- name: Reading variables from var files
hosts: localhost
connection: local
vars_files:
- main.yml
tasks:
- name: Initialize foo server2
command: initialize --host1 {{foo_server1}} to --host2 {{foo_server2}}
- name: Initialize bar server1
command: initialize --host1 {{foo_server1}} to --host2 {{bar_server1}}
- name: Initialize bar server2
command: initialize --host1 {{foo_server1}} to --host2 {{bar_server2}}
- name: Initialize bar server3
command: initialize --host1 {{foo_server1}} to --host2 {{bar_server3}}
I dont want to add multiple lines in the playbook for each server rather wants to loop over the host names from the variable file. I am not sure how i would get this done..i am trying to loop over the hostname.. tried something below but no luck as i am getting undefined variable name..
---
server_list:
foo_server1: 10.10.1.1
foo_server2: 10.10.1.2
bar_server1: 192.168.1.3
bar_server2: 192.168.1.4
bar_server3: 192.168.1.5
Ansible playbook...
---
- hosts: localhost
gather_facts: no
vars_files:
- input.yml
tasks:
- name: Enable replication
local_action: shell initialize --host1 {{item.foo_server1}} --host2 {{item.foo_server2}}
with_items:
- "{{ server_list }}"
Can some one please suggest how can i run the same command on multiple servers. Would appreciate any help offered..
Here is an example for you:
---
- hosts: localhost
gather_facts: no
vars:
servers:
foo_server1: 10.10.1.1
foo_server2: 10.10.1.2
bar_server1: 192.168.1.3
bar_server2: 192.168.1.4
bar_server3: 192.168.1.5
tasks:
- debug:
msg: shell initialize --host1 {{ servers.foo_server1 }} --host2 {{ item.value }}
when: item.key != 'foo_server1'
with_dict: "{{ servers }}"

Resources