Annotate untyped containers and Optional attributes, type the stdlib-shaped metric dicts in the client plugins, and add types-PyYAML/types-psutil to the dev extras plus a mypy override for nio/mattermostdriver (no stubs). Behaviour fixes found on the way: enable_kernel_timestamps() now returns False when SO_TIMESTAMP is unknown instead of raising TypeError, send_shutdown is defined at module level so cleanup() cannot hit a NameError, and a failed subprocess returncode falls back to UNKNOWN. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
"""Configuration loader and defaults for hbc (HeartBeat Client)."""
|
|
|
|
import logging
|
|
import os
|
|
from typing import Any, Dict
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
import yaml
|
|
except Exception:
|
|
yaml = None # type: ignore[assignment]
|
|
|
|
CLIENT_DEFAULTS: Dict[str, Any] = {
|
|
# Network settings
|
|
"hb_port": 50003, # Port where hbd servers listen
|
|
"interval": 10, # Heartbeat interval in seconds
|
|
|
|
# Host identity
|
|
"owner": None, # Optional username to set as this host's owner on the server
|
|
|
|
# Security
|
|
"allow_remote_command": False, # Execute shell commands received in CMD packets from the server
|
|
|
|
# Runtime flags
|
|
"foreground": False,
|
|
"verbose": False,
|
|
"debug": 0,
|
|
|
|
# Plugin configuration
|
|
"plugins": {}, # Per-plugin configuration
|
|
"thresholds": {}, # Threshold configuration for monitoring
|
|
}
|
|
|
|
|
|
def load_config(path=None):
|
|
"""Load configuration from a YAML file and merge with client defaults.
|
|
|
|
If YAML is not available or the file does not exist, defaults are returned.
|
|
|
|
Args:
|
|
path: Path to YAML config file (default: ~/.hbc.yaml)
|
|
|
|
Returns:
|
|
Dictionary with configuration
|
|
"""
|
|
cfg = CLIENT_DEFAULTS.copy()
|
|
if not path:
|
|
# default path (~/.hbc.yaml)
|
|
path = os.path.join(os.path.expanduser("~"), ".hbc.yaml")
|
|
|
|
if os.path.exists(path):
|
|
if yaml:
|
|
logger.info("Loading configuration from %s", path)
|
|
with open(path) as fh:
|
|
data = yaml.safe_load(fh)
|
|
# Merge YAML data with defaults
|
|
# Keep all keys from YAML to support plugin configs and future extensions
|
|
for k, v in data.items():
|
|
cfg[k] = v
|
|
else:
|
|
# yaml not installed: do not attempt to parse; user must ensure defaults
|
|
logger.warning("PyYAML not available - cannot load config from %s, using defaults", path)
|
|
return cfg
|