Ansible omit on given value - ansible

I have a set of data objects I'm passing to a template, and when I render the template I want to omit a given line if the value in the array is null.
Example array:
[
{
'name': 'one'
'place': 'high'
'value': 'set'
}
{
'name': 'two'
'place': null
'value': 'unset'
}
{
'name': 'three'
'place': 'low'
'value': 'whyme'
}
]
Sample template:
{% for item in array %}
- name: {{ item.name }}
place: {{ item.place | default (omit) }}
{% endfor %}
The default(omit) filter isn't working the way I want it to. It's putting the "place:" line into the output with no value. I want the "place:" line to not appear in the output at all.
Actual output:
- name: one
place: high
- name: two
place:
- name: three:
place: low
Desired output:
- name: one
place: high
- name: two
- name: three
place: low

The template below does the job
{% for item in array %}
- name: {{ item.name }}
{% if item.place %} place: {{ item.place }}
{% endif %}
{% endfor %}
gives
- name: one
place: high
- name: two
- name: three
place: low
with the data properly structured
array: [
{
'name': 'one',
'place': 'high',
'value': 'set',
},
{
'name': 'two',
'place': null,
'value': 'unset',
},
{
'name': 'three',
'place': 'low',
'value': 'whyme',
}
]

Related

How to queary with Ansible Jinja2 package Version

I am trying to create a Report with Ansible where i collect the current version from Curl:
{% for host in groups['all']%}
{{ hostvars[host]['ansible_fqdn'] }} {{ hostvars[host]['packages']['curl'] }}
{% endfor %}
In the Respond i get following output
mycoolfqdn [{'name': 'curl', 'version': '7.68.0-1ubuntu2.15', 'arch': 'amd64', 'category': 'web', 'origin': 'Ubuntu', 'source': 'apt'}]
How do i get the version Part 'version': '7.68.0-1ubuntu2.15' so it will look like this:
mycoolfqdn curl 7.68.0-1ubuntu2.15

get ansible_fqdn from all hosts in a group

I am trying to get the ansible_fqdn from all hosts in a group with something in a template with something like this
{% for host in groups.all %}
{{ hostvars[host].ansible_fqdn }}
{% endfor %}
Or using:
{% for host in query('inventory_hostnames', target) | map('extract', hostvars, 'inventory_hostname') %}
{{ hostvars[host].ansible_fqdn }}
{% endfor %}
In all cases I get:
"AnsibleUndefinedVariable: 'ansible.vars.hostvars.HostVarsVars object' has no attribute 'ansible_fqdn'"
I do notice that if I just "print/write":
{{ hostvars[host] }}
The ansible_fqdn is within facter_networking, but also trying:
{{ hostvars[host][facter_networking].fqdn }}
or
{{ hostvars[host][facter_networking].fqdn }}
I get:
fatal: [10.25.176.10]: FAILED! => {
"changed": false,
"msg": "AnsibleUndefinedVariable: ansible.vars.hostvars.HostVarsVars object has no element {
'domain': 'test-x',
'fqdn': 'TEST-X.example.org',
'hostname': 'TEST-X',
'interfaces': {
'ens192': {
'bindings': [{
'address': '10.25.176.10',
'netmask': '255.255.254.0',
'network': '10.25.176.0'
}, {
'address': '10.25.177.226',
'netmask': '255.255.252.0',
'network': '10.25.176.0'
}],
'ip': '10.25.176.10',
'mac': '00:50:56:8f:ce:ca',
'mtu': 1500,
'netmask': '255.255.254.0',
'network': '10.25.176.0'
},
'lo': {
'bindings': [{
'address': '127.0.0.1',
'netmask': '255.0.0.0',
'network': '127.0.0.0'
}],
'ip': '127.0.0.1',
'mtu': 65536,
'netmask': '255.0.0.0',
'network': '127.0.0.0'
}
},
'ip': '10.25.176.10',
'mac': '00:50:56:8f:ce:ca',
'mtu': 1500,
'netmask': '255.255.254.0',
'network': '10.25.176.0',
'primary': 'ens192'
}
}
If I use:
{{ hostvars[host].facter_networking }}
I get:
"msg": "AnsibleUndefinedVariable: 'ansible.vars.hostvars.HostVarsVars object' has no attribute 'facter_networking'
The data is there but any idea about how could I extract it?
This is the playbook:
- name: Gathering info
action: setup
- name: Create .pgpass
template:
src: pgpass.j2
dest: /home/postgres/.pgpass
owner: postgres
group: postgres
mode: 0600
The Ansible facts gathered for the hosts can be accessed from within the ansible_facts dictionary. So, to access a host's fqdn, you would have to access hostvars[host]['ansible_facts']['fqdn'].
Since we are iterating over groups['all'], just make sure that the gather facts task is running on - hosts: all as well.
So, using the above method, the template could look like this:
{% for host in groups['all'] %}
{{ hostvars[host]['ansible_facts']['fqdn'] }}
{% endfor %}
Note that the ansible_ prefix is not required, i.e. fqdn instead of ansible_fqdn.

