You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Render the observability dashboards and alerts with ocf observability render
Problem
The Grafana dashboards and Prometheus alert rules under observability/ render through make dashboards and make alerts, a sed pipeline in the Makefile. That only works from a clone of this repository, so an operator author has to check the framework out at the matching version to render, and the validation of METRIC_NAMESPACE (metric-name characters, the Grafana uid length cap) lives in shell. The framework already ships an ocf binary that generates code from embedded templates and is pinned to the framework version by go install; rendering the observability package belongs in the same place, so a go install .../cmd/ocf@<version> gives an author the templates matching the framework release they build against, with one renderer and one set of validation rules.
Approach
Move observability/dashboards/, observability/alerts/ and observability/alerts/tests/ to internal/observability/templates/ and embed them with go:embed, mirroring internal/scaffold. observability/ keeps README.md and dev/ (compose, provisioning, simulator).
internal/observability exposes Options (MetricNamespace, NamespaceLabel, AlertFormat, PrometheusRuleNamespace, PrometheusRuleLabels), Options.Validate() with the checks the Makefile performs today, and Render(opts, outDir) writing <out>/dashboards/*.json and <out>/alerts/*.yaml. Rendering stays literal placeholder substitution of {{operator_namespace}} and {{namespace_label}} (the contract shared with go-crd-condition-metrics; the templates carry Grafana and Alertmanager {{ }} templating and YAML comments that must survive verbatim). The PrometheusRule wrapper is emitted as a header plus the rule body indented under spec:, as the Makefile does now.
New ocf observability render command with flags mirroring today's Makefile variables: --metric-namespace (required), --namespace-label, --alert-format prometheusrule|rules, --prometheusrule-namespace, --prometheusrule-labels k=v,..., --out (default ./observability). Rendered files are regenerated output, so no --force.
make dashboards, make alerts, make observability-render-dev and make test-alerts become thin wrappers over go run ./cmd/ocf observability render; require_metric_namespace and render_template are removed.
Docs: docs/observability.md rendering section rewritten around the command (install, flag table, output layout, paths), docs/cli.md gains the command, observability/README.md maintainer paths updated, CLAUDE.md reference list gains internal/observability, make sync-plugin.
flowchart LR
T["internal/observability/templates<br/>(go:embed)"] --> R["internal/observability.Render"]
F["ocf observability render<br/>flags -> Options"] --> V["Options.Validate"] --> R
R --> D["out/dashboards/*.json"]
R --> A["out/alerts/*.yaml<br/>(PrometheusRule or rules)"]
M["Makefile: dashboards, alerts,<br/>observability-render-dev, test-alerts"] -->|go run ./cmd/ocf| F
A --> P["promtool check/test<br/>(make test-alerts)"]
Loading
Verification
go install ./cmd/ocf && cd $(mktemp -d) && ocf observability render --metric-namespace demo writes observability/dashboards/{ocf_operator,crd_conditions_browser}.json and observability/alerts/{controller_runtime,crd_conditions,managed_resources}.yaml with no {{operator_namespace}} or {{namespace_label}} left and dashboard uids demo_ocf_operator and demo_crd_conditions_browser.
--alert-format rules writes plain groups: files; the default writes PrometheusRule objects named demo-crd-conditions, ocf-controller-runtime, ocf-managed-resources, with --prometheusrule-namespace and --prometheusrule-labels reflected in metadata.
Byte-for-byte parity: rendering with the new command and with the sed pipeline at the parent commit produces identical files for the same inputs.
ocf observability render without --metric-namespace, with my-operator, with a colon, or with an 18-character namespace exits non-zero with a message naming the rule; Go tests cover each rejection.
go test ./internal/observability/... ./cmd/ocf/... covers Render (both formats, metadata, output file set, overwrite of an existing render) and the command wiring; the template lint test keeps asserting uids, no leftover placeholders, known metric names, and that every alert has a promtool test.
make test-alerts, make lint-dashboards, make observability-render-dev, make all and the observability CI job pass.
Out of scope
A ocf observability test wrapper around promtool.
Changing the placeholders or the template contents.
A public Go API for rendering; the package stays under internal/.
Render the observability dashboards and alerts with
ocf observability renderProblem
The Grafana dashboards and Prometheus alert rules under
observability/render throughmake dashboardsandmake alerts, asedpipeline in the Makefile. That only works from a clone of this repository, so an operator author has to check the framework out at the matching version to render, and the validation ofMETRIC_NAMESPACE(metric-name characters, the Grafana uid length cap) lives in shell. The framework already ships anocfbinary that generates code from embedded templates and is pinned to the framework version bygo install; rendering the observability package belongs in the same place, so ago install .../cmd/ocf@<version>gives an author the templates matching the framework release they build against, with one renderer and one set of validation rules.Approach
observability/dashboards/,observability/alerts/andobservability/alerts/tests/tointernal/observability/templates/and embed them withgo:embed, mirroringinternal/scaffold.observability/keepsREADME.mdanddev/(compose, provisioning, simulator).internal/observabilityexposesOptions(MetricNamespace,NamespaceLabel,AlertFormat,PrometheusRuleNamespace,PrometheusRuleLabels),Options.Validate()with the checks the Makefile performs today, andRender(opts, outDir)writing<out>/dashboards/*.jsonand<out>/alerts/*.yaml. Rendering stays literal placeholder substitution of{{operator_namespace}}and{{namespace_label}}(the contract shared with go-crd-condition-metrics; the templates carry Grafana and Alertmanager{{ }}templating and YAML comments that must survive verbatim). The PrometheusRule wrapper is emitted as a header plus the rule body indented underspec:, as the Makefile does now.ocf observability rendercommand with flags mirroring today's Makefile variables:--metric-namespace(required),--namespace-label,--alert-format prometheusrule|rules,--prometheusrule-namespace,--prometheusrule-labels k=v,...,--out(default./observability). Rendered files are regenerated output, so no--force.make dashboards,make alerts,make observability-render-devandmake test-alertsbecome thin wrappers overgo run ./cmd/ocf observability render;require_metric_namespaceandrender_templateare removed.docs/observability.mdrendering section rewritten around the command (install, flag table, output layout, paths),docs/cli.mdgains the command,observability/README.mdmaintainer paths updated,CLAUDE.mdreference list gainsinternal/observability,make sync-plugin.flowchart LR T["internal/observability/templates<br/>(go:embed)"] --> R["internal/observability.Render"] F["ocf observability render<br/>flags -> Options"] --> V["Options.Validate"] --> R R --> D["out/dashboards/*.json"] R --> A["out/alerts/*.yaml<br/>(PrometheusRule or rules)"] M["Makefile: dashboards, alerts,<br/>observability-render-dev, test-alerts"] -->|go run ./cmd/ocf| F A --> P["promtool check/test<br/>(make test-alerts)"]Verification
go install ./cmd/ocf && cd $(mktemp -d) && ocf observability render --metric-namespace demowritesobservability/dashboards/{ocf_operator,crd_conditions_browser}.jsonandobservability/alerts/{controller_runtime,crd_conditions,managed_resources}.yamlwith no{{operator_namespace}}or{{namespace_label}}left and dashboard uidsdemo_ocf_operatoranddemo_crd_conditions_browser.--alert-format ruleswrites plaingroups:files; the default writesPrometheusRuleobjects nameddemo-crd-conditions,ocf-controller-runtime,ocf-managed-resources, with--prometheusrule-namespaceand--prometheusrule-labelsreflected inmetadata.ocf observability renderwithout--metric-namespace, withmy-operator, with a colon, or with an 18-character namespace exits non-zero with a message naming the rule; Go tests cover each rejection.go test ./internal/observability/... ./cmd/ocf/...coversRender(both formats, metadata, output file set, overwrite of an existing render) and the command wiring; the template lint test keeps asserting uids, no leftover placeholders, known metric names, and that every alert has a promtool test.make test-alerts,make lint-dashboards,make observability-render-dev,make alland theobservabilityCI job pass.Out of scope
ocf observability testwrapper around promtool.internal/.Context
mainafter it merges.dashboards,alerts,require_metric_namespaceandrender_templaterecipes inMakefile.