[I posted this question earlier but it had a number of mistakes so I took it down. My sincere apologies if I wasted anyone's time.]
I have a dictionary in a config file:
foo:
key1: value1
key2: value2
key3: value3
# …
When I initiate the playbook I add the following string variables at the command line:
--extra-vars "k1=key1 k2=key2"
If I want to access a particular dictionary value during a play (assuming I've included the config file in my 'vars_files'), I can do so simply like this:
- debug:
var="foo.{{ k1 }}"
# => foo.key1: value1
Let's say the dictionary name is changeable so I want that to be a variable as well. I can add an additional command line variable:
--extra-vars "k1=key1 k2=key2 dict_name=foo"
I try to access value1
again but this time, it appears that Ansible parses the syntax as a literal string rather than a reference to a variable in the config file. For example:
- set_fact:
dict_value: "{{ dictname ~ '.' ~ k1 }}"
or
- set_fact:
dict_value: "{{ dictname ~ k1 }}"
[For the second case, I add the '.' to the command line definition, e.g. -e "dict_name=foo."
]
I now get a literal result:
- debug:
var=dict_value
# => dict_value: foo.key1
as opposed to => foo.key1: value1
when I had the dictionary name hardwired as a string. "foo.{{ k1 }}"
, as per above, is recognized as requesting access to the dictionary variable in the config file. When I try to make foo
a variable as well, it becomes a literal string.
To summarize then I want to access a dictionary value with a composite created from variables for both the dictionary name and the key (and somehow the '.' needs to be accommodated:
"{{ dict_name }}" appended to '.' appended to "{{ key_name }}" = "{{ composite_variable_to_lookup_value}}"
.
First of all, your original intention is actually valid (note that I've corrected your syntax). You just need to remember that var
parameter of the debug
module holds the name of the variable, whereas when you define a variable using set_fact
module, it's a template that could be rendered to a string. So the result is totally expected. Since debug
accepts either a var
name or a msg
message template, the snippet below illustrates what's happening in the most straightforward way:
---
- name: Test
hosts: localhost
connection: local
gather_facts: false
vars:
foo:
key1: value1
key2: value2
key2: value3
tasks:
- name: Show the variable value
debug:
var: "{{ dict_name }}.{{ k1 }}"
# => foo.key1: value1
- name: Show the literal string
debug:
msg: "{{ dict_name }}.{{ k1 }}"
# => msg: foo.key1
If you want not only to display the value, but to set it as another variable, you can use vars
lookup:
---
- name: Test
hosts: localhost
connection: local
gather_facts: false
vars:
foo:
key1: value1
key2: value2
key2: value3
dict_name: foo
key_name: key1
tasks:
- name: Set the value of the key as another variable
set_fact:
composite_variable_to_lookup_value:
"{{ lookup('vars', dict_name)[key_name] }}"
- name: Show the results
debug:
var: composite_variable_to_lookup_value
# => composite_variable_to_lookup_value: foo.key1 = value1
Note that you will not be able to get it neither as {{ hostvars[inventory_hostname][dict_name][key_name] }}
(see https://stackoverflow.com/a/48362348/16417367) nor as {{ lookup('vars', dict_name ~ '.' ~ key_name }}
(vars
lookup only returns top level variable names).