I need to include an if statement in my httpd.conf template based on whether a directory exists.
Here is what i have so far
{% if ansible_distribution_major_version > 7 and os.path.exists ("/opt/myapp/testapp") %}Include conf/vhost.conf{% endif %}
I get an os is undefined error when i run the task. Any idea what i am doing wrong?
You can't write arbitrary Python code inside Jinja2 expression.
Run Ansible stat module and register result before templating and use this result instead of os.path.exists.
Related
I have developed a playbooks that sends a mail indicating a list of 3-zero-padded numbers.
I want to make the padding in the for loop which prints the information in the mail body.
The playbook takes the number to pad from variable hostvars[host]['number'].
The padding is made via the Ansible syntax
myhost-{{ '%03d' % hostvars[host]['number']|int }}
as you can see in the following task.
Now, I would like to do the padding via Python, because later I want to make more formatting operations on each element printed by the loop.
So I have tried to substitute the upper line with
{{ "myhost-" + str(hostvars[host]['number']).zfill(3) }}
but I am getting this error:
Sending e-mail report...
localhost failed | msg: The task includes an option with an undefined variable. The error was: 'str' is undefined
So I tryed to substitute it (as suggested in comments of this question) with
myhost-{{ hostvars[host].number.zfill(3) }}
but now I get
Sending e-mail report...
localhost failed: {
"msg": "The task includes an option with an undefined variable. The error was: 'int object' has no attribute 'zfill'
}
So, how can I call python inside the for loop in order to manipulate the information to print with Python instead than Ansible?
Note: I want to call python directly in the loop and I don't want to define variable in python and substitute them into the body of the mail.
the task of my playbook:
- name: Sending e-mail report
community.general.mail:
host: myhost
port: 25
sender: mymail
to:
- people#mail.it
subject: "mail of day {{ current_date }}"
subtype: html
body: |
<br>title
<br>text
{% for host in mylist %}
myhost-{{ '%03d' % hostvars[host]['number']|int }}
<br>
{% endfor %}
<br>text
<br>closure
SOLVED
Since the first time the error was raised by the use of bulit-in python str() function , while other elements of python syntax did not raise any error, I guessed python built-in functions cannot be interpreted by Ansible (still I don't understand why).
So I looked up for a way to do the data manipulation by using some python methods of the object, instead than a python function.
So instead of turning the int object into a string with str(my_object), I exploited the int python method .__str__().
So I substituted the upper line with
myhost-{{ hostvars[host].number.__str__().zfill(3) }}
and this time it worked.
Conclusion
This makes me think one cannot use python functions inside ansible {{ }} tags, but only python objects methods.
I'm trying to create a nbconvert (6.x) template that slightly modifies the default latex template.
I created a "no_header" template in <userprofile>\Miniconda3\share\jupyter\nbconvert\templates\no_header:
.
+-- no_header
| +-- conf.json
| +-- no_header.tex.j2
The conf.json contains:
{
"base_template": "latex",
"mimetypes": {
"text/latex": true,
"text/tex": true,
"application/pdf": true
}
}
The no_header.tex.j2 contains:
((*- extends 'latex' -*))
((*- block packages -*))
asdf
((* endblock packages *))
I took the block name packages from the style_jupyter.tex.j2. This section contains some usepackage commands.
I then created a simple notebook and tried using the template to convert it to tex via the command:
jupyter nbconvert --to=latex --template=no_header my_nb.ipynb
The command successfully creates the tex output - But it does not seem to use the template. The output is the exact same if I omit the template parameter to the cli call. Also, the string asdf is not present in the generated file, further indicating that the template was not activated.
When running the above command with --debug, the no_header template is listed under the 'template paths' listing. Also, when I misspelled the template name I got an error, so I think the call does find the template, but somehow does not use it.
What I tried so far:
All the tutorials online only describe the old template format (single files)
The documentation of nbconvert does not contain an mwe
For the approach described above, I followed this github issue.
Can anyone help me here?
The conf.json file is fine, but I think you need to call your entrypoint index.tex.j2. The name of the template is defined by the directory, not the .j2 file name.
Then in your no_header/index.tex.j2, you then specify which template you want to inherit from, e.g. borrowing from the standard latex article you start like this:
((=- Default to the notebook output style -=))
((*- if not cell_style is defined -*))
((* set cell_style = 'style_jupyter.tex.j2' *))
((*- endif -*))
((=- Inherit from the specified cell style. -=))
((* extends cell_style *))
((*- block docclass -*))
\documentclass[11pt]{article}
((*- endblock docclass -*))
and to customize the packages section, you then add as in the question:
((*- block packages -*))
asdf
((* endblock packages *))
Presumably you'll want to put a lot more in the "packages" block. If you want to add to certain blocks rather than override, include a super() call.
The default latex template directory has a number of files which add quite a lot of latex commands; you can track the inheritance chain (in the above example starting from style_jupyter.tex.j2) to see what all the different blocks are called so you can tweak them as needed (e.g. "margins").
I have an Airflow instance that does not translate Jinja variables. I have this code in my DAG.
print 'execution date is: ', ' {{ ds }} '
The above variable is printed literally.
INFO - Subtask: execution date is: {{ ds }}
Jinja2 is installed via pip (I am using Python 2.7). PYTHONPATH are set correctly because an import statement from the jinja module is processed in the same DAG without a problem.
from jinja2 import Environment
I am using airflow 1.8.0.
I am missing something but I am running out of clues.
Fixed. Silly me; I had a format() that prevented Jinja from taking over.
"{path} {{ ds }} ".format(path="the/path/to/spark/code")
Is there a way to change the Jinja2 root directory per-request on Flask? Right now I do:
app.jinja_loader = FileSystemLoader(template_directory)
but it seems to work only once per process (the process chooses the correct directory at first and then stays there, no matter how many changes I make)...
It turns out that a Jinja caching bug is preventing the correct template from loading, so disabling the cache works:
app.jinja_env.cache = None
You can try this:
app._get_current_object().jinja_loader = FileSystemLoader(template_directory)
Docs http://flask.pocoo.org/docs/api/#notes-on-proxies or http://werkzeug.pocoo.org/docs/local/#werkzeug.local.LocalProxy._get_current_object
I am trying to template-ize my Apache httpd configuration for deployment to different environments and I would like to use the Python language Cheetah application to do so. However, I am having difficulty with the command line cheetah program and I believe its a combination of my misunderstanding Cheetah along with a lack of documentation.
My goal is to have a single httpd.conf template file and substitute variables from an environment specific definition file.
httpd.tmpl:
Listen $HTTP_PORT
...
#if $ENABLE_HTTPS == true
<Virtual Host *:$HTTPS_PORT>
...
</VirtualHost>
#end if
production.env:
HTTP_PORT=34120
HTTPS_PORT=34121
ENABLE_HTTPS=true
What is the command line needed to fill this Cheetah template? I've used:
cheetah f --oext conf --debug httpd
But obviously prod.env is not read as an input file. Adding an #include to the top of my template file:
#include "prod.env"
And none of my names are found:
Cheetah.NameMapper.NotFound: cannot find 'APACHE_PORT'
This is not the ideal situation anyway, because I want the ability to specify the name/value mapping file on the command line for each invocation of cheetah.
Thanks!
EDIT: I am aware that I can write a python script to perform the file reading and then substitute using the Cheetah API. However, I'm looking for a way to use the command line to fill my template.
SOLVED
Thanks to the documentation link provided by #pyfunc I now understand how to accomplish this. The main issue is to supply --env on the cheetah command line which passes the current environment variables to cheetah. These environment variables must be exported first however.
Cheetah wraps each chunk of #include text inside a nested Template object.
Use
#include raw "prod.env"
also
#set global $HTTP_PORT="34120"
To include different env files, you will have too templatize that too.
Please look at the following for examples that should help you.
http://packages.python.org/Cheetah/dev_guide/output.html