Conditionally Create a variable - ansible

I have some python code that runs in multiple environments. The code checks for the existence of environment variables, and takes a slightly different path depending on what environment variable is defined. The code is:
def _get_sink_to_function():
# Determine which path we send data to, based on env variables
# One of the following env variables must be present.
funcdict = {
'LOG_SINK': _post_gzip_to_log_sink,
'FIREHOSE_SINK': _post_gzip_to_firehose_sink
}
for v in funcdict.keys():
if os.environ.get(v):
return funcdict[v]
return None
main():
sink_to_func = _get_sink_to_function()
if not sink_to_func:
raise AssertionError('Missing mandatory env variable')
...
sink_to_func(gzip_data)
The environment variables are set using ansible.
Therefore, I would like to conditionally create the environement variable.
For example, in this (valid) ansible code:
LOG_SYNC: "{% if logger == 'one' %}path-to-the-log{% endif %}"
LOG_SYNC is always defined, sometimes with a value of "path-to-the-log", and sometimes as empty. I want LOG_SYNC not to be defined at all if logger is not equal to 'one'.
In other words, I want something like:
{% if logger == 'one' %}
LOG_SYNC: "path-to-the-log"
{% endif %}
But, that does not seem to be allowed.

The compiler, in whatever language you have written code, will need the variable to be defined first, if it is going to be used anytime later.
so you will need to define the variable, assign value NULL then it will not occupy any memory

Related

Inserting template name as class

When creating a Go template, you can give it a name, like in this example, "my_home_template":
var tmplHome = template.Must(template.New("my_home_template").Funcs(funcMap).ParseFiles("templates/base.tmpl", "templates/content_home.tmpl"))
How can I get that template name and use it inside the actual template file?
Ultimately I just want to define a convenient css class, like so:
<body class="my_home_template">
Here's a working solution, taking mkopriva's advice:
When executing a template, pass some custom parameter with dummy data. Here, I just create a "PageHome" parameter to pass to the template, and value is a simple "1", but it could be any value:
tmplHome.ExecuteTemplate(w, "base", map[string]interface{}{"PageHome": "1", "Data": events, "UserFirstName": &u.FirstName, "UserProfilePic": &u.ProfilePic})
Then, inside the template itself, a simple if statement to check if the parameter exists, and do something accordingly:
{{ if .PageHome }}
<body class="PageHome">
{{ else }}
<body>
{{ end }}
All my other template executions don't pass a "PageHome" parameter at all, so the if statement never passes as true for them.
There's probably a more advanced solution using a functions via a template function map, and having a consistent "PageType":"something" parameter in all template executions, but in the end you still have to define a parameter per template execution and still have to build up if statements in your templates anyways.

Using django-widget-tweaks with Jinja2 template engine

I'm using django v1.11.7 with Jinja2 v2.10 as the template engine.
In my website, I wish to render forms using bootstrap. I found out that django-widget-tweaks can be used for this integration.
This package won't work with Jinja templates, since it needs to load a custom tag set into the Jinja environment. Loading tag sets can be complex, since I may need to write an extension.
Is there an easy way to get django-widget-tweaks to work with Jinja? Or is there another way for integrating boostrap with Jinja?
A little late but maybe this can help.
What I did is import the function I wanted to use and called them in my jinja templates:
app_root.jinja2.py
from jinja2 import Environment
from jinja2 import contextfunction
from widget_tweaks.templatetags.widget_tweaks import render_field
def environment(**options):
env = Environment(**options)
env.globals.update({
'render_field': render_field,
})
return env
In template
{% set class = class + "my-html-class" %}
{{ render_field(field, class) }}
EDIT: Anyone with a little bit of Jinja and template tag experience knows this won't work. For my current needs, I defined the two following function in my jinja config and will evaluate my needs at a later time.
def set_attr(bound_field, attr, value):
bound_field.field.widget.attrs[attr] = value
return bound_field
def add_class(bound_field, value):
try:
bound_field.field.widget.attrs['class'] += value
except KeyError:
bound_field.field.widget.attrs['class'] = value
return bound_field
EDIT 2
Other useful link: https://github.com/niwinz/django-jinja/issues/140
To make this solution work, I had to make these changes:
jinja2.py
from jinja2 import Environment
from widget_tweaks.templatetags.widget_tweaks import add_class
from widget_tweaks.templatetags.widget_tweaks import set_attr
def environment(**options):
env = Environment(**options)
env.filters['set_attr'] = set_attr
env.filters['add_class'] = add_class
return env
template.html
{{ form.field |set_attr('attr:val') }}
{{ form.field |add_class('my_class') }}

