Checking grains out of list with saltstack - jinja2

I want to check if a specific version of a program is already installed.
Therefore, I got a state file:
{% set rvs = ['1113','1278'] %}
{% for rv in rvs %}
{% if ('r{{ rv }}' not in grains.get('cat12', [])) %}
... install it ...
{% else %}
... do nothing ...
{% endif %}
{% endfor %}
In my grains I have:
cat12:
- r1113
I would expect that '1278' is installed and list item '1113' triggers nothing, but even that is installed again...

There's no such syntax as using {{ and }} inside {% and %}. What's inside {% and %} is already Jinja. Just concatenate the string literal and the string variable with the ~ operator.
{% if 'r' ~ rv not in grains.get('cat12', []) %}
Or you can use the format filter:
{% if 'r%s'|format(rv) not in grains.get('cat12', []) %}

Related

jinja2 using {if} within {for}

I'm trying to make a template which iterates over a list to check if a string exists. if it does then something happens, if the string isn't in the list, something else should happen. The issue is the result is repeated for all the lines in the list, which i do not want.
e.g.
The list is some simple yaml
LIST:
- A
- B
- C
Jinja looks like
{% for line in mylist %}
{% if 'A' in line %}
{{ A }} Was found in the list
{% else %}
{{ A }} Was not found
{% endif %}
{% endfor %}
So when 'A' matches i get this
A Was found in the list
A Was not found
A Was not found
And when 'A' does not match i get this:
A Was not found
A Was not found
A Was not found
Basically i need to stop it iterating over the list and just do one thing if it matches or one thing if it doesn't match
So if 'A' matches i need it to just do
A was found
If 'A' doesn't match i need it to just do A was not found
Use some kind of flag variable:
{% set ns = namespace(found=false) %}
{% for line in mylist %}
{% if 'A' in line %}
{% set ns.found=true %}
{% endif %}
{% endfor %}
{% if ns.foo %}
{{ A }} Was found in the list
{% else %}
{{ A }} Was not found
{% endif %}

Idiomatic way in Jekyll to inherit default data if project specific data unavailable

I am completely new to Jekyll. I did something like this:
{% assign top_nav = site.data.menus %}
{% if site.data.orgs[site.orgData].menus %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% endif %}
<ul>
{% for menu in top_nav %}
<li>
{{ menu.title }}
</li>
{% endfor %}
</ul>
Basically, I will grab an array of navigation items from a default folder. But if I notice the existence of a menu for a specific organization, then I will override the menu provided by the default folder.
What I don't like about this approach is I now have hundreds of places in my jekyll templates that does this if statement check. If this were any other scripting programming language, I would define a function like function($org_name,$prop) {return $site.data.orgs[$org_name][$prop] ? $site.data.orgs[$org_name][$prop] : $site.data[$prop]; } . What would be the idiomatic way to achieve the same objective in jekyll?
I tried a variation of David Jacquel's suggestion by doing this
./org_var.html
{% assign prop = include.prop %}
{% assign orgVar = site.data[prop] %}
{% if site.data.orgs[site.orgData][prop] %}
{% assign orgVar = site.data.orgs[site.orgData][prop] %}
{% endif %}
./_include/nav.html
{% include_relative ../org_var.html prop=menus %}
{% for menu in orgVar %}
... print menu items
./_layout/header.html
{% include_relative ../org_var prop='electronics.televisions' %}
{% for tv in orgVar%}
{{ tv.modelName }}
... print tv values
{% endfor %}
But I get a syntax error in ../org_var.html saying {% include_relative file.ext param='value' param2='value' %} . The documentation says I can't use relative path with include or include_relative. How do I make my org_var.html a reusable and global function? And will electronics.televisions even evaluate properly to the proper path of my site.data.org.[site.orgData][...path] variable?
Just realized there is a default: modifier for a variable like smarty templates.
{% assign top_nav = site.data.orgs[site.orgData].menus | default: site.data.menus %}
You can use Jekyll includes.
From anywhere you want to use your include :
{% include nav.html org_name=org_name prop=prop %}
Will call _include/nav.html that can be something like this :
{% assign org_name = include.org_name %}
{% assign prop = include.prop %}
{% if site.data.orgs[org_name][prop] %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% else %}
{% assign top_nav = site.data.orgs[site.orgData].menus %}
{% endif %}
<ul>
{% for menu in top_nav %}
...

