how to reference variable variable in jinja2 template - django-templates

In one of my ansible roles I would like to set up a basic network/interfaces stanza, like this:
auto eth1
ifaces eth1 inet dhcp
dns-nameserver {{ ansible_eth1.ipv4.address }}
dns-search maas
I have variables, and I create the stanza with the jinja2 template:
auto {{ iface }}
ifaces {{ iface}} inet dhcp
dns-nameserver {{ ansible_{{ iface }}.ipv4.address }}
dns-search maas
Can I reference a variable variable in a template? I also tried creating a variable in the ansible yaml, like nserver: ansible_{{iface}}.ipv4.address, that didn't work either!

You can use built-in hostvars dict variable to reference variables of host.
auto {{ iface }}
iface {{ iface }} inet dhcp
dns-nameserver {{ hostvars[inventory_hostname]['ansible_'+ iface]['ipv4']['address'] }}
dns-search maas
inventory_hostname is name of current host as known by Ansible.

Related

How to avoid passing sensitive data through values.yml (bitnami chart)

I am trying to deploy a rabbitmq-cluster on minikube based on the chart of Bitnami and facing the following challenge: When I try to pass the credentials using a secret I am getting this error: couldn't find key rabbitmq-password in Secret default/rabbit
I created a secret called rabbit in my minikube cluster and tryed to set the values-file like this:
auth:
# username: user
# password: pass
existingPasswordSecret: rabbit
and also like this:
auth:
username: ${RABBITMQ_USERNAME}
password: ${RABBITMQ_PASSWORD}
existingPasswordSecret: rabbit
This is my secret-file:
apiVersion: v1
kind: Secret
metadata:
name: rabbit
type: Opaque
data:
RABBITMQ_USERNAME: dXNlcg== (bitnami variable)
RABBITMQ_PASSWORD: cGFzcw== (bitnami variable)
This is the default secret of the chart (I am installing the chart using helm install rabbitmq -f rabbitmq/values.yml bitnami/rabbitmq):
apiVersion: v1
kind: Secret
metadata:
name: {{ include "rabbitmq.fullname" . }}
namespace: {{ .Release.Namespace | quote }}
labels: {{- include "common.labels.standard" . | nindent 4 }}
type: Opaque
data:
{{- if not .Values.auth.existingPasswordSecret }}
{{- if .Values.auth.password }}
rabbitmq-password: {{ .Values.auth.password | b64enc | quote }}
{{- else }}
rabbitmq-password: {{ randAlphaNum 10 | b64enc | quote }}
{{- end }}
{{- end }}
The error message is telling you that you are missing the rabbitmq-password key in your secret:
couldn't find key rabbitmq-password in Secret default/rabbit
If we take a look at your secret, we can see you are providing two keys (RABBITMQ_USERNAME and RABBITMQ_PASSWORD), but not the rabbitmq-password key it expects:
apiVersion: v1
kind: Secret
metadata:
name: rabbit
type: Opaque
data:
RABBITMQ_USERNAME: dXNlcg== (bitnami variable)
RABBITMQ_PASSWORD: cGFzcw== (bitnami variable)
Knowing this, you have to provide your password using rabbitmq-password instead of RABBITMQ_PASSWORD. The chart does not provide support for passing the user as a secret, tho. Your secret should look like this:
apiVersion: v1
kind: Secret
metadata:
name: rabbit
type: Opaque
data:
rabbitmq-password: cGFzcw== (bitnami variable)

gcloud deployment-manager undefined properties: UndefinedError: 'properties' is undefined

