Stat returns false, but the file does exist

Hi!

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

My playbook looks like this:

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.

Can you help me?

Thanks!

Try debugging the result, for example:

tasks:

    - name: Check path
      ansible.builtin.stat:
        path: /opt/local/dir/foo/dir2/dir3
      register: path
    
    - name: Debug path.stat
      ansible.builtin.debug:
        var: path.stat

And post the result from the above here?

1 Like

Could you detail exactly in what way “it doesn’t work”? I can easily imagine it doesn’t do what you expect it to do, but “doesn’t work” is a higher bar.

In my test, the playbook fails with the message “Permission denied”, because the directory one level up is owned by root and is not readable by me.

What are the mode, owner, and group of /opt/local/dir/foo/dir2? And what user is your playbook running as on the target host? Those two things probably explain why your playbook can’t stat something inside …/dir2.

2 Likes

Sure.

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

TASK [Debug path.stat] ***************************************************************************************************************************************************************************************
ok: [server] => {
    "file_data1.stat": {
        "exists": false
    }
}

Sure!
If path is /opt/local/dir/foo/dir2/, task reports “File exists”
However, if path is /opt/local/dir/foo/dir2/dir3/, the task says the file doesn’t exist. Which is not true. It indeed exists.

In my case both directories have the same permissions.

/opt/local/dir/foo/dir2/

Access: (0770/drwxrwx---)  Uid: (  853/User2)   Gid: (  850/ Group1)

/opt/local/dir/foo/dir2/dir3/

Access: (0770/drwxrwx---)  Uid: (  853/User2)   Gid: (  850/ Group1)

I’m running my playbook as a user with permissions on the target host. It doesn’t make sense that one directory is reported as existing = true, and the other one as false.

For more info, I issue the following command:

ansible-playbook -i inventory.yml download.yaml -u user1 -v --ask-pass

Thanks for your help!

Consider the output of these commands on the target host:

$ getent passwd user1
$ getent group 850

My guess is “user1” is not a member of group 850 (“Group1” or “group1”?).
user1” has permissions to read /opt/local/dir/foo and can therefore read the directory entry for /opt/local/dir/foo/dir2, but, being neither user2 nor a member of group 850, user1 doesn’t have permissions to read the directory /opt/local/dir/foo/dir2 and therefore cannot read the directory entry for /opt/local/dir/foo/dir2/dir3.

I’m running my playbook as a user with permissions on the target host.

That statement doesn’t help us help you very much.

It doesn’t make sense that one directory is reported as existing = true, and the other one as false.

It doesn’t make sense to you, yet, but we’ll fix that eventually. :slight_smile: The system is not the one that’s confused; it appears to be working fine.

2 Likes

getent passwd user1
user1:x:856:850::/home/user1:/bin/bash

getent group 850
User2:x:850:User3,User1

haha. You’re right. I mean I can SSH to the target server with the same user, and navigate to the specific folder without any problem. :slight_smile:

Thanks!

1 Like

I was hoping those upper-case "U"s were just some weird copy/paste issue.
Do you really have a “User1and a user1? Case matters. So does sanity. If they are supposed to be the same user, you need to spell them the same way. (I strongly recommend all lower-case user and group names.)

$ getent passwd user1   # should return data
$ getent passwd User1   # should return nothing
1 Like

Hi.

Maybe it’s a copy/paste, but I only have a “user1”. No User1 exists.

You have to be exact when you’re trying to get other people to help you, if not only for politness’s sake but because things like case sensitivity do matter in Linux. It makes troubleshooting difficult when one goes through your post history and user1 and user2 are arbitrarily exchanged for User1 and User2, which may or may not be part of the problem.

For whatever it’s worth, I tried to simulate your problem on my own WSL environment and Ansible works fine (so it isn’t a problem where Ansible loses its mind when a directory tree is six directories deep or something). I also simulated some of the solutions posted here, and it looks like if you don’t have permission to a higher level directory in the tree, stat will return “permission denied” and it doesn’t seem like you’re seeing that. So I am kinda intrigued at what’s going on in your environment.

To me, it may be most helpful if you did an “ls -d” on every single directory in the path “/opt/local/dir/foo/dir2/dir3” as in

