network monitoring

This commit is contained in:
Alex Tau 2025-06-07 15:59:05 +03:00
parent 8af7b683b6
commit 8b18d407d7
21 changed files with 434 additions and 53 deletions

View file

@ -33,7 +33,7 @@ List of enabled check sets\. Each check set is a module which checks something a
*Type:* *Type:*
list of (one of “start”, “stop”, “cpu”, “ram”, “temp”, “vulnix”) list of (one of “start”, “stop”, “remind”, “cpu”, “ram”, “temp”, “net”, “vulnix”)
@ -52,7 +52,7 @@ CPU load percentage for a critical alert to be sent\. Null means never generate
*Type:* *Type:*
null or floating point number null or (positive integer or floating point number, meaning >0)
@ -73,7 +73,7 @@ CPU load percentage for a warning alert to be sent\. Null means never generate a
*Type:* *Type:*
null or floating point number null or (positive integer or floating point number, meaning >0)
@ -85,6 +85,166 @@ null or floating point number
## services\.lego-monitoring\.checks\.net\.interfaces
Per-interface configuration of IO byte thresholds\.
*Type:*
attribute set of (submodule)
*Default:*
` { } `
*Example:*
```
{
br0 = {
warningThresholdCombBytes = 700 * 1024 * 128; # 700 Megabits
criticalThresholdCombBytes = 1 * 1024 * 1024 * 128; # 1 Gigabit
};
}
```
*Declared by:*
- [modules/options\.nix](../modules/options.nix)
## services\.lego-monitoring\.checks\.net\.interfaces\.\<name>\.criticalThresholdCombBytes
Combined (sent + received) bytes per second threshold for a critical alert to be sent\. If null, this threshold is disabled and not checked\.
*Type:*
null or (positive integer, meaning >0)
*Default:*
` null `
*Declared by:*
- [modules/options\.nix](../modules/options.nix)
## services\.lego-monitoring\.checks\.net\.interfaces\.\<name>\.criticalThresholdRecvBytes
Received bytes per second threshold for a critical alert to be sent\. If null, this threshold is disabled and not checked\.
*Type:*
null or (positive integer, meaning >0)
*Default:*
` null `
*Declared by:*
- [modules/options\.nix](../modules/options.nix)
## services\.lego-monitoring\.checks\.net\.interfaces\.\<name>\.criticalThresholdSentBytes
Sent bytes per second threshold for a critical alert to be sent\. If null, this threshold is disabled and not checked\.
*Type:*
null or (positive integer, meaning >0)
*Default:*
` null `
*Declared by:*
- [modules/options\.nix](../modules/options.nix)
## services\.lego-monitoring\.checks\.net\.interfaces\.\<name>\.warningThresholdCombBytes
Combined (sent + received) bytes per second threshold for a warning alert to be sent\. If null, this threshold is disabled and not checked\.
*Type:*
null or (positive integer, meaning >0)
*Default:*
` null `
*Declared by:*
- [modules/options\.nix](../modules/options.nix)
## services\.lego-monitoring\.checks\.net\.interfaces\.\<name>\.warningThresholdRecvBytes
Received bytes per second threshold for a warning alert to be sent\. If null, this threshold is disabled and not checked\.
*Type:*
null or (positive integer, meaning >0)
*Default:*
` null `
*Declared by:*
- [modules/options\.nix](../modules/options.nix)
## services\.lego-monitoring\.checks\.net\.interfaces\.\<name>\.warningThresholdSentBytes
Sent bytes per second threshold for a warning alert to be sent\. If null, this threshold is disabled and not checked\.
*Type:*
null or (positive integer, meaning >0)
*Default:*
` null `
*Declared by:*
- [modules/options\.nix](../modules/options.nix)
## services\.lego-monitoring\.checks\.ram\.criticalPercentage ## services\.lego-monitoring\.checks\.ram\.criticalPercentage
@ -94,7 +254,7 @@ RAM usage percentage for a critical alert to be sent\. Null means never generate
*Type:* *Type:*
null or floating point number null or (positive integer or floating point number, meaning >0)
@ -115,7 +275,7 @@ RAM usage percentage for a warning alert to be sent\. Null means never generate
*Type:* *Type:*
null or floating point number null or (positive integer or floating point number, meaning >0)
@ -265,7 +425,7 @@ Critical temperature threshold\.
*Type:* *Type:*
null or floating point number null or (positive integer or floating point number, meaning >0)
@ -307,7 +467,7 @@ Warning temperature threshold\.
*Type:* *Type:*
null or floating point number null or (positive integer or floating point number, meaning >0)

