From 3b10ded3194255970464de5cb7e86fac825f67b7 Mon Sep 17 00:00:00 2001 From: Mikhail Sandakov Date: Mon, 25 Nov 2024 15:14:21 +0200 Subject: [PATCH] Add a preliminary checker to ensure the mount points in /etc/fstab are in the correct order --- pleskdistup/actions/common_checks.py | 24 ++++++++- pleskdistup/common/src/__init__.py | 1 + pleskdistup/common/src/mounts.py | 47 ++++++++++++++++ pleskdistup/common/tests/mountstests.py | 72 +++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 pleskdistup/common/src/mounts.py create mode 100644 pleskdistup/common/tests/mountstests.py diff --git a/pleskdistup/actions/common_checks.py b/pleskdistup/actions/common_checks.py index b023ffc..176832a 100644 --- a/pleskdistup/actions/common_checks.py +++ b/pleskdistup/actions/common_checks.py @@ -7,7 +7,7 @@ import typing from abc import abstractmethod -from pleskdistup.common import action, log, packages, php, plesk, version +from pleskdistup.common import action, log, mounts, packages, php, plesk, version # This action should be considered as deprecated @@ -677,3 +677,25 @@ def _do_check(self) -> bool: return True return False + + +class AssertFstabOrderingIsFine(action.CheckAction): + FSTAB_PATH: str = "/etc/fstab" + + def __init__(self): + self.name = "checking if /etc/fstab is ordered properly" + self.description = """The /etc/fstab file entries is not ordered properly. +\t- {}""" + + def _do_check(self) -> bool: + if not os.path.exists(self.FSTAB_PATH): + # Might be a problem, but it is not something we checking in scope of this check + return True + + missorderings = mounts.get_fstab_configuration_misorderings(self.FSTAB_PATH) + + if len(missorderings) == 0: + return True + + self.description = self.description.format("\n\t- ".join([f"Mount point {mount_point} should be placed after {parent_dir}" for parent_dir, mount_point in missorderings])) + return False diff --git a/pleskdistup/common/src/__init__.py b/pleskdistup/common/src/__init__.py index 1ac2d93..3c5d074 100644 --- a/pleskdistup/common/src/__init__.py +++ b/pleskdistup/common/src/__init__.py @@ -8,6 +8,7 @@ from . import mariadb from . import leapp_configs from . import motd +from . import mounts from . import packages from . import php from . import plesk diff --git a/pleskdistup/common/src/mounts.py b/pleskdistup/common/src/mounts.py new file mode 100644 index 0000000..d5900b8 --- /dev/null +++ b/pleskdistup/common/src/mounts.py @@ -0,0 +1,47 @@ +# Copyright 2023-2024. WebPros International GmbH. All rights reserved. +import os +import typing + + +def get_fstab_configuration_misorderings(configpath: str) -> typing.List[typing.Tuple[str, str]]: + """ + Analyzes the fstab configuration file to find misorderings in mount points. + This function reads the fstab configuration file specified by `configpath` and checks for any misorderings + in the mount points. A misordering is defined as a mount point that appears before its parent directory + in the fstab file. + Args: + configpath (str): The path to the fstab configuration file. + Returns: + List[Tuple[str, str]]: A list of tuples where each tuple contains a misordered parent directory and + its corresponding mount point. + Example: + >>> get_fstab_configuration_misorderings('/etc/fstab') + [('/home', '/home/user'), ('/var', '/var/log')] + """ + + if not os.path.exists(configpath): + return [] + + mount_points_order = {} + with open(configpath, "r") as f: + for iter, line in enumerate(f.readlines()): + if line.startswith("#") or line == "\n" or line == "": + continue + mount_point = line.split()[1] + mount_points_order[mount_point] = iter + + missorderings = [] + for mount_point in mount_points_order.keys(): + if mount_point == "/": + continue + + if mount_points_order["/"] > mount_points_order[mount_point]: + missorderings.append(("/", mount_point)) + + leading_paths = mount_point.split("/")[:-1] + for i in range(1, len(leading_paths) + 1): + parent_dir = "/".join(leading_paths[:i]) + if parent_dir in mount_points_order and mount_points_order[parent_dir] > mount_points_order[mount_point]: + missorderings.append((parent_dir, mount_point)) + + return missorderings diff --git a/pleskdistup/common/tests/mountstests.py b/pleskdistup/common/tests/mountstests.py new file mode 100644 index 0000000..c9d075e --- /dev/null +++ b/pleskdistup/common/tests/mountstests.py @@ -0,0 +1,72 @@ +# Copyright 2023-2024. WebPros International GmbH. All rights reserved. +import unittest +import tempfile + +import src.mounts as mounts + + +class FstabMisorderingTests(unittest.TestCase): + def setUp(self): + self.test_file_path = tempfile.mktemp() + + def test_no_file(self): + self.assertEqual(mounts.get_fstab_configuration_misorderings("noexist.txt"), []) + + def test_empty_file(self): + with open(self.test_file_path, "w") as _: + pass + self.assertEqual(mounts.get_fstab_configuration_misorderings(self.test_file_path), []) + + def test_empty_string(self): + with open(self.test_file_path, "w") as f: + f.write("") + self.assertEqual(mounts.get_fstab_configuration_misorderings(self.test_file_path), []) + + def test_one_mount_point(self): + with open(self.test_file_path, "w") as f: + f.write("# comment\n") + f.write("/dev/sda1 / ext4 defaults 0 1\n") + self.assertEqual(mounts.get_fstab_configuration_misorderings(self.test_file_path), []) + + def test_no_misorderings(self): + with open(self.test_file_path, "w") as f: + f.write("# comment\n") + f.write("/dev/sda1 / ext4 defaults 0 1\n") + f.write("/dev/sda2 /var ext4 defaults 0 1\n") + f.write("proc /proc proc defaults 0 0\n") + f.write("devpts /dev/pts devpts gid=5,mode=620 0 0\n") + f.write("tmpfs /dev/shm tmpfs defaults 0 0\n") + self.assertEqual(mounts.get_fstab_configuration_misorderings(self.test_file_path), []) + + def test_one_misordering(self): + with open(self.test_file_path, "w") as f: + f.write("# comment\n") + f.write("/dev/sda2 /var ext4 defaults 0 1\n") + f.write("/dev/sda1 / ext4 defaults 0 1\n") + f.write("proc /proc proc defaults 0 0\n") + f.write("devpts /dev/pts devpts gid=5,mode=620 0 0\n") + f.write("tmpfs /dev/shm tmpfs defaults 0 0\n") + self.assertEqual(mounts.get_fstab_configuration_misorderings(self.test_file_path), [("/", "/var")]) + + def test_two_misorderings_for_one_parent(self): + with open(self.test_file_path, "w") as f: + f.write("# comment\n") + f.write("/dev/sda2 /var ext4 defaults 0 1\n") + f.write("/dev/sda3 /var/log ext4 defaults 0 1\n") + f.write("/dev/sda1 / ext4 defaults 0 1\n") + f.write("proc /proc proc defaults 0 0\n") + f.write("devpts /dev/pts devpts gid=5,mode=620 0 0\n") + f.write("tmpfs /dev/shm tmpfs defaults 0 0\n") + self.assertEqual(mounts.get_fstab_configuration_misorderings(self.test_file_path), [("/", "/var"), ("/", "/var/log")]) + + def test_several_different_misorderings(self): + with open(self.test_file_path, "w") as f: + f.write("# comment\n") + f.write("/dev/sda2 /var ext4 defaults 0 1\n") + f.write("/dev/sda1 / ext4 defaults 0 1\n") + f.write("/dev/sda5 /home/test ext4 defaults 0 1\n") + f.write("/dev/sda4 /home ext4 defaults 0 1\n") + f.write("proc /proc proc defaults 0 0\n") + f.write("devpts /dev/pts devpts gid=5,mode=620 0 0\n") + f.write("tmpfs /dev/shm tmpfs defaults 0 0\n") + self.assertEqual(mounts.get_fstab_configuration_misorderings(self.test_file_path), [("/", "/var"), ("/home", "/home/test")])