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 support for CloudLinux VM missing os-release and /etc/redhat-release #369

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
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
Loading