-1

I want to check a directory with ansible if it's not empty. I want to have the server hostname or IP address if the directory is not empty. Can anyone help me? Thanks!

I tried to make a test.

- hosts: all
  tasks:
  - find :
      paths: /tmp/foo
      file_type: all
      hidden: true
    register: out

  - fail :
      msg: the /tmp/foo directory is not empty
    when: out.matched != 0
  • 3
    `... it doesn't work` is [not an accurate description of your problem](https://idownvotedbecau.se/itsnotworking/). Please read [ask] paying a particular attention to [mre] then [edit] your question to add the missing informations (what is the current behavior / error? what do you expect instead? what are the debugging steps already taken to start understanding the problem?). – Zeitounator Jun 01 '23 at 08:14

2 Answers2

1

Q: "Check a directory and list servers if empty."

A: There are two very useful patterns you should go step by step through and understand the details.

For example, given two remote hosts, the directory is empty on the second one

shell> ssh admin@test_11 find /tmp/test_dir
/tmp/test_dir
/tmp/test_dir/bar
/tmp/test_dir/foo
shell> ssh admin@test_13 find /tmp/test_dir
/tmp/test_dir

Find the files

    - find:
        paths: /tmp/test_dir
        file_type: any
        hidden: true
      register: out
  1. Crete a dictionary of the facts
  report: "{{ dict(ansible_play_hosts|
                   zip(ansible_play_hosts|
                       map('extract', hostvars, ['out', 'matched']))) }}"

gives

  report:
    test_11: 2
    test_13: 0
  1. Select/reject attributes from a dictionary and get the names of the attributes that match the condition
  empty: "{{ report|dict2items|
             rejectattr('value')|
             map(attribute='key') }}"

gives what you want

  empty:
    - test_13

Example of a complete playbook for testing

- hosts: all

  vars:

    report: "{{ dict(ansible_play_hosts|
                     zip(ansible_play_hosts|
                         map('extract', hostvars, ['out', 'matched']))) }}"
    empty: "{{ report|dict2items|
               rejectattr('value')|
               map(attribute='key') }}"

  tasks:

    - find:
        paths: /tmp/test_dir
        file_type: any
        hidden: true
      register: out

    - debug:
        var: report
      run_once: true

    - debug:
        var: empty
      run_once: true
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
0

I want to check a directory with Ansible if it's not empty.

Since it is not defined what empty means and if there could be zero byte files, I understand your question that you are interested in the folder size.

According Use folder size in Conditional

The size attribute returned by the stat module for a folder does not tell you the size of the folder's contents! It only reports the size of the directory entry, which may depend on a number of factors such as the number of files contained in the directory.

If you're looking to calculate the amount of data contained in a folder, you may proceed further with the answer there or Ansible: Need generic solution to find size of folder/directory or file.

Since that require to use command or shell which is not generally recommended for all cases, it might be possible to transfer the task into a Custom Module. To do so, creating a Custom Module written in Bash or Shell seems to be the best approach.

The following concept / example module takes a string parameter (path) and test if it is a directory or file. After it is providing the size of the directory with all files and including sub directories or the file size only as results set.

Concept / Example Module size.sh

#!/bin/sh

exec 3>&1 4>&2 > /dev/null 2>&1

# Create functions

function return_json() {

    exec 1>&3 2>&4

    jq --null-input --monochrome-output \
        --arg changed "$changed" \
        --arg rc "$rc" \
        --arg stdout "$stdout" \
        --arg stderr "$stderr" \
        --arg directory "$directory" \
        --arg file "$file" \
        --arg msg "$msg" \
       '$ARGS.named'

    exec 3>&1 4>&2 > /dev/null 2>&1

}

# Module helper functions

function dirsize() {

    du -sh "$path" | sort -h

}

function filesize() {

    du -sh "$path"

}

# Module main logic

function module_logic() {

    if [ -f "$path" ]; then
        filesize $path
        file="true"
    elif [ -d "$path" ]; then
        dirsize $path
        directory="true"
    else
        stderr="Cannot access: No such file or directory or Permission denied."
        rc=1
    fi

}

