Skip to content

Commit

Permalink
Add support for CloudLinux VM missing os-release and /etc/redhat-release
Browse files Browse the repository at this point in the history
> closes #240
  • Loading branch information
HorlogeSkynet committed Aug 22, 2024
1 parent 7ce285c commit 2ceba16
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 5 deletions.
39 changes: 34 additions & 5 deletions src/distro/distro.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
Callable,
Dict,
Iterable,
List,
Optional,
Sequence,
TextIO,
Expand Down Expand Up @@ -73,6 +74,7 @@ class InfoDict(TypedDict):


_UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc")
_UNIXPROCDIR = os.environ.get("UNIXPROCDIR", "/proc")
_UNIXUSRLIBDIR = os.environ.get("UNIXUSRLIBDIR", "/usr/lib")
_OS_RELEASE_BASENAME = "os-release"

Expand Down Expand Up @@ -759,6 +761,7 @@ def __init__(
"""
self.root_dir = root_dir
self.etc_dir = os.path.join(root_dir, "etc") if root_dir else _UNIXCONFDIR
self.proc_dir = os.path.join(root_dir, "proc") if root_dir else _UNIXPROCDIR
self.usr_lib_dir = (
os.path.join(root_dir, "usr/lib") if root_dir else _UNIXUSRLIBDIR
)
Expand Down Expand Up @@ -1239,14 +1242,32 @@ def _armbian_version(self) -> str:
except FileNotFoundError:
return ""

@staticmethod
def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]:
def _parse_uname_content(self, lines: Sequence[str]) -> Dict[str, str]:
if not lines:
return {}
props = {}
match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip())
match = re.search(r"^([^\s]+)\s+([^\s]+)", lines[0].strip())
if match:
name, version = match.groups()
name, release = match.groups()

# CloudLinux detection relies on uname release information
release_parts = release.split(".")
if (
# check penultimate release component contains an "el*" version
len(release_parts) > 1
and release_parts[-2].startswith("el")
and (
# CloudLinux < 9 : "lve*" is set in kernel release
any(rc.startswith("lve") for rc in release_parts)
# CloudLinux >= 9 : check whether "kmodlve" is loaded
or "kmodlve" in self._loaded_modules
)
):
props["id"] = "cloudlinux"
props["name"] = "CloudLinux"
# strip "el" prefix and replace underscores by dots
props["release"] = release_parts[-2][2:].replace("_", ".")
return props

# This is to prevent the Linux kernel version from
# appearing as the 'best' version on otherwise
Expand All @@ -1255,9 +1276,17 @@ def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]:
return {}
props["id"] = name.lower()
props["name"] = name
props["release"] = version
props["release"] = release.split("-")[0] # only keep version part
return props

@cached_property
def _loaded_modules(self) -> List[str]:
try:
with open(os.path.join(self.proc_dir, "modules"), encoding="ascii") as fp:
return [line.split()[0] for line in fp]
except OSError:
return []

@staticmethod
def _to_str(bytestring: bytes) -> str:
encoding = sys.getfilesystemencoding()
Expand Down
3 changes: 3 additions & 0 deletions tests/resources/distros/cloudlinuxvm7/bin/uname
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

echo "Linux 3.10.0-962.3.2.lve1.5.24.9.el7.x86_64"
3 changes: 3 additions & 0 deletions tests/resources/distros/cloudlinuxvm8/bin/uname
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

echo "Linux 4.18.0-513.18.1.lve.2.el8.x86_64"
3 changes: 3 additions & 0 deletions tests/resources/distros/cloudlinuxvm9/bin/uname
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

echo "Linux 5.14.0-427.20.1.el9_4.x86_64"
12 changes: 12 additions & 0 deletions tests/resources/distros/cloudlinuxvm9/proc/modules
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
autofs4 23643 2 - Live 0x0000000000000000
btrfs 21980 0 - Live 0x0000000000000000
cdrom 3656 2 hfsplus,hfs, Live 0x0000000000000000
ext4 19980 5 - Live 0x0000000000000000
fat 31261 2 msdos,vfat, Live 0x0000000000000000
fuse 20211 9 - Live 0x0000000000000000
hfs 28747 0 - Live 0x0000000000000000
hfsplus 4168 0 - Live 0x0000000000000000
kmodlve 17657856 2 - Live 0x0000000000000000
msdos 7785 0 - Live 0x0000000000000000
vfat 7785 1 - Live 0x0000000000000000
xor 1770 1 btrfs, Live 0x0000000000000000
42 changes: 42 additions & 0 deletions tests/test_distro.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from distro import distro

RELATIVE_UNIXCONFDIR = distro._UNIXCONFDIR[1:]
RELATIVE_UNIXPROCDIR = distro._UNIXPROCDIR[1:]
RELATIVE_UNIXUSRLIBDIR = distro._UNIXUSRLIBDIR[1:]
MODULE_DISTRO = distro._distro

Expand Down Expand Up @@ -118,11 +119,13 @@ def setup_method(self, test_method: FunctionType) -> None:
# changes it:
self._saved_path = os.environ["PATH"]
self._saved_UNIXCONFDIR = distro._UNIXCONFDIR
self._saved_UNIXPROCDIR = distro._UNIXPROCDIR
self._saved_UNIXUSRLIBDIR = distro._UNIXUSRLIBDIR

def teardown_method(self, test_method: FunctionType) -> None:
os.environ["PATH"] = self._saved_path
distro._UNIXCONFDIR = self._saved_UNIXCONFDIR
distro._UNIXPROCDIR = self._saved_UNIXPROCDIR
distro._UNIXUSRLIBDIR = self._saved_UNIXUSRLIBDIR

def _setup_for_distro(self, distro_root: str) -> None:
Expand All @@ -131,6 +134,7 @@ def _setup_for_distro(self, distro_root: str) -> None:
# distro that runs this test, so we use a PATH with only one entry:
os.environ["PATH"] = distro_bin
distro._UNIXCONFDIR = os.path.join(distro_root, RELATIVE_UNIXCONFDIR)
distro._UNIXPROCDIR = os.path.join(distro_root, RELATIVE_UNIXPROCDIR)
distro._UNIXUSRLIBDIR = os.path.join(distro_root, RELATIVE_UNIXUSRLIBDIR)


Expand Down Expand Up @@ -628,6 +632,42 @@ def test_manjaro1512_lsb_release(self) -> None:
# }
# self._test_outcome(desired_outcome)

def test_cloudlinuxvm7_uname(self) -> None:
self._test_outcome(
{
"id": "cloudlinux",
"name": "CloudLinux",
"version": "7",
"pretty_name": "CloudLinux 7",
"pretty_version": "7",
"best_version": "7",
}
)

def test_cloudlinuxvm8_uname(self) -> None:
self._test_outcome(
{
"id": "cloudlinux",
"name": "CloudLinux",
"version": "8",
"pretty_name": "CloudLinux 8",
"pretty_version": "8",
"best_version": "8",
}
)

def test_cloudlinuxvm9_uname(self) -> None:
self._test_outcome(
{
"id": "cloudlinux",
"name": "CloudLinux",
"version": "9.4",
"pretty_name": "CloudLinux 9.4",
"pretty_version": "9.4",
"best_version": "9.4",
}
)

def test_openbsd62_uname(self) -> None:
self._test_outcome(
{
Expand Down Expand Up @@ -2387,9 +2427,11 @@ def test_repr(self) -> None:
if attr in (
"root_dir",
"etc_dir",
"proc_dir",
"usr_lib_dir",
"_debian_version",
"_armbian_version",
"_loaded_modules",
):
continue
assert f"{attr}=" in repr_str

0 comments on commit 2ceba16

Please sign in to comment.