Reputation: 351
I have an inventory like:
all:
children:
server_group1:
hosts:
host1:
server_group2:
children:
app1:
hosts:
host2:
host3:
app2:
hosts:
host4:
host5:
server_group3:
...
I have organized my server variables like so:
group_vars/server_group2/app1
app1:
name1: value1
name2: value2
group_vars/server_group2/app2
app2:
name1: value11
name2: value21
I am trying to name my dict after the group (thus making them unique) and access it in my playbook:
hosts: server_group2
tasks:
- name: check file
local_action: stat path=path/to/test/{{hostvars[0].name1}}
register: payld_txt
- name: conditional transfer
copy:
src: path/to/test/{{hostvars[0].name1}}
dest: /svr/path/{{hostvars[0].name2}}
when: payld_txt.stat.exists
I end up with this error:
The task includes an option with an undefined variable. The error was: 'name1' is undefined
Where am I going wrong?
Upvotes: 2
Views: 9052
Reputation: 68189
Given the inventory (and the group_vars)shell> ansible-inventory -i hosts --list --yaml
all:
children:
server_group1:
hosts:
host1: {}
server_group2:
children:
app1:
hosts:
host2:
app1: &id001
name1: value1
name2: value2
app2: &id002
name1: value11
name2: value22
host3:
app1: *id001
app2: *id002
app2:
hosts:
host4:
app1: *id001
app2: *id002
host5:
app1: *id001
app2: *id002
ungrouped: {}
'hostvars[0].name1' The error was: 'name1' is undefined
Q: "Where am I going wrong?"
A: name1
is an attribute of the dictionary app1
or app2
. It must be referenced either app1.name1
or app2.name1
. In addition to this, hostvars
is a dictionary, not an array. hostvars[0]
does not exist. An attribute in a dictionary must be referenced by a key. For example,
my_keys: "{{ hostvars.keys() }}"
gives
my_keys: [host1, host2, host3, host4, host5]
You can use the keys in a loop. For example,
- debug:
msg: "{{ hostvars[item].app1.name1 }}"
loop: "{{ my_keys }}"
when: item in groups.app1
- debug:
msg: "{{ hostvars[item].app2.name1 }}"
loop: "{{ my_keys }}"
when: item in groups.app2
gives
TASK [debug] *********************************************************************************
skipping: [host2] => (item=host1)
ok: [host2] => (item=host2) =>
msg: value1
ok: [host2] => (item=host3) =>
msg: value1
skipping: [host2] => (item=host4)
skipping: [host2] => (item=host5)
TASK [debug] *********************************************************************************
skipping: [host2] => (item=host1)
skipping: [host2] => (item=host2)
skipping: [host2] => (item=host3)
ok: [host2] => (item=host4) =>
msg: value11
ok: [host2] => (item=host5) =>
msg: value11
Optionally use json_query to create the list of the keys
my_keys: "{{ hostvars|dict2items|json_query('[].key') }}"
The simplified version of the debug tasks
- debug:
msg: "{{ hostvars[inventory_hostname].app1.name1 }}"
when: inventory_hostname in groups.app1
- debug:
msg: "{{ hostvars[inventory_hostname].app2.name1 }}"
when: inventory_hostname in groups.app2
gives
TASK [debug] *********************************************************************************
ok: [host2] =>
msg: value1
skipping: [host4]
ok: [host3] =>
msg: value1
skipping: [host5]
TASK [debug] *********************************************************************************
skipping: [host2]
skipping: [host3]
ok: [host4] =>
msg: value11
ok: [host5] =>
msg: value11
In fact, addressing hostvars[inventory_hostname]
is not necessary. The simplified tasks below give the same result
- debug:
msg: "{{ app1.name1 }}"
when: inventory_hostname in groups.app1
- debug:
msg: "{{ app2.name1 }}"
when: inventory_hostname in groups.app2
Example of a complete playbook for testing
- hosts: server_group2
vars:
my_keys: "{{ hostvars.keys() }}"
tasks:
- block:
- debug:
var: hostvars[0]
- debug:
var: my_keys|to_yaml
- debug:
msg: "{{ hostvars[item].app1.name1 }}"
loop: "{{ my_keys }}"
when: item in groups.app1
- debug:
msg: "{{ hostvars[item].app2.name1 }}"
loop: "{{ my_keys }}"
when: item in groups.app2
run_once: true
- debug:
msg: "{{ hostvars[inventory_hostname].app1.name1 }}"
when: inventory_hostname in groups.app1
- debug:
msg: "{{ hostvars[inventory_hostname].app2.name1 }}"
when: inventory_hostname in groups.app2
- debug:
msg: "{{ app1.name1 }}"
when: inventory_hostname in groups.app1
- debug:
msg: "{{ app2.name1 }}"
when: inventory_hostname in groups.app2
Upvotes: 3
Reputation: 44799
Before you go any further, you need to fix your inventory which does not respect ansible's structure for yaml sources. A simple command as the following can give you some hints:
$ ansible -i inventories/test.yml all --list-hosts
[WARNING]: Skipping unexpected key (server_group1) in group (all), only "vars", "children" and "hosts" are valid
[WARNING]: Skipping unexpected key (server_group2) in group (all), only "vars", "children" and "hosts" are valid
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
hosts (0):
The correct syntax is:
---
all:
children:
server_group1:
hosts:
host1:
server_group2:
children:
app1:
hosts:
host2:
host3:
app2:
hosts:
host4:
host5:
Which now gives:
$ ansible -i inventories/test.yml all --list-hosts
hosts (5):
host1
host2
host3
host4
host5
Upvotes: 6