Ansible jinja2 template from json file - templates

I have a json host_names.json file with the structure of
{
"host1": "run on host 1",
"host2": "run on host 2",
"host3": "run on host 3"
}
In the same directory, I have a playbook run.yml
---
- name: Run this
connection: local
tasks:
- name: Template
src: "template.j2"
dest: "/my_dest/my_file.txt
I'd like the template to look like this:
#########
# host1 #
#########
run on host 1
end
#########
# host2 #
#########
run on host 2
end
#########
# host3 #
#########
run on host 3
end
How would my template look for this? This is what I currently have
{% for a, b in host_names %}
###########
# {{ a }} #
###########
{{ b }}
end
{% endfor %}

Got it, was just
{% for a, b in host_names.iteritems %}
##########
# {{a}} #
##########
{{ b }}
end
{% endfor %}

Related

Ansible regex with assert operator

I have the following playbook that is trying to assert that a user prompt variable of NX-OS image equals the ansible_net_image captured from a Nexus switch. This is driving me crazy as to the correct format for the test condition.
---
- name: Upgrade NX-OS on switch with pre-checks to load image as required
hosts: nexus-7000
gather_facts: no
vars_prompt:
- name: NX_OS_Upgrade_Version
prompt: "Please enter NX-OS version to upgrade too - ensure that the filename is as used by boot variable"
private: no
##############################################################################
## Start of task execution
##############################################################################
tasks:
- name: Gather IOS configuration and software facts from switches
nxos_facts:
gather_subset: "!hardware"
################################################################################
## Display running image version to terminal
################################################################################
- debug:
msg: "{{ NX_OS_Upgrade_Version }}"
- assert:
that:
- "ansible_net_image | regex:/^bootflash:\\/\\/\\/(.*) == NX_OS_Upgrade_Version"
Upon execution this error is displayed.
fatal: [switcha]: FAILED! => {"msg": "The conditional check 'ansible_net_image | regex:/^bootflash:\/\/\/(.) == NX_OS_Upgrade_Version' failed. The error was: template error while templating string: expected token 'end of statement block', got '/'. String: {% if ansible_net_image | regex:/^bootflash:\/\/\/(.) == NX_OS_Upgrade_Version %} True {% else %} False {% endif %}"}
fatal: [switchb]: FAILED! => {"msg": "The conditional check 'ansible_net_image | regex:/^bootflash:\/\/\/(.) == NX_OS_Upgrade_Version' failed. The error was: template error while templating string: expected token 'end of statement block', got '/'. String: {% if ansible_net_image | regex:/^bootflash:\/\/\/(.) == NX_OS_Upgrade_Version %} True {% else %} False {% endif %}"}
The regex has been tested, but I am struggling to get the correct syntax for the Ansible play.
It would be great if someone could show me what I have got wrong.
Use 7.3.2. Single-Quoted Style to create regex.
See Testing strings.
For example
- hosts: localhost
vars:
ansible_net_image: 'bootflash:///n5000-uk9-kickstart.5.1.3.N2.1b.bin'
NX_OS_Upgrade_Version1: 'n5000-uk9-kickstart.5.1.3.N2.1b'
my_regex1: '^bootflash:///{{ NX_OS_Upgrade_Version1 }}.bin'
NX_OS_Upgrade_Version2: 'n5000-uk9-kickstart.5.1.4.N2.1b'
my_regex2: '^bootflash:///{{ NX_OS_Upgrade_Version2 }}.bin'
tasks:
- assert:
that: ansible_net_image is match(my_regex1)
success_msg: "Image is version {{ NX_OS_Upgrade_Version1 }}"
fail_msg: "Image is NOT version {{ NX_OS_Upgrade_Version1 }}"
- assert:
that: ansible_net_image is match(my_regex2)
success_msg: "Image is version {{ NX_OS_Upgrade_Version2 }}"
fail_msg: "Image is NOT version {{ NX_OS_Upgrade_Version2 }}"
gives
ok: [localhost] => {
"changed": false,
"msg": "Image is version n5000-uk9-kickstart.5.1.3.N2.1b"
}
fatal: [localhost]: FAILED! => {
"assertion": "ansible_net_image is match(my_regex2)",
"changed": false,
"evaluated_to": false,
"msg": "Image is NOT version n5000-uk9-kickstart.5.1.4.N2.1b"
}

link task depending on content

