I'm using SaltStack to manage my infra. Machines are hosted in different DCs, so they also have slightly different network setup.
Currently, I'm running into the following issue:
Comment: Unable to manage file: Jinja variable 'dict object' has no attribute 'macaddress'; line 9
---
[...]
ethernets:
{{ grains['interface_context'] }}:
dhcp4: {{ grains['dhcp4'] }}
dhcp6: {{ grains['dhcp6'] }}
addresses: [{{ grains['ipv4'] }}, "{{ grains['ipv6'] }}"]
{% if grains['macaddress'] %} <======================
match:
macaddress: {{ grains['macaddress'] }}
{% endif %}
routes:
- to: default
[...]
---
As the message indicates, the grain "macaddress" is missing, which I can confirm, it's not set for this minion. But What I do not understand is how I can simply check if this variable/grain exists at all within a jinja template?
I wouldn't expect this error to come up, as I actually wanted to catch it with the if statement.
Can somebody help?
Use get to return None instead of raising:
{% if grains.get('macaddress') is not none %}
Or if you want to treat "empty" values the same:
{% if not grains.get('macaddress') %}
I am currently having troubles with the first if statement in a Jinja2 template resolving to else even though both conditions are met:
{%- elif frontend_type == 'beast' -%}
{{ radosgw_frontend_type }} {{ 'ssl_' if radosgw_frontend_ssl_certificate and haproxy_frontend_ssl_termination is sameas false else '' }}endpoint={{ _rgw_binding_socket }}{{ ' ssl_certificate='+radosgw_frontend_ssl_certificate if radosgw_frontend_ssl_certificate else '' }}
{%- endif -%}
The problematic snippet seems to be and haproxy_frontend_ssl_termination is sameas false as the other condition works fine. I am not sure why this condition is not met even though it seems to work in another template when encapsulated in {% %}.
Any help would be greatly appreciated!
I suspect your problem is the use of the sameas test. From the documentation:
sameas(value, other)
Check if an object points to the same memory address than another object:
That's almost never what you want to do. If you're checking to see if an expression is false, you don't need to explicitly compare it to false. E.g., you could simply write:
{{ 'ssl_' if radosgw_frontend_ssl_certificate and not haproxy_frontend_ssl_termination else '' }}
Jinja2 supports very useful filters to modify a string, eg.
{{ my_string|capitalize }}
What about you want to build the input string? When the string is simple you can always use
{% set my_string = string_1 + string_2 %}
{{ my_string|capitalize }}
But it would be wonderful to actually build this string using templates, just like
{% set my_string = "{{ 'a' }}b{{ 'c' }}" %}
{{ my_string|capitalize }}
that would output Abc..
Did I miss something?
Answer exists in Jinja 2.8, as documented here
The answer is
{% set my_string %}
{{ 'a'}}b{{ 'c' }}
{% endset %}
Are there any liquid shorthands? For example I'm trying to express this in a more concise way:
{% if job.offsite %}}
{{job.offsite}}
{{% else %}}
{{ job.url }}
{% endif %}
For this particular example, you could write:
{{ job.offsite | default: job.url }}
The value provided to the default filter will be used if the left side of the expression is false or nil.
Converting from Django, I'm used to doing something like this:
{% if not var1 %} {% endif %}
and having it work if I didn't put var1 into the context. Jinja2 gives me an undefined error. Is there an easy way to say {% if var1 == None %} or similar?
From the Jinja2 template designer documentation:
{% if variable is defined %}
value of variable: {{ variable }}
{% else %}
variable is not defined
{% endif %}
{% if variable is defined %} is true if the variable is None.
Since not is None is not allowed, that means that
{% if variable != None %}
is really your only option.
You could also define a variable in a jinja2 template like this:
{% if step is not defined %}
{% set step = 1 %}
{% endif %}
And then You can use it like this:
{% if step == 1 %}
<div class="col-xs-3 bs-wizard-step active">
{% elif step > 1 %}
<div class="col-xs-3 bs-wizard-step complete">
{% else %}
<div class="col-xs-3 bs-wizard-step disabled">
{% endif %}
Otherwise (if You wouldn't use {% set step = 1 %}) the upper code would throw:
UndefinedError: 'step' is undefined
In the Environment setup, we had undefined = StrictUndefined, which prevented undefined values from being set to anything. This fixed it:
from jinja2 import Undefined
JINJA2_ENVIRONMENT_OPTIONS = { 'undefined' : Undefined }
Consider using default filter if it is what you need. For example:
{% set host = jabber.host | default(default.host) -%}
or use more fallback values with "hardcoded" one at the end like:
{% set connectTimeout = config.stackowerflow.connect.timeout | default(config.stackowerflow.timeout) | default(config.timeout) | default(42) -%}
You can use kind of Jinja Elvis operator
{{ 'OK' if variable is defined else 'N/A' }}
or additionally check emptiness
{{ 'OK' if (variable is defined and variable) else 'N/A' }}
Jinja templates - Template Designer Documentation
{% if variable is defined %} works to check if something is undefined.
You can get away with using {% if not var1 %} if you default your variables to False eg
class MainHandler(BaseHandler):
def get(self):
var1 = self.request.get('var1', False)
I had an issue like this in Ansible. Ended up having to do a test on both #Garret and #Carsten / #azalea answers, so:
{% if variable is defined and variable %}
value of variable: {{ variable }}
{% else %}
variable is not defined or is falsy
{% endif %}
You can do this :
- debug:
msg: "Executed only if variable is defined"
when:
- variable is defined