How do i filter on ansible stat existence flags? - ansible

I'm executing a simple stat task (Ansible 2.3.1.0) on the named pipe created by wpa_supplicant:
- stat:
path: "/var/run/wpa_supplicant/{{ item }}"
with_items:
- wifi
register: wpa_stats
sudo: true
The variable contains the following data after execution:
ok: [10.10.23.187] => {
"wpa_stats": {
"changed": false,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": true,
"get_mime": true,
"path": "/var/run/wpa_supplicant/wifi"
}
},
"item": "wifi",
"stat": {
"atime": 1497900522.6306846,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 0,
"charset": "binary",
"ctime": 1497900290.0605242,
"dev": 18,
"device_type": 0,
"executable": true,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 796,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": false,
"issock": true,
"isuid": false,
"mimetype": "inode/socket",
"mode": "0770",
"mtime": 1497900290.0605242,
"nlink": 1,
"path": "/var/run/wpa_supplicant/wifi",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": false,
"rusr": true,
"size": 0,
"uid": 0,
"version": null,
"wgrp": true,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": true,
"xoth": false,
"xusr": true
}
}
]
}
}
But this filter returns an empty result:
- debug:
msg: "{{ wpa_stats | json_query('results[*].stat[?exists].path') | list }}"
If I remove the [?exists] filter it works fine:
- debug:
msg: "{{ wpa_stats | json_query('results[*].stat.path') | list }}"
I've also tried using ==. Jmespath is installed and I'm querying other values with JSON filters successfully.
What am I missing?

I guess you want to use pipe expression:
results[*].stat | [?exists].path
From my understating of JMESPath in stat[?filter] filter is applied inside stat (to select elements that are down the path), but you want to apply filter to select/reject stat siblings, so you should stop further projections with pipe and filter elements.

Related

How to get all indices of output array in Ansible

