AnsibleUndefinedVariable: No variable found with this name: region1a"} - ansible

I want to get the output of information after comparing whether the region is the capital?
Help me figure out how to use "lookup" correctly?
{% if capital == lookup('vars', item) %} yes {% else %} no {% endif %}
or
{% if capital.action == {{ item }} %} yes {% else %} no {% endif %}
I get the following error
failed: [localhost] (item=region1a) => {"ansible_loop_var": "item", "changed": false, "item": "region1a", "msg": AnsibleError: template error while templating string: expected token ':', got '}'
here {{ item }} is a variable = region1a
I have these variables
vars:
AllCountry:
- name1
- name2
name1:
- region1a
- region1b
name2:
- region2a
- region2b
capital:
- region1a
- region2a
what am I wrong about?

It seems to me like this is what you are looking to achieve:
{% if item in capital %} yes {% else %} no {% endif %}
But that is really not foolproof. Imagine you have two regions named the same in two countries and one is the capital of one of the countries when the other is not the capital of the other one, how would you do it here?
I would really go with a more tied kind of dictionary like:
countries:
country1:
regions:
- region1
- region2
- region3
capital: region1
country2:
regions:
- region4
- region5
capital: region5
But without your actual use case and what you are trying to build with all this, this is hard to advise on the right type of data structure to construct.

Related

Ansible template from jinja2

Who can tell you how to implement the output of all regions in the name1 group when entering a template named region1a, and when entering a template named region2b, output all regions from the name2 group
I implement it like this:
there is a task that starts template generation:
vars:
AllCountry:
- name1
- name2
name1:
- region1a
- region1b
name2:
- region2a
- region2b
tasks:
- name:
template:
src: "regions.j2"
dest: "{{ item }}.conf"
loop:
- region1a
- region2b
---regions.j2---
regions [{%for count in name1%} "my country = {{count}}", {%end for %}]
this gives the desired output, but only because it is explicitly specified for which name (1 or 2) to output
regions "my country = region1a", "my country = region1b"
For each value specified in the loop, a template configuration file must be generated.
When you specify values in loop region1a and region1b template should generate only one row in the configuration file for region1a.conf
regions "my country = region1a", "my country = region1b"
for region1b generate only one row in the configuration file for region1b.conf
regions "my country = region1a", "my country = region1b"
User β.εηοιτ.βε a more optimal structure was proposed. If convenient, you can use it.
vars:
countries:
country1:
regions:
- region1
- region2
- region3
capital: region1
country2:
regions:
- region4
- region5
capital: region5
Thank you all for your help. Still, I managed to figure it out myself.
Here is the final solution:
{% for country in AllCountry %}
{% if item in lookup('vars', country) %}{% for count in lookup('vars', country) %} "My country = {{ count }}"{% if not loop.last %},{% endif %}{% endfor %}{% endif %}{% endfor %}

How to iterate through three lists in parallel in Yaml file

Need 3 variables to change on every iteration.
ver = [1,2,3]
tes = [a,b,c]
bet = [1a.2b.3c]
{% for v,t,b in ver,tes,bet %}
{{ v }} {{ t }} {{ b}}
{% endfor %}
o/p:
1 a 1a
2 b 2b
3 c 3c
I ran the same, got a very messy o/p. There should be only 3 iterations printing 3 variables in each iteration.
How can i perform the above operations using the for loop ? In the above case
Any suggestions on where I'm going wrong, would help Thanks !
You can use the following code:
{% for i in range([ver|count, tes|count, bet|count]|min) %}
{{ ver[i] }} {{ tes[i] }} {{ bet[i] }}
{% endfor %}
It uses only built in filters and functions:
count
min (to handle sequences with different length, similarly as zip in python)
range
Entire code in python:
import jinja2
ver = [1, 2, 3, 4]
tes = ['a', 'b', 'c']
bet = ['1a', '2b', '3c']
t = jinja2.Template('''{% for i in range([ver|count, tes|count, bet|count]|min) %}
{{ ver[i] }} {{ tes[i] }} {{ bet[i] }}
{% endfor %}
''')
print(t.render(ver=ver, tes=tes, bet=bet))
It looks like you need something that behaves like Python's zip function. Here's one option, in which we simply expose zip to the Jinja environment:
>>> import jinja2
>>> ver=[1,2,3]
>>> tes=['a','b','c']
>>> bet=['1a','2b','3c']
>>> t=jinja2.Template('''{% for v,t,b in zip(ver,tes,bet) %}
... {{ v }} {{ t }} {{ b}}
... {% endfor %}
... ''')
>>> t.environment.globals.update(zip=zip)
>>> print(t.render(ver=ver,tes=tes,bet=bet))
1 2 3
a b c
1a 2b 3c
>>>

Convert lines of file to dictionary in ansible

Have a file that contains line in a format like below:
category1 name=item1
category1 attributes=attr1, attr2
category1 name=item2
category1 attributes=attr1, attr2, attr3
category2 name=item1
category2 attributes=attr1
Looking to get a dictionary in ansible like below:
- category1:
- name: item1
attributes: [attr1, attr2]
- name: item2
attributes: [attr1, attr2, attr3]
- category2:
- name: item1
attributes: [attr1]
I was trying with jinja2 and below is what I get as of now. Problem is that the code is getting complicated after every step. Is there any way using filter or other methods that could produce the expected result with more readable code?
Code:
- set_fact:
converted_data: >-
{%- set res = dict() -%}
{%- for line in content.stdout_lines -%}
{%- set key_val = line.split(' ', 1) -%}
{%- set second_level = [] -%}
{%- if res[key_val[0]] is defined -%}
{%- set second_level = res[key_val[0]] -%}
{%- endif -%}
{%- set val_split = key_val[1].split('=') -%}
{%- set _ = second_level.append( dict({ val_split[0]: (val_split[1].split(',') | map('trim') | list) }) ) -%}
{%- set _ = res.update({key_val[0]: second_level}) -%}
{%- endfor -%}
{{ res }}
Produces:
category1:
- name:
- item1
- attributes:
- attr1
- attr2
- name:
- item2
- attributes:
- attr1
- attr2
- attr3
category2:
- name:
- item1
- attributes:
- attr1
I would strongly advise you to stop writing this in Jinja and switch to Python. It can be a lookup plugin, a module, or just a very simple script to read from stdin and output a json.
Jinja is not designed for algorithms. Whilst you can implement any efficiently computable function using the turing-complete Jinja2 template language, it's going to be very very painful for you and for anyone else reading your code.
If you do it in Python, you can add few tests (just define few 'test_case1', 'test_case2' functions inside your script and use pytest to run them). Without tests you never will get a stable code for all cases (like if some line is missing, or there is a reordering, or duplicates, etc).

Jinja add automatic indentation

In ansible I use a template written in jinja2,
I have an inner for loop which automatically adds space to my config file, which i do not want to.
stick store-response payload_lv(43,1) if serverhello
option ssl-hello-chk
{% set count = 1 %}
{% for ip in sv.ips %}
server server{{ count }} {{ ip }}:443 check
{% set count = count + 1 %}
{% endfor %}
Result is
stick store-response payload_lv(43,1) if serverhello
option ssl-hello-chk
server server1 10.2.0.16:443 check
server server2 10.2.0.20:443 check
Add this line at the top of your template, will preserve the indentation
#jinja2: trim_blocks: True, lstrip_blocks: True

access name of yaml items (pointer reference ?) in liquid template [duplicate]

This question already has answers here:
Iterate over hashes in liquid templates
(3 answers)
Closed 6 years ago.
Say I have yaml data like so :
fruit:
- apple:
- color: "green"
- taste: "bitter"
- banana:
- color: "yellow"
- taste: "sweet"
I would like to parse the list so as to get the printed result :
apple
banana
Is there some way to write a liquid template to achieve said result, without modifying my yaml data (because of course it could be fixed by changing it to name: "banana" and so on...)
{% for item in page.fruit %}
{{ item.?????? }}
{% endfor %}
Cheers
Ok I found the solution in the OP here. As the guy is noting, it is not particularly easy to guess as a newcomer to this train of (object-oriented ?) thought...
---
layout: default
title: qui l'eut cru ?
permalink: /fruits/
fruit:
- apple:
- color: "green"
- taste: "bitter"
- banana:
- color: "yellow"
- taste: "sweet"
---
{% for item in page.fruit %}
{% for browser in item %}
**root of the sublist:** {{browser[0]}}
**contents of the sublist:** {{browser[1]}}
{% endfor %}
{% endfor %}

Resources