mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-25 18:40:06 -04:00
Fetching processes from PROCFS_PATH in docker container.
This commit is contained in:
parent
03a2596799
commit
cccbac9ae9
2 changed files with 44 additions and 10 deletions
|
|
@ -9,11 +9,21 @@ can seamlessly switch between data sources.
|
|||
"""
|
||||
|
||||
import statistics
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import psutil
|
||||
|
||||
from controller.lib.config import is_docker_mode
|
||||
|
||||
# In the Docker development environment the compose file bind-mounts the host's
|
||||
# /proc and /sys read-only so the Controller can report real host metrics
|
||||
# instead of the tiny container namespace. We must tell psutil about it.
|
||||
# Note: PROCFS_PATH only exists on Linux/SunOS/AIX; guard the access.
|
||||
if is_docker_mode() and hasattr(psutil, "PROCFS_PATH"):
|
||||
psutil.PROCFS_PATH = "/host/proc"
|
||||
|
||||
# State for bandwidth rate calculations
|
||||
_previous_network_stats: dict[str, dict] = {}
|
||||
_previous_disk_stats: dict[str, dict] = {}
|
||||
|
|
@ -26,10 +36,15 @@ def reset_bandwidth_stats():
|
|||
_previous_disk_stats = {}
|
||||
|
||||
|
||||
# CPU frequency paths
|
||||
MIN_FREQUENCY_PATH = Path('/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq')
|
||||
MAX_FREQUENCY_PATH = Path('/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq')
|
||||
CUR_FREQUENCY_PATH = Path('/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq')
|
||||
# CPU frequency paths (remapped in Docker dev to the host mounts)
|
||||
if is_docker_mode():
|
||||
MIN_FREQUENCY_PATH = Path('/host/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq')
|
||||
MAX_FREQUENCY_PATH = Path('/host/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq')
|
||||
CUR_FREQUENCY_PATH = Path('/host/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq')
|
||||
else:
|
||||
MIN_FREQUENCY_PATH = Path('/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq')
|
||||
MAX_FREQUENCY_PATH = Path('/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq')
|
||||
CUR_FREQUENCY_PATH = Path('/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq')
|
||||
|
||||
|
||||
def get_cpu_status() -> dict:
|
||||
|
|
@ -357,14 +372,25 @@ def get_processes_status() -> list[dict]:
|
|||
processes = []
|
||||
|
||||
try:
|
||||
# Get processes sorted by CPU usage
|
||||
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent', 'cmdline']):
|
||||
# Two-pass sampling is required for accurate cpu_percent.
|
||||
# First pass: prime the per-process CPU time counters.
|
||||
procs = []
|
||||
for proc in psutil.process_iter(['pid', 'name', 'memory_percent', 'cmdline']):
|
||||
try:
|
||||
info = proc.info
|
||||
cpu_percent = info.get('cpu_percent', 0)
|
||||
proc.cpu_percent() # prime (result ignored)
|
||||
procs.append(proc)
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
# Only include processes using > 1% CPU
|
||||
# Short sample interval. 0.2s is a good balance for "top" display.
|
||||
time.sleep(0.2)
|
||||
|
||||
# Second pass: read the actual percentage since the prime call.
|
||||
for proc in procs:
|
||||
try:
|
||||
cpu_percent = proc.cpu_percent()
|
||||
if cpu_percent and cpu_percent > 1:
|
||||
info = proc.info
|
||||
cmdline = info.get('cmdline') or [info.get('name', '')]
|
||||
command = ' '.join(cmdline) if cmdline else info.get('name', '')
|
||||
|
||||
|
|
@ -376,7 +402,7 @@ def get_processes_status() -> list[dict]:
|
|||
"pid": info.get('pid'),
|
||||
"percent_cpu": int(cpu_percent),
|
||||
"percent_mem": int(info.get('memory_percent', 0)),
|
||||
"command": command[:512], # Limit command length
|
||||
"command": command[:512],
|
||||
})
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -71,6 +71,14 @@ async def lifespan(app: FastAPI):
|
|||
logger.info("WROLPi Controller v%s starting...", __version__)
|
||||
logger.info("Docker mode: %s", is_docker_mode())
|
||||
|
||||
# When running under Docker dev, status.py will have already remapped
|
||||
# psutil.PROCFS_PATH to /host/proc (and the sysfs paths) so we report
|
||||
# real host metrics instead of the container's tiny namespace.
|
||||
if is_docker_mode():
|
||||
import psutil
|
||||
procfs_path = getattr(psutil, "PROCFS_PATH", "N/A (not supported on this platform)")
|
||||
logger.info("Using host procfs for stats: %s", procfs_path)
|
||||
|
||||
# Try to load config from drive if mounted
|
||||
if is_primary_drive_mounted():
|
||||
if reload_config_from_drive():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue