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

NAS-133293 / 25.04 / remove psutil from truenas_install #796

Merged
merged 5 commits into from
Dec 28, 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
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ idna==3.7
jsonschema==3.2.0
packaging==21.3
pexpect==4.8.0
psutil==5.8.0
ptyprocess==0.7.0
pyparsing==3.0.9
PyYAML==6.0.1
Expand Down
10 changes: 7 additions & 3 deletions scale_build/utils/system.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import psutil
from functools import cache

REQUIRED_RAM_GB = 16 * (1024 ** 3)

REQUIRED_RAM = 16 # GB
__all__ = ("has_low_ram",)


@cache
def has_low_ram():
return psutil.virtual_memory().total < REQUIRED_RAM * 1024 * 1024 * 1024
with open('/proc/meminfo') as f:
for line in filter(lambda x: 'MemTotal' in x, f):
return int(line.split()[1]) * 1024 < REQUIRED_RAM_GB
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
install_requires=[
'coloredlogs',
'toposort',
'psutil',
'requests',
'pyyaml'
],
Expand Down
24 changes: 10 additions & 14 deletions truenas_install/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
import sys
import tempfile

import psutil

from licenselib.license import ContractType, License

from .dhs import TRUENAS_DATA_HIERARCHY
from .fhs import TRUENAS_DATASETS
from .utils import getmntinfo, get_pids

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -185,23 +184,20 @@ def precheck(old_root):
pass

processes = defaultdict(list)
for p in psutil.process_iter():
processes[p.name()].append(p.pid)
for p in get_pids():
processes[p.name].append(p)
running_services = []
for service, title, process_name, cmdline in services:
if process_name in processes:
# If we report an enabled service, we don't want to report the same service running.
if title not in enabled_services:
for pid in processes[process_name]:
for proc in processes[process_name]:
if cmdline is not None:
try:
if cmdline not in psutil.Process(pid).cmdline():
continue
except psutil.NoSuchProcess:
if cmdline not in proc.cmdline.decode(errors="ignore"):
continue

try:
with open(f"/proc/{pid}/cgroup") as f:
with open(f"/proc/{proc.pid}/cgroup") as f:
cgroups = f.read().strip()
except FileNotFoundError:
cgroups = ""
Expand Down Expand Up @@ -276,10 +272,10 @@ def main():

old_root_dataset = None
if old_root is not None:
try:
old_root_dataset = next(p for p in psutil.disk_partitions() if p.mountpoint == old_root).device
except StopIteration:
pass
for i in getmntinfo():
if i.mountpoint == old_root:
old_root_dataset == i.mount_source
break

write_progress(0, "Creating dataset")
if input.get("dataset_name"):
Expand Down
76 changes: 76 additions & 0 deletions truenas_install/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from collections.abc import Generator
from dataclasses import dataclass
from functools import cached_property
from os import makedev, scandir

__all__ = ("get_pids", "getmntinfo",)


@dataclass(frozen=True, kw_only=True)
class PidEntry:
cmdline: bytes
pid: int

@cached_property
def name(self) -> bytes:
"""The name of process as described in man 2 PR_SET_NAME"""
with open(f"/proc/{self.pid}/status", "rb") as f:
# first line in this file is name of process
# and this is in procfs, which is considered
# part of linux's ABI and is stable
return f.readline().split(b"\t", 1)[-1].strip()


@dataclass(slots=True, frozen=True, kw_only=True)
class DevIdEntry:
major: int
minor: int
dev_t: int


@dataclass(slots=True, frozen=True, kw_only=True)
class MntEntry:
mount_id: int
parent_id: int
device_id: DevIdEntry
root: str
mountpoint: str
mount_opts: list[str]
fs_type: str
mount_source: str
super_opts: list[str]


def get_pids() -> Generator[PidEntry] | None:
"""Get the currently running processes on the OS"""
with scandir("/proc/") as sdir:
for i in filter(lambda x: x.name.isdigit(), sdir):
try:
with open(f"{i.path}/cmdline", "rb") as f:
cmdline = f.read().replace(b"\x00", b" ")
yield PidEntry(cmdline=cmdline, pid=int(i.name))
except FileNotFoundError:
# process could have gone away
pass


def getmntinfo() -> Generator[MntEntry]:
with open('/proc/self/mountinfo') as f:
for line in f:
mnt_id, parent_id, maj_min, root, mp, opts, extra = line.split(" ", 6)
fstype, mnt_src, super_opts = extra.split(' - ')[1].split()
major, minor = maj_min.split(':')
major, minor = int(major), int(minor)
devid = makedev(major, minor)
deventry = DevIdEntry(major=major, minor=minor, dev_t=devid)
yield MntEntry(**{
'mount_id': int(mnt_id),
'parent_id': int(parent_id),
'device_id': deventry,
'root': root.replace('\\040', ' '),
'mountpoint': mp.replace('\\040', ' '),
'mount_opts': opts.upper().split(','),
'fs_type': fstype,
'mount_source': mnt_src.replace('\\040', ' '),
'super_opts': super_opts.upper().split(','),
})
Loading