Reputation: 6337
I want to define a dictionary variable that various host groups can add their own keys to in group_vars (not using set_fact
). E.g. something like this:
group_vars\ftp_servers.yml:
important_ports:
ftp: 21
group_vars\web_servers.yml:
important_ports:
http: 80
so that when run on a server with both of these roles the dictionary is combined, i.e. important_ports
=
{
ftp: 21,
http: 80
}
This is exactly what hash_behaviour = merge
does, but it's deprecated and will be removed in Ansible 2.13. How do I achieve the same thing without that?
The only solution I've seen recommended is to use the combine
filter:
set_fact:
important_ports: "{{ important_ports | combine({ http: 80 }) }}"
This works in a set_fact
task, but fails in group_vars with "recursive loop detected in template string: {{ important_ports | combine({ http: 80 }) }}"
I even tried initialising the variable to empty dictionary (important_ports: {}
) in group_vars/all, which is supposed to be evaluated before other group_vars, but it still gives the same error.
Upvotes: 8
Views: 2294
Reputation: 44809
A (not so clean...) possible solution to this specific problem. This is based on convention where you use the group name in the var name for specific group ports.
Note that if you redefine the same port name with a different value, the latest loaded group will win.
Given the following all-in-one inventory placed in inventories/mergegroups/hosts.yml
---
all:
vars:
ansible_connection: local
important_ports: >-
{%- set result={} -%}
{%- for group in groups -%}
{{ result.update(lookup('vars', group + '_important_ports', default={})) }}
{%- endfor -%}
{{ result }}
ftp_servers:
vars:
ftp_servers_important_ports:
ftp: 21
hosts:
a:
b:
web_servers:
vars:
web_servers_important_ports:
http: 80
hosts:
a:
other_group:
vars:
other_group_important_ports:
mysql: 3306
hosts:
a:
b:
no_port_group:
# as you can see no port definition here.
hosts:
a:
b:
c:
We get the following results for the 3 different host:
$ ansible -i inventories/mergegroups/ a -m debug -a msg="{{ important_ports }}"
a | SUCCESS => {
"msg": {
"ftp": 21,
"http": 80,
"mysql": 3306
}
}
$ ansible -i inventories/mergegroups/ b -m debug -a msg="{{ important_ports }}"
b | SUCCESS => {
"msg": {
"ftp": 21,
"mysql": 3306
}
}
$ ansible -i inventories/mergegroups/ c -m debug -a msg="{{ important_ports }}"
c | SUCCESS => {
"msg": {}
}
Upvotes: 6