23
flake.lock generated
View file

@ -16,6 +16,22 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-29335f": {
"locked": {
"lastModified": 1745804731,
"narHash": "sha256-v/sK3AS0QKu/Tu5sHIfddiEHCvrbNYPv8X10Fpux68g=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "29335f23bea5e34228349ea739f31ee79e267b88",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nixpkgs",
"rev": "29335f23bea5e34228349ea739f31ee79e267b88",
"type": "github"
}
},
"pyproject-build-systems": { "pyproject-build-systems": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -65,6 +81,7 @@
"root": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-29335f": "nixpkgs-29335f",
"pyproject-build-systems": "pyproject-build-systems", "pyproject-build-systems": "pyproject-build-systems",
"pyproject-nix": "pyproject-nix", "pyproject-nix": "pyproject-nix",
"uv2nix": "uv2nix" "uv2nix": "uv2nix"
@ -80,11 +97,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1745697651, "lastModified": 1749170547,
"narHash": "sha256-r4A/fkiCenEapHkjJWPiNUZEfviuXMCr6mRozJ5dC4o=", "narHash": "sha256-zOptuFhTr9P0A+unFaOBFx5E5T6yx0qE8VrUGVrM96U=",
"owner": "pyproject-nix", "owner": "pyproject-nix",
"repo": "uv2nix", "repo": "uv2nix",
"rev": "cb6508484d534dafd097713b575f2aebc3417de0", "rev": "7ae60727d4fc2e41aefd30da665e4f92ba8298f1",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -1,6 +1,8 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
# this is for uv 0.6.17, 0.7.0 has a change uv2nix doesn't yet support: https://github.com/astral-sh/uv/pull/13176
nixpkgs-29335f.url = "github:nixos/nixpkgs/29335f23bea5e34228349ea739f31ee79e267b88";
pyproject-nix = { pyproject-nix = {
url = "github:pyproject-nix/pyproject.nix"; url = "github:pyproject-nix/pyproject.nix";
@ -25,6 +27,7 @@
{ {
self, self,
nixpkgs, nixpkgs,
nixpkgs-29335f,
uv2nix, uv2nix,
pyproject-nix, pyproject-nix,
pyproject-build-systems, pyproject-build-systems,
@ -78,6 +81,7 @@
# This example is only using x86_64-linux # This example is only using x86_64-linux
pkgs = nixpkgs.legacyPackages.x86_64-linux; pkgs = nixpkgs.legacyPackages.x86_64-linux;
pkgs-29335f = nixpkgs-29335f.legacyPackages.x86_64-linux;
# Use Python 3.12 from nixpkgs # Use Python 3.12 from nixpkgs
python = pkgs.python312; python = pkgs.python312;
@ -125,7 +129,7 @@
impure = pkgs.mkShell { impure = pkgs.mkShell {
packages = [ packages = [
python python
pkgs.uv pkgs-29335f.uv
]; ];
env = env =
{ {
@ -205,7 +209,7 @@
pkgs.mkShell { pkgs.mkShell {
packages = [ packages = [
virtualenv virtualenv
pkgs.uv pkgs-29335f.uv
]; ];
env = { env = {

View file

@ -60,6 +60,15 @@ package:
warning_percentage = warningPercentage; warning_percentage = warningPercentage;
critical_percentage = criticalPercentage; critical_percentage = criticalPercentage;
}; };
net.interfaces = lib.mapAttrs (_: interfaceCfg: {
warning_threshold_sent_bytes = interfaceCfg.warningThresholdSentBytes;
critical_threshold_sent_bytes = interfaceCfg.criticalThresholdSentBytes;
warning_threshold_recv_bytes = interfaceCfg.warningThresholdRecvBytes;
critical_threshold_recv_bytes = interfaceCfg.warningThresholdRecvBytes;
warning_threshold_comb_bytes = interfaceCfg.warningThresholdCombBytes;
critical_threshold_comb_bytes = interfaceCfg.criticalThresholdCombBytes;
}) cfg.checks.net.interfaces;
}; };
}; };
in lib.mkIf cfg.enable { in lib.mkIf cfg.enable {

View file

@ -6,6 +6,7 @@
let let
tempSensorOptions = (import ./suboptions/tempSensorOptions.nix) { inherit lib; }; tempSensorOptions = (import ./suboptions/tempSensorOptions.nix) { inherit lib; };
vulnixWhitelistRule = (import ./suboptions/vulnixWhitelistRule.nix) { inherit lib; }; vulnixWhitelistRule = (import ./suboptions/vulnixWhitelistRule.nix) { inherit lib; };
netInterfaceOptions = (import ./suboptions/netInterfaceOptions.nix) { inherit lib; };
in in
{ {
options.services.lego-monitoring = { options.services.lego-monitoring = {
@ -32,6 +33,7 @@ in
"cpu" "cpu"
"ram" "ram"
"temp" "temp"
"net"
"vulnix" "vulnix"
]); ]);
@ -96,12 +98,12 @@ in
cpu = { cpu = {
warningPercentage = lib.mkOption { warningPercentage = lib.mkOption {
type = lib.types.nullOr lib.types.float; type = lib.types.nullOr lib.types.numbers.positive;
default = 80.0; default = 80.0;
description = "CPU load percentage for a warning alert to be sent. Null means never generate a CPU warning alert."; description = "CPU load percentage for a warning alert to be sent. Null means never generate a CPU warning alert.";
}; };
criticalPercentage = lib.mkOption { criticalPercentage = lib.mkOption {
type = lib.types.nullOr lib.types.float; type = lib.types.nullOr lib.types.numbers.positive;
default = 90.0; default = 90.0;
description = "CPU load percentage for a critical alert to be sent. Null means never generate a CPU critical alert."; description = "CPU load percentage for a critical alert to be sent. Null means never generate a CPU critical alert.";
}; };
@ -109,16 +111,31 @@ in
ram = { ram = {
warningPercentage = lib.mkOption { warningPercentage = lib.mkOption {
type = lib.types.nullOr lib.types.float; type = lib.types.nullOr lib.types.numbers.positive;
default = 80.0; default = 80.0;
description = "RAM usage percentage for a warning alert to be sent. Null means never generate a RAM warning alert."; description = "RAM usage percentage for a warning alert to be sent. Null means never generate a RAM warning alert.";
}; };
criticalPercentage = lib.mkOption { criticalPercentage = lib.mkOption {
type = lib.types.nullOr lib.types.float; type = lib.types.nullOr lib.types.numbers.positive;
default = 90.0; default = 90.0;
description = "RAM usage percentage for a critical alert to be sent. Null means never generate a RAM critical alert."; description = "RAM usage percentage for a critical alert to be sent. Null means never generate a RAM critical alert.";
}; };
}; };
net = {
interfaces = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule netInterfaceOptions);
default = { };
description = "Per-interface configuration of IO byte thresholds.";
example = lib.literalExpression ''
{
br0 = {
warningThresholdCombBytes = 700 * 1024 * 128; # 700 Megabits
criticalThresholdCombBytes = 1 * 1024 * 1024 * 128; # 1 Gigabit
};
}'';
};
};
}; };
}; };
} }

View file

@ -0,0 +1,39 @@
{
lib,
...
}:
{
options = {
warningThresholdSentBytes = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
default = null;
description = "Sent bytes per second threshold for a warning alert to be sent. If null, this threshold is disabled and not checked.";
};
criticalThresholdSentBytes = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
default = null;
description = "Sent bytes per second threshold for a critical alert to be sent. If null, this threshold is disabled and not checked.";
};
warningThresholdRecvBytes = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
default = null;
description = "Received bytes per second threshold for a warning alert to be sent. If null, this threshold is disabled and not checked.";
};
criticalThresholdRecvBytes = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
default = null;
description = "Received bytes per second threshold for a critical alert to be sent. If null, this threshold is disabled and not checked.";
};
warningThresholdCombBytes = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
default = null;
description = "Combined (sent + received) bytes per second threshold for a warning alert to be sent. If null, this threshold is disabled and not checked.";
};
criticalThresholdCombBytes = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
default = null;
description = "Combined (sent + received) bytes per second threshold for a critical alert to be sent. If null, this threshold is disabled and not checked.";
};
};
}