I'm gathering info on SSL certs on servers (looking for expiration date) using the find module.
- name: Find certs on server
find:
path: /etc/ssl/custom/certs
file_type: file
patterns: "*.crt"
recurse: yes
register: find_result
- debug:
var: find_result
The results are:
ok: [server00] => {
"find_result": {
"changed": false,
"examined": 5,
"failed": false,
"files": [
{
"atime": 1622749788.1552677,
"ctime": 1622744497.4393551,
"dev": 2050,
"gid": 0,
"gr_name": "root",
"inode": 19531534,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1622744497.4393551,
"nlink": 1,
"path": "/etc/ssl/custom/certs/somewebsite0.com.crt",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 1879,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
},
{
"atime": 1622719627.2477663,
"ctime": 1616545902.3681087,
"dev": 2050,
"gid": 0,
"gr_name": "root",
"inode": 19531253,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1613754568.0,
"nlink": 1,
"path": "/etc/ssl/custom/certs/somewebsite1.com.crt",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 2081,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
},
{
"atime": 1622719627.2197664,
"ctime": 1616545902.3721087,
"dev": 2050,
"gid": 0,
"gr_name": "root",
"inode": 19535012,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1601653231.0,
"nlink": 1,
"path": "/etc/ssl/custom/certs/somewebsite2.com.crt",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 2269,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
],
"matched": 3,
"msg": ""
}
}
I'm needing the path portion of the output ("path": "/etc/ssl/custom/certs/somewebsite1.com.crt"), and if I use find_result.files[0].path it only gives me a single result for each host, when I need every *.crt file.
How can I access each index? I try to use the shell module to perform an action on the .crt file, but again, it's only grabbing the first one due to the [0] index, like so:
- name: Check expiration
shell: "cat {{ find_result.files[0].path }} | openssl x509 -noout -enddate"
register: date
- debug:
var: date.stdout_lines
ok: [server00] => {
"date.stdout_lines": [
"notAfter=Apr 2 19:50:38 2018 GMT"
]
}
Here would be an example playbook based on it:
- hosts: localhost
tasks:
- name: Find certs on server
find:
path: /etc/ssl/custom/certs
file_type: file
patterns: "*.crt"
recurse: yes
register: find_result
- debug:
var: find_result
- name: Play with the data just to demonstrate
set_fact:
IRGeekSauce_list: "{{ (IRGeekSauce_list|default([])) + [item.path] }}"# <-- add each list item to a custom list
with_items: '{{ find_result.files }}' # <-- here we get the files as a list.
- name: your list
debug:
msg: '{{ IRGeekSauce_list }}'
- include_tasks: anothertasklist.yml
loop: '{{ IRGeekSauce_list }}'
loop_control:
loop_var: singlepathvariable
And then you have another "playbook" with just the tasks 'anothertasklist.yml'
- name: hello
debug:
msg: 'You are now in another playbook'
- name:
debug:
msg: 'Woho: {{ singlepathvariable }}'
- name:
openssl_certificate_info:
howeverthatmoduleworks...
And you should be able to just take the entire and include find_result.files as the loop, and then instead just use the loopvar singlepathvariable(and maybe rename it) and just take out the path as {{ singlepathvariable.path }}

How do I access "results" when original ansible task uses with_subelements

I am trying to generate a list of "views" and the "domains" in each view.
i.e.:
internal/baseserver1
internal/baseserver2
external/baseserver1
...
For each of the above, I want to check for the existence of a "regular" file on the remote host under a known directory inserting the above values into the list of files to be checked. I am attempting to check the value of isreg for each view/host in the above list.
roles/default/main.yml
---
zone_dir: /var/named
zone_domains:
- domain:
name: "jlhimpel.net"
hostmaster_email: "john"
views:
- view:
name: internal
hosts:
- host:
name: baseserver1
ip: 192.168.1.20
- host:
name: baseserver2
ip: 192.168.1.30
- view:
name: external
hosts:
- host:
name: baseserver1
ip: 343.22.56.237
...
roles/tasks/main.yml
---
- name: Debug fqn zone path
stat:
path: /var/named/internal/jlhimpel.net.zone
register: f
become: true
- name: Display f
debug:
var: f
- name: Display f.stat.isreg
debug:
var: f.stat.isreg
- name: Debug symbolic zone path
stat:
path: "{{ zone_dir }}/{{ item[1].name }}/{{ item[0].name }}.zone"
loop: "{{ zone_domains|subelements('views') }}"
register: p
become: true
- name: Display p
debug:
var: p
- name: Display p.results.stat.isreg
debug:
var: item.isreg
with_items:
p.results.stat
...
Output:
PLAY [dnsServiceGroup] *********************************************************
TASK [Gathering Facts] *********************************************************
ok: [testFedora.jlhimpel.net]
TASK [pocDnsService : Debug fqn zone path] *************************************
ok: [testFedora.jlhimpel.net]
TASK [pocDnsService : Display f] ***********************************************
ok: [testFedora.jlhimpel.net] => {
"f": {
"changed": false,
"failed": false,
"stat": {
"atime": 1582308757.2357316,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "b8e6ecf9a617314ed1e040b4cd72dbde3dc9753c",
"ctime": 1581784999.833953,
"dev": 64768,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 25,
"gr_name": "named",
"inode": 18788348,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0640",
"mtime": 1581784999.1509356,
"nlink": 1,
"path": "/var/named/internal/jlhimpel.net.zone",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": false,
"rusr": true,
"size": 406,
"uid": 0,
"version": "1161797691",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
}
TASK [pocDnsService : Display f.stat.isreg] ************************************
ok: [testFedora.jlhimpel.net] => {
"f.stat.isreg": true
}
TASK [pocDnsService : Debug symbolic zone path] ********************************
ok: [testFedora.jlhimpel.net] => (item=[{'domain': None, 'name': 'jlhimpel.net', 'hostmaster_email': 'john', 'views': [{'view': None, 'name': 'internal', 'hosts': [{'host': None, 'name': 'baseserver1', 'ip': '192.168.1.20'}, {'host': None, 'name': 'baseserver2', 'ip': '192.168.1.30'}]}, {'view': None, 'name': 'external', 'hosts': [{'host': None, 'name': 'baseserver1', 'ip': '343.22.56.237'}]}]}, {'view': None, 'name': 'internal', 'hosts': [{'host': None, 'name': 'baseserver1', 'ip': '192.168.1.20'}, {'host': None, 'name': 'baseserver2', 'ip': '192.168.1.30'}]}])
ok: [testFedora.jlhimpel.net] => (item=[{'domain': None, 'name': 'jlhimpel.net', 'hostmaster_email': 'john', 'views': [{'view': None, 'name': 'internal', 'hosts': [{'host': None, 'name': 'baseserver1', 'ip': '192.168.1.20'}, {'host': None, 'name': 'baseserver2', 'ip': '192.168.1.30'}]}, {'view': None, 'name': 'external', 'hosts': [{'host': None, 'name': 'baseserver1', 'ip': '343.22.56.237'}]}]}, {'view': None, 'name': 'external', 'hosts': [{'host': None, 'name': 'baseserver1', 'ip': '343.22.56.237'}]}])
TASK [pocDnsService : Display p] ***********************************************
ok: [testFedora.jlhimpel.net] => {
"p": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": false,
"get_mime": true,
"path": "/var/named/internal/jlhimpel.net.zone"
}
},
"item": [
{
"domain": null,
"hostmaster_email": "john",
"name": "jlhimpel.net",
"views": [
{
"hosts": [
{
"host": null,
"ip": "192.168.1.20",
"name": "baseserver1"
},
{
"host": null,
"ip": "192.168.1.30",
"name": "baseserver2"
}
],
"name": "internal",
"view": null
},
{
"hosts": [
{
"host": null,
"ip": "343.22.56.237",
"name": "baseserver1"
}
],
"name": "external",
"view": null
}
]
},
{
"hosts": [
{
"host": null,
"ip": "192.168.1.20",
"name": "baseserver1"
},
{
"host": null,
"ip": "192.168.1.30",
"name": "baseserver2"
}
],
"name": "internal",
"view": null
}
],
"stat": {
"atime": 1582308757.2357316,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "b8e6ecf9a617314ed1e040b4cd72dbde3dc9753c",
"ctime": 1581784999.833953,
"dev": 64768,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 25,
"gr_name": "named",
"inode": 18788348,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0640",
"mtime": 1581784999.1509356,
"nlink": 1,
"path": "/var/named/internal/jlhimpel.net.zone",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": false,
"rusr": true,
"size": 406,
"uid": 0,
"version": "1161797691",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
},
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": false,
"get_mime": true,
"path": "/var/named/external/jlhimpel.net.zone"
}
},
"item": [
{
"domain": null,
"hostmaster_email": "john",
"name": "jlhimpel.net",
"views": [
{
"hosts": [
{
"host": null,
"ip": "192.168.1.20",
"name": "baseserver1"
},
{
"host": null,
"ip": "192.168.1.30",
"name": "baseserver2"
}
],
"name": "internal",
"view": null
},
{
"hosts": [
{
"host": null,
"ip": "343.22.56.237",
"name": "baseserver1"
}
],
"name": "external",
"view": null
}
]
},
{
"hosts": [
{
"host": null,
"ip": "343.22.56.237",
"name": "baseserver1"
}
],
"name": "external",
"view": null
}
],
"stat": {
"atime": 1582326121.0318115,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "5deeb57dfd80c5b264ab5ebff8af728b2a551860",
"ctime": 1582079607.5288289,
"dev": 64768,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 25378368,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0640",
"mtime": 1582079607.4818277,
"nlink": 1,
"path": "/var/named/external/jlhimpel.net.zone",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": false,
"rusr": true,
"size": 406,
"uid": 0,
"version": "2850301314",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
]
}
}
TASK [pocDnsService : Display f.stat[].isreg] **********************************
ok: [testFedora.jlhimpel.net] => (item=p.results.stat) => {
"ansible_loop_var": "item",
"item": "p.results.stat",
"item.isreg": "VARIABLE IS NOT DEFINED!"
}
Any advise would be greatly appreciated.
Sorry for pasting such verbose output.
The task below
- name: Display p.results.stat.isreg
debug:
msg: "{{ item }}"
loop: "{{ p.results|json_query('[].stat.isreg') }}"
gives
"msg": true
"msg": true

