jinja2 navigate dynamically to json object [duplicate] - json

This question already has answers here:
How can I use Ansible nested variable?
(2 answers)
Closed 4 years ago.
My question looks trivial but I already spend some hours on it.
How to dynamically navigate into a json variable, with jinja2.
ex: I get
ansible_lvm.vgs:
"vgs": {
"vgdata": {
"free_g": "16",
"size_g": "0"
},
"vgswap": {
"free_g": "0",
"size_g": "00"
}
}
In a jinja2 structure I would like to get "free_g" attribut for "vgdata":
None of the code hereafter works:
{% set my_vg_name = 'vg_data' %}
{% set my_vg_size = ansible_lvm.vgs.(my_vg_name).free_g %}
{% set my_vg_size = ansible_lvm.vgs.{{my_vg_name}}.free_g %}
{% set my_vg_size = ansible_lvm.vgs|selectattr(my_vg_name, 'free_g') %}
Thanks for your help,

So, I hope that code snippet at the top is just an example, and not really what you are using, since it's malformed JSON. And I hope you are not actually asking the vgs object for vg_data when the key is vgdata, because that will never end well.
That aside:
You access dict objects in python using vgs[my_vg_name] syntax, or if you aren't sure that vgs contains that key, vgs.get(my_vg_name, {}) to provide an empty dict as the default if vgs does not contain a key whose value is in the my_vg_name variable.
Perhaps it's just a bad question, but if you always want vgdata.free_g then why the dynamic access at all?

Related

Liquid Map Arithmetic Operations

Hello wise people of StackOverflow,
I have an exchange rates file that I am mapping from XML to JSON in an Azure logic app using Transform XML To JSON. I have two rates (Ask and Bid) within the XML. A node in the XML file looks like so:
<quote>
<ask>110.0668027</ask>
<bid>108.1461645</bid>
<currency>AFA</currency>
<date>2022-07-27T23:59:59+0000</date>
<midpoint>109.1064836</midpoint>
</quote>
I then need to map to JSON but I wish for the JSON output to only show a single rate which must be calculated as (Ask+Bid)/2 to give me the average.
I have created a liquid map like so:
{
"EffectiveDate": "2022-06-06",
"BaseCurrency": "GBP",
"ExchangeRates":
[
{% for data in content.response.quotes %}
{
"ExchangeRate": "({{data.quote.ask}} + {{data.quote.bid}})/2",
"TargetCurrency": "{{data.quote.currency}}"
},
{%endfor%}
]
}
But when I run the logic app the JSON output looks like so:
{
"ExchangeRate": "(110.0668027 + 108.1461645)/2",
"TargetCurrency": "AFA"
},
Which is obviously not what I want to see! What is wrong with the syntax in my Liquid map?
In Liquid you have to use math filters to manipulate integers.
So I would do something like that:
First calculate your value to divide.
{% assign value_2 = value_2 | divided_by:2 %}
Then output your values by adding them:
{{ value_1 | plus: value_2}}
More info about math filters here: Documentation about math filters

How can I stop the loaded variables to duplicate in Flask? [duplicate]

This question already has answers here:
stop flask duplicating a loaded variable
(2 answers)
Closed 3 years ago.
I'm building a simple data analysis web-app using an API endpoint from an ERP.
I want to display the result of my query in a table, so I iter through the results and my data gets displayed nicely.
However when I refresh my page, my data gets duplicated.
My problem is the same as in this post.
I have tried to fix my code using the solution of the post above but without success.
This is my route for my Flask app
#app.route('/results', methods=["POST", "GET"])
def results():
code = hasCode()
if request.method == "POST":
quote_reference = request.form["quote"]
products = resultsList(code, quote_reference)
try:
return render_template("results.html", products=products)
except BaseException:
return "There was a problem with your request"
else:
return render_template("/")
my products are being initiated in the resultList() function and refers to the function underneath:
def resultsList(code, quote_reference):
"""Creates a list of results that can be passed to the template of the
results.html template
"""
# initiating the variable
my_list = {
'quantity': [],
'description': [],
'price': [],
'img': []
}
# The pandalize function fetches the data from the ERP
query = pandalize(code, quote_reference)
# Grabbing all reasults from the "pandalize function" and appending them to the list
for i, row in query.iterrows():
my_list["quantity"].append(row["quantity"])
my_list["description"].append(row["name"])
my_list["price"].append(row["price"])
my_list["img"].append(row["id"])
# Zipping the list
products = zip(
my_list["quantity"],
my_list["description"],
my_list["price"],
my_list["img"]
)
return products
finally, the loop is in the results.html file:
{% for i in products %}
<tr>
<td class="quantity">{{ i[0] }}</td>
<td class="description">{{ i[1] }}</td>
<td class="price">{{ i[2] }}</td>
<td class="img">{{ i[3] }}</td>
</tr>
{% endfor %}
According to this answer I would need to initialize my list (products) inside my resultsList() function for it to work. However I still experience doubling of data.
I don't really understand what I'm doing wrong. Any ideas ?
After checking the results of all functions and going back upstream, it seemed that the original answer was correct. I need to initialize the list each time.
I noticed that my initial list was being populated by my request (the 'pandalize()' function). This had for effect that each time the pandalize function was called, the list became longer and longer.
It has now been fixed.