View file

@ -16,12 +16,12 @@ let
description = "Whether this reading is enabled."; description = "Whether this reading is enabled.";
}; };
warningTemp = lib.mkOption { warningTemp = lib.mkOption {
type = lib.types.nullOr lib.types.float; type = lib.types.nullOr lib.types.numbers.positive;
default = null; default = null;
description = "Warning temperature threshold."; description = "Warning temperature threshold.";
}; };
criticalTemp = lib.mkOption { criticalTemp = lib.mkOption {
type = lib.types.nullOr lib.types.float; type = lib.types.nullOr lib.types.numbers.positive;
default = null; default = null;
description = "Critical temperature threshold."; description = "Critical temperature threshold.";
}; };

View file

@ -6,6 +6,7 @@ readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
dependencies = [ dependencies = [
"alt-utils>=0.0.8", "alt-utils>=0.0.8",
"humanize>=4.12.3",
"psutil>=7.0.0", "psutil>=7.0.0",
"telethon>=1.40.0", "telethon>=1.40.0",
] ]

View file

@ -82,6 +82,9 @@ async def async_main():
is_reminder=True, is_reminder=True,
) )
], ],
check_sets.NET: [
IntervalChecker(checks.NetIOTracker().net_check, interval=datetime.timedelta(minutes=5), persistent=True)
],
} }
checkers = [] checkers = []

