stat.checksum return value missing in ansible 2.2 - ansible

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.

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 }}

Need to find conf file on the system and need to replace a line

Everyone, I am using the below script to find all the httpd.conf file in /tmp using the find module and after that, i need to change the server root for all the httpd.conf files that I got from the find module. I am using the Below code.
getting the below error while executing the lineinline module.
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Destination {'files': [{'uid': 0, 'woth': False, 'mtime': 1554392266.9903164, 'inode': 4232796, 'isgid': False, 'size': 11753, 'roth': True, 'isuid': False, 'isreg': True, 'pw_name': 'root', 'gid': 0, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'root', 'path': '/tmp/httpd.conf', 'xusr': False, 'atime': 1554391744.8432574, 'isdir': False, 'ctime': 1554392266.9903164, 'wgrp': False, 'xgrp': False, 'dev': 51714, 'isblk': False, 'isfifo': False, 'mode': '0644', 'islnk': False}], 'changed': False, 'failed': False, 'examined': 14, 'msg': '', 'matched': 1} does not exist !", "rc": 257}
to retry, use: --limit #/etc/ansible/findnew.retry
---
- name: Recursively find httpd.conf file in /tmp
connection: local
hosts: localhost
tasks:
- find:
paths: /tmp
patterns: '*.conf'
recurse: yes
register: filestoser
- debug: var=filestoser
- lineinfile:
path: '{{ filestoser }}'
state: present
regexp: '^ServerRoot'
line: 'ServerRoot_new'
Your problem is that you're trying to use the variable filestoser as a filename, but it's not: it's the result of the find task. If you take a look at the output of your debug task you'll see something like this:
TASK [debug] **********************************************************************************
ok: [localhost] => {
"filestoser": {
"changed": false,
"examined": 44,
"failed": false,
"files": [
{
"atime": 1554394659.885133,
"ctime": 1554394659.885133,
"dev": 45,
"gid": 21937,
"gr_name": "lars",
"inode": 172846,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1554394659.885133,
"nlink": 1,
"path": "/tmp/etc/httpd/httpd.conf",
"pw_name": "lars",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 11753,
"uid": 21937,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
],
"matched": 1,
"msg": ""
}
}
In other words, filestoser is a dictionary. The files key contains a list of files that were matched by the files task. You could rewrite your lineinfile task like this, if you want to operate on the first file found:
- lineinfile:
path: '{{ filestoser.files.0.path }}'
state: present
regexp: '^ServerRoot'
line: 'ServerRoot_new'

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

How do i filter on ansible stat existence flags?

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.

Return Values of Ansible Commands

I am trying to find the return values of Ansible commands so I can better program in Ansible Playbooks. Using stat as an example. I don't see any any of the return values listed in the documentation.
http://docs.ansible.com/stat_module.html
I am however able to find them by doing adhoc commands. Is there a better way? Perhaps they are not documented because it is OS specific in each instance.
For example:
ansible 12.34.56.78 -m stat -a "path=/appserver"
12.34.56.78 | success >> {
"changed": false,
"stat": {
"atime": 1424197918.2113113,
"ctime": 1423779491.431509,
"dev": 64768,
"exists": true,
"gid": 1000,
"inode": 9742,
"isblk": false,
"ischr": false,
"isdir": true,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": false,
"issock": false,
"isuid": false,
"mode": "0755",
"mtime": 1423585087.2470782,
"nlink": 4,
"pw_name": "cloud",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 4096,
"uid": 1000,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": true,
"xoth": true,
"xusr": true
}
}
Your best bet is to do exactly what you did, or to write a playbook that dumps the contents of what the module returns:
- stat: path=/path/to/file
register: st
- debug: var=st
Part of the reason the stat command doesn't document everything it returns is because as the documentation for the module states:
Retrieves facts for a file similar to the linux/unix ‘stat’ command.
So you can find out what all those properties mean if you invoke man 2 stat in a linux shell.

Resources