How can I use jinja2 to join with quotes in Ansible? - 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('\"'', ''\"') + '\"' }}"

Related

How to replace several characters in an Ansible variable's value?

I have a variable called joomlaversion which I get using json_query. The value of joomlaversion is 4.0.2 but I am trying to swap the dots with dashes so it becomes 4-0-2
How can I substitute dots for dashes in this ansible variable value?
I am using Ansible 2.9.6
Here is what I have tried.
---
- name: Download JSON content
uri:
url: https://api.github.com/repos/joomla/joomla-cms/releases
return_content: yes
register: jsoncontent
- name: Get latest version of Joomla from the tag using contains
set_fact:
joomlaversion: "{{ jsoncontent.json | to_json | from_json |json_query(jmesquery)|json_query(jmesquery2) }}"
vars:
jmesquery: "[? (draft==`false` && prerelease==`false`)]"
jmesquery2: "[?name.contains(#, 'Joomla! 4')].tag_name|[0]"
- name: Replace the dots with dashes in Joomla version
set_fact:
joomlaversion2: "{{ joomlaversion }} | replace('.', '-')"
#joomlaversion2: '{{ joomlaversion | regex_findall("\\."),("\\-") }}'
Rather than changing the dots to dashes it is appending | replace('.','-') on to the variable value, so it becomes "4.0.2 | replace ('.', '-')"
Perhaps I could use filters as is mentioned at https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#manipulating-strings
If I could split it using split(".") then join it again afterwards perhaps?
If I could split it using split(".") then join it again afterwards perhaps?
You could very well do that!
E.g.:
- set_fact:
joomlaversion2: "{{ joomlaversion.split('.') | join('-') }}"
Or, use regex_replace, which will find a pattern and replace it with hyphen.
# since . matches any char, we need to escape it with \
- set_fact:
joomlaversion2: "{{ joomlaversion | regex_replace('\.', '-') }}"
you have to add {{ }} and escape . with \:
- set_fact:
joomlaversion: "4.0.2"
- set_fact:
joomlaversion2: "{{ joomlaversion | regex_replace('\\.', '-') }}"
- debug:
var: joomlaversion2
result:
ok: [localhost] => {
"joomlaversion2": "4-0-2"
}

Using Jinja filter with two variables in Ansible

I am trying to get a random host in a group that contains a list of IP's. We are running into some issues as our group name uses a variable, but the line is already in {{'s due to the Jinja random call.
- hosts: "{{ {{ env }}_as_group | random }}"
ERROR! template error while templating string: expected token 'end of print statement', got '{'. String: {{ {{ env }}_as_group | random }}
The env variable is passed into the playbook on execution with ansible-playbook "-e env=stage" myplaybook.yml
Looking around online, most people solve this with vars[env], however that doesnt seem to quite work for us -
- hosts: "{{ vars[env]_as_group | random }}"
ERROR! template error while templating string: expected token 'end of print statement', got '_as_group'. String: {{ tag_aws_autoscaling_groupName_[ env ]_as_group | random }}
If I make it - hosts: "{{ stage_as_group | random }}", it works as expected.
How can I set the host to pull a random value in the group {{ env }}_as_group?
In Ansible, moustache should not be stacked.
So you should use the proper Jinja concatenation operator: ~.
Ending with:
- hosts: "{{ vars[env ~ '_as_group'] | random }}"
This said it is not totally clear to me what stage_as_group really is: is it a list or a hosts group?
If this is a group in you inventory, this won't work because random works on a sequence, and a host group is a string, not a sequence.
For that use case, you probably want this instead:
- hosts: "{{ groups[env ~ '_as_group'] | random }}"

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 }}"

How can I use default with variable in 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) }}"

How to concatenate string in YAML?

I am writing a playbook in which I need to execute mysql query and pass
output in json format. playbook code working fine just I want facing error in string concatenate part. If I am passing sample json string it is working fine.
- name: Execute php script with json parameter
command: php -f /path/to/php/test.php "{'colors':{'red','blue','yellow'}}"
register: php_output
output.stdout_lines is variable already set in my playbook which contains output in {'red','blue','yellow'} format.
- name: Execute php script with json parameter
command: php -f /path/to/php/test.php '{"stdout_lines": {{output.stdout_lines}} }'
register: php_output
So how can I concatenate output.stdout_lines variable in '{"stdout_lines": {{output.stdout_lines}} }' ? any suggestions
stdout_lines was created for convenience. Back in the day we only had stdout. Which is what you want, I think:
command: php -f /path/to/php/test.php '{"stdout_lines": {{output.stdout}} }'
and if you want to really concat yourself, say because you have your own list of strings then you can use the Jinja2 built-in filter join:
- hosts: localhost
gather_facts: False
tags: so9
vars:
- str_list: ['Hello', 'world', '!', ]
tasks:
- debug: msg="orig list={{ str_list }}"
- debug: msg="concated = {{ str_list | join(' ') }}"
- set_fact: concated_str="{{ str_list | join(' ') }}"
- debug: msg="assigned to a variable concated_str = {{ concated_str }}"
Try like this.
vars:
- img_path: "/var/lib/libvirt/images/{{ instance_name }}-disk2.img"
Where instance name is a another variable
This will do
- name: Generate JSON output based on template
template: src=colors.json.j2 dest=/tmp/colors.json
with_items: colors
It will generate a file like
{'colors':
{
'blue',
'red',
'green',
}
}
The to_json filter is what you want.
Ansible doesn't store variables as JSON strings, it stores them as Python objects. When you're debugging e.g. with -vvv, Ansible displays these Python objects as JSON strings, but that's for your convenience.
To produce the desired command:
- name: Execute php script with json parameter
vars:
# define my desired object
my_object:
colors: "{{ output.stdout_lines }}"
# my_object contains a dict with a single key
# "colors" who's value is the list contained
# in output.stdoutlines
command: "php -f /path/to/php/test.php {{ my_object | to_json | quote }}"
register: php_output
to_json takes the object stored in my_object and outputs a JSON string.
quote automatically handles any shell quoting that might be required for the JSON string. e.g. If my JSON string contains double-quotes, quote will wrap the whole JSON string in single-quotes.

Resources