View file

@ -1,4 +1,5 @@
from dataclasses import dataclass from dataclasses import dataclass, field
from datetime import datetime
from .enum import AlertType, Severity from .enum import AlertType, Severity
@ -8,3 +9,4 @@ class Alert:
alert_type: AlertType alert_type: AlertType
message: str message: str
severity: Severity severity: Severity
created: datetime = field(default_factory=datetime.now)

View file

@ -3,13 +3,16 @@ from enum import IntEnum, StrEnum
class AlertType(StrEnum): class AlertType(StrEnum):
BOOT = "BOOT" BOOT = "BOOT"
CPU = "CPU"
ERROR = "ERROR" ERROR = "ERROR"
TEST = "TEST"
REMIND = "REMIND"
CPU = "CPU"
NET = "NET"
RAM = "RAM" RAM = "RAM"
TEMP = "TEMP" TEMP = "TEMP"
TEST = "TEST"
VULN = "VULN" VULN = "VULN"
REMIND = "REMIND"
# LOGIN = "LOGIN" # LOGIN = "LOGIN"
# SMART = "SMART" # TODO # SMART = "SMART" # TODO
# RAID = "RAID" # RAID = "RAID"

View file

@ -18,8 +18,12 @@ async def get_client() -> TelegramClient:
def format_message(alert: Alert, note: str) -> str: def format_message(alert: Alert, note: str) -> str:
severity_emoji = SEVERITY_TO_EMOJI[alert.severity] severity_emoji = SEVERITY_TO_EMOJI[alert.severity]
note_formatted = f" - <i>{note}</i>" if note else "" note_formatted = f"{note}, " if note else ""
message = f"{severity_emoji} {alert.alert_type} Alert{note_formatted}\n{alert.message}" if "ongoing" in note_formatted:
note_formatted += f"since {alert.created.isoformat()}"
else:
note_formatted += f"at {alert.created.isoformat()}"
message = f"{severity_emoji} {alert.alert_type} Alert - <i>{note_formatted}</i>\n{alert.message}"
return message return message

View file

@ -1,4 +1,5 @@
from .cpu import cpu_check from .cpu import cpu_check
from .net import NetIOTracker
from .ram import ram_check from .ram import ram_check
from .remind import remind_check from .remind import remind_check
from .temp import temp_check from .temp import temp_check

