Skip to main content

UNDERSTANDING GRAFANA AUTOMATION IN SWAMP

Grafana has two kinds of state: the configuration it serves (dashboards, alert rules, contact points, notification policies) and the telemetry it proxies (Prometheus metrics, Loki logs). The @keeb/grafana extension handles both through one behavior type. The @shrug/grafana-ext extension adds a separate type for the server-admin work of managing service accounts. This page covers how those pieces fit with Swamp's behaviors, types and methods, and the decisions they leave to a team.

One behavior per Grafana instance

@keeb/grafana/instance takes grafanaUrl as its only required global argument. A behavior of this type therefore stands for one Grafana server. Its methods are things you can do to that server. A team with a staging and a production Grafana creates two behaviors, one for each URL, rather than one behavior that is told which server to use on each run.

This keeps the target of every run explicit. When you run pushDashboard on the production behavior, there is no argument that could quietly point it somewhere else. Each behavior also keeps its own data history, so results from staging and production never mix. The cost is a little repetition. If you have many instances, the factory pattern is one way to reduce it.

Dashboards and alert rules as files

pushDashboard and pushAlertRule read JSON from files in the repository. exportDashboard writes a Grafana dashboard back out to a file. Together they let Git hold a record of what Grafana should contain, so changes can be reviewed and reverted like any other code.

This raises a question the extension does not answer for you: which side is the source of truth? Some teams treat the repository as authoritative. They edit JSON, push it, and treat UI changes as drift. Others build in the UI, where Grafana's editor is most convenient, and export to the repository as a snapshot. Both work. Mixing them without agreement does not, because a push overwrites edits made in the UI, and an export overwrites uncommitted edits to the file. getDashboard sits between the two. It stores the full dashboard content, including panels and variables, as data without touching any file, which helps you compare what Grafana holds with what the repository says it should.

What each method writes

Every method writes a named resource. discover writes instance. pushDashboard and exportDashboard write dashboard. getDashboard writes dashboardContent. pushAlertRule writes alert, and createAnnotation writes annotation. queryMetrics writes queryResult and queryLogs writes logResult.

The two query methods matter most here. A PromQL or LogQL result that would normally live only in a Grafana panel becomes versioned data in the repository. Later workflow steps can read it, and you can query it after the fact. The Data Layer covers how those versions are kept, and the Data reference describes how to query them.

queryLogs is described in @keeb/grafana as the Loki sibling of queryMetrics. The readme of @shrug/grafana-ext describes adding a queryLogs to @keeb/grafana/instance alongside queryMetrics. The current @keeb/grafana lists queryLogs as its own method, so log queries no longer depend on the second extension.

Credentials

The two behavior types treat credentials differently. On @keeb/grafana/instance, apiKey is optional, because some Grafana servers on a private network accept anonymous API calls. On @shrug/grafana-admin/instance, adminPassword is required, because creating service accounts needs server-admin rights over basic auth.

In both cases the value belongs in a vault. The definition refers to it with ${{ vault.get('<vault-name>', '<key>') }} and never holds the value itself. Swamp then redacts the secret from output and stored data. The Storing Secrets tutorial walks through this, and the Vaults reference covers the expression and the vault types.

The admin control plane

ensureServiceAccount is idempotent. Given an org ID, a name and a role, it makes sure a service account with that role exists. If one already exists, a repeat run leaves it as it is. It is a dry run unless confirm is true. Without confirm, the serviceAccount resource records the plan, so you can read what would change before anything does.

When mintToken is set, the new token is printed once and never persisted. The serviceAccount resource holds state and plan but never the secret. This is a deliberate gap. Swamp does not keep a long-lived Grafana credential in its data store, so whoever runs the method has to decide where the token goes next, often into a vault for an @keeb/grafana/instance behavior to use as its apiKey. Because the admin password and that decision both carry weight, many teams limit who can run this behavior. On a shared server, the swamp serve access controls are one way to do that.

Alert routing as a sequence

Alerting in @keeb/grafana takes three methods, and their order matters. configureContactPoint creates or updates a Discord webhook contact point. configureNotificationPolicy sets the default notification policy to route to a named contact point. pushAlertRule pushes rules whose notifications follow that policy. If a policy names a contact point that does not exist yet, or a rule fires before its route is in place, notifications go nowhere.

Running the three as steps in a workflow fixes that order and records each run together. The webhook URL for the contact point is a secret like any other and fits the same vault pattern.

Annotations and queries inside workflows

The methods that write to Grafana and the methods that read from it combine well around a change. A deployment workflow can call createAnnotation to mark the moment on a dashboard, or on every dashboard if the annotation is global. Later steps can run queryMetrics or queryLogs to check the service. Because the query results are stored as data, assert steps can check them and stop the workflow when a check fails.

Repeated runs need some care. Pushing the same dashboard or rule again converges to the same state, but each createAnnotation call adds a new annotation. A workflow that is retried can therefore leave duplicate marks on a dashboard. Make Workflows Idempotent covers ways to deal with steps like this.