Dotliquid not identifying explicitly given null value in a json body - json

I am working on a JSON transformation using Dotliquid. I want to check if the value of a field is null or not. for example,
{
"Lines": null,
"Value": "String"
}
In my template I want to do the following
{% if Lines == null %}
"Value": "Lines are null"
{% else %}
"Value": "Lines are not null"
{% endif %}
The result I am getting after rendering this is
{
"Value": "Lines are not null"
}
I don't understand what I am doing wrong.
When I give the input JSON as
{
"Value": "String"
}
Then I am getting the correct result. The problem occurs only when I provide null value explicitly
Any suggestions?

Maybe this will help?
Truthy and Falsey
Try
{% if Lines == false %}
"Value": "Lines are null"
{% else %}
"Value": "Lines are not null"
{% endif %}
I have found the liquid language works best of truth or false

Perhaps it cannot return a true because "Lines" is not there to be evaluated.
Perhaps you could try:
{% if Lines != null %}
"Value": "Lines are not null"
{% else %}
"Value": "Lines are null"
{% endif %}

Related

filtering key and value of json data in jinja2

i have json file from url that i want to filter using jinja. The json file is loaded in my ansible as a variable "get_devices". Here is the json file :
{
"vni": {
"13": {
"192.168.13.2": {
"mac": "50:00:00:10:00:03",
"state": "active",
"type": "local"
},
"192.168.13.3": {
"mac": "50:00:00:05:00:03",
"remoteVtep": "10.0.0.6",
"state": "active",
"type": "remote"
},
"fe80::5200:ff:fe05:3": {
"mac": "50:00:00:05:00:03",
"remoteVtep": "10.0.0.6",
"state": "active",
"type": "remote"
},
"fe80::5200:ff:fe10:3": {
"mac": "50:00:00:10:00:03",
"state": "active",
"type": "local"
}
}
}
}
I'm new at using jinja, so the template might contain many mistakes and error. The template is like this :
{% for item in get_devices.json.results -%}
{% for key, value in item.vni.iteritems() %}
VNI Data
VNI Number : {{ key }}
{% for key, value in value.iteritems() %}
- IP : {{ key }}
{% for key, value in value.iteritems() %}
{{ value }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
And the expected result is like this :
VNI DATA
VNI Number : 13
- IP : 192.168.13.3
50:00:00:10:00:03
10.0.0.6
active
local
- IP : fe80::5200:ff:fe05:3
50:00:00:10:00:03
10.0.0.6
active
local
and so on. However, notice that some of the data don't have the remoteVtep so to keep the order of the resulting "values" in the same line, I want to replace remoteVtep with "-" if the data doesn't have remoteVtep. How to declare this in jinja2? This is an example of the desired output (of data that don't have remoteVtep):
- IP : 192.168.13.2
50:00:00:10:00:03
-
active
local
What changes are needed to achieve this? Thank you.

Jinja2 filter nested dictionary based on boolean value

I have the following dict variable users in Jinja2:
"users": {
"user1": {
"alive": true,
"age": 22
},
"user2": {
"alive": false,
"age": 34
}
}
and I want to filter all alive users with jinja filter, but after a long search I am still not able to achieve that on such nested structure. Could anyone please help?
For now, I am just passing all users with {{ users }}, but I guess it should be possible to filter it with built in Jinja filters. Just cannot figure out the right sequence of them.
users: {'user1': {'alive': True, 'age': 22}, 'user2': {'alive': False, 'age': 34}}
this j2 file does the job:
{% for user in users if users[user].alive %}
{{ user }}: {{ users[user] }}
{% endfor %}
result:
user1: {'alive': True, 'age': 22}

how to generate html report for multiple hosts using ansible and jinja2

my playbook
- name: create HTML report
template:
src: report.j2
dest: /cktreport.html
delegate_to: localhost
run_once: true
report.j2
<!DOCTYPE html>
<html>
<body>
<table>
<thead>
<tr>
<th>HOSTNAME</th>
<th>PORT</th>
<th>CKTID</th>
</tr>
</thead>
<tbody>
{% for item in output.parsed %}
<tr>
{% if 'CID' in item.DESCRIP %}
<td>{{inventory_hostname}}</td>
<td>{{item.PORT}}</td>
<td>{{item.DESCRIP}}</td>
{%elif 'ckid' in item.DESCRIP %}
<td>{{inventory_hostname}}</td>
<td>{{item.PORT}}</td>
<td>{{item.DESCRIP}}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
'output.parsed' has below info
TASK [debug] *******************************************************************
ok: [host-1] => {
"msg": [
{
"DESCRIP": "CID: xxxx",
"PORT": "Gi0/0/0",
"PROTOCOL": "up",
"STATUS": "up"
},
{
"DESCRIP": "",
"PORT": "Gi0/0/1",
"PROTOCOL": "up",
"STATUS": "up"
},
{
"DESCRIP": "",
"PORT": "Gi0/0/2",
"PROTOCOL": "down",
"STATUS": "down"
},
{
"DESCRIP": "ckid: XXXX",
"PORT": "Gi0/0/3",
"PROTOCOL": "up",
"STATUS": "up"
}
]
}
ok: [host-2] => {
"msg": [
{
"DESCRIP": "CID: xxxx",
"PORT": "Gi0/0/1",
"PROTOCOL": "up",
"STATUS": "up"
},
{
"DESCRIP": "",
"PORT": "Gi0/0/6",
"PROTOCOL": "up",
"STATUS": "up"
},
{
"DESCRIP": "",
"PORT": "Gi0/0/7",
"PROTOCOL": "down",
"STATUS": "down"
},
{
"DESCRIP": "ckid: XXXX",
"PORT": "Gi0/0/8",
"PROTOCOL": "up",
"STATUS": "up"
}
]
}
issue i have is - when i run playbook , cktreport.html is generated for just host-1,
i have multiple hosts, how to generate single/one cktreport.html such a way that it has all hosts info in it.
i know i need to modify jinja2 template but not sure what logic to use.
I'll take for granted your playbook targets the magic group all. Just replace in the template below with the correct group if this is not the case.
If you are doing something more complex (targeting several groups, using an advance host pattern, using limits on the command line...) have a look at special variables like ansible_play_hosts which will be more adapted.
It is in most cases a bad practice to loop directly on host lists outside of the natural play host loop... except when there is a good reason and this one. In your template, you need to go over all hosts to include in the report then loop on the parsed info you previously gathered. I believe the following template should meet your requirements (untested).
Notes:
since h actually contains the inventory_hostname, I used it directly for conciseness. But you can replace with hostvars[h].inventory_hostname if you prefer. The result will be absolutely identical.
your example template was not valid (closing endfor hanging arround with no opennig for). I fixed that below.
I left your if stanza as they were but you have several options to DRY here and check both conditions at once (with the match test or other regexp solutions...) to output the same piece of html afterwards. I'll let you explore that on your own if you wish.
<!DOCTYPE html>
<html>
<body>
<table>
<thead>
<tr>
<th>HOSTNAME</th>
<th>PORT</th>
<th>CKTID</th>
</tr>
</thead>
<tbody>
{% for h in groups['all'] %}
{% for item in hostvars[h].output.parsed %}
<tr>
{% if 'CID' in item.DESCRIP %}
<td>{{ h }}</td>
<td>{{ item.PORT }}</td>
<td>{{ item.DESCRIP }}</td>
{%elif 'ckid' in item.DESCRIP %}
<td>{{ h }}</td>
<td>{{ item.PORT }}</td>
<td>{{ item.DESCRIP }}</td>
{% endif %}
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
</body>
</html>

Using two JSON sources for Jekyll output

Suppose I have a list of projects (let's call that proj.json) and a list of smaller sub-projects (sub_proj.json) that are associated with the list of projects. The files are as follows:
proj.json
[{
"title": "Project 1",
"description": "aaa.",
"subproj": ["RefSP1", "RefSP2"]
},
{
"title": "Project 2",
"description": "aaa.",
"subproj": ["RefSP3"]
}]
sub_proj.json
[{
"title": "Sub Project 1",
"description": "aaa.",
"key": "RefSP1"
},
{
"title": "Sub Project 2",
"description": "aaa.",
"key": "RefSP2"
},
{
"title": "Sub Project 3",
"description": "aaa.",
"key": "RefSP3"
}]
But in the output.html, I seem to be missing something. The code is below: (I removed it of formatting for simplicity)
{% for item in site.data.proj %}
{{ item.title }}
{% assign key_array = item.subproj %}
{% for sub in key_array %}
{% assign subproject = site.data.sub_proj | where:"key",sub %}
{{ subproject.title | inspect }}
{% endfor %}
I seem to get the correct number of subprojects using {{ subproject.title | inspect }}, but they're all nil. Adding jsonify doesn't really do anything.
edit:
Printing out {{ item | inspect }}
results in
{ "title"=>"Project 1","description"=>"aaa.","subproj"=>["RefSP1","RefSP2"]}
But {{ subproject | inspect }}
comes out as
[{"title"=>"Sub Project 1","description"=>"aaa.","key"=>"RefSP1"}] [{"title"=>"Sub Project 2","description"=>"aaa.","key"=>"RefSP2"}]
The square brackets are the main difference. I tried removing them through filters, still nothing.

jinja2 template for loop idention error in json file

I'm trying to use a jinja2 template to render a json file. The structure is similar to:
"rows": [
{% for product in products %}
{
"id": {{ loop.index }},
"name": {{ product }},
"available": true
}{% if not loop.last %},
{% else %}
{% endif %}
{% endfor %}
],
[...]
The problem is that the output json is rendered as:
"rows": [
{
"id": {{ loop.index }},
"name": {{ product }},
"available": true
},
{
"id": {{ loop.index }},
"name": {{ product }},
"available": true
}
],
[...]
Note the bad indentation in the first { of each row. How can I solve this?
Thank you.
You can add a - to the Jinja2 enclosure to discard spaces in that direction:
{%- for product in products %}
Please read the documentation of Whitespace Control for details.