Ansible Nested variables and Jinja2 templates - ansible

I'm trying to figure out why my jinja2 template (and ansible for that matter) cannot find my variables in my inventory file.
Here is my inventory file:
all:
hosts:
test05:
ansible_host: 192.168.x.x
filebeat:
version: 7.15.2
applog:
- title: Separate Application Log Path with Tags
type: log
paths:
- /var/log/something/moresomething/current
tags: '["something", "application"]'
- title: Separate Application Log Path, with Tags, and "decode_json_fields" processor.
type: log
paths:
- /var/log/something/moresomething/blah-shell.log
tags: ["application", "something"]
fields: ["message"]
depth: 2
- title: Separate Application Log Path, with Tags, and Multiline fields
type: log
paths:
- /var/log/something/moresomething/production.log
tags: ["application", "something"]
multiline_type: pattern
multiline_patern: 'Started'
multiline_negate: true
multiline_match: after
Then attempting to get the first title. I'm doing the following:
- name: debugging
debug:
var: filebeat.applog.title
when I run this I end up getting filebeat.applog.title: VARIABLE IS NOT DEFINED! which I think is good since it doesn't know what title I want. So changing this to
- name: debugging
debug:
var: filebeat.applog.0.title
I end up getting what I want filebeat.applog.0.title: Separate Application Log Path with Tags. However, how do I use this in a jinja2 template?
I have the following for a template, I know I need to update this to loop through the different items in my inventory. That's a different problem on how to loop through this.
title: {{ filebeat.applog.title }}
- type: {{ filebeat.applog.type }}
enabled: true
paths:
- {{ filebeat.applog.path }}
tags: {{ filebeat.applog.tags }}
{% if filebeat.applog.fields is defined %}
processors:
- decode_json_fields:
fields: {{ filebeat.applog.fields }}
max_depth: {{ filebeat.applog.depth }}
target: {{ filebeat.applog.target | default "" }}
{% endif %}
{% if filebeat.applog.multiline_pattern is defined %}
multiline.type: {{ filebeat.applog.multiline_type }}
multiline.pattern: {{ filebeat.applog.multiline_pattern }}
multiline.negate: {{ filebeat.applog.multiline_negate }}
multiline.match: {{ filebeat.applog.multiline_match }}
{% endif %}
each time I get the following, even when I do use {{ filebeat.applog.0.logtitle }} in the template:
fatal: [test05]: FAILED! => changed=false
msg: |-
AnsibleError: template error while templating string: expected token 'end of print statement', got 'string'. String: title: {{ filebeat.applog.title }}
- type: {{ filebeat.applog.type }}
enabled: true
paths:
- {{ filebeat.applog.path }}
tags: {{ filebeat.applog.tags }}
{% if filebeat.applog.fields is defined %}
processors:
- decode_json_fields:
fields: {{ filebeat.applog.fields }}
max_depth: {{ filebeat.applog.depth }}
target: {{ filebeat.applog.target | default "" }}
{% endif %}
{% if filebeat.applog.multiline_pattern is defined %}
multiline.type: {{ filebeat.applog.multiline_type }}
multiline.pattern: {{ filebeat.applog.multiline_pattern }}
multiline.negate: {{ filebeat.applog.multiline_negate }}
multiline.match: {{ filebeat.applog.multiline_match }}
{% endif %}
I'm not sure what I'm missing or doing wrong. I'm thinking I'm doing something wrong since this the first time doing something like this.

So the template you have should either:
have a for loop to iterate over filebeat.applog
OR
reference n'th element of filebeat.applog
Aside from that, there are some errors like below:
1.
target: {{ filebeat.applog.target | default "" }}
This is the main one, and this is what the error message is complaining about, i.e. got 'string'. The correct usage for default filter is {{ some_variable | default("") }}.
2.
{% if filebeat.applog.multiline_pattern is defined %}
In the inventory this variable is mis-spelled, i.e. multiline_patern (missing one "t"). Fix this in your inventory.
3.
when I do use {{ filebeat.applog.0.logtitle }} in the template
This should be {{ filebeat.applog.0.title }} to work.
Considering the above fixes, a template that loops over filebeat.applog such as below should work:
{% for applog in filebeat.applog %}
title: {{ applog.title }}
- type: {{ applog.type }}
enabled: true
paths: {{ applog.paths }}
tags: {{ applog.tags }}
{% if applog.fields is defined %}
processors:
- decode_json_fields:
fields: {{ applog.fields }}
max_depth: {{ applog.depth }}
target: {{ applog.target | default("") }}
{% endif %}
{% if applog.multiline_pattern is defined %}
multiline.type: {{ applog.multiline_type }}
multiline.pattern: {{ applog.multiline_pattern }}
multiline.negate: {{ applog.multiline_negate }}
multiline.match: {{ applog.multiline_match }}
{% endif %}
{% endfor %}

Related

Looping through a map in helm

