Jinja2 filter nested dictionary based on boolean value - jinja2

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}

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.

ansible dictionary key value pairs

I am new to Ansible/json and I am trying to parse the following json:
{
"resultCPU": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_facts": {
"CPU": "6",
"VM": "tigger"
},
{
"ansible_facts": {
"CPU": "4",
"VM": "pooh"
},
I need to set the value of the items in this json so that pooh=4 and tigger=6. I will need to refer to both these values later (advice on how to do that would help as well).
I have tried using cpuvm "{{ resultCPU.results |selectattr('VM') |map(attribute='CPU')|list }}" but it complains "'dict object' has no attribute VM".
What am I doing wrong?
Your selectattr ignored the ansible_facts between results: [] and the VM you tried to map. Thankfully, the attribute kwarg understands dot notation
- debug:
msg: >-
VMs are {{ resultCPU.results | map(attribute="ansible_facts.VM") | list }}
CPUs are {{ resultCPU.results | map(attribute="ansible_facts.CPU") | list }}
The together filter may interest you, too
and as for "I will need to refer to both these values later (advice on how to do that would help as well)." that is usually what set_fact: is used for, but without more specifics about what you have tried and what shape you are expecting, it's hard to give a more specific answer

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.

Check if variable is in a list within a dictionary in Ansible

I have the following tasks:
- name: Retrieve records from Route53
route53:
command: get
zone: "{{ stag_zone }}"
record: "{{ stag_record }}"
type: A
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
register: rec
- name: Print records
debug: var=rec
- name: Record contains IP
debug: msg="{{rec}} contains {{stag_ip}}"
when: "'{{stag_ip}}' in {{rec.set.values}}"
The Print records task outputs something like this:
ok: [XXX.XXX.XXX.XXX] => {
"var": {
"rec": {
"changed": false,
"invocation": {
"module_args": "",
"module_name": "route53"
},
"set": {
"alias": false,
"record": "YYY.XXX.ZZZ.",
"ttl": "300",
"type": "A",
"value": "AAA.AAA.AAA.AAA,BBB.BBB.BBB.BBB",
"values": [
"AAA.AAA.AAA.AAA",
"BBB.BBB.BBB.BBB"
],
"zone": "XXX.ZZZ."
}
}
}
}
And I want to execute "Record contains IP" task only when {{stag_ip}} is in {{rec.set.values}}. But my when clause is definitely broken. It outputs this:
fatal: [XXX.XXX.XXX.XXX] => Failed to template {% if 'QQQ.QQQ.QQQ.QQQ' in <built-in method values of dict object at 0x7fb66f54e6e0> %} True {% else %} False {% endif %}: template error while templating string: unexpected '<'
How can I "cast" rec.set.values to a list?
The problem here is because values is a dict method. So it has "precedence" over accessing keys. To fix this, one has to explicitly call get:
when: stag_ip in rec.set.get('values')