ls -ld /opt/
ls -ld /opt/local/
ls -ld /opt/local/dir/
ls -ld /opt/local/dir/foo/
ls -ld /opt/local/dir/foo/dir2/
ls -ld /opt/local/dir/foo/dir2/dir3/

And pasting the results here, ensuring your case-sensitivity correctly matches what you post here to your target system that’s exhibiting the problem. This’d help me, at least, create an identical tree structure to what you have.

Also, random thought… but your dir3 isn’t a hard or soft link, is it?

3 Likes

There’s your problem: “user1” is not in the 850 group.

User1” is, or would be if such a user existed.

user1” ≠ “User1

2 Likes

Hi @mcen1 and @utoddl.

I’m trying to be as much specific as possible, but the confussion with the users may come from the fact that I’m trying to obfuscate real data. For me it would be easier just copy and paste, but there’s sensitive data I don’t want to post, and that makes it more difficult for all of us.

Let me think about your posts and about the way of sharing data without leading to confussion.

One way or another, you r help is greatly appreciated :slight_smile:

Hi again

I have several servers with (in theory) the same configuration. So I have run the playbook against 4 of them.

Trying to narrow down the problem, I have found some similarities and differences between those that work as expected and those that don’t.

The following data has been retrieved logging into each server via SSH as the same user (user1) that runs the ansible playbook from the control node.

For the pair of servers that ansible reports existing folder.

Folder permissions: 750
Uid: 853
Gid: 850
getent passwd user1
user1:x:856:850:Application User:/home/user1:/bin/bash
getent group 850
Group850:x:850:
id
uid=856(user1) gid=850(Group850) groups=850(Group850),856(Group856) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

For the pair of servers that ansible reports NON existing folder.

Folder permissions: 770 (broader permissions)
Uid: 853
Gid: 850
getent passwd user1
user1:x:856:850::/home/user1:/bin/bash
getent group 850
Group850:x:850:user1, (and other users)
id
uid=856(user1) gid=850(Group850) groups=850(Group850),856(Group856) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Hope this helps us to solve the mistery.

This seems to indicate that you’re running the system with SELinux.
The output of ‘id’ (you seem to have forgotten the invocation in the second text) shows that the context is the same. But it also shows that the user is part of more groups.
From what I remember of SELinux, that can (negatively) affect what the user can do.

Since the problem is a permission problem (one way or the other), the solution could be to either make sure the group membership is the same, or the folder has the same permissions.
Or tweak the SELinux settings so that the user has sufficient effective permissions.
I don’t use SELinux (for this very reason) so I don’t know how to do that.

I remember being surprised upon learning that group memberships in /etc/groups were supplemental, that it wasn’t necessary or even desired for users primary groups – as per /etc/passwd – to be reflected in /etc/groups.

It would be interesting to see if the situation changed on one of these hosts where user1:x:856:850 and you then removed the unnecessary listing of user1 from the /etc/group entry for Group850. That’s the experiment I would try next.


* I'm assuming your passwd and group entries are coming from local files in /etc. If that's not the case, please mention that.

Indeed, I’m running SELinux. It was not my choice :slight_smile:

I’m limitated with regards to the operations I can do on the server. I can’t add or remove users / groups :frowning:

The passwd and groups show the same if I check the /etc files. IE:

cat /etc/passwd | grep user1
user1:x:856:850:Application user :/home/ user1:/bin/bash

cat /etc/group | grep 850
Group850:x:850:

It’s odd that Group 850 shows no users (???), and it’s curiously the case when ansible reports existing file …

That is precisely the point I’m curious about. if “getent group 850” shows something different from “grep :850: /etc/group”, then that’s one problem. If that difference is what’s causing different results from Ansible’s “stat” task, then (2) I and I’m sure others here would be interested in that, and (1) your organization has business reasons to investigate since it may have impacts for y’all.

Understood, and I sympathize. Someone, though, must have administrative rights (i.e. root). I’d recommend having a conversation them about this, in particular to remove primary group members from the supplemental groups list.

Tangentially, I’m running SELinux on every host I touch, have been for years, and am glad of it. While my gut feeling is this isn’t an SELinux issue, it also wouldn’t be the first time I’ve been wrong in that regard. Grain of salt, etc.

In my case, getent group 850 shows the same as grep :850: /etc/group

I’ll try to talk to some with admin rights, because it might be a rights collision of some kind.

Thanks!