chore: complete 2.0.2 maintenance baseline

This commit is contained in:
cppla
2026-08-20 12:35:47 +08:00
parent 1147f9c5dd
commit 5e7a58c263
16 changed files with 749 additions and 81 deletions
+46 -35
View File
@@ -208,6 +208,34 @@ def get_cpu_model():
return vendor
return normalize_cpu_model(lscpu.get('architecture') or platform.machine() or platform.processor())
def get_os_name():
try:
sysname = platform.system().lower()
if sysname.startswith('linux'):
os_name = 'linux'
try:
with open('/etc/os-release') as f:
for line in f:
if line.startswith('ID='):
value = line.strip().split('=', 1)[1].strip().strip('"')
if value:
os_name = value
break
except Exception:
pass
return os_name
if sysname.startswith('darwin'):
return 'darwin'
if sysname.startswith('freebsd'):
return 'freebsd'
if sysname.startswith('openbsd'):
return 'openbsd'
if sysname.startswith('netbsd'):
return 'netbsd'
return sysname or 'unknown'
except Exception:
return 'unknown'
def liuliang():
NET_IN = 0
NET_OUT = 0
@@ -276,6 +304,22 @@ diskIO = {
}
monitorServer = {}
def update_net_speed(avgrx, avgtx, now_clock=None):
if now_clock is None:
now_clock = time.monotonic()
previous_clock = netSpeed.get("clock", 0.0)
previous_rx = netSpeed.get("avgrx", 0)
previous_tx = netSpeed.get("avgtx", 0)
diff = now_clock - previous_clock
initialized = previous_clock > 0 and diff > 0
netSpeed["diff"] = diff if initialized else 0.0
netSpeed["clock"] = now_clock
netSpeed["netrx"] = int((avgrx - previous_rx) / diff) if initialized and avgrx >= previous_rx else 0
netSpeed["nettx"] = int((avgtx - previous_tx) / diff) if initialized and avgtx >= previous_tx else 0
netSpeed["avgrx"] = avgrx
netSpeed["avgtx"] = avgtx
return netSpeed["netrx"], netSpeed["nettx"]
def _ping_thread(host, mark, port):
lostPacket = 0
packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
@@ -330,13 +374,7 @@ def _net_speed():
dev = dev[1].split()
avgrx += int(dev[0])
avgtx += int(dev[8])
now_clock = time.time()
netSpeed["diff"] = now_clock - netSpeed["clock"]
netSpeed["clock"] = now_clock
netSpeed["netrx"] = int((avgrx - netSpeed["avgrx"]) / netSpeed["diff"])
netSpeed["nettx"] = int((avgtx - netSpeed["avgtx"]) / netSpeed["diff"])
netSpeed["avgrx"] = avgrx
netSpeed["avgtx"] = avgtx
update_net_speed(avgrx, avgtx)
time.sleep(INTERVAL)
def _disk_io():
@@ -617,34 +655,7 @@ if __name__ == '__main__':
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
array['io_read'] = diskIO.get("read")
array['io_write'] = diskIO.get("write")
# report OS (normalized)
try:
sysname = platform.system().lower()
if sysname.startswith('linux'):
os_name = 'linux'
# try distro from os-release
try:
with open('/etc/os-release') as f:
for line in f:
if line.startswith('ID='):
val = line.strip().split('=',1)[1].strip().strip('"')
if val: os_name = val
break
except Exception:
pass
elif sysname.startswith('darwin'):
os_name = 'darwin'
elif sysname.startswith('freebsd'):
os_name = 'freebsd'
elif sysname.startswith('openbsd'):
os_name = 'openbsd'
elif sysname.startswith('netbsd'):
os_name = 'netbsd'
else:
os_name = sysname or 'unknown'
except Exception:
os_name = 'unknown'
array['os'] = os_name
array['os'] = get_os_name()
items = []
for _n, st in monitorServer.items():
key = str(_n)
+44 -32
View File
@@ -148,6 +148,32 @@ def get_cpu_model():
return vendor
return get_platform_cpu_arch()
def get_os_name():
try:
sysname = platform.system().lower()
if sysname.startswith('windows'):
return 'windows'
if sysname.startswith('darwin') or 'mac' in sysname:
return 'darwin'
if 'bsd' in sysname:
return 'bsd'
if sysname.startswith('linux'):
os_name = 'linux'
try:
with open('/etc/os-release') as f:
for line in f:
if line.startswith('ID='):
value = line.strip().split('=', 1)[1].strip().strip('"')
if value:
os_name = value
break
except Exception:
pass
return os_name
return sysname or 'unknown'
except Exception:
return 'unknown'
def _get_net_io_counters():
with _net_io_counters_lock:
return psutil.net_io_counters(pernic=True)
@@ -236,6 +262,22 @@ diskIO = {
}
monitorServer = {}
def update_net_speed(avgrx, avgtx, now_clock=None):
if now_clock is None:
now_clock = time.monotonic()
previous_clock = netSpeed.get("clock", 0.0)
previous_rx = netSpeed.get("avgrx", 0)
previous_tx = netSpeed.get("avgtx", 0)
diff = now_clock - previous_clock
initialized = previous_clock > 0 and diff > 0
netSpeed["diff"] = diff if initialized else 0.0
netSpeed["clock"] = now_clock
netSpeed["netrx"] = int((avgrx - previous_rx) / diff) if initialized and avgrx >= previous_rx else 0
netSpeed["nettx"] = int((avgtx - previous_tx) / diff) if initialized and avgtx >= previous_tx else 0
netSpeed["avgrx"] = avgrx
netSpeed["avgtx"] = avgtx
return netSpeed["netrx"], netSpeed["nettx"]
def _ping_thread(host, mark, port):
lostPacket = 0
packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN)
@@ -286,13 +328,7 @@ def _net_speed():
continue
avgrx += stats.bytes_recv
avgtx += stats.bytes_sent
now_clock = time.time()
netSpeed["diff"] = now_clock - netSpeed["clock"]
netSpeed["clock"] = now_clock
netSpeed["netrx"] = int((avgrx - netSpeed["avgrx"]) / netSpeed["diff"])
netSpeed["nettx"] = int((avgtx - netSpeed["avgtx"]) / netSpeed["diff"])
netSpeed["avgrx"] = avgrx
netSpeed["avgtx"] = avgtx
update_net_speed(avgrx, avgtx)
time.sleep(INTERVAL)
def _disk_io():
@@ -570,31 +606,7 @@ if __name__ == '__main__':
array['tcp'], array['udp'], array['process'], array['thread'] = tupd()
array['io_read'] = diskIO.get("read")
array['io_write'] = diskIO.get("write")
# report OS (normalized)
try:
sysname = platform.system().lower()
if sysname.startswith('windows'):
os_name = 'windows'
elif sysname.startswith('darwin') or 'mac' in sysname:
os_name = 'darwin'
elif 'bsd' in sysname:
os_name = 'bsd'
elif sysname.startswith('linux'):
# try distro from os-release
try:
with open('/etc/os-release') as f:
for line in f:
if line.startswith('ID='):
val = line.strip().split('=',1)[1].strip().strip('"')
if val: os_name = val
break
except Exception:
os_name = 'linux'
else:
os_name = sysname or 'unknown'
except Exception:
os_name = 'unknown'
array['os'] = os_name
array['os'] = get_os_name()
items = []
for _n, st in monitorServer.items():
key = str(_n)
+1 -1
View File
@@ -11,7 +11,7 @@ CLIENT_DIR = Path(__file__).resolve().parent
class ClientArgumentTests(unittest.TestCase):
def test_password_with_user_text_does_not_replace_username(self):
if importlib.util.find_spec("psutil") is None:
if "psutil" not in sys.modules and importlib.util.find_spec("psutil") is None:
sys.modules["psutil"] = types.ModuleType("psutil")
arguments = [
+127
View File
@@ -0,0 +1,127 @@
import runpy
import sys
import threading
import time
import types
import unittest
from collections import namedtuple
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from unittest import mock
CLIENT_DIR = Path(__file__).resolve().parent
def load_client(filename):
if filename == "client-psutil.py" and "psutil" not in sys.modules:
try:
__import__("psutil")
except ImportError:
sys.modules["psutil"] = types.ModuleType("psutil")
return runpy.run_path(str(CLIENT_DIR / filename))
class ClientMetricTests(unittest.TestCase):
def test_psutil_counter_reads_are_serialized_and_keep_nowrap_enabled(self):
client = load_client("client-psutil.py")
active = 0
maximum_active = 0
calls = []
state_lock = threading.Lock()
def fake_counters(*args, **kwargs):
nonlocal active, maximum_active
with state_lock:
active += 1
maximum_active = max(maximum_active, active)
calls.append((args, kwargs))
time.sleep(0.002)
with state_lock:
active -= 1
return {}
with mock.patch.object(client["psutil"], "net_io_counters", side_effect=fake_counters, create=True):
with ThreadPoolExecutor(max_workers=12) as executor:
list(executor.map(lambda _index: client["_get_net_io_counters"](), range(48)))
self.assertEqual(maximum_active, 1)
self.assertEqual(len(calls), 48)
self.assertTrue(all(kwargs == {"pernic": True} for _args, kwargs in calls))
def test_psutil_totals_exclude_virtual_interfaces(self):
client = load_client("client-psutil.py")
counters = namedtuple("Counters", "bytes_sent bytes_recv")
values = {
"eth0": counters(500, 1000),
"ens5": counters(300, 700),
"lo": counters(9000, 9000),
"docker0": counters(8000, 8000),
"veth123": counters(7000, 7000),
}
with mock.patch.object(client["psutil"], "net_io_counters", return_value=values, create=True):
self.assertEqual(client["liuliang"](), (1700, 800))
def test_linux_totals_read_proc_and_exclude_virtual_interfaces(self):
client = load_client("client-linux.py")
proc_net_dev = """Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
eth0: 1000 10 0 0 0 0 0 0 500 5 0 0 0 0 0 0
ens5: 700 7 0 0 0 0 0 0 300 3 0 0 0 0 0 0
lo: 9000 9 0 0 0 0 0 0 9000 9 0 0 0 0 0 0
veth123: 8000 8 0 0 0 0 0 0 8000 8 0 0 0 0 0 0
"""
with mock.patch("builtins.open", mock.mock_open(read_data=proc_net_dev)):
self.assertEqual(client["liuliang"](), (1700, 800))
def test_network_speed_starts_and_resets_at_zero(self):
for filename in ("client-linux.py", "client-psutil.py"):
with self.subTest(client=filename):
client = load_client(filename)
state = client["update_net_speed"].__globals__["netSpeed"]
state.update({"clock": 0.0, "diff": 0.0, "avgrx": 0, "avgtx": 0, "netrx": 0, "nettx": 0})
self.assertEqual(client["update_net_speed"](1000, 1000, 100.0), (0, 0))
self.assertEqual(client["update_net_speed"](1400, 1300, 102.0), (200, 150))
self.assertEqual(client["update_net_speed"](10, 1500, 103.0), (0, 200))
self.assertEqual(client["update_net_speed"](5, 4, 104.0), (0, 0))
def test_os_detection_uses_linux_distribution_id(self):
os_release = 'NAME="Alpine Linux"\nID=alpine\nVERSION_ID=3.22\n'
for filename in ("client-linux.py", "client-psutil.py"):
with self.subTest(client=filename):
client = load_client(filename)
with mock.patch.object(client["platform"], "system", return_value="Linux"), \
mock.patch("builtins.open", mock.mock_open(read_data=os_release)):
self.assertEqual(client["get_os_name"](), "alpine")
def test_os_detection_has_platform_fallbacks(self):
psutil_client = load_client("client-psutil.py")
with mock.patch.object(psutil_client["platform"], "system", return_value="Windows Server 2022"):
self.assertEqual(psutil_client["get_os_name"](), "windows")
linux_client = load_client("client-linux.py")
with mock.patch.object(linux_client["platform"], "system", return_value="FreeBSD"):
self.assertEqual(linux_client["get_os_name"](), "freebsd")
def test_cpu_model_prefers_specific_model_and_has_vendor_fallback(self):
linux_client = load_client("client-linux.py")
linux_globals = linux_client["get_cpu_model"].__globals__
with mock.patch.dict(linux_globals, {
"get_cpuinfo_values": lambda: {"model name": "AMD EPYC 7B13"},
"get_lscpu_info": lambda: {"vendor id": "AuthenticAMD", "architecture": "x86_64"},
}):
self.assertEqual(linux_client["get_cpu_model"](), "AMD EPYC 7B13")
psutil_client = load_client("client-psutil.py")
platform_module = psutil_client["platform"]
uname = types.SimpleNamespace(processor="", machine="x86_64")
with mock.patch.object(platform_module, "processor", return_value=""), \
mock.patch.object(platform_module, "uname", return_value=uname), \
mock.patch.object(platform_module, "machine", return_value="x86_64"), \
mock.patch.object(platform_module, "platform", return_value="Linux GenuineIntel"):
self.assertEqual(psutil_client["get_cpu_model"](), "GenuineIntel")
if __name__ == "__main__":
unittest.main()