Ansible: How to create nested dictionary using Jinja2

Here is the output.
"result.containers":[
{
"Image":"ca.docker/webproxy:1.0.0",
"Names":[
"/customer1"
]
},
{
"Image":"docker.local/egacustomer:1.0.1",
"Names":[
"/registrator"
]
}
]
I'm trying to get the following output using jinja2
"containerlist"=>{
"webproxy": {
"name": "customer1"
},
"egacustomer": {
"name": "registrator"
}
}
Here is my jinja2 code.
- set_fact:
containerlist: |
{
{% for item in result.containers %}
{{ item.Image.split('/')[-1].split(':')[0] | replace('\n', '') }}
name : {{ item.Names[0][1:] | replace('\n', '') }}
{% endfor %}
}
I get the below output.
"containerlist": "{\nwebproxy\n name : customer1\negacustome\n name : registrator\n}"
Could someone please help me get the desired output. Any help would be greatly appreciated
The data in YAML
result:
containers:
- Image: ca.docker/webproxy:1.0.0
Names:
- /customer1
- Image: docker.local/egacustomer:1.0.1
Names:
- /registrator
The tasks below
- set_fact:
containerlist: "{{ containerlist|default({})|
combine({key: {'name': name}}) }}"
loop: "{{ result.containers }}"
vars:
key: "{{ (item.Image.split(':')|first).split('/')|last }}"
name: "{{ item.Names[0][1:] }}"
- debug:
var: containerlist
give
containerlist:
egacustomer:
name: registrator
webproxy:
name: customer1
But, the result is not a list. It's a dictionary. If you want a list use this
- set_fact:
containerlist: "{{ containerlist|default([]) +
[{key: {'name': name}}] }}"
loop: "{{ result.containers }}"
vars:
key: "{{ (item.Image.split(':')|first).split('/')|last }}"
name: "{{ item.Names[0][1:] }}"
- debug:
var: containerlist
give
containerlist:
- webproxy:
name: customer1
- egacustomer:
name: registrator

I am unable to fix the ansible playbook

