Jinja not Translating Variables in Airflow DAGs - python

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")

Related

How can I call python directly inside Ansible playbook, in a for loop?

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.

Import error for templated queries in Python using JinjaSql

So, I'm trying to create SQL templates with certain parameters would change based on the call. I reviewed many other methods but I found the method using JinjaSql more suitable and readable for the requirement of my module.
I tried creating a class as below (code shortened) to create a templated list of queries.
from jinjasql import JinjaSql
j = JinjaSql(param_style='pyformat')
class QueryTemplate(object):
def highest_pp_team_score(self, tour_name, year):
params = {'tour_name': [], 'year': []}
params['tour_name'].append(tour_name)
params['year'].append(year)
template = """
SELECT
id.match_id,
id.inning,
id.team
FROM
innings_deliveries as id
WHERE
id.name LIKE {{ tour_name }}
AND YEAR(id.start_date) = {{ year }}
"""
query, bind_params = j.prepare_query(template, params)
return query % bind_params
... when I try and run, I get the below error. It's on the import itself.
ImportError: cannot import name 'Markup' from 'jinja2.utils'
After reading about the issue, I couldn't find any resolutions to my case but I did find a thread with similar issue. It needed me to add few lines to the import. Since, the original issue was related to flask, I couldn't implement it to my case.
This is an issue in the library you are using. It has been reported on their issue tracker already, see https://github.com/sripathikrishnan/jinjasql/issues/50
What you could do is to downgrade your Jinja version to the one before 3.1.0 that brought those breaking changes of removing Markup and escape.
If you do have a requirements.txt file to install your dependencies, this is as simple as adding a line in it like
jinja2<3.1.0
And redo a
pip install --requirements requirements.txt
If you don't have such a file but are installing your packages with pip, you could do
pip install --upgrade 'jinja2<3.1.0'

nbconvert 6: How to customize Latex template

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").

Ansible Tower - How to get a list of the environment variables

Within Tower there is a lot of options to add environment variables before execution. I have set some variables that get pulled into a python inventory script. However the script is responding with an error. I think the python code is not getting the values or the values are not in the correct format.
I would like to see how the environment variables are being exposed to the python script. Is there a way to get these added to the debug output in the job log?
The problem was I wasn't executing a playbook. I was executing a custom python inventory script and I need to be able to see how Ansible was loading the variables to be able to troubleshoot why the script wouldn't load the variables. I added some code to the python script to send me an email with the list of environmental variables. You can also write this to a file on the drive, but if you are using tower, you have to expose the folder location under the admin settings -> Jobs -> paths to expose. I decided it would be easier to just get an email while testing.
import smtplib
import datetime
import time
ts = time.time()
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
output = ""
output +=('Time Start {} \r\n '.format(st))
for a in os.environ:
output +=('Var: {} Value: {} \r\n'.format(a, os.getenv(a)))
def send_email(addr_from, addr_to, contents):
svr = smtplib.SMTP('smtp.mail.local', 25)
msg = 'Subject: Subject goes here.\n\n{0}'.format(contents)
svr.sendmail(addr_from, addr_to, msg)
send_email('addr_from#mail.com','addr_to#mail.com',output)
Here is a picture of the variables
Then here is a picture of the script.
But this didn't work. Here is the code that worked.
The problem was that when you query the environmental variable in python, if its a dictionary, it will return with single quotes and you have to convert that to double quotes and json.loads it to get it to load as a dictionary.
There is multiple problems solved with this. I hope this helps others needing to troubleshoot Ansible with Python.
Just use debug along with the 'env' lookup.Below home is the environment variable.
- name: Show env variable
debug:
msg: "{{ lookup('env','HOME') }}"
https://docs.ansible.com/ansible/latest/plugins/lookup/env.html

Defining os_path in ansible jinja template

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.

Categories

Resources