How do I check if variable defined in an Ansible playbook contains a string value?

I want to validate that the input values passed to the variables as extra_args.
I want to run a pre-task that passes if the variable contains a string value, else fails if it contains anything else.
The values are passed to them as extra_args when executing the playbook.
I want to run a pre-task that passes if the variable contains a string value, else fails if it contains anything else.
This task fails if the variable is not a string object:
- fail:
when: variable is not string
But be aware that all values passed as extra-vars will be strings, because that's what they are -- anything you type on your keyboard is a valid string. As there is no type declaration, even if a variable contains a numerical value, it will be stored in a string object.
It is different to variable values defined in YAML which undergo type autodetection performed by YAML parser. For example if you type myvar: true in YAML, it will be considered Boolean object true, but if you pass the same value with --extra-vars "myvar:true", it will be a string object true.
You need to specify another condition.
Here are few filters and tests in ansible you may find it useful
http://docs.ansible.com/ansible/latest/playbooks_filters.html
http://docs.ansible.com/ansible/latest/playbooks_tests.html
for validation you might use it as follows:
tasks:
- fail: msg="Variable '{{ item }}' is not a string"
when: string | search("^[a-zA-Z]*$")
I prefer to use the 'assert' module for such cases like this.
- name: Test if the type of 'variable' is string
assert:
that:
- variable is defined
- variable is string
fail_msg: |
variable: {{ variable | d() | to_nice_json }}
seealso: type check examples: https://github.com/ssato/ansible-role-assertive-programming-examples/blob/master/tasks/pre_type_checks.yml
BTW, if you want to define variables with types you want using --extra-vars (-e) option, you need to prepare yaml files define these variables and let them loaded using '#' such like '-e #/path/to/the/yaml_file'.

Go capturing template variables and names

I am experimenting with Go's templates.
I am curious: is it possible to do the following: {{$myVariable := randomStringFunc | saveFunc}}
Where:
$myVariable - randomly chosen variable name
randomStringFunc - function that generates random strings
TRICKY: saveFunc - a function that saves the variable name and its value
I have looked into capture-or-assign-golang-template-output-to-variable but I am not sure how and if it can help me achieve my goal.
EDIT
In the end I would like to have a mapping between the variable name that is defined in the template and the value that is assigned to it:
var variableMapping map[string]string
After template execution the content of variableMapping should be something like:
{
"$myVariable:"randomString1",
"$anotherVariable":"5",
"$thirdVariableInMyTemplate":"false"
}

Show default content in a template if an object is nil otherwise show based on the set property

In my template, I would like to include some default meta tags (90% of the time). However, when a specific property is set, I would like to show a different set of text.
I know I can set an anonymous struct and set a property with either "default" or "some-x". However, this means, I need to add an anonymous struct to 90% of my handlers that just currently pass nil.
Is there way to do something like
{{if eq . nil}}
// default meta tag
{{else if eq .MetaValue "some-x"}}
//other
{{end}}
If I try something like my above code, it compiles but doesn't do what I want. Appreciate any suggestions on how to handle it properly without adding a lot of boiler plate.
Thanks!
{{if not .}}
output when . is nil or otherwise empty including
false, 0, and any array, slice, map, or string of length zero
{{else if eq .MetaValue "some-x"}}
// some-x case
{{else}}
// other case
{{end}}
If you want to ensure you're only checking against nil and not 0, false, the empty string, or any other falsey type, you can use the kindIs function to accomplish this.
{{ if kindIs "invalid" . }}
// only if variable is literally nil. falsey values will fallthrough.
{{ else if eq .MetaValue "some-x" }}
// other
{{ else }}
// final case, if any
{{ end }}
I've been recently facing an issue with identifying nil vs 0 values in a Helm Chart (which uses Go templates, including sprig) and haven't found any solutions posted, so I thought I'd add mine here.
I came up with a kind of ugly solution which is to quote the value and then check for a string that matches "<nil>" (with quotes, so you'd actually be checking (quote .Values.thing | eq "\"<nil>\"")). This allows differentiating tests against empty values vs defined 0 values. In my case, I was trying to build a config file where some default options were non-0, so when 0 was explicitly set, I wanted to know that 0 was set instead of just omitted.
Hopefully this can be a help to someone else.
It would be nice to have a better way to do this, but so far I haven't found anything that doesn't require creating and adding my own template functions.

Resources