I'm able to get the timestamp of a file using Ansible stat module.
- stat:
path: "/var/test.log"
register: filedets
- debug:
msg: "{{ filedets.stat.mtime }}"
The above prints mtime as 1594477594.631616 which is difficult to understand.
I wish to know how can I put a when condition check to see if the file is less than 20 hours old?
You can also achieve this kind of tasks without going in the burden to do any computation via find and its age parameter:
In your case, you will need a negative value for the age:
Select files whose age is equal to or greater than the specified time.
Use a negative age to find files equal to or less than the specified time.
You can choose seconds, minutes, hours, days, or weeks by specifying the first letter of any of those words (e.g., "1w").
Source: https://docs.ansible.com/ansible/latest/modules/find_module.html#parameter-age
Given the playbook:
- hosts: all
gather_facts: no
tasks:
- file:
path: /var/test.log
state: touch
- find:
paths: /var
pattern: 'test.log'
age: -20h
register: test_log
- debug:
msg: "The file is exactly 20 hours old or less"
when: test_log.files | length > 0
- file:
path: /var/test.log
state: touch
modification_time: '202007102230.00'
- find:
paths: /var
pattern: 'test.log'
age: -20h
register: test_log
- debug:
msg: "The file is exactly 20 hours old or less"
when: test_log.files | length > 0
This gives the recap:
PLAY [all] **********************************************************************************************************
TASK [file] *********************************************************************************************************
changed: [localhost]
TASK [find] *********************************************************************************************************
ok: [localhost]
TASK [debug] ********************************************************************************************************
ok: [localhost] => {
"msg": "The file is exactly 20 hours old or less"
}
TASK [file] *********************************************************************************************************
changed: [localhost]
TASK [find] *********************************************************************************************************
ok: [localhost]
TASK [debug] ********************************************************************************************************
skipping: [localhost]
PLAY RECAP **********************************************************************************************************
localhost : ok=5 changed=2 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
- stat:
path: "/var/test.log"
register: filedets
- debug:
msg: "{{ (ansible_date_time.epoch|float - filedets.stat.mtime ) > (20 * 3600) }}"
Related
I'm attempting to get an until loop working for an import_tasks, and to break the loop when it meets a condition within the import_tasks. Not sure if this is even possible, or if there's a better way to acheive this? Making it slightly more tricky is one of the tasks in include_tasks is a powershell script which returns a status message which is used to satisfy the until requirement.
So yeah, the goal is to run check_output.yml until there is no longer any RUNNING status reported by the script.
main.yml:
- import_tasks: check_output.yml
until: "'RUNNING' not in {{outputStatus}}"
retries: 100
delay: 120
check_output.yml
---
- name: "Output Check"
shell: ./get_output.ps1" # this will return `RUNNING` in std_out if it's still running
args:
executable: /usr/bin/pwsh
register: output
- name: "Debug output"
debug: outputStatus=output.stdout_lines
For the record, this works just fine if I don't use import_tasks and just use an until loop on the "Output Check" task. The problem with that approach is you have to run Ansible with -vvv to get the status message for each of the loops which causes a ton of extra, unwanted debug messages. I'm trying to get the same status for each loop without having to add verbosity.
Ansible version is 2.11
Q: "(Wait) until there is no longer any RUNNING status reported by the script."
A: An option might be the usage of the module wait_for.
For example, create the script on the remote host. The script takes two parameters. The PID of a process to be monitored and DELAY monitoring interval in seconds. The script writes the status to /tmp/$PID.status
# cat /root/bin/get_status.sh
#!/bin/sh
PID=$1
DELAY=$2
ps -p $PID > /dev/null 2>&1
STATUS=$?
while [ "$STATUS" -eq "0" ]
do
echo "$PID is RUNNING" > /tmp/$PID.status
sleep $DELAY
ps -p $PID > /dev/null 2>&1
STATUS=$?
done
echo "$PID is NONEXIST" > /tmp/$PID.status
exit 0
Start the script asynchronously
- command: "/root/bin/get_status.sh {{ _pid }} {{ _delay }}"
async: "{{ _timeout }}"
poll: 0
register: get_status
In the next step wait for the process to stop running
- wait_for:
path: "/tmp/{{ _pid }}.status"
search_regex: NONEXIST
retries: "{{ _retries }}"
delay: "{{ _delay }}"
After the condition passed or the module wait_for reached the timeout run async_status to make sure the script terminated
- async_status:
jid: "{{ get_status.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: "{{ _retries }}"
delay: "{{ _delay }}"
Example of a complete playbook
- hosts: test_11
vars:
_timeout: 60
_retries: "{{ (_timeout/_delay|int)|int }}"
tasks:
- debug:
msg: |-
time: {{ '%H:%M:%S'|strftime }}
_pid: {{ _pid }}
_delay: {{ _delay }}
_timeout: {{ _timeout }}
_retries: {{ _retries }}
when: debug|d(false)|bool
- command: "/root/bin/get_status.sh {{ _pid }} {{ _delay }}"
async: "{{ _timeout }}"
poll: 0
register: get_status
- debug:
var: get_status
when: debug|d(false)|bool
- wait_for:
path: "/tmp/{{ _pid }}.status"
search_regex: NONEXIST
retries: "{{ _retries }}"
delay: "{{ _delay }}"
- debug:
msg: "time: {{ '%H:%M:%S'|strftime }}"
when: debug|d(false)|bool
- async_status:
jid: "{{ get_status.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: "{{ _retries }}"
delay: "{{ _delay }}"
- debug:
msg: "time: {{ '%H:%M:%S'|strftime }}"
when: debug|d(false)|bool
- file:
path: "/tmp/{{ _pid }}.status"
state: absent
when: _cleanup|d(true)|bool
On the remote, start a process to be monitored. For example,
root#test_11:/ # sleep 60 &
[1] 28704
Run the playbook. Fit _timeout and _delay to your needs
shell> ansible-playbook pb.yml -e debug=true -e _delay=3 -e _pid=28704
PLAY [test_11] *******************************************************************************
TASK [debug] *********************************************************************************
ok: [test_11] =>
msg: |-
time: 09:06:34
_pid: 28704
_delay: 3
_timeout: 60
_retries: 20
TASK [command] *******************************************************************************
changed: [test_11]
TASK [debug] *********************************************************************************
ok: [test_11] =>
get_status:
ansible_job_id: '331975762819.28719'
changed: true
failed: 0
finished: 0
results_file: /root/.ansible_async/331975762819.28719
started: 1
TASK [wait_for] ******************************************************************************
ok: [test_11]
TASK [debug] *********************************************************************************
ok: [test_11] =>
msg: 'time: 09:07:27'
TASK [async_status] **************************************************************************
changed: [test_11]
TASK [debug] *********************************************************************************
ok: [test_11] =>
msg: 'time: 09:07:28'
TASK [file] **********************************************************************************
changed: [test_11]
PLAY RECAP ***********************************************************************************
test_11: ok=8 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Below is my playbook to print the file.
I used couple of approaches but the file is not printed as is i.e. the new line formatting is gone when ansible prints the file contents.
- name: List startup files
shell: cat /tmp/test.txt
register: readws
- debug:
msg: "/tmp/test.txt on {{ inventory_hostname }} is: {{ readws.stdout_lines }}"
- debug:
msg: "/tmp/test.txt on {{ inventory_hostname }} is: {{ lookup('file', '/tmp/test.txt') }}"
cat /tmp/test.txt
i
m
good
Expected Ansible output:
TASK [debug] *****************************************************************************************
ok: [localhost] => {
"msg": "/tmp/test.txt on localhost is:
i
m
good
"
}
Ansible output:
TASK [List startup files] ******************************************************************
changed: [localhost]
TASK [debug] *****************************************************************************************
ok: [localhost] => {
"msg": "/tmp/test.txt on localhost is: [u'i', u'm ', u'good']"
}
TASK [debug] *****************************************************************************************
ok: [localhost] => {
"msg": "/tmp/test.txt on localhost is: i\nm \ngood"
}
Can you please suggest ?
You cannot really get what you require (unless maybe if you change the output callback plugin...).
The closest you can get is by displaying a list of lines like in the following example:
- name: Show file content
vars:
my_file: /tmp/test.txt
msg_content: |-
{{ my-file }} on localhost is:
{{ lookup('file', my_file) }}
debug:
msg: "{{ msg_content.split('\n') }}"
This might help who might come looking for simpler way to display a file in ansible.
stdout_lines prints the file with reasonable formatting.
- name: display the file needed
shell: cat /tmp/test.txt
register: test_file
- debug:
var: test_file.stdout_lines
I want to check if there is a specific file in all subdirs of a folder. If the file doesn't exists, I want to create it.
This is my playbook:
---
- hosts: localhost
become: 'yes'
vars:
dir_path: "/tmp/test"
tasks:
- name: Find /tmp/test/ all directories
find:
paths: /tmp/test/
recurse: no
file_type: directory
register: dir_list
- debug: var=dir_list
- name: check if test file exists
stat:
path: "{{ dir_list.files | map(attribute='path') }}/test.txt"
register: file_exists
loop: "{{ dir_list.files | map(attribute='path') | list }}"
- name: create file
shell: touch {{ files_exists.item }}/test.txt
register: create_file
when: not file_exists.stat.exists
loop: "{{ file_exists.item }} | list }}"
But the "create file" fails, any idea how to solve this?
Your use of loop in the last tasks is wrong: you are not using the item created during iteration when checking for file existence.
(Note for your next question: avoid using sentences like "it fails" or "it doesn't work" on their own as they do not accurately describe your problem)
In your example, you are trying to create the file with shell when there is a file module made just for that purpose. I used it my below example:
The playbook:
---
- name: Create missing file in subdirs
hosts: localhost
gather_facts: false
vars:
dir_path: "/tmp/test"
file_name: "test.txt"
tasks:
- name: "Find subdirs in {{ dir_path }}"
find:
paths: "{{ dir_path }}"
recurse: no
file_type: directory
register: dir_list
- name: "Show result of dir listing "
debug:
var: dir_list
verbosity: 1
- name: "Check if {{ file_name }} exists in subdirs"
stat:
path: "{{ item }}/{{ file_name }}"
register: file_check
loop: "{{ dir_list.files | map(attribute='path') | list }}"
- name: "Show the file check result"
debug:
var: file_check
verbosity: 1
- name: "Create file where it does not exist"
file:
path: "{{ item }}/{{ file_name }}"
state: touch
loop: "{{ file_check.results | rejectattr('stat.exists') | map(attribute='item') | list }}"
Which gives (use ansible-playbook -v to see verbosity: 1 debug tasks)
# Create test dir and subdirs
$ for d in {a..d}; do mkdir -p /tmp/test/$d; done
# Add the test file in one dir for demo
$ touch /tmp/test/c/test.txt
# Show the situation before running the playbook
$ tree /tmp/test/
/tmp/test/
├── a
├── b
├── c
│ └── test.txt
└── d
4 directories, 1 file
# Run the playbook (run with debug for yourself if you wish)
$ ansible-playbook play.yml
PLAY [Create missing file in subdirs] *****************************************************************************************************************************************************************************
TASK [Find subdirs in /tmp/test] **********************************************************************************************************************************************************************************
ok: [localhost]
TASK [Show result of dir listing] *********************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Check if test.txt exists in subdirs] ************************************************************************************************************************************************************************
ok: [localhost] => (item=/tmp/test/a)
ok: [localhost] => (item=/tmp/test/b)
ok: [localhost] => (item=/tmp/test/c)
ok: [localhost] => (item=/tmp/test/d)
TASK [Show the file check result] *********************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Create file where it does not exist] ************************************************************************************************************************************************************************
changed: [localhost] => (item=/tmp/test/a)
changed: [localhost] => (item=/tmp/test/b)
changed: [localhost] => (item=/tmp/test/d)
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
# Check the result
$ tree /tmp/test/
/tmp/test/
├── a
│ └── test.txt
├── b
│ └── test.txt
├── c
│ └── test.txt
└── d
└── test.txt
4 directories, 4 files
# Run the playbook again to demonstrate idempotency
$ ansible-playbook play.yml
PLAY [Create missing file in subdirs] *****************************************************************************************************************************************************************************
TASK [Find subdirs in /tmp/test] **********************************************************************************************************************************************************************************
ok: [localhost]
TASK [Show result of dir listing] *********************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Check if test.txt exists in subdirs] ************************************************************************************************************************************************************************
ok: [localhost] => (item=/tmp/test/a)
ok: [localhost] => (item=/tmp/test/b)
ok: [localhost] => (item=/tmp/test/c)
ok: [localhost] => (item=/tmp/test/d)
TASK [Show the file check result] *********************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Create file where it does not exist] ************************************************************************************************************************************************************************
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
I'm working on a playbook that does the following:
Goes into a specified path on each Windows server
Slurps text from a file and adds it to a variable
Performs a check on the variable to see if a string of text exists
Writes the results to a file based on the outcome.
Here is the code I have for this:
---
- name: Slurps text from file on Windows server
hosts: win
gather_facts: false
tasks:
- name: Get text
slurp:
src: D:\testsearch.ini
register: norequest
- name: Check for norequest=false in variable
lineinfile:
dest: ./norequest.csv
line: "{{ inventory_hostname }} There is a false value"
state: present
create: true
insertafter: EOF
when: '"''NoRequest = False'' in norequest.content|b64decode"|lower'
delegate_to: localhost
- name: Check for norequest=true in variable
lineinfile:
dest: ./norequest.csv
line: "{{ inventory_hostname }} There is a true value."
state: present
create: true
insertafter: EOF
when: '"''NoRequest = True'' in norequest.content|b64decode"|lower'
delegate_to: localhost
Based on my results, it looks like the playbook slurps the text from the files on both test servers and adds it all to the variable, then performs the conditional check against one of the servers (since the task itself is being delegated to localhost) and outputs the results to the file as though they all came from SERVER1 (the last part seems to be due to the delegation).
PLAY [Slurps text from file on Windows server] *******************************
TASK [Delete previous norequest file] *******************************
changed: [SERVER1 -> localhost]
TASK [Get text] ***************************************
ok: [SERVER2]
ok: [SERVER1]
TASK [Check for norequest=false in variable] ********************************
changed: [SERVER1 -> localhost]
TASK [Check for norequest=true in variable] *******************************
changed: [SERVER1 -> localhost]
PLAY RECAP *******************************
SERVER1 : ok=4 changed=3 unreachable=0 failed=0
SERVER2 : ok=1 changed=0 unreachable=0 failed=0
Here are the contents of the file after the playbook is run:
SERVER1 There is a false value
SERVER1 There is a true value.
This is what the outcome should be if the playbook worked as I want it to:
SERVER1 There is a false value
SERVER2 There is a true value.
I feel like part (or all) of my issue might be that I'm looking at this through a PowerShell lens; as in, "FOR EACH server, get the text from the file, perform a conditional check, write the output to the outfile, then move on to the next server." Is something like that possible in an Ansible playbook? I've looked into dictionaries as a way to solve this, but the only good examples I could find used pre-existing dictionaries or dictionaries populated at runtime with basic server info.
Seems to me, that the when: condition was wrong. Matching is now done via a regexp. Tested it with this playbook:
---
- name: Slurps text from file on Windows server
hosts:
- SERVER1
- SERVER2
gather_facts: false
tasks:
- name: Get text
slurp:
src: D:\testsearch.ini
register: norequest
- name: Check for norequest=false in variable
lineinfile:
dest: ./norequest.csv
line: "{{ inventory_hostname }} There is a false value"
state: present
create: true
insertafter: EOF
when: 'norequest["content"] | b64decode | lower | regex_search("norequest *= *false")'
delegate_to: localhost
- name: Check for norequest=true in variable
lineinfile:
dest: ./norequest.csv
line: "{{ inventory_hostname }} There is a true value"
state: present
create: true
insertafter: EOF
when: 'norequest["content"] | b64decode | lower | regex_search("norequest *= *true")'
delegate_to: localhost
The file testsearch.ini has the following contents on the systems:
SERVER1
NoRequest = False
SERVER2
NoRequest = True
Executing the playbook with ansible-playbook -i hosts play.yml gives the following output:
PLAY [SERVER1,SERVER2] *********************************************************
TASK [Get text] ****************************************************************
ok: [SERVER1]
ok: [SERVER2]
TASK [Check for norequest=false in variable] ***********************************
skipping: [SERVER2]
ok: [SERVER1 -> localhost]
TASK [Check for norequest=true in variable] ************************************
skipping: [SERVER1]
ok: [SERVER2 -> localhost]
PLAY RECAP *********************************************************************
SERVER1 : ok=2 changed=0 unreachable=0 failed=0
SERVER2 : ok=2 changed=0 unreachable=0 failed=0
The contents of norequest.csv after the run is
SERVER1 There is a false value
SERVER2 There is a true value
Does anyone knows how to get the list of remote files under a particular Dir and to iterate over them and list out the contents of each file via ansible?
For example , i have a location /var/spool/cron and it has many files which i need to cat <file> by iterate over each of them.
fileglob and lookup works locally.
Below is the play but not working as expected.
---
- name: Playbook to quick check the cron jobs for user
hosts: all
remote_user: root
gather_facts: False
tasks:
- name: cron state
shell: |
ls /var/spool/cron/
register: cron_status
- debug: var=item
with_items:
- "{{ cron_status.stdout_lines }}"
Try this as an example
---
- name: Playbook
hosts: all
become: root
gather_facts: False
tasks:
- name: run ls-
shell: |
ls -d1 /etc/cron.d/*
register: cron_status
- name: cat files
shell: cat {{ item }}
register: files_cat
with_items:
- "{{ cron_status.stdout_lines }}"
- debug: var=item
with_items:
- "{{ files_cat.results| map(attribute='stdout_lines')|list }}"
Just for the sake you someones Intrest..
Below Play will give you more cleaner stdout
---
- name: hostname
hosts: all
become: root
gather_facts: False
tasks:
- name: checking cron entries
shell: more /var/spool/cron/*
register: cron_status
- debug: var=cron_status.stdout_lines