Ansible check file problem

banderas20

Active Member
Joined
Aug 1, 2018
Messages
131
Reaction score
50
Credits
1,035
Hi!

I'm running a simple ansible playbook which performs a task depending if a file exists or not.

My playbook looks like this:

Code:
tasks:
    - name: Check file
      stat:
        path: /opt/local/dir/foo/dir2/dir3/
      register: file_data1
    
    - name: Reports existing folder
      debug:
        msg: "File exists"
      when: file_data1.stat.exists

The playbook reports the existence of the file if path is "/opt/local/dir/foo/dir2/".
If the path is "/opt/local/dir/foo/dir2/dir3/" or deeper, it doesn't work.

It seems an issue with the file depth. But I haven't found anything related.

Can you help me?

Thanks!
 


I tested your playbook and added a task. It seems to work for me.
Code:
- hosts: all
  tasks:
    - name: Check file
      stat:
        path: /opt/local/dir/foo/dir2/dir3/
      register: file_data1
 
    - name: Reports existing folder
      debug:
        msg: "File exists"
      when: file_data1.stat.exists
 
    - name: Reports existing folder as var
      debug:
        var: file_data1.stat.path
      when: file_data1.stat.exists

Code:
TASK [Reports existing folder]

ok: [testhost] => {
    "msg": "File exists"
}

TASK [Reports existing folder as var]

ok: [testhost] => {
    "file_data1.stat.path": "/opt/local/dir/foo/dir2/dir3"
}
 
Last edited:
- hosts: all

Looks like he is missing a hosts section.

My playbooks usually have a header that looks like this.

---
- name: Gather Server Information
hosts: 10.0.0.175
gather_facts: no

tasks:

... then the rest of the playbook here.
 
Looks like he is missing a hosts section.

My playbooks usually have a header that looks like this.

---
- name: Gather Server Information
hosts: 10.0.0.175
gather_facts: no

tasks:

... then the rest of the playbook here.
I have the hosts section. I removed it from the snippet.

I tested your playbook and added a task. It seems to work for me.
Code:
- hosts: all
  tasks:
    - name: Check file
      stat:
        path: /opt/local/dir/foo/dir2/dir3/
      register: file_data1
 
    - name: Reports existing folder
      debug:
        msg: "File exists"
      when: file_data1.stat.exists
 
    - name: Reports existing folder as var
      debug:
        var: file_data1.stat.path
      when: file_data1.stat.exists

Code:
TASK [Reports existing folder]

ok: [testhost] => {
    "msg": "File exists"
}

TASK [Reports existing folder as var]

ok: [testhost] => {
    "file_data1.stat.path": "/opt/local/dir/foo/dir2/dir3"
}

Still doesn't work for me.

Code:
TASK [Reports existing folder] **********************************************************************************************************************************************
skipping: [server]

TASK [Reports existing folder as var] **********************************************************************************************************************************************
skipping: [server]




