Ansible write variables into YAML file - python

I have a specific ansible variable structure that I want to get from the vault into a yaml file on my hosts.
Lets assume a structure like this:
secrets:
psp1:
username: this
password: that
secret_key: 123
...
I need something like a "generic" template to output whatever "secrets" contains at the moment, since the content changes almost completely based on the current environment.
The easiest solution I can think of is to output the whole structure in an template like this:
# config/secrets.yml
{{ secrets | to_yaml }}
But the jinja2 to_yaml filter does only "yamlify" the first level, deeper nestings are outputted in json.
Can I work around that problem somehow? Is there an easier way to achieve what I want?
Thanks for any help!

As jwodder said, it's valid.
If you're using to_yaml (instead of to_nice_yaml) you have fairly old install of ansible, it's time to upgrade.
Use to_nice_yaml
It's possible to pass your own kwargs to filter functions, which usually pass them on to underlying python module call. Like this one for your case. So something like:
{{ secrets | to_nice_yaml( width=50, explicit_start=True, explicit_end=True) }}
only catch is you can't override indent=4,* allow_unicode=True, default_flow_style=False
* Note that indent can now be overridden, at least as of Ansible 2.2.0 (I use it to indent 2 spaces to follow coding standards for one project).
Better documentation for to_nice_yaml can be found here.

Related

Get list of templates with pyvmomi Vmware vCenter

I would like to list all template available un my vCenter.
I dont know how do this. I try to get all object in content.rootFolder and compare if it's a virtualmachine or not. But I can't find templates.
I see i can do this:
container = content.viewManager.CreateContainerView(
content.rootFolder, [[vim.VirtualMachine]], True)
but nothing,
thanks for ur help. With that, I suppose I am able to find a specific template.
You are looking for vm.config.template if that property is true the VirtualMachine is marked as a template. You should be using a property collector to make your code fast. Take a look at this sample. There is a list of vm_properties starting on line 38. You could remove them and just use "name" and "config.template" if those are the only things you care about. Then modify the printing at the bottom.. add a simple if vm["config.template"]: xxx so it only printed if that property was set.. something like that.

How can I use Django built-in filters with Jinja2 using Appengine SDK?

