Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/62066.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed salt.states.file.managed() for follow_symlinks=True and test=True
27 changes: 26 additions & 1 deletion salt/modules/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -5335,11 +5335,18 @@ def check_managed(
serole=None,
setype=None,
serange=None,
follow_symlinks=False,
**kwargs
):
"""
Check to see what changes need to be made for a file

follow_symlinks
If the desired path is a symlink, follow it and check the permissions
of the file to which the symlink points.

.. versionadded:: 3005

CLI Example:

.. code-block:: bash
Expand Down Expand Up @@ -5390,6 +5397,7 @@ def check_managed(
serole=serole,
setype=setype,
serange=serange,
follow_symlinks=follow_symlinks,
)
# Ignore permission for files written temporary directories
# Files in any path will still be set correctly using get_managed()
Expand Down Expand Up @@ -5426,6 +5434,7 @@ def check_managed_changes(
setype=None,
serange=None,
verify_ssl=True,
follow_symlinks=False,
**kwargs
):
"""
Expand All @@ -5441,6 +5450,12 @@ def check_managed_changes(

.. versionadded:: 3002

follow_symlinks
If the desired path is a symlink, follow it and check the permissions
of the file to which the symlink points.

.. versionadded:: 3005

CLI Example:

.. code-block:: bash
Expand Down Expand Up @@ -5510,6 +5525,7 @@ def check_managed_changes(
serole=serole,
setype=setype,
serange=serange,
follow_symlinks=follow_symlinks,
)
__clean_tmp(sfn)
return changes
Expand All @@ -5531,6 +5547,7 @@ def check_file_meta(
setype=None,
serange=None,
verify_ssl=True,
follow_symlinks=False,
):
"""
Check for the changes in the file metadata.
Expand Down Expand Up @@ -5607,14 +5624,22 @@ def check_file_meta(
will not attempt to validate the servers certificate. Default is True.

.. versionadded:: 3002

follow_symlinks
If the desired path is a symlink, follow it and check the permissions
of the file to which the symlink points.

.. versionadded:: 3005
"""
changes = {}
if not source_sum:
source_sum = dict()

try:
lstats = stats(
name, hash_type=source_sum.get("hash_type", None), follow_symlinks=False
name,
hash_type=source_sum.get("hash_type", None),
follow_symlinks=follow_symlinks,
)
except CommandExecutionError:
lstats = {}
Expand Down
1 change: 1 addition & 0 deletions salt/states/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -3118,6 +3118,7 @@ def managed(
setype=setype,
serange=serange,
verify_ssl=verify_ssl,
follow_symlinks=follow_symlinks,
**kwargs
)

Expand Down
144 changes: 144 additions & 0 deletions tests/pytests/unit/modules/file/test_file_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import getpass
import logging
import os

import pytest
import salt.modules.file as filemod
import salt.utils.files
import salt.utils.platform

log = logging.getLogger(__name__)


@pytest.fixture
def configure_loader_modules():
return {filemod: {"__context__": {}}}


@pytest.fixture
def tfile(tmp_path):
filename = str(tmp_path / "file-check-test-file")

with salt.utils.files.fopen(filename, "w") as fp:
fp.write("Hi hello! I am a file.")
os.chmod(filename, 0o644)

yield filename

os.remove(filename)


@pytest.fixture
def a_link(tmp_path, tfile):
linkname = str(tmp_path / "a_link")
os.symlink(tfile, linkname)

yield linkname

os.remove(linkname)


def get_link_perms():
if salt.utils.platform.is_linux():
return "0777"
return "0755"


@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
def test_check_file_meta_follow_symlinks(a_link, tfile):
user = getpass.getuser()
lperms = get_link_perms()

# follow_symlinks=False (default)
ret = filemod.check_file_meta(
a_link, tfile, None, None, user, None, lperms, None, None
)
assert ret == {}

ret = filemod.check_file_meta(
a_link, tfile, None, None, user, None, "0644", None, None
)
assert ret == {"mode": "0644"}

# follow_symlinks=True
ret = filemod.check_file_meta(
a_link, tfile, None, None, user, None, "0644", None, None, follow_symlinks=True
)
assert ret == {}


@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
def test_check_managed_follow_symlinks(a_link, tfile):
user = getpass.getuser()
lperms = get_link_perms()

# Function check_managed() ignores mode changes for files in the temp directory.
# Trick it to not recognize a_link as such.
a_link = "/" + a_link

# follow_symlinks=False (default)
ret, comments = filemod.check_managed(
a_link, tfile, None, None, user, None, lperms, None, None, None, None, None
)
assert ret is True
assert comments == "The file {} is in the correct state".format(a_link)

ret, comments = filemod.check_managed(
a_link, tfile, None, None, user, None, "0644", None, None, None, None, None
)
assert ret is None
assert comments == "The following values are set to be changed:\nmode: 0644\n"

# follow_symlinks=True
ret, comments = filemod.check_managed(
a_link,
tfile,
None,
None,
user,
None,
"0644",
None,
None,
None,
None,
None,
follow_symlinks=True,
)
assert ret is True
assert comments == "The file {} is in the correct state".format(a_link)


@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
def test_check_managed_changes_follow_symlinks(a_link, tfile):
user = getpass.getuser()
lperms = get_link_perms()

# follow_symlinks=False (default)
ret = filemod.check_managed_changes(
a_link, tfile, None, None, user, None, lperms, None, None, None, None, None
)
assert ret == {}

ret = filemod.check_managed_changes(
a_link, tfile, None, None, user, None, "0644", None, None, None, None, None
)
assert ret == {"mode": "0644"}

# follow_symlinks=True
ret = filemod.check_managed_changes(
a_link,
tfile,
None,
None,
user,
None,
"0644",
None,
None,
None,
None,
None,
follow_symlinks=True,
)
assert ret == {}