diff --git a/changelog/66980.fixed.md b/changelog/66980.fixed.md new file mode 100644 index 000000000000..499e1961eb1b --- /dev/null +++ b/changelog/66980.fixed.md @@ -0,0 +1 @@ +make file.symlink/_symlink_check() respect follow_symlinks diff --git a/salt/modules/file.py b/salt/modules/file.py index 19b2bf10de09..877cfecbb3a3 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -4201,9 +4201,10 @@ def stats(path, hash_type=None, follow_symlinks=True): salt '*' file.stats /etc/passwd """ path = os.path.expanduser(path) + exists = os.path.exists if follow_symlinks else os.path.lexists ret = {} - if not os.path.exists(path): + if not exists(path): try: # Broken symlinks will return False for os.path.exists(), but still # have a uid and gid diff --git a/salt/states/file.py b/salt/states/file.py index f33727a8ba54..e2907889e00f 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -983,12 +983,14 @@ def _set_symlink_ownership(path, user, group, win_owner): return _check_symlink_ownership(path, user, group, win_owner) -def _symlink_check(name, target, force, user, group, win_owner): +def _symlink_check(name, target, force, user, group, win_owner, follow_symlinks=False): """ Check the symlink function """ changes = {} - if not os.path.exists(name) and not __salt__["file.is_link"](name): + exists = os.path.exists if follow_symlinks else os.path.lexists + + if not exists(name) and not __salt__["file.is_link"](name): changes["new"] = name return ( None, @@ -1788,7 +1790,7 @@ def symlink( return _error(ret, msg) tresult, tcomment, tchanges = _symlink_check( - name, target, force, user, group, win_owner + name, target, force, user, group, win_owner, follow_symlinks ) if not os.path.isdir(os.path.dirname(name)): diff --git a/tests/pytests/unit/modules/file/test_file_basics.py b/tests/pytests/unit/modules/file/test_file_basics.py index 5da99d6e47af..d981c96bca51 100644 --- a/tests/pytests/unit/modules/file/test_file_basics.py +++ b/tests/pytests/unit/modules/file/test_file_basics.py @@ -294,3 +294,18 @@ def test_symlink_lexists_called_follow_symlinks_false(): filemod.symlink(tfile, a_link, follow_symlinks=False) lexists.assert_called() exists.assert_not_called() + + +def test_symlink_lexists_called_follow_symlinks_true(): + tfile = "/tmp/file-basics-test-file" + a_link = "/tmp/a_link" + + exists = MagicMock(return_value=False) + lexists = MagicMock(return_value=False) + + with patch("os.path.exists", exists), patch("os.path.lexists", lexists), patch( + "os.symlink", MagicMock(return_value=True) + ): + filemod.symlink(tfile, a_link, follow_symlinks=True) + lexists.assert_not_called() + exists.assert_called()