A normal file.recurse state results in broken permissions of the managed directory.
Use a state such as:
/home/foo/.hooks:
file.recurse:
- source: salt://users/files/hooks
- user: foo
- group: foo
- dir_mode: 2755
- file_mode: 755
which creates the following directory:
/home/foo# ls -lah
total 32K
drwxr-x--- 5 foo foo 4.0K Jul 26 09:00 .
drwxr-xr-x 4 root root 4.0K Jul 26 08:59 ..
...
dr-x--xrwt 3 foo foo 4.0K Jul 26 09:00 .hooks
...
I had to add an explicit file.directory state for /home/foo/.hooks to get correct (and sensible) permissions.
# salt-minion --versions-report
Salt Version:
Salt: 2016.3.1
Dependency Versions:
cffi: 0.8.6
cherrypy: Not Installed
dateutil: 2.2
gitdb: Not Installed
gitpython: Not Installed
ioflo: Not Installed
Jinja2: 2.7.3
libgit2: Not Installed
libnacl: Not Installed
M2Crypto: Not Installed
Mako: Not Installed
msgpack-pure: Not Installed
msgpack-python: 0.4.2
mysql-python: 1.2.3
pycparser: 2.10
pycrypto: 2.6.1
pygit2: Not Installed
Python: 2.7.9 (default, Mar 1 2015, 12:57:24)
python-gnupg: Not Installed
PyYAML: 3.11
PyZMQ: 14.4.0
RAET: Not Installed
smmap: Not Installed
timelib: Not Installed
Tornado: 4.2.1
ZMQ: 4.0.5
System Versions:
dist: debian 8.5
machine: x86_64
release: 3.16.0-4-amd64
system: Linux
version: debian 8.5
# salt --versions-report
Salt Version:
Salt: 2016.3.1
Dependency Versions:
cffi: 0.8.6
cherrypy: Not Installed
dateutil: 2.2
gitdb: 0.5.4
gitpython: 0.3.2 RC1
ioflo: Not Installed
Jinja2: 2.7.3
libgit2: Not Installed
libnacl: Not Installed
M2Crypto: Not Installed
Mako: Not Installed
msgpack-pure: Not Installed
msgpack-python: 0.4.2
mysql-python: 1.2.3
pycparser: 2.10
pycrypto: 2.6.1
pygit2: Not Installed
Python: 2.7.9 (default, Mar 1 2015, 12:57:24)
python-gnupg: Not Installed
PyYAML: 3.11
PyZMQ: 14.4.0
RAET: Not Installed
smmap: 0.8.2
timelib: Not Installed
Tornado: 4.2.1
ZMQ: 4.0.5
System Versions:
dist: debian 8.5
machine: x86_64
release: 3.16.0-4-amd64
system: Linux
version: debian 8.5
@babilen i'm not able to replicate this on centos7 salt 2016.3.1:
ch3ll@ch3ll-master î‚° /srv/salt î‚° ls -lah /home/foo/
total 12K
drwxr-sr-x. 3 ch3ll ch3ll 4.0K Jul 27 11:27 .
drwxr-xr-x. 11 root root 4.0K Jul 27 11:36 ..
drwxr-sr-x. 2 ch3ll ch3ll 4.0K Jul 27 11:27 .hooks
Using the state:
/home/.hooks:
file.recurse:
- source: salt://test1/hooks
- user: ch3ll
- group: ch3ll
- dir_mode: 2755
- file_mode: 755
Anything i'm missing? Are you running this with a pre-existing directory maybe? Anything that would help me to replicate this. thanks
Thank you for testing this, @Ch3LL !
The only striking difference is that I run it on Debian and not CentOS, but that really shouldn'tâ„¢ make a difference. I'll look into this again, but I've seen this both on vagrant boxes and actual VMs, so I doubt that it is specific to my testing setup.
So, I managed to reproduce it. This _only_ happens if the directory doesn't exist yet and multiple directories are being created (i.e. files being synced are found in nested directories).
The exact configuration I used was:
# cat /srv/salt/salttest/top.sls
base:
'*':
- recurse_bug
# cat /srv/salt/salttest/recurse_bug.sls
/home/vagrant/.hooks:
file.recurse:
- source: salt://users/files/hooks
- user: vagrant
- group: vagrant
- dir_mode: 2755
- file_mode: 755
# find /srv/salt/salttest/users/
/srv/salt/salttest/users/
/srv/salt/salttest/users/files
/srv/salt/salttest/users/files/hooks
/srv/salt/salttest/users/files/hooks/foo
/srv/salt/salttest/users/files/hooks/foo/bar
/srv/salt/salttest/users/files/hooks/foo/bar/baz
/srv/salt/salttest/users/files/hooks/foo/bar/baz/some_file
# ls -lah ~vagrant/.hooks/
total 12K
dr-x--xrwt 3 vagrant vagrant 4.0K Jul 28 08:27 .
drwxr-xr-x 4 vagrant vagrant 4.0K Jul 28 08:31 ..
drwxr-sr-x 3 vagrant vagrant 4.0K Jul 28 08:27 foo
I find it surprising that only the managed directory (i.e. the name argument) shows the broken permissions and not the other.
@terminalmage Didn't you work on file.recurse recently?
@babilen In develop only.
@terminalmage The behaviour is the same in develop. I've just tested this against git HEAD (i.e. 2ad9efe47a806a671749fed71bcc0d7a92c98138) and was able to reproduce it there also.
Do you see something different?
Well, that would be expected, since we branched 2016.3 from develop originally, and any changes in the 2016.3 branch are merged forward into the develop branch.
I didn't try to replicate this, I was only answering your question.
Ah, I was just under the impression that you would be the best person to ask about this. Sorry if that wasn't the case.
I am familiar enough with the code to address it, but I probably won't be able to get to it for a couple days. I'm juggling a few other issues at the moment.
I wasn't able to reproduce this on any of the following:
2016.3 branchdevelop branchDo you have an ACL set on /home/vagrant? What is the output of getfacl /home/vagrant? It's possible that a bad ACL is causing the directory to be created with those permissions, and Salt is only checking/fixing the mode for directories under name.
@terminalmage Thank you for looking into this. I am not entirely sure why you can't reproduce it, which is why I am providing a complete example. It is using libvirt, but I'm sure that you can use vagrantbox too.
Vagrantfile and salt/minion files:$ cat Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "debian/jessie64"
config.vm.provider :libvirt do |libvirt|
libvirt.memory = "1024"
end
config.vm.define :salttest do |salttest|
salttest.vm.hostname = "recurse-bug.test"
salttest.vm.provision "shell", inline: "apt-get -qq install ca-certificates curl"
salttest.vm.provision :salt do |salt|
salt.install_type = "stable"
salt.install_master = true
salt.minion_config = "salt/minion"
end
end
end
$ cat salt/minion
master: recurse-bug.test
vagrant up, vagrant ssh and sudo -isalt-key -A → "Y"root@recurse-bug:~# mkdir -p /srv/salt/users/files/hooks/foo/bar/baz
root@recurse-bug:~# touch /srv/salt/users/files/hooks/foo/bar/baz/some_file
$ cat /srv/salt/top.sls
base:
'*':
- recurse_bug
$ cat /srv/salt/recurse_bug.sls
/home/vagrant/hooks:
file.recurse:
- source: salt://users/files/hooks
- user: vagrant
- group: vagrant
- dir_mode: 2755
- file_mode: 755
root@recurse-bug:~# ls -lah /home/vagrant/
total 12K
drwxr-xr-x 3 vagrant vagrant 4.0K Jun 6 18:17 .
drwxr-xr-x 3 root root 4.0K Jun 6 18:17 ..
drwx------ 2 vagrant vagrant 4.0K Aug 9 11:51 .ssh
root@recurse-bug:~# salt '*' state.highstate
recurse-bug.test:
----------
ID: /home/vagrant/hooks
Function: file.recurse
Result: True
Comment: Recursively updated /home/vagrant/hooks
Started: 12:03:39.450219
Duration: 39.3 ms
Changes:
----------
/home/vagrant/hooks/foo/bar/baz:
----------
/home/vagrant/hooks/foo/bar/baz:
New Dir
/home/vagrant/hooks/foo/bar/baz/some_file:
----------
diff:
New file
mode:
0755
user:
vagrant
Summary for recurse-bug.test
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
root@recurse-bug:~# ls -lah /home/vagrant/
total 16K
drwxr-xr-x 4 vagrant vagrant 4.0K Aug 9 12:03 .
drwxr-xr-x 3 root root 4.0K Jun 6 18:17 ..
drwx------ 2 vagrant vagrant 4.0K Aug 9 11:51 .ssh
dr-x--xrwt 3 vagrant vagrant 4.0K Aug 9 12:03 hooks
I would be quite surprised if you are seeing different behaviour. I also tested this against different salt versions and git HEADs. It would be interesting to know what you did exactly when you tried to reproduce it.
Oh and you wanted to see the following:
root@recurse-bug:~# getfacl /home/vagrant/
getfacl: Removing leading '/' from absolute path names
# file: home/vagrant/
# owner: vagrant
# group: vagrant
user::rwx
group::r-x
other::r-x
which is not unusual in any way. The directory that exhibits the buggy behaviour looks like:
root@recurse-bug:~# getfacl /home/vagrant/hooks/
getfacl: Removing leading '/' from absolute path names
# file: home/vagrant/hooks/
# owner: vagrant
# group: vagrant
# flags: --t
user::r-x
group::--x
other::rwx
Yeah, I was just guessing on the facl, there are no default entries in the output so that rules that out.
Just built your vagrant box and working on testing now. The only difference in my SLS was that I did not use a user or group parameter, I'll step through with a debugger and see if that mattered at all (I can't see why it would).
Was able to reproduce in vagrant box, commencing step-through with debugger.
OK, I was finally able to reproduce on my laptop, outside of your vagrant example... It turns out that this only occurs when the source dir does not have any files in it (only subdirectories). My setup contained files in the source dir as well as subdirectories. What is happening here is that we end up calling file.check_perms with a malformed mode the first time around (one converted to octal when it was already octal in the first place). When there are files in the source dir, however, we end up executing the file.directory state within file.recurse, which corrects the mode which was initially set incorrectly.
This bug exists back in the 2015.8 branch and likely going back much further, it's just that most use cases for file.recurse don't involve the source dir being devoid of actual files, so not enough people hit this edge case to notice it until now.
I'm working on a fix and an integration test now, should have it done by the end of the day. Thanks for your help in troubleshooting. In retrospect I would have been able to reproduce this much sooner if I had duplicated your example from several days ago, but I have a file.recurse test directory in my file_roots that I typically use for troubleshooting bug reports like this, and I did have several levels of directories being created, so it seemed to match your case well enough. It was only when I started stepping through with a debugger on both my laptop and your vagrant box to see how the cases differed that I noticed the discrepancy.
Fixed in https://github.com/saltstack/salt/pull/35309, integration test included.
Thank you very much!
No prob! Thank you for helping me troubleshoot, and for helping uncover a corner case that looks to have been introduced nearly _4 years ago_. (!!!)
:+1: to @babilen