feat: replace YAML editor with form UI for threshold configurations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+76
-1
@@ -25,6 +25,74 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
eventlog = notify_mod.eventlog
|
||||
|
||||
|
||||
def _build_threshold_configs_from_form(form_data: dict) -> dict:
|
||||
"""Convert form-submitted flat threshold data to nested threshold_configs YAML structure.
|
||||
|
||||
Input: {config_name: {metric_path: {warning, critical, operator, hysteresis, enabled, count, display}}}
|
||||
Output: {config_name: {thresholds: {plugin: {metric: {warning, critical, ...}}}}}
|
||||
"""
|
||||
result = {}
|
||||
for config_name, metrics in form_data.items():
|
||||
if not isinstance(metrics, dict):
|
||||
continue
|
||||
thresholds = {}
|
||||
for metric_path, values in metrics.items():
|
||||
_insert_threshold_metric(thresholds, metric_path, values)
|
||||
result[config_name] = {"thresholds": thresholds}
|
||||
return result
|
||||
|
||||
|
||||
def _insert_threshold_metric(thresholds: dict, metric_path: str, values: dict) -> None:
|
||||
"""Insert a single metric into the nested threshold YAML structure."""
|
||||
if not isinstance(values, dict):
|
||||
return
|
||||
|
||||
cfg = {}
|
||||
op = values.get("operator", ">")
|
||||
if op and op != ">":
|
||||
cfg["operator"] = op
|
||||
|
||||
for key, cast in (("warning", float), ("critical", float), ("hysteresis", float)):
|
||||
v = values.get(key)
|
||||
if v is not None:
|
||||
try:
|
||||
cfg[key] = cast(v)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
count = values.get("count")
|
||||
if count is not None:
|
||||
try:
|
||||
cfg["count"] = int(count)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
display = values.get("display", "")
|
||||
if display:
|
||||
cfg["display"] = display
|
||||
|
||||
if not values.get("enabled", True):
|
||||
cfg["enabled"] = False
|
||||
|
||||
parts = metric_path.split(".", 2)
|
||||
|
||||
if len(parts) == 1:
|
||||
# e.g. "rtt"
|
||||
thresholds[metric_path] = cfg
|
||||
elif len(parts) == 2:
|
||||
plugin, metric = parts
|
||||
thresholds.setdefault(plugin, {})[metric] = cfg
|
||||
else:
|
||||
plugin, intermediate, leaf = parts
|
||||
thresholds.setdefault(plugin, {})
|
||||
if plugin == "disk_monitor":
|
||||
thresholds[plugin].setdefault("partitions", {}).setdefault(intermediate, {})[leaf] = cfg
|
||||
elif plugin == "zfs_monitor":
|
||||
thresholds[plugin].setdefault("pools", {}).setdefault(intermediate, {})[leaf] = cfg
|
||||
else:
|
||||
thresholds[plugin].setdefault(intermediate, {})[leaf] = cfg
|
||||
|
||||
def _render_template(html_str: str, **context) -> str:
|
||||
tmpl = jinja2.Template(html_str)
|
||||
return tmpl.render(**context)
|
||||
@@ -1228,10 +1296,17 @@ async def start(
|
||||
attrs.pop("client_secret", None)
|
||||
data["oauth"] = new_oauth
|
||||
|
||||
for section in ("notification_channels", "thresholds", "dns"):
|
||||
for section in ("notification_channels", "dns"):
|
||||
if section in payload:
|
||||
configio_mod.apply_yaml_section(data, section, payload[section])
|
||||
|
||||
if "thresholds" in payload:
|
||||
tc = payload["thresholds"]
|
||||
if isinstance(tc, str):
|
||||
configio_mod.apply_yaml_section(data, "thresholds", tc)
|
||||
elif isinstance(tc, dict):
|
||||
data["threshold_configs"] = _build_threshold_configs_from_form(tc)
|
||||
|
||||
if "hosts" in payload:
|
||||
h = payload["hosts"]
|
||||
if isinstance(h, dict):
|
||||
|
||||
Reference in New Issue
Block a user