View file

@ -10,19 +10,19 @@ IS_TESTING = False
def cpu_check() -> list[Alert]: def cpu_check() -> list[Alert]:
percentage = cpu_percent() percentage = cpu_percent()
config = cvars.config.get().checks.cpu config = cvars.config.get().checks.cpu
if config.critical_percentage and (IS_TESTING or percentage > config.critical_percentage): if config.critical_percentage and (IS_TESTING or percentage >= config.critical_percentage):
return [ return [
Alert( Alert(
alert_type=AlertType.CPU, alert_type=AlertType.CPU,
message=f"CPU load: {percentage:.2f}% > {config.critical_percentage:.2f}%", message=f"CPU load: {percentage:.2f}% >= {config.critical_percentage:.2f}%",
severity=Severity.CRITICAL, severity=Severity.CRITICAL,
) )
] ]
elif config.warning_percentage and (IS_TESTING or percentage > config.warning_percentage): elif config.warning_percentage and (IS_TESTING or percentage >= config.warning_percentage):
return [ return [
Alert( Alert(
alert_type=AlertType.CPU, alert_type=AlertType.CPU,
message=f"CPU load: {percentage:.2f}% > {config.warning_percentage:.2f}%", message=f"CPU load: {percentage:.2f}% >= {config.warning_percentage:.2f}%",
severity=Severity.WARNING, severity=Severity.WARNING,
) )
] ]

View file

@ -0,0 +1,87 @@
from dataclasses import dataclass, field
from typing import Optional
from humanize import naturalsize
from psutil import net_io_counters
from lego_monitoring.alerting.alert import Alert
from lego_monitoring.alerting.enum import AlertType, Severity
from lego_monitoring.core import cvars
IS_TESTING = False
SECONDS_BETWEEN_CHECKS = 5 * 60
@dataclass
class NetIOTracker:
sent_per_interface: dict[str, int] = field(default_factory=dict, init=False)
recv_per_interface: dict[str, int] = field(default_factory=dict, init=False)
@staticmethod
def check_threshold(
current_stat_bytes_per_sec: float,
critical_threshold: Optional[int],
warning_threshold: Optional[int],
stat_name: str,
interface: str,
) -> Optional[Alert]:
if critical_threshold and (IS_TESTING or current_stat_bytes_per_sec >= critical_threshold):
current_stat_natural = naturalsize(current_stat_bytes_per_sec, binary=True)
critical_threshold_natural = naturalsize(critical_threshold, binary=True)
return Alert(
alert_type=AlertType.NET,
message=f"Interface {interface} {stat_name} {current_stat_natural}/s >= {critical_threshold_natural}/s",
severity=Severity.CRITICAL,
)
elif warning_threshold and (IS_TESTING or current_stat_bytes_per_sec >= warning_threshold):
current_stat_natural = naturalsize(current_stat_bytes_per_sec, binary=True)
warning_threshold_natural = naturalsize(warning_threshold, binary=True)
return Alert(
alert_type=AlertType.NET,
message=f"Interface {interface} {stat_name} {current_stat_natural}/s >= {warning_threshold_natural}/s",
severity=Severity.WARNING,
)
def net_check(self) -> list[Alert]:
alerts = []
current_stats = net_io_counters(pernic=True)
config = cvars.config.get().checks.net
for interface, thresholds in config.interfaces.items():
if interface in self.sent_per_interface and interface in self.recv_per_interface:
sent_since_last_check_per_sec = (
current_stats[interface].bytes_sent - self.sent_per_interface[interface]
) / SECONDS_BETWEEN_CHECKS
recv_since_last_check_per_sec = (
current_stats[interface].bytes_recv - self.recv_per_interface[interface]
) / SECONDS_BETWEEN_CHECKS
comb_since_last_check_per_sec = sent_since_last_check_per_sec + recv_since_last_check_per_sec
if alert := self.check_threshold(
sent_since_last_check_per_sec,
thresholds.critical_threshold_sent_bytes,
thresholds.warning_threshold_sent_bytes,
"sent",
interface,
):
alerts.append(alert)
if alert := self.check_threshold(
recv_since_last_check_per_sec,
thresholds.critical_threshold_recv_bytes,
thresholds.warning_threshold_recv_bytes,
"recv",
interface,
):
alerts.append(alert)
if alert := self.check_threshold(
comb_since_last_check_per_sec,
thresholds.critical_threshold_comb_bytes,
thresholds.warning_threshold_comb_bytes,
"comb",
interface,
):
alerts.append(alert)
self.sent_per_interface[interface] = current_stats[interface].bytes_sent
self.recv_per_interface[interface] = current_stats[interface].bytes_recv
return alerts