My ansible version and config:
Code:
ansible [core 2.14.16]
  config file = None
  configured module search path = ['/home/alberto/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/alberto/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.11.2 (main, Aug 26 2024, 07:20:54) [GCC 12.2.0] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True

Thanks!
 
My ansible version and config:
Code:
ansible [core 2.14.14]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/maarten/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /home/maarten/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.18 (main, Oct  4 2024, 00:00:00) [GCC 11.4.1 20231218 (Red Hat 11.4.1-3)] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True
 
Last edited:
Last edited:
I setup a virtualenv with the same ansible-core and python version as yours.

Code:
ansible --version                                                                                                                                                                                                                                                                                                                           17:39:57  324µs 
ansible [core 2.14.16]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/maarten/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/maarten/venv/ansible/lib64/python3.11/site-packages/ansible
  ansible collection location = /home/maarten/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/maarten/venv/ansible/bin/ansible
  python version = 3.11.7 (main, Oct  9 2024, 00:00:00) [GCC 11.4.1 20231218 (Red Hat 11.4.1-3)] (/home/maarten/venv/ansible/bin/python3.11)
  jinja version = 3.1.4
  libyaml = True

It still works.
Code:
PLAY [all]

TASK [Gathering Facts]

ok: [localhost]

TASK [Check file]

ok: [localhost]

TASK [Reports existing folder]

ok: [localhost] => {
    "msg": "File exists"
}

TASK [Reports existing folder VAR]

ok: [localhost] => {
    "file_data1.stat.path": "/opt/local/dir/foo/dir2/dir3"
}
 
Last edited:
Hi @f33dm3bits ,

I have tried with another directory with even more depth level and it works (???). However, with that specific directory it doesn't.
I was thinking about permission issues, but I am running the playbook as an user with privileges over the folder.
Then I also checked in case there were symlinks, so I added "follow": true, but it doesn't work either. Moreover there aren't symlinks.

I ran the playbook with verbosity (-vvv) and I got no information:

Code:
ok: [server] => {
    "changed": false,
    "invocation": {
        "module_args": {
            "checksum_algorithm": "sha1",
            "follow": true,
            "get_attributes": true,
            "get_checksum": true,
            "get_md5": false,
            "get_mime": true,
            "path": "/opt/local/dir/foo/dir2/dir3"
        }
    },
    "stat": {
        "exists": false
    }
}

It's very strange...
 
I was thinking about permission issues, but I am running the playbook as an user with privileges over the folder.
If you run Ansible as a user who doesn't have a permission for a directory you get a fatal, permission denied.
Code:
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Permission denied"}

Are you using the default ansible.cfg or did you customize it?
 
If you run Ansible as a user who doesn't have a permission for a directory you get a fatal, permission denied.
Code:
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Permission denied"}

Are you using the default ansible.cfg or did you customize it?
I have configured nothing. In fact, apparently I have no config file:

config file = None
 
config file = None
Try placing a default ansible.cfg in your working directory where you run ansible from.
How did you install Ansible? Which Linux distribution are you using and which version?
 
Last edited:
Try placing a default ansible.cfg in your working directory where you run ansible from.
How did you install Ansible? Which Linux distribution are you using and which version?
I have placed that default cfg file.
I installed it with sudo apt install ansible in a Debian GNU/Linux 12 (bookworm)
 
I have placed that default cfg file.
I installed it with sudo apt install ansible in a Debian GNU/Linux 12 (bookworm)
I installed that.
Code:
grep -i pretty /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"


ansible --version
ansible [core 2.14.16]
  config file = None
  configured module search path = ['/home/maarten/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/maarten/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.11.2 (main, Aug 26 2024, 07:20:54) [GCC 12.2.0] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True
It still works for me.
Code:
TASK [Reports existing folder] 


ok: [localhost] => {
    "msg": "File exists"
}

TASK [Reports existing folder VAR] 
ok: [localhost] => {
    "file_data1.stat.path": "/opt/local/dir/foo/dir2/dir3"
}
What do you use to execute your playbook?
 
I installed that.
Code:
grep -i pretty /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"


ansible --version
ansible [core 2.14.16]
  config file = None
  configured module search path = ['/home/maarten/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/maarten/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.11.2 (main, Aug 26 2024, 07:20:54) [GCC 12.2.0] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True
It still works for me.
Code:
TASK [Reports existing folder]


ok: [localhost] => {
    "msg": "File exists"
}

TASK [Reports existing folder VAR]
ok: [localhost] => {
    "file_data1.stat.path": "/opt/local/dir/foo/dir2/dir3"
}
What do you use to execute your playbook?
ansible-playbook -i inventory.yml file.yaml -u user -vvv --ask-pass

The host is defined at the top of the playbook.
 
A few ansible tips.

Some distro's by default put the ansible.cfg in /etc/ansible
That is where ansible expects it to be by default.

You can also create a file called "hosts" and put it in /etc/ansible
Then you don't have to include the inventory file every time you type the command.

vvv is a little too verbose for me, I usually use a single v, unless I'm really having problems.

If you install a package called "sshpass" ( available for most distros ) and copy the ssh key over
then you don't have to enter a password everytime. A simple way to do this is..

ssh-keygen -t ecdsa -b 384


Just press enter several times to go with the defaults, I recommend not using a passphrase ( leave it null )
After the key is created, run the following command as the user you run the playbook as.

ssh-copy-id [email protected]

You will have to type in the password once, but after that you shouldn't need to.

Finally, if I can ( this isn't always possible ) I test it locally. In the example above where you are
simply grepping for the release name in the os-release file, you could probably do that on the localhost.
The advantage of doing this, is that you know the script works and it isn't a ssh or permission problems
before you run it remotely.

When possible use the built-in ansible modules, instead of writing your own. For example...

Code:
- name: Gather Server Information
  hosts: localhost
  gather_facts: yes

  tasks:

    - name: Get Uptime
      command: "uptime -p"
      register: uptime_result

    - name: Get Video Card
      shell: "lspci | grep VGA | cut -f3 -d:"
      register: shell_output

    - name: Replace null video if needed
      set_fact:
        video: "{{ shell_output.stdout | default('unknown') }}"

    - name: Check for root filesystem device
      shell: "mount | grep ' / ' | awk '{ print $1 }'"
      register: root_fs_device
      changed_when: false
      failed_when: root_fs_device.rc != 0

    - name: Create Text Output
      set_fact:
        server_info_text: |
          Hostname: {{ ansible_nodename }}
          CPU Model: {{ ansible_processor[2] }}
          CPU Cores: {{ ansible_processor_vcpus }}
          Date and Time: {{ ansible_date_time.date }} {{ ansible_date_time.time }}
          IPv4 Address: {{ ansible_default_ipv4.address }}
          Interface: {{ ansible_default_ipv4.interface }}
          IPv4 Netmask: {{ ansible_default_ipv4.netmask }}
          IPv4 Gateway: {{ ansible_default_ipv4.gateway }}
          MAC Address: {{ ansible_default_ipv4.macaddress }}
          IPv6 Address: {{ ansible_default_ipv6.address }}
          IPv6 Gateway: {{ ansible_default_ipv6.gateway }}
          IPv6 Prefix: {{ ansible_default_ipv6.prefix }}
          Distribution: {{ ansible_distribution }} {{ ansible_distribution_version }}
          Kernel: {{ ansible_kernel }}
          SELinux Status: {{ ansible_selinux.status }}
          Uptime: {{ uptime_result.stdout }}
          Memory: {{ ansible_memtotal_mb }} MB
          Video Card: {{ video }}
          Python Version: {{ ansible_python_version }}

    - name: Print Text Output
      debug:
        msg: "{{ server_info_text }}"

There is a line in this playbook, that has ansible_distribution and ansible_distribution_version.
There is another line with ansible_kernel

These are built in modules that will give you the same info as grepping the os-release file.

To see a list of all the standard macros, run this command.

ansible -m setup localhost

There are a lot more, but that's good start.
 
ansible-playbook -i inventory.yml file.yaml -u user -vvv --ask-pass
You don't need to use -u if your user on the system you are running ansible from is the same as on the remote host. This is all I use, for your test playbook. I just use an inventory file since I'm used to that but shouldn't make a difference for this test.
Code:
ansible-playbook -i inventory -l localhost test.yml
ansible-playbook -i inventory -l 192.168.122.118 test.yml
 
Still doesn't work for me.

Code:
TASK [Reports existing folder] **********************************************************************************************************************************************
skipping: [server]

TASK [Reports existing folder as var] **********************************************************************************************************************************************
skipping: [server]
With my Debian 12 install and Ansible the only way I have been able to replicate this result is by changing the first task to a non-existing directory name, which then looks like this.

Code:
- hosts: all
  tasks:
    - name: Check file
      stat:
        #path: /opt/local/dir/foo/dir2/dir3
        path: /opt/local/dir/foo/dir2/dir33
      register: file_data1
   
    - name: Reports existing folder
      debug:
        msg: "File exists"
      when: file_data1.stat.exists
   
    - name: Reports existing folder VAR
      debug:
        var: file_data1.stat.path
      when: file_data1.stat.exists
When executed that looks like this.
Code:
TASK [Gathering Facts]
ok: [localhost]

TASK [Check file]

ok: [localhost]

TASK [Reports existing folder]

skipping: [localhost]

TASK [Reports existing folder VAR]

skipping: [localhost]
So it makes me think you might have a typo in one of the directories on the host where you are running it or you made a typo in the path name in the playbook task. So that the path in the task doesn't correspond to the path on the remote host your are checking for, that's the only reasonable explanation that would makes sense of this.
 
So it makes me think you might have a typo in one of the directories on the host where you are running it or you made a typo in the path name in the playbook task. So that the path in the task doesn't correspond to the path on the remote host your are checking for, that's the only reasonable explanation that would makes sense of this.
I'm using -u because the user is different. Thanks for pointing it out. ;)

It can't be a typo, because if I login into the target server and paste the path from my playbook into the console, the prompt moves to that directory.

To recap, I'm running this command:
Code:
ansible-playbook -i inventory.yml playbook.yaml -u user -v --ask-pass

Code:
TASK [Checking folder1] **********************************************************************************************************************************************
ok: [server] => {"changed": false, "stat": {"exists": false}}

If I change the path to check on the playbook by an upper level, it does find the folder.
 
It can't be a typo, because if I login into the target server and paste the path from my playbook into the console, the prompt moves to that directory.
Share the permissions and ownership(user and group) of the entire directory structure of "/opt/local" and your remote user, that way I can replicate your situation. Because there is no way in hell that the stat module is the problem because I am using the same Debian version and Ansible version as you on my test system where I am running your playbook.
 
Try creating a task that creates the "missing directory" first, run it and see what happens?
Code:
tasks:
    - name: Create missing directory
      file:
        path: /opt/local/dir/foo/dir2/dir3
        state: directory
        mode: "0755"
 
    - name: Check file
      stat:
        path: /opt/local/dir/foo/dir2/dir3
      register: file_data1
 
    - name: Reports existing folder, msg?
      debug:
        msg: "File exists"
      ignore_errors: true
      when: file_data1.stat.exists
 
    - name: Reports existing folder, var?
      debug:
          var: file_data1.stat.path
      ignore_errors: true
      when: file_data1.stat.exists
 
Last edited:

Members online


Top