fixes saltstack/salt#54508 fix mount.mounted does not handle blanks properly

This commit is contained in:
nicholasmhughes 2022-09-22 21:41:47 -04:00 committed by Megan Wilhite
parent cb2bfc8857
commit 80e7e3bac2
5 changed files with 70 additions and 70 deletions

1
changelog/54508.fixed Normal file
View file

@ -0,0 +1 @@
Fix mount.mounted does not handle blanks properly

View file

@ -1312,9 +1312,9 @@ def mount(
cmd = "mount " cmd = "mount "
if device: if device:
cmd += "{} {} {} ".format(args, device, name) cmd += "{} '{}' '{}' ".format(args, device, name)
else: else:
cmd += "{} ".format(name) cmd += "'{}' ".format(name)
out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False) out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False)
if out["retcode"]: if out["retcode"]:
return out["stderr"] return out["stderr"]
@ -1374,9 +1374,9 @@ def remount(name, device, mkmnt=False, fstype="", opts="defaults", user=None):
args += " -t {}".format(fstype) args += " -t {}".format(fstype)
if __grains__["os"] not in ["OpenBSD", "MacOS", "Darwin"] or force_mount: if __grains__["os"] not in ["OpenBSD", "MacOS", "Darwin"] or force_mount:
cmd = "mount {} {} {} ".format(args, device, name) cmd = "mount {} '{}' '{}' ".format(args, device, name)
else: else:
cmd = "mount -u {} {} {} ".format(args, device, name) cmd = "mount -u {} '{}' '{}' ".format(args, device, name)
out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False) out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False)
if out["retcode"]: if out["retcode"]:
return out["stderr"] return out["stderr"]
@ -1416,9 +1416,9 @@ def umount(name, device=None, user=None, util="mount"):
return "{} does not have anything mounted".format(name) return "{} does not have anything mounted".format(name)
if not device: if not device:
cmd = "umount {}".format(name) cmd = "umount '{}'".format(name)
else: else:
cmd = "umount {}".format(device) cmd = "umount '{}'".format(device)
out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False) out = __salt__["cmd.run_all"](cmd, runas=user, python_shell=False)
if out["retcode"]: if out["retcode"]:
return out["stderr"] return out["stderr"]
@ -1535,11 +1535,11 @@ def swapon(name, priority=None):
if __grains__["kernel"] == "SunOS": if __grains__["kernel"] == "SunOS":
if __grains__["virtual"] != "zone": if __grains__["virtual"] != "zone":
__salt__["cmd.run"]("swap -a {}".format(name), python_shell=False) __salt__["cmd.run"]("swap -a '{}'".format(name), python_shell=False)
else: else:
return False return False
else: else:
cmd = "swapon {}".format(name) cmd = "swapon '{}'".format(name)
if priority and "AIX" not in __grains__["kernel"]: if priority and "AIX" not in __grains__["kernel"]:
cmd += " -p {}".format(priority) cmd += " -p {}".format(priority)
__salt__["cmd.run"](cmd, python_shell=False) __salt__["cmd.run"](cmd, python_shell=False)
@ -1569,13 +1569,13 @@ def swapoff(name):
if name in on_: if name in on_:
if __grains__["kernel"] == "SunOS": if __grains__["kernel"] == "SunOS":
if __grains__["virtual"] != "zone": if __grains__["virtual"] != "zone":
__salt__["cmd.run"]("swap -a {}".format(name), python_shell=False) __salt__["cmd.run"]("swap -a '{}'".format(name), python_shell=False)
else: else:
return False return False
elif __grains__["os"] != "OpenBSD": elif __grains__["os"] != "OpenBSD":
__salt__["cmd.run"]("swapoff {}".format(name), python_shell=False) __salt__["cmd.run"]("swapoff '{}'".format(name), python_shell=False)
else: else:
__salt__["cmd.run"]("swapctl -d {}".format(name), python_shell=False) __salt__["cmd.run"]("swapctl -d '{}'".format(name), python_shell=False)
on_ = swaps() on_ = swaps()
if name in on_: if name in on_:
return False return False

View file

