How to create array template in Ansible? - ansible

I have a template file config.j2:
{% for host in groups['dbs'] %}
ips= {{ hostvars[host].ansible_default_ipv4.address }}
{% endfor %}
My output is:
ips= 192.168.231.91
ips= 192.168.231.92
ips= 192.168.231.93
I want save in array variable like this:
ips=['192.168.231.91','192.168.231.92','192.168.231.93']
How can do this?

Solution
ips=[{{ groups['dbs'] | map("regex_replace", "(.*)", "'\\1'") | join(",") }}]
Explanation
Strings ips[ and ] are printed directly in the template;
The Jinja2 expression processes the groups['dbs'] list:
map filter applies a filter (regex_replace) to individual elements of the list;
regex_replace filter surrounds each list element (string) in single quotes;
join filter converts the resulting list to comma-delimited string in the output.

Related

Access yaml key name with liquid

Is it possible to access the key names along with key values from a yaml file using liquid?
For example from a .yaml file that looks like this:
- type: a
id: b
author: c
website: d
Have liquid code that looks something like this:
{%- for item in YAMLFILE -%}
{{ item.??? }} = {{ item.??? }}
{%- endfor -%}
with the following output:
type = a
id = b
author = c
website = d
I am trying to do this this way because my yaml file has different key names along with values and it would be a pain having to embed a bunch of different if else statements to account for every possible key name.
Thank you all so much!
Assuming your yaml file is in _data/test, you can use:
{% for list in site.data.test %}
{% for item in list %}
{{ item[0] }} = {{ item[1] }}
{% endfor %}
{% endfor %}
item[0] is the key and item[1] is the value. It will work with different number of keys and names in each list.
Also be aware that four spaces in Markdown formats the content of the second for loop as a code block. Simply do not indent if putting this code in a Markdown file.

How to add a column in a line in Ansible Jinja2 template using for loop?

I want to update a line in Jinja2 template as follows
Let's say, I have a variable x equal to 4, then, I want a row/line as:
abc 1 2 3
in my template:
{% for val in range(1, x | int) %}
abc {{ val }} {{ val+1 }} .......
{% endfor %}
If I use for loop it adds a new line, Is their way I can achieve aforementioned requirement?
Here you are:
abc{% for val in range(1, x|int) %} {{ val }}{% endfor %}
Jinja2 is a templating engine. If you put a newline character in the source template, it will be present in the output.
You can either write everything in one line, or use whitespace control to remove unnecessary space.

How can one generate a dict in Jinja/Ansible as a var?

I need to dynamically generate a dict and assign it to an Ansible var so that the same data is available to every host and does not need to be regenerated on each one. This will be looped over by a task and template. It is possible to build lists by nesting Jinja in a var definition like so:
var_list: >
[
{% set data = [] %}
{% for host in groups['all'] %}
{{ data.append(host) }}
{% endfor %}
{{ data }}
]
However, I am not able to do so with dicts:
var_dict: >
{
{% set data = dict() %}
{% for host in groups['all'] %}
{{ data | combine({host: []}) }}
{% endfor %}
{{ data }}
}
This results in a giant, garbled string: {u'host.subdom.dom.tld': []} {}...
What I am expecting is a var set to a true dict object that can have its components referenced individually (like {{ var_dict.host1[0] }}), with a structure similar to the following JSON:
{
"host1": [],
"host2": []
}
Is there a way to cause this to expand into a proper dict when assigned to the variable? Or is there perhaps another way to generate a dict from a loop without that awful set_fact hackery?
Either of your templates is broken (the first one produces nested lists, the second one prints data in loop with this expression {{ data | combine({host: []}) }}, the value of data remains empty until the end).
Jinja2 is a templating engine, you don't really need to create data structures to print them later. You can form your output directly.
For the list:
var_list: >
[ {% for host in groups['all'] %}'{{ host }}',{% endfor %} ]
For the dictionary:
var_dict: >
{ {% for host in groups['all'] %}'{{ host }}': [],{% endfor %} }
As you expect the values to be interpreted by Ansible, you don't need to pay attention to the trailing coma, otherwise there is loop.last.

Ansible, how to use jinja2 template to access specific value in a list

New to Jinja2 templating
I can iterate over a list using a for conditional which is simple enough but i am trying to do the below...
I have a variable that contains a un-ordered lists of values which are group names. I would like to access the group_names lists/variable and check if a specific item in this list exists and then perform an action if that value is found.
group_names: [ "groupname1", "groupname2", "groupname3", "groupname4"]
Sounds like you want:
{% if "somevalue" in group_names %}
whatever stuff
{% endif %}
http://jinja.pocoo.org/docs/2.9/templates/

How can I use Jinja2 to generate an index-like list?

In an index, references are listed alphabetically and grouped by letter. Also, instead of a simple alphabetical sort, leading articles and punctuation are removed before sorting. The result would look like this:
A
Abba
The Archer
Away From Here
B
"Bangkok" Mike
Bullets
I'm using the Pelican static site generator, which uses Jinja2 in its templates, and I'd like to create an index like this of TV shows that I've blogged about on my site.
TV show names are listed in a metadata field {{ article.showname }} (only one show per post, so only one show in the metadata field) and so are easily retrieved. But stripping the leading article/punctuation, grouping by first letter and inserting the correct letter of the alphabet is more than I know how to do.
Possible steps I could take
I could strip the leading article/punctuation and create another metadata field with the show name that's ready to be sorted, called, say, {{ article.shownamesort }}. For that matter, if there's not an easy way to group the names by their first letter, I could create a metadata field with the show's first (sortable) letter, {{ article.shownameletter }}.
For each letter, I could create a loop that begins by grabbing that letter's posts:
{% if article.shownameletter == "A" %}
Once that's done, I don't know how to sort the text from one metadata field based on the text of a different metadata field. That is, I don't know how to print the {{ article.showname }} list that's sorted by the {{ article.shownamesort }} list. Can this be done in Jinja2? For the record, if there's a solution that takes a completely different approach, I'd be very happy with it, including if it required different/more metadata fields.
I did something like that on the tags and categories pages. It iterates over all the characters and then prints the results
Iterate over the letters:
{% for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"|list %}
...
{% endfor %}
Comparison for show or not show the tag:
{% if char == tag|upper|truncate(1, True, end='') %}
...
{% endif %}
Full example:
{% for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"|list %}
<h2>{{char}}</h2>
{% for tag, articles in tags|sort %}
{% if char == tag|upper|truncate(1, True, end='') %}
<dt>{{ tag }}</dt>
{% for article in articles|sort %}
<dd>{{ article.title }}</dd>
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}

Resources