Prometheus gains a "Widget templates" tab beside Targets. It lists the built-in templates and an admin's own, any that no longer pass the checker first. A template opens as its YAML beside a live preview drawn over a chosen target exactly as the dashboard widget draws it (routes.draw, now shared by both). An admin writes or pastes a new one, reads a .yaml upload into the editor to look over, duplicates any template under a free name, edits and deletes their own; anyone can export the YAML. Built-in templates are read-only. Custom templates are rows in prometheus_widget_templates (migration prometheus_002_templates), kept in backups, keyed "custom:<id>" so a rename keeps its widgets. Saving needs a template that passes the checker and a name no other template has. Create, update and delete are audited and link to the template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
71 lines
2.5 KiB
Python
71 lines
2.5 KiB
Python
# plugins/prometheus/__init__.py
|
|
from __future__ import annotations
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from quart import Quart
|
|
|
|
_app: "Quart | None" = None
|
|
|
|
|
|
def setup(app: "Quart") -> None:
|
|
global _app
|
|
_app = app
|
|
from .models import PrometheusTarget, PrometheusWidgetTemplate # noqa: F401 — registers the tables
|
|
register_widgets()
|
|
|
|
|
|
def register_widgets() -> None:
|
|
"""One dashboard widget for every target and template (System 181's
|
|
ruling). Its target and template lists are read when the widget picker
|
|
opens, so a new target or template appears without a restart."""
|
|
from steward.core.widgets import register_widget
|
|
|
|
from . import library
|
|
register_widget({
|
|
"key": "prometheus",
|
|
"label": "Prometheus",
|
|
"description": "One scrape target drawn by a widget template: Fabled Archives, or one you copy in",
|
|
"hx_url": "/plugins/prometheus/widget",
|
|
"detail_url": "/plugins/prometheus/targets/{target}",
|
|
"plugin": "prometheus",
|
|
"poll": True,
|
|
"default_title": library.default_title,
|
|
"params": [
|
|
{"key": "target", "label": "Target", "type": "select", "default": "",
|
|
"options_from": library.target_options,
|
|
"empty": "No targets yet: add one under Prometheus first."},
|
|
{"key": "template", "label": "Template", "type": "select", "default": "",
|
|
"options_from": library.template_options,
|
|
"empty": "No templates yet."},
|
|
],
|
|
})
|
|
|
|
|
|
def get_scheduled_tasks() -> list:
|
|
from .scheduler import make_scrape_task
|
|
return [make_scrape_task(_app)]
|
|
|
|
|
|
def get_blueprint():
|
|
from .routes import prometheus_bp
|
|
return prometheus_bp
|
|
|
|
|
|
def get_nav() -> list[dict]:
|
|
# Surfaces in the sidebar's Infrastructure group (scraped endpoints).
|
|
return [{"label": "Prometheus", "href": "/plugins/prometheus/"}]
|
|
|
|
|
|
def get_alert_metrics() -> dict[str, list[str]]:
|
|
"""The metric names are whatever each endpoint exposes, so the list is
|
|
empty here and the rule form offers the names recorded so far."""
|
|
return {"prometheus": []}
|
|
|
|
|
|
def get_audit_entities() -> dict:
|
|
"""Audit rows about a target or a widget template name it and link to its page."""
|
|
from .models import PrometheusTarget, PrometheusWidgetTemplate
|
|
return {"prometheus_target": (PrometheusTarget, "/plugins/prometheus/targets/{}"),
|
|
"prometheus_template": (PrometheusWidgetTemplate, "/plugins/prometheus/templates/custom:{}")}
|