@ -241,10 +241,12 @@ def mounted(
# Get the active data # Get the active data
active = __salt__["mount.active"](extended=True) active = __salt__["mount.active"](extended=True)
real_name = os.path.realpath(name) real_name = os.path.realpath(name)
# real_name for comparisons to the active mount list
comp_real_name = real_name.replace(" ", "\\040")
if device.startswith("/"): if device.startswith("/"):
if "bind" in opts and real_name in active: if "bind" in opts and comp_real_name in active:
_device = device _device = device.replace(" ", "\\040")
if active[real_name]["device"].startswith("/"): if active[comp_real_name]["device"].startswith("/"):
# Find the device that the bind really points at. # Find the device that the bind really points at.
while True: while True:
if _device in active: if _device in active:
@ -257,9 +259,9 @@ def mounted(
+ active[_device]["superopts"] + active[_device]["superopts"]
) )
) )
active[real_name]["opts"].append("bind") active[comp_real_name]["opts"].append("bind")
break break
_device = os.path.dirname(_device) _device = os.path.dirname(_device.replace("\\040", " "))
real_device = _real_device real_device = _real_device
else: else:
# Remote file systems act differently. # Remote file systems act differently.
@ -272,8 +274,8 @@ def mounted(
+ active[_device]["superopts"] + active[_device]["superopts"]
) )
) )
active[real_name]["opts"].append("bind") active[comp_real_name]["opts"].append("bind")
real_device = active[real_name]["device"] real_device = active[comp_real_name]["device"]
else: else:
real_device = os.path.realpath(device) real_device = os.path.realpath(device)
elif device.upper().startswith("UUID="): elif device.upper().startswith("UUID="):
@ -324,25 +326,25 @@ def mounted(
if "device_name" in fuse_match.groupdict(): if "device_name" in fuse_match.groupdict():
real_device = fuse_match.group("device_name") real_device = fuse_match.group("device_name")
if real_name in active: if comp_real_name in active:
if "superopts" not in active[real_name]: if "superopts" not in active[comp_real_name]:
active[real_name]["superopts"] = [] active[comp_real_name]["superopts"] = []
if mount: if mount:
device_list.append(active[real_name]["device"]) device_list.append(active[comp_real_name]["device"])
device_list.append(os.path.realpath(device_list[0])) device_list.append(os.path.realpath(device_list[0]))
alt_device = ( alt_device = (
active[real_name]["alt_device"] active[comp_real_name]["alt_device"]
if "alt_device" in active[real_name] if "alt_device" in active[comp_real_name]
else None else None
) )
uuid_device = ( uuid_device = (
active[real_name]["device_uuid"] active[comp_real_name]["device_uuid"]
if "device_uuid" in active[real_name] if "device_uuid" in active[comp_real_name]
else None else None
) )
label_device = ( label_device = (
active[real_name]["device_label"] active[comp_real_name]["device_label"]
if "device_label" in active[real_name] if "device_label" in active[comp_real_name]
else None else None
) )
if alt_device and alt_device not in device_list: if alt_device and alt_device not in device_list:
@ -450,7 +452,7 @@ def mounted(
_id = _info[_param] _id = _info[_param]
opt = _param + "=" + str(_id) opt = _param + "=" + str(_id)
_active_superopts = active[real_name].get("superopts", []) _active_superopts = active[comp_real_name].get("superopts", [])
for _active_opt in _active_superopts: for _active_opt in _active_superopts:
size_match = re.match( size_match = re.match(
r"size=(?P<size_value>[0-9]+)(?P<size_unit>k|m|g)", r"size=(?P<size_value>[0-9]+)(?P<size_unit>k|m|g)",
@ -464,7 +466,7 @@ def mounted(
_active_superopts.append(_active_opt) _active_superopts.append(_active_opt)
if ( if (
opt not in active[real_name]["opts"] opt not in active[comp_real_name]["opts"]
and opt not in _active_superopts and opt not in _active_superopts
and opt not in mount_invisible_options and opt not in mount_invisible_options
and opt not in mount_ignore_fs_keys.get(fstype, []) and opt not in mount_ignore_fs_keys.get(fstype, [])
@ -622,7 +624,7 @@ def mounted(
ret["changes"]["umount"] += ", current: " + ", ".join(device_list) ret["changes"]["umount"] += ", current: " + ", ".join(device_list)
out = __salt__["mount.umount"](real_name, user=user) out = __salt__["mount.umount"](real_name, user=user)
active = __salt__["mount.active"](extended=True) active = __salt__["mount.active"](extended=True)
if real_name in active: if comp_real_name in active:
ret["comment"] = "Unable to unmount" ret["comment"] = "Unable to unmount"
ret["result"] = None ret["result"] = None
return ret return ret
@ -630,7 +632,7 @@ def mounted(
else: else:
ret["comment"] = "Target was already mounted" ret["comment"] = "Target was already mounted"
# using a duplicate check so I can catch the results of a umount # using a duplicate check so I can catch the results of a umount
if real_name not in active: if comp_real_name not in active:
if mount: if mount:
# The mount is not present! Mount it # The mount is not present! Mount it
if __opts__["test"]: if __opts__["test"]:
@ -658,7 +660,7 @@ def mounted(
ret["comment"] = out ret["comment"] = out
ret["result"] = False ret["result"] = False
return ret return ret
elif real_name in active: elif comp_real_name in active:
# (Re)mount worked! # (Re)mount worked!
ret["comment"] = "Target was successfully mounted" ret["comment"] = "Target was successfully mounted"
ret["changes"]["mount"] = True ret["changes"]["mount"] = True
@ -939,10 +941,11 @@ def unmounted(
# Get the active data # Get the active data
active = __salt__["mount.active"](extended=True) active = __salt__["mount.active"](extended=True)
if name not in active: comp_name = name.replace(" ", "\\040")
if comp_name not in active:
# Nothing to unmount # Nothing to unmount
ret["comment"] = "Target was already unmounted" ret["comment"] = "Target was already unmounted"
if name in active: if comp_name in active:
# The mount is present! Unmount it # The mount is present! Unmount it
if __opts__["test"]: if __opts__["test"]:
ret["result"] = None ret["result"] = None

View file

@ -473,13 +473,13 @@ def test_mount():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.mount("name", "device") assert mount.mount("name", "device")
mock.assert_called_with( mock.assert_called_with(
"mount device name ", python_shell=False, runas=None "mount 'device' 'name' ", python_shell=False, runas=None
) )
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.mount("name", "device", fstype="fstype") assert mount.mount("name", "device", fstype="fstype")
mock.assert_called_with( mock.assert_called_with(
"mount -t fstype device name ", "mount -t fstype 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -497,13 +497,13 @@ def test_mount():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.mount("name", "device") assert mount.mount("name", "device")
mock.assert_called_with( mock.assert_called_with(
"mount device name ", python_shell=False, runas=None "mount 'device' 'name' ", python_shell=False, runas=None
) )
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.mount("name", "device", fstype="fstype") assert mount.mount("name", "device", fstype="fstype")
mock.assert_called_with( mock.assert_called_with(
"mount -v fstype device name ", "mount -v fstype 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -521,7 +521,7 @@ def test_mount():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.mount("name", "device") assert mount.mount("name", "device")
mock.assert_called_with( mock.assert_called_with(
"mount -o defaults device name ", "mount -o defaults 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -529,7 +529,7 @@ def test_mount():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.mount("name", "device", fstype="fstype") assert mount.mount("name", "device", fstype="fstype")
mock.assert_called_with( mock.assert_called_with(
"mount -o defaults -t fstype device name ", "mount -o defaults -t fstype 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -578,7 +578,7 @@ def test_remount_already_mounted_no_fstype():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.remount("name", "device") assert mount.remount("name", "device")
mock.assert_called_with( mock.assert_called_with(
"mount -u -o noowners device name ", "mount -u -o noowners 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -590,7 +590,7 @@ def test_remount_already_mounted_no_fstype():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.remount("name", "device") assert mount.remount("name", "device")
mock.assert_called_with( mock.assert_called_with(
"mount -o remount device name ", python_shell=False, runas=None "mount -o remount 'device' 'name' ", python_shell=False, runas=None
) )
with patch.dict(mount.__grains__, {"os": "Linux"}): with patch.dict(mount.__grains__, {"os": "Linux"}):
@ -600,7 +600,7 @@ def test_remount_already_mounted_no_fstype():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.remount("name", "device") assert mount.remount("name", "device")
mock.assert_called_with( mock.assert_called_with(
"mount -o defaults,remount device name ", "mount -o defaults,remount 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -618,7 +618,7 @@ def test_remount_already_mounted_with_fstype():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.remount("name", "device", fstype="type") assert mount.remount("name", "device", fstype="type")
mock.assert_called_with( mock.assert_called_with(
"mount -u -o noowners -t type device name ", "mount -u -o noowners -t type 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -630,7 +630,7 @@ def test_remount_already_mounted_with_fstype():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.remount("name", "device", fstype="type") assert mount.remount("name", "device", fstype="type")
mock.assert_called_with( mock.assert_called_with(
"mount -o remount -v type device name ", "mount -o remount -v type 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -642,7 +642,7 @@ def test_remount_already_mounted_with_fstype():
with patch.dict(mount.__salt__, {"cmd.run_all": mock}): with patch.dict(mount.__salt__, {"cmd.run_all": mock}):
assert mount.remount("name", "device", fstype="type") assert mount.remount("name", "device", fstype="type")
mock.assert_called_with( mock.assert_called_with(
"mount -o defaults,remount -t type device name ", "mount -o defaults,remount -t type 'device' 'name' ",
python_shell=False, python_shell=False,
runas=None, runas=None,
) )
@ -681,30 +681,24 @@ def test_is_fuse_exec():
with patch.object(salt.utils.path, "which", return_value=None): with patch.object(salt.utils.path, "which", return_value=None):
assert not mount.is_fuse_exec("cmd") assert not mount.is_fuse_exec("cmd")
def _ldd_side_effect(cmd, *args, **kwargs): which_mock = MagicMock(side_effect=lambda x: x)
""" ldd_mock = MagicMock(
Neither of these are full ldd output, but what is_fuse_exec is side_effect=[
looking for is 'libfuse' in the ldd output, so these examples textwrap.dedent(
should be sufficient enough to test both the True and False cases.
"""
return {
"ldd cmd1": textwrap.dedent(
"""\ """\
linux-vdso.so.1 (0x00007ffeaf5fb000) linux-vdso.so.1 (0x00007ffeaf5fb000)
libfuse3.so.3 => /usr/lib/libfuse3.so.3 (0x00007f91e66ac000) libfuse3.so.3 => /usr/lib/libfuse3.so.3 (0x00007f91e66ac000)
""" """
), ),
"ldd cmd2": textwrap.dedent( textwrap.dedent(
"""\ """\
linux-vdso.so.1 (0x00007ffeaf5fb000) linux-vdso.so.1 (0x00007ffeaf5fb000)
""" """
), ),
}[cmd] ]
)
which_mock = MagicMock(side_effect=lambda x: x)
ldd_mock = MagicMock(side_effect=_ldd_side_effect)
with patch.object(salt.utils.path, "which", which_mock): with patch.object(salt.utils.path, "which", which_mock):
with patch.dict(mount.__salt__, {"cmd.run": _ldd_side_effect}): with patch.dict(mount.__salt__, {"cmd.run": ldd_mock}):
assert mount.is_fuse_exec("cmd1") assert mount.is_fuse_exec("cmd1")
assert not mount.is_fuse_exec("cmd2") assert not mount.is_fuse_exec("cmd2")

View file

@ -1291,9 +1291,11 @@ def test_fstab_absent_absent():
salt_mock["mount.fstab"].assert_called_with("/etc/fstab") salt_mock["mount.fstab"].assert_called_with("/etc/fstab")
def test_bind_mount_copy_active_opts(): @pytest.mark.parametrize("mount_name", ["/home/tmp", "/home/tmp with spaces"])
name = "/home/tmp" def test_bind_mount_copy_active_opts(mount_name):
device = "/home/tmp" name = mount_name
device = name
active_name = name.replace(" ", "\\040")
fstype = "none" fstype = "none"
opts = [ opts = [
"bind", "bind",
@ -1307,7 +1309,7 @@ def test_bind_mount_copy_active_opts():
mock_active = MagicMock( mock_active = MagicMock(
return_value={ return_value={
"/home/tmp": { active_name: {
"alt_device": "/dev/vda1", "alt_device": "/dev/vda1",
"device": "/dev/vda1", "device": "/dev/vda1",
"device_label": None, "device_label": None,
@ -1318,14 +1320,14 @@ def test_bind_mount_copy_active_opts():
"mountid": "105", "mountid": "105",
"opts": ["rw", "relatime"], "opts": ["rw", "relatime"],
"parentid": "25", "parentid": "25",
"root": "/home/tmp", "root": active_name,
"superopts": ["rw", "discard", "errors=remount-ro"], "superopts": ["rw", "discard", "errors=remount-ro"],
}, },
} }
) )
mock_read_mount_cache = MagicMock( mock_read_mount_cache = MagicMock(
return_value={ return_value={
"device": "/home/tmp", "device": device,
"fstype": "none", "fstype": "none",
"mkmnt": False, "mkmnt": False,
"opts": ["bind", "nodev", "noexec", "nosuid", "rw"], "opts": ["bind", "nodev", "noexec", "nosuid", "rw"],
@ -1347,11 +1349,11 @@ def test_bind_mount_copy_active_opts():
"realpath", "realpath",
MagicMock( MagicMock(
side_effect=[ side_effect=[
"/home/tmp", name,
"/dev/vda1", "/dev/vda1",
"/home/tmp", name,
"/dev/vda1", "/dev/vda1",
"/home/tmp", name,
"/dev/vda1", "/dev/vda1",
] ]
), ),