I am new to yaml and helm templating and have a question in it.
I have the following in my values.yaml file
regionInfo:
usa:
DrRegions: uk
region: usa
region_key: usa
uk:
DrRegions: usa
region: uk
region_key: lhr
I need to iterate over the above map and the output should be in this format for each region
{{ $region }}:
dnsAbbrev: {{ region_key }}
abbrev: {{ region_key }}
drRegion: {{ DrRegions }}
I tried the following
Method 1
{{ range $reg, $props := .Values.regionInfo }}
{{ $reg }}:
dnsAbbrev: {{ $props.region_key }}
abbrev: {{ $props.region_key }}
drRegion: {{ $props.DrRegions }}
{{ end }}
Method 2
{{ range reg, props := .Values.regionInfo }}
{{ range $props }}
{{ $reg }}:
dnsAbbrev: {{ .region_key }}
abbrev: {{ .region_key }}
drRegion: {{ .DrRegions }}
{{ end }}
{{ end }}
I was getting couldn't range over map in both the scenarios... Any help or guidance on this is highly appreciated.

Ansible conditional betwen variables

I have to check whether source and target are not the same directories and if they are not to change the name:
#Renaming bamboo-home folder
- name: Get {{ bamboo_home_symlink }} symlink target
stat:
path: "{{ bamboo_home_symlink }}"
register: symlinkhome_target
tags:
- upgrade
- name: change name of folder to be {{ bamboo_home }}
shell: mv '{{ symlinkhome_target.stat.lnk_source }}' '{{ bamboo_home }}'
when: symlinkhome_target.stat.lnk_source is not {{ bamboo_home }}
tags:
- upgrade
Unfortunately I have got following error:
19:02:31 TASK [change name of folder to be /usr/data/atlassian/bamboo-8.1.2-home] *******
19:02:31 task path: /opt/data/jenkins/workspace/Team Infrastructure Services and Tools/Bamboo/Bamboo Dev/Bamboo-dev install/roles/bamboo/tasks/main.yml:146
19:02:31 [WARNING]: conditional statements should not include jinja2 templating
19:02:31 delimiters such as {{ }} or {% %}. Found: symlinkhome_target.stat.lnk_source is
19:02:31 not {{ bamboo_home }}
19:02:31 Read vars_file 'vars/secure-user.yml'
19:02:31 Read vars_file 'vars/dev.yml'
19:02:31 [WARNING]: conditional statements should not include jinja2 templating
19:02:31 delimiters such as {{ }} or {% %}. Found: symlinkhome_target.stat.lnk_source is
19:02:31 not {{ bamboo_home }}
19:02:31 fatal: [server.domain.company.net]: FAILED! => {
19:02:31 "msg": "The conditional check 'symlinkhome_target.stat.lnk_source is not {{ bamboo_home }}' failed. The error was: template error while templating string: expected token 'name', got '/'. String: {% if symlinkhome_target.stat.lnk_source is not /usr/data/atlassian/bamboo-8.1.2-home %} True {% else %} False {% endif %}\n\nThe error appears to be in '/opt/data/jenkins/workspace/Team Infrastructure Services and Tools/Bamboo/Bamboo Dev/Bamboo-dev install/roles/bamboo/tasks/main.yml': line 146, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: change name of folder to be {{ bamboo_home }}\n ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n with_items:\n - {{ foo }}\n\nShould be written as:\n\n with_items:\n - \"{{ foo }}\"\n"
19:02:31 }
symlinkhome_target is defined. See result of stat:
19:02:31 "stat": {
19:02:31 "exists": true,
19:02:31 "gid": 0,
19:02:31 "gr_name": "root",
19:02:31 "inode": 142127337,
19:02:31 "lnk_source": "/opt/data/atlassian/bamboo-8.1.2-home",
19:02:31 "lnk_target": "/usr/data/atlassian/bamboo-8.1.2-home",
19:02:31 "mimetype": "inode/symlink",
19:02:31 }
The warning tells you what you are doing wrong that causes the error message.
19:02:31 [WARNING]: conditional statements should not include jinja2 templating
19:02:31 delimiters such as {{ }} or {% %}.
Additionally, you should be testing for equality (!=) not identity (is not).
- name: change name of folder to be {{ bamboo_home }}
shell: mv '{{ symlinkhome_target.stat.lnk_source }}' '{{ bamboo_home }}'
when: symlinkhome_target.stat.lnk_source != bamboo_home
tags:
- upgrade

concatenate variables in Jinja2

