Skip to content
Advertisement

find the latest file that was modified within last minute in ansible?

I have a list of files in a particular directory as shown below:

david@host:~/jobs/process/workspace/files$ ls -lrth
total 68K
-rw-r--r-- 1 david david 7.8K Oct  1 11:10 golden_proc.init.1569953435497
-rw-r--r-- 1 david david 7.7K Oct  2 12:11 golden_proc.init.1570043494149
-rw-r--r-- 1 david david 7.7K Oct  2 20:15 golden_proc.init.1570072510929

Each file name ends with timestamp in it. Now I need to find one latest file which was modified or created just a minute back in ansible.

  • If there is no file like that then return successfully from the ansible by logging “cannot find any file” if this is possible to do.
  • If there is a file like that then copy that file to “/tmp” folder.
  • If there are multiple files generated or modified in the last minute then use the latest one.

Is this possible to do in ansible? I saw there is a find module in ansible but not sure how can I make above things work using that module?

---
- name: Play 1
  hosts: 127.0.0.1
  tasks:
      - name: find the latest file
        find: paths=/var/lib/jobs/workspace/process/files
              file_type=file
              age=-{{ time_window }}m
              age_stamp=mtime
        register: files

Advertisement

Answer

This is definitely something possible, you are even close from the solution.

As you might have seen it doing a debug of your find already, the return of it contains a list of files, this list would just be empty if you have no file.

So it become pretty easy to see when the list is empty with Jinja

- debug:
    msg: '{{ files.files if files.files|count > 0 else "cannot find any file" }}'

This syntax is using an inline if as well as a count filter.

Regarding the fact that you want the most recent file now, you can also use a set of Jinja filers: the filter sort will help you sort the files by modification time, and the filter first will help you get only the first element of you list.

- debug:
    msg: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path }}'

Now you just need to combine both in one long Jinja expression:

- debug:
    msg: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path if files.files|count > 0 else "cannot find any file" }}'

In order to copy the file, you will need one extra Jinja filter that is specific to Ansible and that is basename, in order to get the name of the file out of its full path

- debug:
    msg: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path | basename if files.files|count > 0 else "cannot find any file" }}'

But you will also need the when statement so your copy will be skipped if there is no matching file:

- name: Copy file, if found                 
  copy:
    src: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path }}'
    dest: '/tmp/{{ (files.files | sort(attribute="mtime", reverse=true) | first).path | basename }}'
  when: files.files|count > 0

A full working playbook for you to test:

---
- hosts: localhost
  connection: locale

  vars:
    var_files:
      - { 'name': 'a', 'time': 86400 }
      - { 'name': 'b', 'time': 30 }
      - { 'name': 'c', 'time': 20 }

  tasks:
    - name: creating a bunch of matching files
      file:
        path: '/data/{{ item.name }}'
        state: touch
      with_items: '{{ var_files }}'

    - name: aging those files
      file:
        path: '/data/{{ item.name }}'
        modification_time: '{{ "%Y%m%d%H%M.%S" | strftime( ( ansible_date_time.epoch | int ) - item.time ) }}'
      with_items: '{{ var_files }}'

    - name: find the latest file
      find: paths=/data
        file_type=file
        age=-1m
        age_stamp=mtime
      register: files

    - debug:
        msg: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path if files.files|count > 0 else "cannot find any file" }}'

    - name: Copy file, if found
      copy:
        src: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path }}'
        dest: '/tmp/{{ (files.files | sort(attribute="mtime", reverse=true) | first).path | basename }}'
      when: files.files|count > 0

    - name: removing files to test the behaviour with no matching files
      file:
        path: '/data/{{ item.name }}'
        state: absent
      with_items: '{{ var_files }}'

    - name: find the latest file
      find: paths=/data
        file_type=file
        age=-1m
        age_stamp=mtime
      register: files

    - debug:
        msg: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path if files.files|count > 0 else "cannot find any file" }}'    

    - name: Copy file, if found                 
      copy:
        src: '{{ (files.files | sort(attribute="mtime", reverse=true) | first).path }}'
        dest: '/tmp/{{ (files.files | sort(attribute="mtime", reverse=true) | first).path | basename }}'
      when: files.files|count > 0

And the corresponding output of that playbook

PLAY [localhost] ********************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************
ok: [localhost]

TASK [creating a bunch of matching files] *******************************************************************************************************
changed: [localhost] => (item={'name': 'a', 'time': 86400})
changed: [localhost] => (item={'name': 'b', 'time': 30})
changed: [localhost] => (item={'name': 'c', 'time': 20})

TASK [aging those files] ************************************************************************************************************************
changed: [localhost] => (item={'name': 'a', 'time': 86400})
changed: [localhost] => (item={'name': 'b', 'time': 30})
changed: [localhost] => (item={'name': 'c', 'time': 20})

TASK [find the latest file] *********************************************************************************************************************
ok: [localhost]

TASK [debug] ************************************************************************************************************************************
ok: [localhost] => {
    "msg": "/data/c"
}

TASK [Copy file, if found] **********************************************************************************************************************
changed: [localhost]

TASK [removing files to test the behaviour with no matching files] ******************************************************************************
changed: [localhost] => (item={'name': 'a', 'time': 86400})
changed: [localhost] => (item={'name': 'b', 'time': 30})
changed: [localhost] => (item={'name': 'c', 'time': 20})

TASK [find the latest file] *********************************************************************************************************************
ok: [localhost]

TASK [debug] ************************************************************************************************************************************
ok: [localhost] => {
    "msg": "cannot find any file"
}

TASK [Copy file, if found] **********************************************************************************************************************
skipping: [localhost]

PLAY RECAP **************************************************************************************************************************************
localhost                  : ok=9    changed=4    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
Advertisement