View file

@ -10,19 +10,19 @@ IS_TESTING = False
def ram_check() -> list[Alert]: def ram_check() -> list[Alert]:
percentage = virtual_memory().percent percentage = virtual_memory().percent
config = cvars.config.get().checks.ram config = cvars.config.get().checks.ram
if config.critical_percentage and (IS_TESTING or percentage > config.critical_percentage): if config.critical_percentage and (IS_TESTING or percentage >= config.critical_percentage):
return [ return [
Alert( Alert(
alert_type=AlertType.RAM, alert_type=AlertType.RAM,
message=f"RAM usage: {percentage:.2f}% > {config.critical_percentage:.2f}%", message=f"RAM usage: {percentage:.2f}% >= {config.critical_percentage:.2f}%",
severity=Severity.CRITICAL, severity=Severity.CRITICAL,
) )
] ]
elif config.warning_percentage and (IS_TESTING or percentage > config.warning_percentage): elif config.warning_percentage and (IS_TESTING or percentage >= config.warning_percentage):
return [ return [
Alert( Alert(
alert_type=AlertType.RAM, alert_type=AlertType.RAM,
message=f"RAM usage: {percentage:.2f}% > {config.warning_percentage:.2f}%", message=f"RAM usage: {percentage:.2f}% >= {config.warning_percentage:.2f}%",
severity=Severity.WARNING, severity=Severity.WARNING,
) )
] ]

View file

@ -11,16 +11,16 @@ def temp_check() -> list[Alert]:
temps = sensors.get_readings() temps = sensors.get_readings()
for sensor, readings in temps.items(): for sensor, readings in temps.items():
for r in readings: for r in readings:
if r.critical_temp is not None and (IS_TESTING or r.current_temp > r.critical_temp): if r.critical_temp is not None and (IS_TESTING or r.current_temp >= r.critical_temp):
alert = Alert( alert = Alert(
alert_type=AlertType.TEMP, alert_type=AlertType.TEMP,
message=f"{sensor} {r.label}: {r.current_temp}°C > {r.critical_temp}°C", message=f"{sensor} {r.label}: {r.current_temp}°C >= {r.critical_temp}°C",
severity=Severity.CRITICAL, severity=Severity.CRITICAL,
) )
elif r.warning_temp is not None and (IS_TESTING or r.current_temp > r.warning_temp): elif r.warning_temp is not None and (IS_TESTING or r.current_temp >= r.warning_temp):
alert = Alert( alert = Alert(
alert_type=AlertType.TEMP, alert_type=AlertType.TEMP,
message=f"{sensor} {r.label}: {r.current_temp}°C > {r.warning_temp}°C", message=f"{sensor} {r.label}: {r.current_temp}°C >= {r.warning_temp}°C",
severity=Severity.WARNING, severity=Severity.WARNING,
) )
else: else:

View file

@ -6,6 +6,7 @@ from alt_utils import NestedDeserializableDataclass
from . import enums from . import enums
from .checks.cpu import CpuCheckConfig from .checks.cpu import CpuCheckConfig
from .checks.net import NetCheckConfig
from .checks.ram import RamCheckConfig from .checks.ram import RamCheckConfig
from .checks.temp import TempCheckConfig from .checks.temp import TempCheckConfig
from .checks.vulnix import VulnixCheckConfig from .checks.vulnix import VulnixCheckConfig
@ -17,6 +18,7 @@ class ChecksConfig(NestedDeserializableDataclass):
ram: RamCheckConfig = field(default_factory=RamCheckConfig) ram: RamCheckConfig = field(default_factory=RamCheckConfig)
temp: TempCheckConfig = field(default_factory=TempCheckConfig) temp: TempCheckConfig = field(default_factory=TempCheckConfig)
vulnix: Optional[VulnixCheckConfig] = None # vulnix check WILL raise if this config section is None vulnix: Optional[VulnixCheckConfig] = None # vulnix check WILL raise if this config section is None
net: NetCheckConfig = field(default_factory=NetCheckConfig)
@dataclass @dataclass

