I am trying to create a config from a template using ansible which should look like this
files:
'/opt/services':
box 1:
url: localhost:5623
box 2:
url: localhost:5623
box 3:
url: localhost:5623
I have a variable {{ box_names }} which gives ["box 1", "box 2", "box 3", and so on]
rn my task looks like this
tasks:
- name: print the box names
debug:
msg: "box names: {{ box_names }}"
- name: Settings | Import default config
template:
src: test.yaml.j2
dest: "/opt/test/config.yaml"
owner: "{{ user.name }}"
group: "{{ user.name }}"
mode: 0775
loop: "{{ box_names }}"
and my config template looks like
files:
'/opt/services':
{{ item }}:
url: localhost:5623
but the final template only shows box 1 and not box 2 or box 3. how do I make the config show all the items of the loop?
use the loop inside the template j2 file:
files:
'/opt/services':
{% for box in box_names %}
{{box}}:
url: localhost:5623
{% endfor %}
The task:
- name: Settings | Import default config
template:
src: test.yaml.j2
dest: "/opt/test/config.yaml"
owner: "{{ user.name }}"
group: "{{ user.name }}"
mode: 0775
result:
files:
'/opt/services':
box 1:
url: localhost:5623
box 2:
url: localhost:5623
box 3:
url: localhost:5623
if you want ot use this result as var file, i suggest you to add quotes around key in the template file
Create the dictionary
files:
/opt/services: "{{ dict(box_names|
product([{'url': 'localhost:5623'}])) }}"
gives
files:
/opt/services:
box 1:
url: localhost:5623
box 2:
url: localhost:5623
box 3:
url: localhost:5623
Then, the template is trivial
shell> cat test.yaml.j2
files:
{{ files|to_nice_yaml }}
Related
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 %}
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
I have problem and i don't did i even start correctly.
i have hosts file that looks like
all:
children:
application1:
children:
application1-webserver:
hosts:
host1.domain.net:
host2.domain.net:
application1-database:
hosts:
dbhost1.domain.net:
application2:
children:
application2-webserver:
hosts:
host3.domain.net:
host4.domain.net:
application1-database:
hosts:
dbhost2.domain.net:
app-servers:
hosts:
host1.domain.net:
host2.domain.net:
host3.domain.net:
host4.domain.net:
I have created template file. I know it is not pg_hba.conf, but it is no mater now, if i get IPs out it will be easy
{% for i in groups['app-servers'] %}
{{ hostvars[i]['ansible_default_ipv4_address'] }}
{% endfor %}
So maybe for time to time i have to run this script to create "new" enviroment, and i don't want to change IPs from app-servers manually. What i want is to get IP from FQDN.
Need this so i can limit access to db from network, just to those servers.
Thanks for help.
The variable holding the global info is ansible_default_ipv4. It is only available if you have gathered facts on your host (make sure you did not use gather_facts: false on your play).
It's a hash containing several keys among which address. As an example (obfuscated), this is what I get on my localhost:
$ ansible localhost -m setup -a gather_subset=network -a filter=*default_ipv4*
localhost | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "x.y.z.a",
"alias": "interface",
"broadcast": "x.y.z.255",
"gateway": "x.y.z..1",
"interface": "interface",
"macaddress": "xx:xx:xx:xx:xx:xx",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "x.y.z..0",
"type": "ether"
}
},
"changed": false
}
So the name of the var you are looking for in your template is ansible_default_ip4.address
Your full fixed template:
{% for i in groups['app-servers'] %}
{{ hostvars[i].ansible_default_ipv4.address }}
{% endfor %}
Possible alternative notations (mixing dot and array notation):
{{ hostvars[i]['ansible_default_ipv4']['address'] }}
{{ hostvars[i].ansible_default_ipv4['address'] }}
etc.
So i got it. It is little complicated.
Playbook looks like this:
---
- hosts: app-servers
tasks:
- ping:
- hosts: dbhost1.domain.net
tasks:
- include_role:
name: test-for
...
Hosts file like above:
all:
children:
application1:
children:
application1-webserver:
hosts:
host1.domain.net:
host2.domain.net:
application1-database:
hosts:
dbhost1.domain.net:
application2:
children:
application2-webserver:
hosts:
host3.domain.net:
host4.domain.net:
application1-database:
hosts:
dbhost2.domain.net:
app-servers:
hosts:
host1.domain.net:
host2.domain.net:
host3.domain.net:
host4.domain.net:
Only after i ping hosts i get IPs i need
Then in template:
{% for i in groups['app-servers'] %}
{{ hostvars[i].ansible_default_ipv4.address }}
{% endfor %}
And it works.
Thanks
I have page front matter with multiple levels. My page front matter looks like this:
grids:
- template: section
background_image: "/uploads/2018/05/01/q-mark.png"
rows:
- template: row
stack-columns: tablet-s
cols:
- template: column
title: "Column-1 Title"
- template: section
background_image: "/uploads/2018/05/01/lk.png"
rows:
- template: row
stack-columns: tablet-s
cols:
- template: column
title: "Column-2 Title"
rows:
- template: row
stack-columns: tablet-l
cols:
- template: column
title: "Column-3 Title"
I can display the first-level template name for both of my grids:
{{ range .Params.grids }}
{{ .template }}
{{ end }}
How can I return the template name of rows and cols within the loop?
I figured it out. You can use a nested range to access parameters with multiple levels:
{{ range .Params.grids }}
<p>Grid template name: {{ .template }}</p>
{{ range .rows }}
<p><strong>row template name: </strong>{{ .template }}</p>
{{ range .cols }}
<p><em>col template name:</em> {{ .template }}</p>
{{ end }}
{{ end }}
{{ end }}
This displays:
Grid template name: section
row template name: row
col template name: column
Grid template name: section
row template name: row
col template name: column
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] }}.