I've tried several different ways a while ago, each of them gave a different exception, so I gave up and decided to manually write filters when I need them. But I'm missing the native escapejs and other useful but simple filters.
There are several related questions and answers, but as far as I see none of them gives a seamless way to implement this. I guess the main problem is that django filters routines are tied too much to the django environment.
Please answer only if you managed to use built-in django filters in the Appengine SDK environment, from my experience it's harder compared to a normal environment, as Appengine environment is limited
Template tags in the Django template engine are simple functions that accept values and parameters. They can all be accessed directly in the source code.
This is output from IPython:
In [173]: from django.template.defaultfilters import date
In [174]: date??
Type: function
String Form:<function date at 0xa2935f0>
File: /usr/local/python/thor/lib/python2.7/site-packages/django/template/defaultfilters.py
Definition: date(value, arg=None)
Source:
#register.filter(expects_localtime=True, is_safe=False)
def date(value, arg=None):
"""Formats a date according to the given format."""
if not value:
return u''
if arg is None:
arg = settings.DATE_FORMAT
try:
return formats.date_format(value, arg)
except AttributeError:
try:
return format(value, arg)
except AttributeError:
return ''
Most of the Django-specific magic resides in the decorator (register.filter) and in the way that the language resolves calls when you type {% load <template library> %} in your template. Look for the definitions in <module>.templatetags modules. Built-ins are located in django.template.defaulttags and django.template.defaultfilters.
If Jinja2 has a way to define new template filters (which it probably does), then you could simply wrap handmade template filters to actual Django functions.
So basically, just create Jinja2 filters that point to the actual Django function definitions.
Edit:
If you do not have access to the actual Django functions, just copy-paste the source code and remove or adapt Django-specific stuff.
The escapejs filter is actually a call to this function in django.utils.html:
_base_js_escapes = (
('\\', r'\u005C'),
('\'', r'\u0027'),
('"', r'\u0022'),
('>', r'\u003E'),
('<', r'\u003C'),
('&', r'\u0026'),
('=', r'\u003D'),
('-', r'\u002D'),
(';', r'\u003B'),
(u'\u2028', r'\u2028'),
(u'\u2029', r'\u2029')
)
# Escape every ASCII character with a value less than 32.
_js_escapes = (_base_js_escapes +
tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
def escapejs(value):
"""Hex encodes characters for use in JavaScript strings."""
for bad, good in _js_escapes:
value = mark_safe(force_unicode(value).replace(bad, good))
return value
I alluded to this in my comment, but I'll be more specific here since I have more space. Django is an end-to-end web application framework, which happens to include its own template language, that for lack of a better term is just called the "Django template language". All the template tags and filters in the docs are specific to that language.
If you choose to use Jinja2, you choose to use that template language's structures to the exclusion of Django's. (Obviously the model and view stuff is a separate layer, but in principle, those could be swapped too--it's all loosely coupled.) So the Django docs for templating are no good to you in that case. If you want to format a float in Jinja2, it looks like you need to use the format filter, according to the Jinja docs.
Without more info, I really can't say what's causing your ImportError, but floatformat is not going to work in a Jinja2 template, so maybe that has something to do with it.

Python routes not working for non-static URLs

I'm trying to write a unit test for an old pylons 0.9.7 application.
The issue we have is that it's very easy to accidentally hard-code URL
paths in our jinja2 templates, which works fine until someone hosts
our application at a different prefix (i.e.- hosts it at
http://localhost/foo/ instead of just http://localhost/). I'm
doing this using the default "functional test" setup that paste
created for me. I query every controller action, and pass in a custom
SCRIPT_NAME like so:
response = self.app.get('/some/url/path',
extra_environ={'SCRIPT_NAME' : '/custom_prefix'})
I then use beautifulsoup to parse the document, iterating over all the
tags that have an href attribute or a src attribute, and ensure
that it starts with '/custom_prefix'.
Here's where things get odd: When we pass an absolute path in to
pylons.url (which is actually a routes.util.URLGenerator)in our templates like this:
{{ h.stylesheet_link(h.url('/css/style.css')) }}
...it works perfectly. However, when we call pylons.url with keyword
arguments like this:
{{ h.link_to('Home', h.url(controller='person', action='home')) }}
...the prefix is not inserted. However, the url() function works
correctly when running this correctly (i.e.- using mod_wsgi or
pastedeploy) with a non-empty SCRIPT_NAME.
I guess that I'm missing a critical step, but I can't think what it is.

store html templates in docstrings?

I am using Flask to write a web service for an internal app here at my work. Many of the web services URI's return HTML partials, and I am trying to figure out a clean way to store the html template strings. I don't want to put the template strings in separate files, since they are usually only a few lines long and I don't want to have 20 template files that each have 3 lines in them. I was thinking about defining a function's html template string in the docstring of the function, as I feel like that would serve multiple purposes. It would serve as documentation, basically saying "this is what I output", as well as keeping me from having to store 3-line templates strings in separate files. Here is what I am talking about:
#app.route('/path/to/my/resource/<int:_id>')
def some_resource(_id):
"""
<select id="resource-{{ resource.id }}" class="resource">
{% for choice in choices %}
<option id="choice-{{ choice.id }}" value="{{ choice.id }}">
{{ choice.text }}
</option>
{% endfor %}
</select>
"""
# retrieving resource, etc...
return render_template_string(some_resource.__doc__, **kwargs)
I don't know whether this would be a nightmare to maintain or not...any thoughts?
I think its a bad plan.
Docstrings are for documentation, the template is not documentation. Documentation is supposed to describe what the function is being used for. An HTML template is a poor substitute for that.
You can use multi-line strings to hold your template, and thats probably a good idea. You don't gain anything by making them docstrings.
It's certainly an interesting idea, and following the example of doctest, it's not entirely unheard of to put functionally-useful things in your docstrings instead of just text. The obvious drawback is that then there's no documentation in the docstring. Now, this may or may not be a huge problem if the methods are not something that programmers will likely need documentation on via help() (or by auto-generated docs using the docstrings).
However, why not either:
just use a local string variable - the downside would be that you can't get at it via __doc__ from outside the scope of the function
if it's just used that once, just put it into the render_template_string call - same drawbacks as #1, but also doesn't apply if it's used more than once
create another decorator that takes this string as an argument - especially if it just follows the pattern above where you're just using it the once and you're always doing the same call at the end, this would allow you to pull it out of that method
In some templating engines, if an object has a __html__ method, it's output is treated as a safe (escaped) string.
def fn(x):
bla = x
fn.__html__ = lambda : '''
<h1>Headline</h1>
<p>lorem ipsum</p>
'''

Jinja2: Looking for a View-Helper

I'am new to the Jinja2 template engine. Is there something like the view-helpers from Zend Framework? Can i create simple functions and reuse them all over all my template-files?
Something like this?
#somewhere in my python code:
def nice_demo_function(message):
""""return a simple message"""
return message
So i can to use that:
<!-- now in my template-file -->
{% nice_demo_function('yes, this works great!') %}
There are a number of ways you can expose helper functions to your templates. You could define them using macros, and then import them into templates that use them. You could add functions to the globals attribute of your Template objects, or pass them to the render() method. You could subclass Template to do the same without having to repeat yourself each time. If you want to get really fancy, you could look into writing extensions as well (but you probably don't need to go that deep).
At some point you will have created a Jinja2 environment. The environment has an attribute on it called filters which is a dict that maps names to functions. So what you want to do is:
def my_helper(value):
return "-~*#--- %s ---#*~-" % value
env = Jinja2.Environment(...)
env.filters['my_helper'] = my_helper
Now in your template you can do:
<p>The winner is {{ winner | my_helper }}</p>
And your function will be called with the value of the variable, in this case winner. If you are using Pylons, this all happens in config/environment.py.

Categories