There is sample code here that uses the following code snippet to handle undefined properties.
{% if properties["cidr"] is defined %}
{% set cidr = properties["cidr"] %}
{% else %}
{% set cidr = "10.10.0.0/16" %}
{% endif %}
github deployment-manager example
However, when I attempt to use similar code:
{% if properties['prod'] is defined %}
{% set machine_type = 'n1-highmem-8' %}
{% set num_nodes = 3 %}
{% else %}
{% set machine_type = 'g1-small' %}
{% set num_nodes = 1 %}
{% endif %}
and deploy as follows:
gcloud deployment-manager deployments create xxx --template kubernetes.jinja --automatic-rollback-on-error --preview
I get the following error:
- code: MANIFEST_EXPANSION_USER_ERROR location: /deployments/xxx/manifests/manifest-1597981115450 message: |-
Manifest expansion encountered the following errors: Exception in kubernetes.jinja
Traceback (most recent call last):
return template.render(resource)
return self.environment.handle_exception(exc_info, True)
reraise(exc_type, exc_value, tb)
File "<template>", line 19, in top-level template code
return obj[argument]
UndefinedError: 'properties' is undefined
Resource: kubernetes.jinja Resource: config
When I deploy with properties it works.
gcloud deployment-manager deployments create xxx --template kubernetes.jinja --automatic-rollback-on-error --preview --properties prod:false
How can I setup a jinja script to have default values and/or detect missing properties without throwing an exception?
UPDATE:
Adding ANY property, even a different one seems to be enough to have the script execute. It appears the properties attribute is COMPLETELY missing by default!
gcloud deployment-manager deployments create xxx --template kubernetes.jinja --automatic-rollback-on-error --preview --properties adsfsdfsdf:Asdfasdfasdf
You need to define properties either in the config that uses the template or when deploying from the command line.
See: https://cloud.google.com/deployment-manager/docs/configuration/templates/define-template-properties
E.g.
gcloud deployment-manager deployments create xxx \
--template=kubernetes.jinja \
--properties=prod:...

nornir napalm jinja Template Issue