I have 3 tasks..
first task checks if a file contains <ip> <hostname> pattern
second task adds a line if the sought after string is not present.
third task corrects the line if it is bad.
the 3 tasks run well independently but I want to run them together somehow linked.
I have the following playbook using as model /etc/hosts.
---
- name: check hosts playbook
hosts: centos
tasks:
- name: check whether a line in the form of '<ip> <hostname>' exists
lineinfile:
path: /var/tmp/hosts
regexp: '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s\w+'
state: absent
check_mode: true
register: line_exists
- name: append_host_file
lineinfile:
path: /var/tmp/hosts
insertafter: '^(127\.0\.0\.1|)(?:\d{1,3}\.){3}\d{1,3}'
line: '{{ ansible_default_ipv4.address }} {{ansible_hostname }}'
backup: yes
when: not line_exists.changed
- name: correct_hosts_file
lineinfile:
path: /var/tmp/hosts
regexp: '^(?!{{ ansible_default_ipv4.address }}\s{{ ansible_hostname }})(?:\d{1,3}\.){3}\d{1,3}\s\w+'
line: '{{ ansible_default_ipv4.address }} {{ansible_hostname }}'
when: line_exists.changed
the issue i have is the correct task is running when the line is correct.. so i need to use some other sort of criteria to prevent it from running when the line in the file is correct...if the line in the file is wrong it work because it replaces it.
It's a common problem with lineinfile, it's not that useful as it looks.
My advice: load file content into variable (- command: cat /etc/hosts), register it (register: old_hosts) than iterate over each line of that variable in a template.
- name: get hosts
command: cat /etc/hosts
register: old_hosts
- name: write hosts
template:
src: hosts.j2
dest: /etc/hosts
hosts.j2:
{% for line in old_hosts.stdout_lines %}
{% if line (....) %}
...
{% endif %}
{% endfor %}

ansible parse text string from stdout

My problem is with ansible and parsing stdout. I need to capture the stdout from an ansible play and parse this output for a specific substring within stdout and save into a var. My specific use case is below
- shell: "vault.sh --keystore EAP_HOME/vault/vault.keystore |
--keystore-password vault22 --alias vault --vault-block |
vb --attribute password --sec-attr 0penS3sam3 --enc-dir |
EAP_HOME/vault/ --iteration 120 --salt 1234abcd"
register: results
become: true
This generates an output with the following line, the goal is to capture the masked key that jboss vault generates and save that in an ansible var so I can use it to configure the standalone.xml template:
vault-option name="KEYSTORE_PASSWORD" value="MASK-5dOaAVafCSd"/>
I need a way parse this string with possibly regex and save the "MASK-5dOaAVafCSd" substring into an ansible var using set_facts module or any other ansible module.
Currently my code looks like this
#example stdout
results: vault-option name=\"KEYSTORE_PASSWORD\" value=\"MASK-5dOaAVafCSd\"/>
- name: JBOSS_VAULT:define keystore password masked value variable
set_fact:
masked_value: |
"{{ results.stdout |
regex_replace('^.+(MASK-.+?)\\.+','\\\1') }}"
This code is defining masked_value as the results.stdout, not the expected capture group.
You are very close. I advice you to use regex101.com to test regular expressions.
Here is my solution:
---
- hosts: localhost
gather_facts: no
tasks:
- shell: echo 'vault-option name="KEYSTORE_PASSWORD" value="MASK-5dOaAVafCSd"'
register: results
- set_fact:
myvalue: "{{ results.stdout | regex_search(regexp,'\\1') }}"
vars:
regexp: 'value=\"([^"]+)'
- debug:
var: myvalue
result:
ok: [localhost] => {
"myvalue": [
"MASK-5dOaAVafCSd"
]
}
Update:
regex_search returns a list of found matches, so to get only first one use:
{{ results.stdout | regex_search(regexp,'\\1') | first }}
The above solution worked for me, however I had to do some extra logic to filter shell command output to get to the line which contains following
<vault-option name="KEYSTORE_PASSWORD" value="MASK-6qcNdkIprlA"/>
because vault command output has many lines in it. Once this line is captured, the solution given by Konstantin works just fine. Below is the whole thing that needs to done in one place.
- name: Creating jboss vault
shell: |
{{ baseDir }}/bin/vault.sh -e {{ vaultDir }} -k {{ keystoreURL }} -p {{ keystorePassword }} \
-s {{ keystoreSalt }} -i {{ iterationCount }} -v {{ keystoreAlias }} -b {{ vaultBlock }} \
-a {{ attributeName }} -x {{ attributeValue }}
register: vaultResult
- set_fact:
jbossKeystorePassword: "{{ item | regex_search('value=\"([^\"]+)','\\1') | first }}"
when: item | trim | match('.*KEYSTORE_PASSWORD.*')
with_items:
- "{{ vaultResult.stdout_lines }}"
- debug:
var: jbossKeystorePassword
Be sure to replace all variables with your values in above vault.sh command.