# Set default values

changed="false"
rc=0
stdout=""
stderr=""
directory="false"
file="false"
msg=""

source "$1"

# Check prerequisites

if ! which jq &>/dev/null; then
    exec 1>&3 2>&4
    printf "{ \"changed\": \"$changed\",
           \"rc\": \"1\" ,
           \"stdout\": \"\",
           \"stderr\": \"Command not found: This module require 'jq' installed on the target host. Exiting ...\",
           \"directory\": \"false\" ,
           \"file\": \"false\",
           \"msg\": \"\"}"
    exit 127
fi

if ! grep -q "Red Hat Enterprise Linux" /etc/redhat-release; then
    stderr="Operation not supported: Red Hat Enterprise Linux not found. Exiting ..."
    rc=95

    return_json

    exit $rc

fi

# Validate parameter key and value

if [ -z "$path" ]; then
    stderr="Invalid argument: Parameter path is not provided. Exiting ..."
    rc=22

    return_json

    exit $rc
fi

if [[ $path == *['!:*']* ]]; then
    stderr="Invalid argument: Value path contains invalid characters. Exiting ..."
    rc=22

    return_json

    exit $rc
fi

if [ ${#path} -ge 127 ]; then
    stderr="Argument too long: Value path has too many characters. Exiting ..."
    rc=7

    return_json

    exit $rc
fi

# Main

module_logic $path

changed="false"
msg=$(module_logic $path | sed 's/\t/ /g')

return_json

exit $rc

Test Playbook size.yml

---
- hosts: test
  become: false
  gather_facts: false

  tasks:

  - name: Get size behind path
    size:
      path: /root/anaconda-ks.cfg
    register: result
    ignore_errors: true

  - name: Get size behind path
    size:
      path: ''
    register: result
    ignore_errors: true

  - name: Get size behind path
    size:
    register: result
    ignore_errors: true

  - name: Get size behind path
    size:
      path: "/home/{{ ansible_user }}/*"
    register: result
    ignore_errors: true

  - name: Get size behind path
    size:
      path: "/home/{{ ansible_user }}/1111111111/2222222222/3333333333/4444444444/5555555555/6666666666/7777777777/8888888888/9999999999/0000000000/aaaaaaaaaa/bbbbbbbbbb/cccccccccc/"
    register: result
    ignore_errors: true

  - name: Get size behind path
    size:
      path: /home/{{ ansible_user }}
    register: result

  - name: Show result
    debug:
      var: result

Result ansible-playbook --user ${ANSIBLE_USER} size.yml

TASK [Get size behind path] **********************************************
fatal: [test.example.com]: FAILED! => changed=false
  msg: ''
  rc: '1'
  stderr: 'Cannot access: No such file or directory or Permission denied.'
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>
...ignoring

TASK [Get size behind path] **********************************************
fatal: [test.example.com]: FAILED! => changed=false
  msg: ''
  rc: '1'
  stderr: Parameter path is not provided. Exiting ...
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>
...ignoring

TASK [Get size behind path] **********************************************
fatal: [test.example.com]: FAILED! => changed=false
  directory: 'false'
  file: 'false'
  msg: ''
  rc: '22'
  stderr: 'Invalid argument: Value path contains invalid characters. Exiting ...'
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>
...ignoring

TASK [Get size behind path] **********************************************
fatal: [test.example.com]: FAILED! => changed=false
  msg: ''
  rc: '7'
  stderr: Argument 'path' too long. Exiting ...
  stderr_lines: <omitted>
  stdout: ''
  stdout_lines: <omitted>
...ignoring

TASK [Get size behind path] **********************************************
changed: [test.example.com]

TASK [Show result] *******************************************************
ok: [test.example.com] =>
  result:
    changed: 'false'
    failed: false
    msg: 722M /home/user
    rc: '0'
    stderr: ''
    stderr_lines: []
    stdout: ''
    stdout_lines: []

Thanks to

For script and module

For general Linux and Shell

U880D
  • 8,601
  • 6
  • 24
  • 40