I am trying to write a playbook to create two files .When nested variables are defined. I have got the output but this is not what I expect . I need to create two files with only the variables defines
playbook.yml
- hosts: all
vars:
variable:
- name: "item1"
vars:
- { id: 1, type: "get" , resource: "Customerid" }
- { id: 17, type: "post", resource: "Cus" }
- name: "item2"
vars:
- { id: 2, type: "get", resource: "Customerid" }
tasks:
- template:
src: template.j2
dest: "{{ item.name }}"
with_items: "{{ variable }}"
template.j2 file content
{% for item in variable %}
Item Name: {{ item.name }}
{% for item_var in item.vars %}
{% if item_var['type'] == 'get' %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Get function
{% else %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Post function
{% endif %}
{% endfor %}
{% endfor %}
Current result of two files created item1 and item2:
item1
Item Name: item1
Item ID: 1
Item Resource: Customerid
Get function
Item ID: 17
Item Resource: Cus
Post function
Item Name: item2
Item ID: 2
Item Resource: Customerid
Get function
item2
Item Name: item1
Item ID: 1
Item Resource: Customerid
Get function
Item ID: 17
Item Resource: Cus
Post function
Item Name: item2
Item ID: 2
Item Resource: Customerid
Get function
I would like to get the below output when two files are created . Not sure how to get this. Desired output:
item1
Item Name: item1
Item ID: 1
Item Resource: Customerid
Get function
Item ID: 17
Item Resource: Cus
Post function
item2
Item Name: item2
Item ID: 2
Item Resource: Customerid
Get function
Just remove the duplicate loop from the template.
Item Name: {{ item.name }}
{% for item_var in item.vars %}
{% if item_var['type'] == 'get' %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Get function
{% else %}
Item ID: {{ item_var['id'] }}
Item Resource: {{ item_var['resource'] }}
Post function
{% endif %}
{% endfor %}
The template might be simplified
Item Name: {{ item.name }}
{% for item_var in item.vars %}
Item ID: {{ item_var.id }}
Item Resource: {{ item_var.resource }}
{{ item_var.type|capitalize }} function
{% endfor %}

ansible, jinja template with loops, losing newlines [duplicate]

This question already has answers here:
How do I get an Ansible template to honor new lines after a conditional
(5 answers)
Closed 4 years ago.
Trying to build a JSON file from a template. It works ok as such, but for some reason newlines within loop constructs go missing, which I find rather irksome; the file "works" (is machine readable just fine), but for human consumption it's pretty ill-suited.
Here's my template:
{
"Users":
[
{% for username,user in _vpn_user_accounts.items() %}
{
"Name" : "{{ user.name }}",
"Hash" : "{{ user.hash }}",
"Cns" : [
{% for cn in user.cns.get(server_name, []) %}
"{{ cn }}"{% if not loop.last -%},{% endif %}
{% endfor %}
],
"key_ids" : [
{% for key in user.get( 'keys' , []) %}
{% if key.public is defined %}
"{{ key.public }}"{% if not loop.last %},{% endif %}
{% endif %}
{% endfor %}
],
"comment" : "{{ user.get( 'comment', '' ) }}"
} {% if not loop.last %},{% endif %}
{% endfor %}
]
}
Here's some sample data:
- andrej:
name: "andrej"
hash: "$2b$10$8EF3H.../Wj0RchEqU6"
cns:
h:
- "andrej_linux_h_201808171440"
- "andrej_linuxvm_h_201809131031"
- "andrej_mac_h_201808171441"
- "andrej_phone_h_201808171441"
w:
- "andrej_linux_w_201808171439"
- "andrej_linuxvm_w_201809131031"
- "andrej_mac_w_201808171441"
- "andrej_phone_w_201808171441"
keys:
- name: "andrej"
public: "kbjrvtni"
- name: "andrej2"
public: "ijrltifu"
- name: "andrej3"
public: "rbcvncbt"
comment: "systems"
This is my desired outcome (running against server "w"):
{
"Users":
[
{
"Name" : "andrej",
"Hash" : "$2b$10$8EF3H.../Wj0RchEqU6",
"Cns" : [
"andrej_linux_w_201808171439",
"andrej_linuxvm_w_201809131031",
"andrej_mac_w_201808171441",
"andrej_phone_w_201808171441"
],
"key_ids" : [
"kbjrvtni",
"ijrltifu",
"rbcvncbt"
],
"comment" : "systems guy"
}
]
}
This is what I get:
{
"Users":
[
{
"Name" : "andrej",
"Hash" : "$2b$10$8EF3H.../Wj0RchEqU6",
"Cns" : [
"andrej_linux_w_201808171439", "andrej_linuxvm_w_201809131031", "andrej_mac_w_201808171441", "andrej_phone_w_201808171441" ],
"key_ids" : [
"kbjrvtni", "ijrltifu", "rbcvncbt" ],
"comment" : "systems guy"
}
]
}
I have experimented with #Jinja2: trim_blocks and #Jinja2: keep_newline, neither of which showed the desired result. Well, trim_blocks kind of did, but it also gave me a bunch of empty lines where the jinja conditionals were ... unsatisfactory.
Any hints on how to resolve this? As I said, it works, but it irks me immensely that I can't get human readable, nice output.
And this little change actually made the problem go away in the end.
#jinja2: trim_blocks:False
{
"Users":
[
{% for username,user in _vpn_user_accounts.items() %}
{
"Name" : "{{ user.name }}",
"Hash" : "{{ user.hash }}",
"Cns" : [
{%- for cn in user.cns.get(server_name, []) %}
"{{ cn }}"{% if not loop.last -%},{% endif %}
{%- endfor %}
],
"key_ids" : [
{%- for key in user.get( 'keys' , []) %}
{% if key.public is defined %}
"{{ key.public }}"{% if not loop.last %},{% endif %}
{% endif %}
{%- endfor %}
],
"comment" : "{{ user.get( 'comment', '' ) }}"
} {% if not loop.last %},{% endif %}
{% endfor %}
]
}

Resources