Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a preliminary checker to ensure the mount points in /etc/fstab are in the correct order #93

Merged
merged 1 commit into from
Nov 26, 2024
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
24 changes: 23 additions & 1 deletion pleskdistup/actions/common_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

misorderings = mounts.get_fstab_configuration_misorderings(self.FSTAB_PATH)

if len(misorderings) == 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 misorderings]))
return False
1 change: 1 addition & 0 deletions pleskdistup/common/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 48 additions & 0 deletions pleskdistup/common/src/mounts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 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: typing.Dict[str, int] = {}
ukablan-wpc marked this conversation as resolved.
Show resolved Hide resolved
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

misorderings: typing.List[typing.Tuple[str, str]] = []
ukablan-wpc marked this conversation as resolved.
Show resolved Hide resolved
for mount_point in mount_points_order.keys():
if mount_point == "/":
continue

parent_dir: str = mount_point
root_found: bool = False

while not root_found:
parent_dir = os.path.dirname(parent_dir)
if parent_dir in mount_points_order and mount_points_order[parent_dir] > mount_points_order[mount_point]:
misorderings.append((parent_dir, mount_point))
if parent_dir == "/":
root_found = True

return misorderings
83 changes: 83 additions & 0 deletions pleskdistup/common/tests/mountstests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# 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")])

def test_file_without_root(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/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), [("/home", "/home/test")])