How can I use default with variable in Ansible? - ansible

I know that I can use a simple hardcoded string in default but I am trying to do this:
myvar: "{{ lookup('env','var1') | default("{{var2}}",true) }}"
But it adds that as a string instead of evaluating it.

Once you opened a Jinja2 expression with {{ you don't need to open it again (especially quoted) and you can refer to the variables by their names:
myvar: "{{ lookup('env','var1') | default(var2, true) }}"

Related

regex_replace by a var content in jinja template

I have a jinja template and i want to replace a string by the content of a variable
exemple :
ansible_hostname: 'host-to'
item.suffixe: 'cool'
the result will be : host-cool-to
I did this :
{{ ansible_hostname | regex_replace('-to', '-{{ item.suffixe }}-to') }}
of course the '-{{ item.suffixe }}-to' was not interpreted and the result is :
host-{{ item.suffixe }}-to
Is it possible to use a variable in regex_replace ? How ? in the ansible exemple they don't show anythings like this
Q: "Is it possible to use a variable in regex_replace ?"
A: Yes. It's possible. It's easier to put the parameters into variables. For example
- debug:
msg: "{{ hostname | regex_replace(regex, replace) }}"
vars:
hostname: host-to
suffix: cool
regex: '-to'
replace: '-{{ suffix }}-to'
gives
msg: host-cool-to

Ansible - How to Escape Nested Jinja within Filter

I want to use nested jinja expression within filter, but am failing it to do.
I have a variable file that looks like this:
NAME: "test"
VAR: ["a","b","c-test","d", "t-test"]
and now, I want to use ansible filters in the same variable file to extract a specific string from the VAR list.
I have tried:
NAME: "test"
VAR: ["a","b","c-test","d","test-t"]
testc: "{{ VAR | select('match', 'c-{{ NAME }}') | list }}"
testt: "{{ VAR | select('match', '{{ NAME }}-t') | list }}"
and
NAME: "test"
VAR: ["a","b","c-test","d","test-t"]
testc: "{{ VAR | select('match', 'c-\'{{ NAME }}\'') | list }}"
testt: "{{ VAR | select('match', '{{ NAME }}-t') | list }}"
with no success.
I have the same issue to use nested Jinja within filters other the 'select'.
How do you use or escape the nested jinja expression within ansible filter?
You can't nest double curly brackets. Names inside double curly brackets are evaluated as variables already so you don't need to enclose them in another pair of double curly brackets to evaluate them. You can simply use the concatenation operator ~ to concatenate the string literal 'c-' with the variable NAME directly:
test: "{{ VAR | select('match', 'c-' ~ NAME) | list }}"
test: "{{ VAR | select('match', NAME ~ '-t') | list }}"

What does conditional "when: var | d()" mean in Ansible 2.5

I am unable to source from Ansible documents a clear meaning of a conditional such as when: var | d(). Is someone able give a clear explanation?
E.g. Below works whether inputing extra-var value from cli or defaulting to local ENV variable value:
vars:
my_var: "{{ e_var | default(ansible_env.USER | default(False,true)) }}"
tasks:
- name: Conditional check
debug:
msg: "{{ my_var }}"
when: my_var | d()
But this fails:
vars:
my_var: "{{ e_var | default(ansible_env.USER | default(false,true)) }}"
tasks:
- name: Conditional check
debug:
msg: "{{ my_var }}"
when: my_var
What is when: my_var | d() exactly doing? How how does it interplay with the | default(false,true) part in the variable declaration?
d is an alias to the default filter. It is a Jinja2 filter, so head for the Jinja2 docs. They work the same:
default(value, default_value=u'', boolean=False)
[ ]
Aliases: d
Regarding the problem you are facing, it is because Ansible processes a condition consisting of only a variable name differently from a more complex expression (which is passed directly to Jinja2/Python) (the actual code starts here):
If the my_var variable has a value of user01, the conditional will try to find a value of user01 variable and fail because it doesn't exist.
If you just add a logical conjunction (which in common sense is redundant), Ansible will process the whole expression differently and it will work:
when: my_var and true
In your case using another default filter in the expression is also redundant, but it prevents Ansible from trying to resolve a "nested" variable value.

Variable interpolation with ansible filters and environment variables

I've got a role that bootstraps a user's OSX workstation. In it, I need to ensure that xdg variables are set properly, using the following precedence:
defaults/main.yml
user's environment variable
any other value (set in vars, host_vars, command line, etc)
I've tried a couple different approaches, but the basic problem I'm having is that I can't nest variable interpolation, so approach one (and all the others I could think of to try) in defaults/main.yml have failed:
# if the env var doesn't exist, it'll set it to an empty string, doesn't look
# like there is a way to specify the 'default' string that should be used
# xdg_cache_home: "{{ lookup('env','XDG_CACHE_HOME') }}"
# this is just bad syntax, can't have nested '{{ }}'
# xdg_config_home: "{{ lookup('env','XDG_CACHE_HOME') | default("{{ home }}/.cache", true) }}"
# this simply fails to define the variable, i'm not sure why
# xdg_cache_home: "{{ default( lookup('env','XDG_CACHE_HOME'), join(lookup('env', 'HOME', '.cache'))) }}"
The next approach I tried was to just set the defaults using the first method (empty string if empty) and then inspect and set a default value in the roles/myrole/tasks/main.yml:
- name: set default xdg_cache_home
set_fact: xdg_cache_home="{{ join(lookup('env', 'HOME', '/.cache')) }}"
when: "{{ xdg_cache_home }}" == ""
But I can't get that to work either. Any suggestions or advice?
Found the answer in the jinja documentation - using the jinja string concatenation operator (~):
xdg_cache_home: "{{ lookup('env', 'XDG_CACHE_HOME') | default(ansible_user_dir ~ '/.cache', true) }}"
xdg_config_home: "{{ lookup('env', 'XDG_CONFIG_HOME') | default(ansible_user_dir ~ '/.config', true) }}"
xdg_data_home: "{{ lookup('env', 'XDG_DATA_HOME') | default(ansible_user_dir ~ '/.local/share', true) }}"

How can I use jinja2 to join with quotes in Ansible?

I have an ansible list value:
hosts = ["site1", "site2", "site3"]
if I try this:
hosts | join(", ")
I get:
site1, site2, site3
But I want to get:
"site1", "site2", "site3"
Why not simply join it with the quotes?
"{{ hosts | join('", "') }}"
Ansible has a to_json, to_nice_json, or a to_yaml in it's filters:
{{ some_variable | to_json }}
{{ some_variable | to_yaml }}
Useful if you are outputting a JSON/YAML or even (it's a bit cheeky, but JSON mostly works) a python config file (ie Django settings).
For reference: https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#filters-for-formatting-data
The previous answer leaves "" if the list is empty. There is another approach that may be more robust, e.g. for assigning the joined list as a string to a different variable (example with single quotes):
{{ hosts | map("regex_replace","(.+)","\'\\1\'") | join(',')}}
From a json file file_name.json array like this
"hosts": [
"site1",
"site2",
"site3"
]
Set_fact from a json file
- name: Set variables from parameters file
set_fact:
vars_from_json: "{{ lookup('file', 'file_name.json') | from_json }}"
Use join with double quote and comma, and wrap all around in double quote
- name: Create host list
set_fact:
host_list: "{{ '\"' + vars_from_json.hosts | join('\"'', ''\"') + '\"' }}"

Resources