Consul-template if else condition

I have below consul-template.
{{ range service "mysql_slave.mysql" "any" }}
host_name {{.Node}}
command check_nrpe!check_procs_1
{{end}}
I want to add if my hostname match "database-1" then command "check_procs_1" and others command "check_procs_2"
output
host_name node_server
command check_nrpe!check_procs_2
host_name database-1
command check_nrpe!check_procs_1
host_name webserver
command check_nrpe!check_procs_2
To solve this issue we can use below fix.
{{ range service "mysql_slave.mysql" "any" }}
{{ if eq .Node "database-1" }}
host_name {{.Node}}
command check_nrpe!check_procs_1
{{else}}
host_name {{.Node}}
command check_nrpe!check_procs_2
{{end}}
{{end}}

Empty docstrings when running django-piston docs under nginx

I'm using django-piston for my REST json api, and I have it all set up for documentation through pistons built in generate_doc function. Under the django runserver, it works great. The template that loops over the doc objects successfully lists the docstrings for both the class and for each method.
When I serve the site via nginx and uwsgi, the docstrings are empty. At first I thought this was a problem with the django markup filter and using restructuredtext formatting, but when I turned that off and just simply tried to see the raw docstring values in the template, they are None.
I don't see any issues in the logs, and I can't understand why nginx/uwsgi is the factor here, but honestly it does work great over the dev runserver. I'm kind of stuck on how to start debugging this through nginx/uwsgi. Has anyone run into this situation or have a suggestion of where I can start to look?
My doc view is pretty simple:
views.py
def ApiDoc(request):
docs = [
generate_doc(handlers.UsersHandler),
generate_doc(handlers.CategoryHandler),
]
c = {
'docs': docs,
'model': 'Users'
}
return render_to_response("api/docs.html", c, RequestContext(request))
And my template is almost identical to the stock piston template:
api/docs.html
{% load markup %}
...
{% for doc in docs %}
<h5>top</h5>
<h3><a id="{{doc.name}}">{{ doc.name|cut:"Handler" }}:</a></h3>
<p>
{{ doc.doc|default:""|restructuredtext }}
</p>
...
{% for method in doc.get_all_methods %}
{% if method.http_name in doc.allowed_methods %}
<dt><a id="{{doc.name}}_{{method.http_name}}">request</a> <i>{{ method.http_name }}</i></dt>
{% if method.doc %}
<dd>
{{ method.doc|default:""|restructuredtext }}
<dd>
{% endif %}
The rendered result of this template under nginx would be that doc.doc and method.doc are None. I have tried removing the filter and just checking the raw value to confirm this.
I'm guessing the problem would have to be somewhere in the uwsgi layer, and its environment. Im running uwsgi with a config like this:
/etc/init/uwsgi.conf
description "uWSGI starter"
start on (local-filesystems
and runlevel [2345])
stop on runlevel [016]
respawn
exec /usr/sbin/uwsgi \
--uid www-data \
--socket /opt/run/uwsgi.sock \
--master \
--logto /opt/log/uwsgi_access.log \
--logdate \
--optimize 2 \
--processes 4 \
--harakiri 120 \
--post-buffering 8192 \
--buffer-size 8192 \
--vhost \
--no-site
And my nginx server entry location snippet looks like this:
sites-enabled/mysite.com
server {
listen 80;
server_name www.mysite.com mysite.com;
set $home /var/www/mysite.com/projects/mysite;
set $pyhome /var/www/mysite.com/env/mysite;
root $home;
...
location ~ ^/(admin|api)/ {
include uwsgi_params;
uwsgi_pass uwsgi_main;
uwsgi_param UWSGI_CHDIR $home;
uwsgi_param UWSGI_SCRIPT wsgi_app;
uwsgi_param UWSGI_PYHOME $pyhome;
expires epoch;
}
...
}
Edit: Configuration Info
Server: Ubuntu 11.04
uWSGI version 1.0
nginx version: nginx/1.0.11
django non-rel 1.3.1
django-piston latest pypi 0.2.3
python 2.7
uWSGI is starting up the interpreter in way equivalent to -OO option to Python command line. This second level of optimisation removes doc strings.
-OO : remove doc-strings in addition to the -O optimizations
Change:
--optimize 2
to:
--optimize 1