get value from manual grains doesn't work currently

trying to get Grains value in Jinja template but i dont know how to get it to work..
i'm traing to get fqdn and manually added grain (appfqdn)
here is the jinja
{%- set SERVERNAME = grains['fqdn'] -%}
{%- set APPTIER = grains['appfqdn'] -%}
the result of first line work very well. i get the fqdn of the server.
2nd one doesn't. i got it like this: [u'client02.lab.home']
as you can see there is u and ' and []
not sure how to grab it correctly.
also when i grab the value on salt master manfully with json format output. this is hop i get it.
salt 'client03.lab.home' grains.item fqdn --out json
{
"client03.lab.home": {
"fqdn": "client03.lab.home"
}
}
salt 'client03.lab.home' grains.item appfqdn --out json
{
"client03.lab.home": {
"appfqdn": [
"client02.lab.home"
]
}
}
not sure how to use jinja to get the value correctly without the single quot, the u and brackets..
Thank you
I found the the solution.
{%- set APPTIER = grains['appfqdn'][0] -%}
was able to to get the right result.

Creating list of ip's in ansible using given range within jinja template

i want to generate a list of ip addresses (using range of last 8bits so 120-190 translates to x.x.x.120 - x.x.x.190) in defaults/main.yml in my role, and later use it to create new network interfaces and generate a new config file. I tried this approach:
defaults/main.yml:
ip_list: "{%for address_end in range(50,99)%} 192.168.0.{{address_end}}{%endfor%}"
conf_list: "{%for ip in ip_list%}server {{ip}}:6666 {%endfor%}"
and then to use it in template
template.conf.j2:
{% for conf_line in conf_list %}
{{conf_line}}
{% endfor %}
and all i got in generated config file was:
s
e
r
v
e
r
:
6
6
6
6
s
e
r
v
e
r
1
:
6
so my guess is that i'm not generating a list but just a long string and when I use for loop in template.conf.j2 I iterate over single chars. I tried using answer to this problem but all i got was syntax error. Any ideas for what might help me ?
You should format your vars as JSON lists if you want them to be lists.
1.1.1.1 2.2.2.2 3.3.3.3 is a string.
['1.1.1.1', '2.2.2.2', '3.3.3.3'] will be converted to list.
But there is alternative approach for you:
ip_list: "{{ lookup('sequence', 'start=50 count=12 format=192.168.0.%d', wantlist=True) }}"
conf_list: "{{ ip_list | map('regex_replace','(.*)','server \\1:6666') | list }}"
Kostantin answer was of much help, but i found just realized that generating config entries in my case could be solved in an less complex way. Instead of trying to iterate over list or a string variable variable in jinja template file template.conf.j2 like did with :
{% for conf_line in conf_list %}
{{conf_line}}
{% endfor %}
you could just enter insert new line signs while generating string in defaults/main.yml:
conf_list: "{%for ip in ip_list%}server {{ip}}:6666\n{%endfor%}"
and then just insert that whole string into a template.conf.j2 like this:
{{conf_line}}
nevertheless i have no other idea how to generate list of ip addresses other than the one Konstantin proposed.

Combining two variables for use in Twig

I'm using Google app engine and I'm trying to set the value of a textarea based on the concatenation of two string variables. Let's say I have 4 items, and each item has multiple fields. So in my Python I'm passing the dictionary { 'value0': newValue }. I'm using a for loop (iterator value num) and I want to use in my HTML something equivalent to {{ value }}{{ num }} where the variable referenced is value0.
I've tried {{ value~num }} but nothing works. If I could use an array that would be even better - such as {{ value[num] }}