Ansible template from jinja2 - ansible

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

Related

Ansible Nested lists into jinja template

I am attempting to past a nested list into jinja to create a configuration file for Telegraf using the SNMP input plug-in.
So far I have been able to parse the following simple list into a suitable configuration file.
List:
- name: CpuUsage
oid: 1.3.6.1.4.1.5951.4.1.1.41.1.0
- name: mgmt_CPU
oid: 1.3.6.1.4.1.5951.4.1.1.41.6.1.2.8.77.103.109.116.32.67.80.85
- name: MemUsage
oid: 1.3.6.1.4.1.5951.4.1.1.41.2.0
- name: TotRxMbits
oid: 1.3.6.1.4.1.5951.4.1.1.43.27.0
- name: TotTxMbits
oid: 1.3.6.1.4.1.5951.4.1.1.43.30.0
- name: httpTotRequestsRate
oid: 1.3.6.1.4.1.5951.4.1.1.48.76.0
- name: tcpCurClientConnEstablished
oid: 1.3.6.1.4.1.5951.4.1.1.46.12.0
- name: tcpCurServerConnEstablished
oid: 1.3.6.1.4.1.5951.4.1.1.46.10.0
- name: tcpCurClientConnClosing
oid: 1.3.6.1.4.1.5951.4.1.1.46.9.0
into the following config:
[[inputs.snmp.field]]
name = "CpuUsage"
oid = "1.3.6.1.4.1.5951.4.1.1.41.1.0"
conversion = "int"
[[inputs.snmp.field]]
name = "mgmt_CPU"
oid = "1.3.6.1.4.1.5951.4.1.1.41.6.1.2.8.77.103.109.116.32.67.80.85"
conversion = "int"
[[inputs.snmp.field]]
name = "MemUsage"
oid = "1.3.6.1.4.1.5951.4.1.1.41.2.0"
conversion = "int"
[[inputs.snmp.field]]
name = "TotRxMbits"
oid = "1.3.6.1.4.1.5951.4.1.1.43.27.0"
conversion = "int"
[[inputs.snmp.field]]
name = "TotTxMbits"
oid = "1.3.6.1.4.1.5951.4.1.1.43.30.0"
conversion = "int"
[[inputs.snmp.field]]
name = "httpTotRequestsRate"
oid = "1.3.6.1.4.1.5951.4.1.1.48.76.0"
conversion = "int"
[[inputs.snmp.field]]
name = "tcpCurClientConnEstablished"
oid = "1.3.6.1.4.1.5951.4.1.1.46.12.0"
conversion = "int"
[[inputs.snmp.field]]
name = "tcpCurServerConnEstablished"
oid = "1.3.6.1.4.1.5951.4.1.1.46.10.0"
conversion = "int"
[[inputs.snmp.field]]
name = "tcpCurClientConnClosing"
oid = "1.3.6.1.4.1.5951.4.1.1.46.9.0"
conversion = "int"
Where I am stuck is with the following list of lists
netscaler_citrix_vserver:
- name: name
oid: NS-ROOT-MIB::vsvrName
is_tag: "true"
- name: fullName
oid: NS-ROOT-MIB::vsvrFullName
is_tag: "true"
- name: requests
oid: NS-ROOT-MIB::vsvrTotalRequests
- name: state
oid: NS-ROOT-MIB::vsvrState
- name: servicesUp
oid: NS-ROOT-MIB::vsvrCurServicesUp
netscaler_citrix_vservice:
- name: vserver
oid: NS-ROOT-MIB::vserverFullName
is_tag: "true"
- name: vservice
oid: NS-ROOT-MIB::vsvrServiceFullName
is_tag: "true"
- name: hits
oid: NS-ROOT-MIB::vsvrServiceHits
I've tried a number of variations, but each proving unsuccessful. I'm trying to get the following output:
[[inputs.snmp.table]]
name = "netscaler_citrix_vserver"
# oid omitted, to allow collection of specific columns only
[[inputs.snmp.table.field]]
name = "name"
oid = "NS-ROOT-MIB::vsvrName"
is_tag = true
[[inputs.snmp.table.field]]
name = "fullName"
oid = "NS-ROOT-MIB::vsvrFullName"
is_tag = true
[[inputs.snmp.table.field]]
name = "requests"
oid = "NS-ROOT-MIB::vsvrTotalRequests"
[[inputs.snmp.table.field]]
name = "state"
oid = "NS-ROOT-MIB::vsvrState"
[[inputs.snmp.table.field]]
name = "servicesUp"
oid = "NS-ROOT-MIB::vsvrCurServicesUp"
[[inputs.snmp.table]]
name = "netscaler_citrix_vservice"
# oid omitted, to allow collection of specific columns only
[[inputs.snmp.table.field]]
name = "vserver"
oid = "NS-ROOT-MIB::vserverFullName"
is_tag = true
[[inputs.snmp.table.field]]
name = "vservice"
oid = "NS-ROOT-MIB::vsvrServiceFullName"
is_tag = true
[[inputs.snmp.table.field]]
name = "hits"
oid = "NS-ROOT-MIB::vsvrServiceHits"
Basically I need to reference the top-level entry and for each top-level entry list the sub-level entries also.
Any help would be appreciated.
the code used to create the first list is pretty straightforward, as follows:
[[inputs.snmp.field]]
name = "{{ item.name }}"
oid = "{{ item.oid }}"
{% endfor %}
for the SNMP table code I've resorted to explicitly declaring the table name as follows:
[[inputs.snmp.table]]
name = "netscaler_citrix_vserver"
{% for item in netscaler_citrix_vserver %}
[[inputs.snmp.table.field]]
name = "{{ item.name }}"
oid = "{{ item.oid }}"
{% if item.is_tag is defined %}
is_tag = {{item.is_tag}}
{% endif %}
{% endfor %}
[[inputs.snmp.table]]
name = "netscaler_citrix_vservice"
{% for item in netscaler_citrix_vservice %}
[[inputs.snmp.table.field]]
name = "{{ item.name }}"
oid = "{{ item.oid }}"
{% if item.is_tag is defined %}
is_tag = {{item.is_tag}}
{% endif %}
{% endfor %}
Of course as soon as I posted the answer from another question in related questions popped up. Resolved with the following code
{% for input_snmp_table in input_snmp_tables recursive %}
[[inputs.snmp.table]]
name = {{ input_snmp_table.table_name }}
{% for input_snmp_table_fields in input_snmp_table.input_snmp_table_fields %}
[[inputs.snmp.table.field]]
name = "{{ input_snmp_table_fields.name }}"
oid = "{{ input_snmp_table_fields.oid}}"
{% if input_snmp_table_fields.is_tag is defined %}
is_tag = {{input_snmp_table_fields.is_tag}}
{% endif %}
{% endfor %}
{% endfor %}```

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

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.

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).

NUNJUKS: For loop to create list of variables, but instead creates strings

I'm using nunjucks to create a JSON export file. I have a list of variables that have the same name except for an incrementing number on the end. I'm using a for loop in the following way:
{% for i in range(1, 6) -%}
{% set items = ["{{ answer",i, " }}"] %}
"Solution{{ i }}" : "{{ items | join }}",
{%- endfor %}
I want answer1 to grab the variable answer1, but instead it is giving me a string "{{ anwser1 }}" .
Any idea how to use the for loop to point to each variable (answer1, answer2, answer3, etc)?
You can add some global function or filter to get access to a context (vars scope) by name.
const nunjucks = require('nunjucks');
const env = new nunjucks.Environment();
env.addGlobal('getContext', function (prop) {
return prop ? this.ctx[prop] : this.ctx;
});
const tpl = `{% for i in range(1, 4)%} {{ getContext('a' + i) }} {% endfor %}`;
const output = env.renderString(tpl, {a1: 10, a2:20, a3: 30, b: 1, c: 2});
console.log(output);

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

Resources