How to grab filepath from ansibles find module

I'm using Ansible for some IAC(infra as code) tasks.
I have a playbook where I'm using the find module recursively to search for readable files.
Here is an example of it:
- name: Application logs with read access
become: true
find:
paths: /
file_type: file
recurse: yes
patterns:
- '*.log'
- '*.config'
register: rapplogs
- set_fact: read_app_logs={{rapplogs.matched}}
- debug: var=read_app_logs
- set_fact: read_log_list={{rapplogs.files}}
- debug: var=read_log_list
run_once: True
failed_when: read_app_logs >= 1
ignore_errors: True
The output of it is like this:
TASK [infra_pt : set_fact] ******************************************************************
ok: [192.168.47.135]
TASK [infra_pt : debug] *********************************************************************
ok: [192.168.47.135] => {
"read_app_logs": "72"
}
TASK [infra_pt : set_fact] ******************************************************************
ok: [192.168.47.135]
TASK [infra_pt : debug] *********************************************************************
fatal: [192.168.47.135]: FAILED! => {
"failed_when_result": true,
"read_log_list": {
"changed": false,
"examined": 210060,
"failed": false,
"files": [
{
"atime": 1558446815.3474104,
"ctime": 1558446815.3474104,
"dev": 64768,
"gid": 0,
"gr_name": "root",
"inode": 2065610,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1558446815.3474104,
"nlink": 1,
"path": "/test2.log",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 0,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
},
From the output list I actually want to access only the "mode" and "path" objects, how this can be done? Any idea?
Try json_query
- set_fact:
read_app_logs: "{{ rapplogs.files|json_query('[].{path: path, mode: mode}') }}"
(not tested)
Sure. You can just iterate over the list of matched files and refer to whichever keys are of interest:
- debug:
msg: "mode of {{ item.path }} is {{ item.mode }}"
loop: "{{ read_log_list.files }}"
Which, given your example output, would produce something like this:
TASK [debug] **********************************************************************************
ok: [localhost] => (item={u'islnk': False, u'uid': 0, u'rgrp': True, u'xoth': False, u'rusr': True, u'woth': False, u'nlink': 1, u'issock': False, u'mtime': 1558446815.3474104, u'gr_name': u'root', u'path': u'/test2.log', u'xusr': False, u'atime': 1558446815.3474104, u'inode': 2065610, u'isgid': False, u'size': 0, u'isdir': False, u'wgrp': False, u'ctime': 1558446815.3474104, u'isblk': False, u'xgrp': False, u'isuid': False, u'dev': 64768, u'roth': True, u'isreg': True, u'isfifo': False, u'mode': u'0644', u'pw_name': u'root', u'gid': 0, u'ischr': False, u'wusr': True}) => {
"msg": "mode of /test2.log is 0644"
}

Ansible retrieve multiple array values from results

I'd like to be able to iterate over all of the name values, but I'm not sure how to do so with Ansible. The variable domain is a list, and register is used.
- name: find *.ccfg files in domain(s)
find:
paths: "/tmp/opt/{{ item }}/ccfg"
patterns: "*.ccfg"
recurse: yes
excludes: "Admin.ccfg"
with_items: "{{ domain }}"
register: files
when: ('local' in group_names)
- debug:
msg: "{{ files.results }}"
The path value in each array could be anywhere from 1 to 20. Each index in the array has multiple values. Some arrays may not have any values
Standard Output:
ok: [127.0.0.1] => {
"msg": [
{
"_ansible_ignore_errors": null,
"_ansible_item_label": "CIE",
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": false,
"examined": 3,
"failed": false,
"files": [
{
"atime": 1541632866.4095802,
"ctime": 1541632866.4095802,
"dev": 64768,
"gid": 0,
"gr_name": "root",
"inode": 52174935,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1541632866.4095802,
"nlink": 1,
"path": "/tmp/opt/CIE/ccfg/cie.ccfg",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 0,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
],
Take a look at the json_query filter:
- debug:
msg: "{{ item }}"
with_items: "{{ files | json_query('results[*].files[*].path') }}"
Official doco: https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#json-query-filter
Shameless plug with more examples: https://parko.id.au/2018/08/16/complex-data-structures-and-the-ansible-json_query-filter

stat.checksum return value missing in ansible 2.2

I am trying to find the checksum of a file in a playbook using the stat module.
---
- name: loading checksum to variable
stat:
path: /data/foo.256
checksum_algorithm: sha256
register: origin
- debug:
msg: "The checksum of the file is {{ origin.stat.checksum }}"
The error I get when I run the playbook is
fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'dict object' has no attribute 'checksum'\n\nThe error appears to have been in '/data/playbooks/roles/test/tasks/main.yml': line 8, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
I tried to get some more verbosity using -vvv to the play and i noticed that there is no checksum in the return values of the module.
ok: [localhost] => {
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha256",
"follow": false,
"get_checksum": true,
"get_md5": true,
"mime": false,
"path": "/data/foo.256"
},
"module_name": "stat"
},
"stat": {
"atime": 1505250191.0,
"ctime": 1505250179.0,
"dev": 2057,
"executable": true,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 5945,
"isblk": false,
"ischr": false,
"isdir": true,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": false,
"issock": false,
"isuid": false,
"mode": "0755",
"mtime": 1505250179.0,
"nlink": 2,
"path": "/data/foo.256",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 4096,
"uid": 0,
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": true,
"xoth": true,
"xusr": true
}
}
So, I re-ran the play using one of the return values displayed and the play seems to work successfully.
The version of ansible I am using is 2.2.0.0
ansible 2.2.0.0
config file = /etc/ansible/ansible.cfg
configured module search path = Default w/o overrides
What am i missing here?
I see "isdir": true. Checksum is not displayed for directories.

Resources