Jekyll Liquid Errors are puzzling me

I have been trying to create a site with Github and I'm new to the whole thing. I have been struggling with a piece of code that has been giving me some headache:
{% for item in site.static_files %}
{% if item.path contains '/archive' %}
{% if item.path contains 'index.html' == false %}
{% assign split_path = item.path | split: '/' %}
<p>{{item.path}}</p>
{% assign filename = split_path.last %}
<p>{{ filename }}</p>
{% endif %}
{% endif %}
{% endfor %}
This generates the following error:
Error:
Liquid Warning: Liquid Syntax Error (line 5): Expected end_of_string but found comparison in "item.path contains 'index.html' == false" in archive/index.html
Can anyone help?
Replace:
if item.path contains 'index.html' == false
With:
unless item.path contains 'index.html'
Liquid's getting confused.

Change variable in included jinja2 template

Say I have two templates:
main.j2
{% include "vars.j2" %}
main: {{ var1 }}
vars.j2
{% set var1 = 123 %}
vars: {{ var1 }}
When run, only this line is output:
vars: 123
i.e. var1 is undefined in main.j2, even though it gets set to a value in the included vars.j2 template.
How can I pass variables from included template back to template that includes it? I considered chaining extends, but wondered if there's a more elegant approach.
I recently had a need to do the same thing, and found 2 solutions.
If you have Jinja version 2.10 or later, namespaces can be used:
main_ns.j2:
{% set ns = namespace() %}
{% include "vars_ns.j2" %}
main_ns: {{ ns.var1 }}
vars_ns.j2:
{% set ns.var1 = 123 %}
vars_ns: {{ ns.var1 }}
In Jinja 2.2 or later, it can be accomplished with block scoping of variables. I put the variable settings in the base template so that multiple children can extend it.
vars_block.j2:
{% set var1 = 123 %}
vars_block: {{ var1 }}
{% block content scoped %}{% endblock %}
main_block.j2:
{% extends "vars_block.j2" %}
{% block content %}
main_block: {{ var1 }}
{% endblock %}
You can try using with:
{% with var1=0 %}
{% include "vars.j2" %}
vars: {{ var1 }}
{% endwith %}

What does capturing a liquid variable then assigning to nil do?

Jekyll bootstrap includes the file _includes/JB/setup:
{% capture jbcache %}
<!--
- Dynamically set liquid variables for working with URLs/paths
-->
{% if site.JB.setup.provider == "custom" %}
{% include custom/setup %}
{% else %}
{% if site.safe and site.JB.BASE_PATH and site.JB.BASE_PATH != '' %}
{% assign BASE_PATH = site.JB.BASE_PATH %}
{% assign HOME_PATH = site.JB.BASE_PATH %}
{% else %}
{% assign BASE_PATH = nil %}
{% assign HOME_PATH = "/" %}
{% endif %}
{% if site.JB.ASSET_PATH %}
{% assign ASSET_PATH = site.JB.ASSET_PATH %}
{% else %}
{% capture ASSET_PATH %}{{ BASE_PATH }}/assets/themes/{{ page.theme.name }}{% endcapture %}
{% endif %}
{% endif %}
{% endcapture %}{% assign jbcache = nil %}
I understand that this 1) captures the text as a variable then 2) assigns it to nil immediately, effectively throwing it away. So what does this do?
Because you want the side-effects of rendering but don't want the rendered output. If you don't capture, the rendered content is output. But you don't actually want the output, so you throw it away when you're done. It's a slight hack.
So if you want to compute without outputting the result, capturing in a variable is a reasonable thing to do. The "then assign to nil" hack is a way of saying we are interested in the side-effects of the rendering computation, not the output. Those other assignments persist have effects that persist even when the variable is thrown out.
The {%include custom/setup %}'s output will similarly be thrown away, but its side-effects may be important.