How to queary with Ansible Jinja2 package Version - ansible

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

Related

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.

How to fix Jinja2 yml indentation

I have the below structure of data source in yml format.
systemEmailAccount:
mode: DEFAULT
username: test#gmail.com
password: Test#123
displayName: "Test"
senderAddress: test#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 1458168133864
secondarySystemEmailAccount:
mode: DEFAULT
username: test2#gmail.com
password: Test#123
displayName: "Test2"
senderAddress: test2#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 14581681338777
I'm trying to regenerate it to a new file using this jinja2 template snippet.
systemEmailAccount:
{% for key,value in config.systemEmailAccount.items() %}
{% if key == "mode" or key == "username" or key == "password" or key == "senderAddress" or key == "tokenExpires" %}
{{ key }}: {{ value }}
{% else %}
{{ key }}: {{ '"' }}{{ value }}{{ '"' }}
{% endif %}
{% endfor %}
secondarySystemEmailAccount:
{% for key,value in config.secondarySystemEmailAccount.items() %}
{% if key == "mode" or key == "username" or key == "password" or key == "senderAddress" or key == "tokenExpires" %}
{{ key }}: {{ value }}
{% else %}
{{ key }}: {{ '"' }}{{ value }}{{ '"' }}
{% endif %}
{% endfor %}
But the indentation does not seem right in the output.
emailAccount1:
username: test#gmail.com
mode: DEFAULT
password: Test#123
displayName: "Test"
senderAddress: test#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 1458168133864
emailAccount2:
username: test2#gmail.com
mode: DEFAULT
password: Test#123
displayName: "Test2"
senderAddress: test2#gmail.com
oauthClientId: "xxxxxxx"
oauthSecret: "xxxxxxxxx"
tokenExpires: 1458168133864
Any suggestion to fix this?
have a look at those 2 topics from official jinja2 docs
white space control: https://jinja.palletsprojects.com/en/2.11.x/templates/#whitespace-control
filter indent: https://jinja.palletsprojects.com/en/2.11.x/templates/?highlight=indent#indent
try this snippet below:
systemEmailAccount:
{%- for key,value in config.systemEmailAccount.items() %}
{%- if key == "mode" or key == "username" or key == "password" or key == "senderAddress" or key == "tokenExpires" %}
{%- filter indent(width=2) %}
{{ key }}: {{ value }}
{%- endfilter %}
{%- else %}
{%- filter indent(width=2) %}
{{ key }}: {{ '"' }}{{ value }}{{ '"' }}
{%- endfilter %}
{%- endif %}
{%- endfor %}
[..]

Ansible omit on given value

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',
}
]

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