View file

@ -0,0 +1,19 @@
from dataclasses import dataclass, field
from typing import Optional
from alt_utils import NestedDeserializableDataclass
@dataclass
class NetInterfaceConfig:
warning_threshold_sent_bytes: Optional[int] = None
critical_threshold_sent_bytes: Optional[int] = None
warning_threshold_recv_bytes: Optional[int] = None
critical_threshold_recv_bytes: Optional[int] = None
warning_threshold_comb_bytes: Optional[int] = None
critical_threshold_comb_bytes: Optional[int] = None
@dataclass
class NetCheckConfig(NestedDeserializableDataclass):
interfaces: dict[str, NetInterfaceConfig] = field(default_factory=dict)

View file

@ -9,6 +9,7 @@ class CheckSet(StrEnum):
CPU = "cpu" CPU = "cpu"
RAM = "ram" RAM = "ram"
TEMP = "temp" TEMP = "temp"
NET = "net"
VULNIX = "vulnix" VULNIX = "vulnix"

46
uv.lock generated
View file

@ -1,13 +1,23 @@
version = 1 version = 1
revision = 2
requires-python = ">=3.12" requires-python = ">=3.12"
[[package]] [[package]]
name = "alt-utils" name = "alt-utils"
version = "0.0.8" version = "0.0.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/31/15/67246107a8c808a9e99b34fd0024bebe954a67f3c315821eae985b87db7f/alt_utils-0.0.8.tar.gz", hash = "sha256:4b2901df0be4af736210277d58e231d4c4bce597a8fc665a8dd3e7b582705081", size = 6103 } sdist = { url = "https://files.pythonhosted.org/packages/31/15/67246107a8c808a9e99b34fd0024bebe954a67f3c315821eae985b87db7f/alt_utils-0.0.8.tar.gz", hash = "sha256:4b2901df0be4af736210277d58e231d4c4bce597a8fc665a8dd3e7b582705081", size = 6103, upload_time = "2025-05-10T19:36:49.187Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/5a/7fe15b55fa0ff5528643750c409cd14da005406aef312b32512d8a8487ab/alt_utils-0.0.8-py3-none-any.whl", hash = "sha256:af5549c49543ff4a02b735308bc2a5bfb7f20755620652fd969a648bbaecbc47", size = 6378 }, { url = "https://files.pythonhosted.org/packages/9a/5a/7fe15b55fa0ff5528643750c409cd14da005406aef312b32512d8a8487ab/alt_utils-0.0.8-py3-none-any.whl", hash = "sha256:af5549c49543ff4a02b735308bc2a5bfb7f20755620652fd969a648bbaecbc47", size = 6378, upload_time = "2025-05-10T19:36:47.954Z" },
]
[[package]]
name = "humanize"
version = "4.12.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/22/d1/bbc4d251187a43f69844f7fd8941426549bbe4723e8ff0a7441796b0789f/humanize-4.12.3.tar.gz", hash = "sha256:8430be3a615106fdfceb0b2c1b41c4c98c6b0fc5cc59663a5539b111dd325fb0", size = 80514, upload_time = "2025-04-30T11:51:07.98Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a0/1e/62a2ec3104394a2975a2629eec89276ede9dbe717092f6966fcf963e1bf0/humanize-4.12.3-py3-none-any.whl", hash = "sha256:2cbf6370af06568fa6d2da77c86edb7886f3160ecd19ee1ffef07979efc597f6", size = 128487, upload_time = "2025-04-30T11:51:06.468Z" },
] ]
[[package]] [[package]]
@ -16,6 +26,7 @@ version = "0.1.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "alt-utils" }, { name = "alt-utils" },
{ name = "humanize" },
{ name = "psutil" }, { name = "psutil" },
{ name = "telethon" }, { name = "telethon" },
] ]
@ -23,6 +34,7 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "alt-utils", specifier = ">=0.0.8" }, { name = "alt-utils", specifier = ">=0.0.8" },
{ name = "humanize", specifier = ">=4.12.3" },
{ name = "psutil", specifier = ">=7.0.0" }, { name = "psutil", specifier = ">=7.0.0" },
{ name = "telethon", specifier = ">=1.40.0" }, { name = "telethon", specifier = ">=1.40.0" },
] ]
@ -31,30 +43,30 @@ requires-dist = [
name = "psutil" name = "psutil"
version = "7.0.0" version = "7.0.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003 } sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload_time = "2025-02-13T21:54:07.946Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051 }, { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload_time = "2025-02-13T21:54:12.36Z" },
{ url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535 }, { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload_time = "2025-02-13T21:54:16.07Z" },
{ url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004 }, { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload_time = "2025-02-13T21:54:18.662Z" },
{ url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986 }, { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload_time = "2025-02-13T21:54:21.811Z" },
{ url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544 }, { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload_time = "2025-02-13T21:54:24.68Z" },
{ url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053 }, { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload_time = "2025-02-13T21:54:34.31Z" },
{ url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885 }, { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload_time = "2025-02-13T21:54:37.486Z" },
] ]
[[package]] [[package]]
name = "pyaes" name = "pyaes"
version = "1.6.1" version = "1.6.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/44/66/2c17bae31c906613795711fc78045c285048168919ace2220daa372c7d72/pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f", size = 28536 } sdist = { url = "https://files.pythonhosted.org/packages/44/66/2c17bae31c906613795711fc78045c285048168919ace2220daa372c7d72/pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f", size = 28536, upload_time = "2017-09-20T21:17:54.23Z" }
[[package]] [[package]]
name = "pyasn1" name = "pyasn1"
version = "0.6.1" version = "0.6.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322 } sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload_time = "2024-09-10T22:41:42.55Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135 }, { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload_time = "2024-09-11T16:00:36.122Z" },
] ]
[[package]] [[package]]
@ -64,9 +76,9 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pyasn1" }, { name = "pyasn1" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload_time = "2025-04-16T09:51:18.218Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload_time = "2025-04-16T09:51:17.142Z" },
] ]
[[package]] [[package]]
@ -77,7 +89,7 @@ dependencies = [
{ name = "pyaes" }, { name = "pyaes" },
{ name = "rsa" }, { name = "rsa" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/58/af/9b7111e3f63fffe8e55b7ceb8bda023173e2052f420b6debcb25fd2fbc15/telethon-1.40.0.tar.gz", hash = "sha256:40e83326877a2e68b754d4b6d0d1ca5ac924110045b039e02660f2d67add97db", size = 646723 } sdist = { url = "https://files.pythonhosted.org/packages/58/af/9b7111e3f63fffe8e55b7ceb8bda023173e2052f420b6debcb25fd2fbc15/telethon-1.40.0.tar.gz", hash = "sha256:40e83326877a2e68b754d4b6d0d1ca5ac924110045b039e02660f2d67add97db", size = 646723, upload_time = "2025-04-21T09:12:10.506Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/5a/c5370edb3215d19a6e858f4169b8eec725ba55f9d39df0f557508048c037/Telethon-1.40.0-py3-none-any.whl", hash = "sha256:146fd4cb2a7afa66bc67f9c2167756096a37b930f65711a3e7399ec9874dcfa7", size = 722013 }, { url = "https://files.pythonhosted.org/packages/2c/5a/c5370edb3215d19a6e858f4169b8eec725ba55f9d39df0f557508048c037/Telethon-1.40.0-py3-none-any.whl", hash = "sha256:146fd4cb2a7afa66bc67f9c2167756096a37b930f65711a3e7399ec9874dcfa7", size = 722013, upload_time = "2025-04-21T09:12:08.399Z" },
] ]