Jinja Template Issue when using napalm function within nornir framework.
updated: My hosts are Cisco IOS devices.
I am running this nornir Jinja template script in a python3.6 virtualenv. I have other simple nornir and napalm code running fine, which makes we suspect the issue is related to jinja2 template function i am trying to use.
The error i am receiving is below. Can anyone assist me with spotting the problem?
working nornir script w/ napalm function - Example showing working environment
from nornir.core import InitNornir
from nornir.plugins.tasks import text
from nornir.plugins.tasks.networking import napalm_get, napalm_configure
from nornir.plugins.functions.text import print_title, print_result
from nornir.core.exceptions import NornirExecutionError
import logging
nr = InitNornir(config_file="config.yaml", dry_run=True)
ctil_net = nr.filter(site="ctil", type="network_device")
core = nr.filter(role="core", type="network_device")
results_napalm_get = nr.run(
task=napalm_get, getters=["facts", "interfaces"]
)
print_result(results_napalm_get)
Nornir script causing error:
from nornir.core import InitNornir
from nornir.plugins.tasks import text
from nornir.plugins.tasks.networking import napalm_get, napalm_configure
from nornir.plugins.functions.text import print_title, print_result
from nornir.core.exceptions import NornirExecutionError
import logging
nr = InitNornir(config_file="config.yaml", dry_run=True)
ctil_net = nr.filter(site="ctil", type="network_device")
core = nr.filter(role="core", type="network_device")
def basic_configuration(task):
# Transform inventory data to configuration via a template file
r = task.run(task=text.template_file,
name="Base Template Configuration",
template="base.j2", ## modified
path=f"templates",
severity_level=logging.DEBUG)
# Save the compiled configuration into a host variable
task.host["config"] = r.result
print (r.result)
# Deploy that configuration to the device using NAPALM
task.run(task=networking.napalm_configure,
name="Loading Configuration on the device",
replace=False,
configuration=task.host["config"],
severity_level=logging.INFO)
try:
print_title("Playbook to configure the network")
result = core.run(task=basic_configuration)
print_result(result)
except NornirExecutionError:
print("ERROR!!!")
config.yaml
num_workers: 100
inventory: nornir.plugins.inventory.simple.SimpleInventory
SimpleInventory:
host_file: "inventory/hosts.yaml"
group_file: "inventory/groups.yaml"
base.j2 (template file)
hostname {{ system.hostname }}
ip domain-name {{ site }}.{{ domain }}
base.j2 (template file) - Alt version (same exact error msg / result
hostname {{ host.name }}
ip domain-name {{ site }}.{{ domain }}
Hosts.yaml
switch101:
nornir_host: 192.168.2.101
site: ctil
role: core
groups:
- lab
nornir_nos: ios
type: network_device
switch007:
nornir_host: 192.168.2.7
site: ctil
role: access
groups:
- production
nornir_nos: ios
type: network_device
error output when I run:
$ python adv-nornir-example.py
**** Playbook to configure the network *****************************************
basic_configuration*************************************************************
* switch101 ** changed : False *************************************************
vvvv basic_configuration ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ERROR
Subtask: Base Template Configuration (failed)
---- Base Template Configuration ** changed : False ---------------------------- ERROR
Traceback (most recent call last):
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/nornir/core/task.py", line 62, in start
r = self.task(self, **self.params)
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/nornir/plugins/tasks/text/template_file.py", line 26, in template_file
**merged
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/nornir/core/helpers/jinja_helper.py", line 11, in render_from_file
return template.render(**kwargs)
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/jinja2/asyncsupport.py", line 76, in render
return original_render(self, *args, **kwargs)
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/jinja2/environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/jinja2/_compat.py", line 37, in reraise
raise value.with_traceback(tb)
File "templates/base.j2", line 2, in top-level template code
hostname {{ system.hostname }}
File "/home/melshman/projects/virtualenv/nornir/lib/python3.6/site-packages/jinja2/environment.py", line 430, in getattr
return getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'system' is undefined
^^^^ END basic_configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You are not passing system to the template. I think what you are trying to do in your template is:
hostname {{ host.name }}
ip domain-name {{ site }}.{{ domain }}
Basically the template, unless you add extra kwargs, is going to have access to the host itself via the host variable and to all of the host attributes specified in the inventory.

Consul-Template returns empty map?

Hi everyone,
I am trying to fetch a client token from approle auth method in vault. I have configured consul-template that it gets the role-id and the secret-id then, uses them to get the client_token at auth/approle/login end point. What is really weird is that first two steps are successfully executed and returned the data, however, getting the client_token is the struggle here. I analyzed the requests using wireshark and checked the response for the request that asks for the client_token, and it shows clearly the json result with the client_token included. But consul template does recognize the return and gives me this result:
{322a47b9-bf23-193d-8117-228637253fde 0 false map[] [] 0xc42001cf50 <nil>}.
The same way is used to request the secret-id but consul-template has successfully returned it and has recognized the json object. Isn't that weird?!
You can find the consul template below:
{{define "token" }}
{{ with secret "auth/approle/role/python-role/role-id" }}{{ $role:= (print "role_id= " .Data.role_id) }}
{{ with secret "auth/approle/role/python-role/secret-id" "role_name= python-role" }}{{ $secret:= (print "secret_id= " .Data.secret_id) }}
{{- with secret "auth/approle/login/" $role $secret -}}{{ . }}{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{template "token"}}
Also, below is the wireshark trace that I used to check that the request went right:
Does anyone have an idea?
Thanks in advance.

How to use when condition in Ansible?

I cannot figure out this Ansible task
i run my playbook ansible-playbook play.yml -e proxyHost=$proxyHost -e proxyPort=$proxyPort
- name: Set proxy when provided
set_fact: proxyproperty=" -Dhttp.proxyHost={{ proxyHost }} -Dhttp.proxyPort={{ proxyPort }} -Dhttps.proxyHost={{ proxyHost }} -Dhttps.proxyPort={{ proxyPort }} -Dhttp.nonProxyHosts=localhost|127.0.0.1|{{ ip }}|{{ fqdn }}|{{ hostName }}"
when: proxyHost is defined
So why is it when i have not set $ProxyHost this ansible task is still being triggered? What am i missing?
Python (hence Ansible) differentiates between an undefined variable and a variable with an empty value.
You define the proxyHost variable in Ansible, but in case when $proxyHost is undefined in shell/environment, you assign proxyHost an empty value.
You need, for example, to compare it to an empty string:
when: proxyHost != ''