I'm struggling with the following example data from Satellite server when templating with Jinja2 in Ansible:
"results": {
"test.example.com": {
"interfaces": "eth0,lo",
"ipaddress_eth0": "10.251.0.45",
"ipaddress_lo": "127.0.0.1",
"netmask_eth0": "255.255.255.0",
"netmask_lo": "255.0.0.0",
"network_eth0": "10.251.0.0",
"network_lo": "127.0.0.0",
This piece of code will return: 127.0.0.1, but I want to replace 'ipaddress_lo' with the variable interface.
I've tried a million combinations... without any luck... please advice.
{% for items in my_host_facts.json.results %}
{% for interface in my_host_facts.json.results[items].interfaces.split(",") %}
{{ interface }}:
address: "{{ my_host_facts.json.results[items].ipaddress_lo }}"
netmask: "{{ my_subnet.json.mask }}"
network: "{{ my_subnet.json.network }}"
gateway: "{{ my_subnet.json.gateway }}"
{% endfor %}
dns: [ "{{ my_subnet.json.dns_primary }}", "{{ my_subnet.json.dns_secondary }}" ]
{% endfor %}
Kind regards,
Try {{ my_host_facts.json.results[items]['ipaddress_'+interface] }}.

Ansible template adds 'u' to array in template

I have the following vars inside of my ansible playbook I got the following structure
domains:
- { main: 'local1.com', sans: ['test.local1.com', 'test2.local.com'] }
- { main: 'local3.com' }
- { main: 'local4.com' }
And have the following inside of the my conf.j2
{% for domain in domains %}
[[acme.domains]]
{% for key, value in domain.iteritems() %}
{% if value is string %}
{{ key }} = "{{ value }}"
{% else %}
{{ key }} = {{ value }}
{% endif %}
{% endfor %}
{% endfor %}
Now when I go in the VM and see the file I get the following:
Output
[[acme.domains]]
main = "local1.com
sans = [u'test.local1.com', u'test2.local.com']
[[acme.domains]]
main = "local3.com"
[[acme.domains]]
main = "local4.com"
Notice the u inside of the sans array.
Excpeted output
[[acme.domains]]
main = "local1.com"
sans = ["test.local1.com", "test2.local.com"]
[[acme.domains]]
main = "local3.com"
[[acme.domains]]
main = "local4.com"
Why is this happening and how can I fix it?
You get u' ' because you print the object containing the Unicode strings and this is how Python renders it by default.
You can filter it with list | join filters:
{% for domain in domains %}
[[acme.domains]]
{% for key, value in domain.iteritems() %}
{% if value is string %}
{{ key }} = "{{ value }}"
{% else %}
{{ key }} = ["{{ value | list | join ('\',\'') }}"]
{% endif %}
{% endfor %}
{% endfor %}
Or you can rely on the fact, that the string output after sans = is a JSON and render it with to_json filter:
{{ key }} = {{ value | to_json }}
Either will get you:
[[acme.domains]]
main = "local1.com"
sans = ["test.local1.com", "test2.local.com"]
[[acme.domains]]
main = "local3.com"
[[acme.domains]]
main = "local4.com"
But the first one is more versatile.

Ansible: multi line over playbook

I have a question about multi line and Ansible playbook:
I have created a playbook with a line very large, I need to cut this line for better reading. How I can doing it?
- name: 'Create VM Azure :-P '
shell: if ! grep {{ item }} /tmp/vm_{{ rgName }}; then azure vm create --vm-size {{ groups['item'][vmsize] }} --resource-group {{ rgName }} --name {{ item }} --location {{ location }} --admin-username {{ username }} --ssh-publickey-file {{ sshfile }} --storage-account-name {{ rgName | lower }} --os-type {{ groups['item'][type_os] }} --image-urn {{ image }} --data-disk-size {{ disksize }} --subnet-id {{ subnetid_key }} --nic-names {{ item }}; fi
with_items: groups['test']
I would like to make it as follows way, but I have some errors when execute the playbook
- name: 'Create VM Azure :-P '
shell: if ! grep {{ item }} /tmp/vm_{{ rgName }}; then
azure vm create --vm-size {{ groups['item'][vmsize] }}
--resource-group {{ rgName }} --name {{ item }}
--location {{ location }} --admin-username {{ username }}
--ssh-publickey-file {{ sshfile }} --storage-account-name {{ rgName | lower }}
--os-type {{ groups['item'][type_os] }} --image-urn {{ image }}
--data-disk-size {{ disksize }} --subnet-id {{ subnetid_key }}
--nic-names {{ item }}; fi
with_items: groups['test']
The error:
ERROR! Syntax Error while loading YAML.
The error appears to have been in '/home/pvillarruel/docker/azure-ansible/data/playbook.yml': line 79, column 1, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
shell: if ! grep {{ item }} /tmp/vm_{{ rgName }}; then azure vm create --vm-size
{{ groups['item'][vmsize] }} --resource-group {{ rgName }} --name {{ item }}
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
Thanks
Use a YAML block scalar, they were designed exactly for this kind of thing:
shell: >
if ! grep {{ item }} /tmp/vm_{{ rgName }}; then
azure vm create --vm-size {{ groups['item'][vmsize] }}
--resource-group {{ rgName }} --name {{ item }}
--location {{ location }} --admin-username {{ username }}
--ssh-publickey-file {{ sshfile }}
--storage-account-name {{ rgName | lower }}
--os-type {{ groups['item'][type_os] }} --image-urn {{ image }}
--data-disk-size {{ disksize }} --subnet-id {{ subnetid_key }}
--nic-names {{ item }}; fi
The > indicates that the following block is a scalar and lines should be folded, i.e. a newline character will be converted into a single space. You also do not need to worry about special characters, everything will be taken literally in a folded block scalar.

Resources