Documentation
¶
Overview ¶
Package amconfig renders an Alertmanager configuration from stored receivers and routes. It is the part of alerting where a bug becomes org A's alert reaching org B's Slack.
It is the ONE renderer: the control plane renders every org's configuration with it from its Postgres rows, and `forge env up` renders a local stack's configuration with it from the env's KCL (one org, "local"), so an alert routes the same way on a laptop as in production. The package knows nothing about where receivers are stored or how the config reaches Alertmanager.
An org is the unit of routing isolation: a self-hoster with one team uses one.
The routing invariant ¶
The rendered root route has the BLACKHOLE receiver as its default and one child route per org, each matched STRICTLY on `reliant_org_id="<org>"` with continue: false. Everything below an org's route is that org's own: its env routes (matched by labels the rule author set) and its receivers. Nothing an alert, a rule or an env route says can move it out of its org's subtree, because:
- reliant_org_id is set by the evaluator from the RuleSource's identity and can never come from a rule (forge/pkg/alerting strips reliant_*);
- every child's own matchers are ANDed under the org matcher, so they narrow, never widen;
- env routes and receivers are loaded per org and an env route naming a receiver the org does not have is DROPPED at render time (and reported), so a route can only ever point at the receiver of its own org;
- receiver names are namespaced per org ("<org>/<name>"), so two orgs that both call a receiver "oncall" cannot collide into one;
- an org with no receivers gets no route and therefore the blackhole.
Autopilot receivers ¶
An autopilot receiver (a Reliant Autopilot automation) is reached by no env route. It gets a route of its own at the TOP of its org's subtree, with continue: true, so every alert of the org that passes its filter reaches it and then carries on to the org's own routing exactly as before. Three things keep that true:
- the route sits inside the org's subtree, so it narrows the org matcher like any child and cannot see another org's alerts;
- it is scoped to the environments its automation's project owns (reliant_env_id, resolved by the caller into Autopilot.EnvIDs) — an autopilot receiver with no environment in scope gets no route at all;
- the org's own routing is wrapped in ONE catch-all child that keeps the org's default receiver. Alertmanager uses a parent's receiver only when no child matched, so without the wrapper a match on the autopilot route would silently cost the org its default (in-app) delivery.
The filter is a severity match OR an alert-name match (the platform's issue alerts, whatever their severity); Alertmanager ANDs a route's matchers, so the OR is two children of a blackhole parent, the first match winning.
TestNoRouteDeliversAcrossOrgs enumerates this property over the real Alertmanager routing tree (dispatch.NewRoute), not over the YAML.
Secrets ¶
Receiver secrets are never in the config. Each is a file in the mounted Secret, referenced through the receiver's *_file fields (slack api_url_file, pagerduty routing_key_file, webhook http_config.authorization.credentials_file, email auth_password_file). The renderer returns the set of files the Secret must contain; it never sees a value.
Index ¶
Constants ¶
const ( TypeSlack = "slack" TypeWebhook = "webhook" TypeEmail = "email" TypePagerDuty = "pagerduty" TypeInApp = "reliant_inapp" TypeAutopilot = "autopilot" )
Receiver types, as stored.
const Blackhole = "blackhole"
Blackhole is the default receiver: it has no integrations, so an alert that reaches it is delivered to no one.
const DefaultReceiverName = "reliant-inapp"
DefaultReceiverName is the platform-owned in-app receiver every org with rules gets (the syncer adds it). It is the org's default, so what an org names its own receivers can never change where unrouted alerts go.
const OrgLabel = "reliant_org_id"
OrgLabel is the label every route is scoped by.
const SecretDir = "/etc/alertmanager/secrets"
SecretDir is where the Alertmanager Secret is mounted.
const TestLabel = "reliant_test_receiver"
TestLabel selects exactly one receiver of an org for a test notification. Only the platform sets it: the evaluator drops every "reliant_" label a rule declares and routeNode refuses a matcher on one, so no rule can reach a receiver this way.
Variables ¶
This section is empty.
Functions ¶
func ClusterInternal ¶
ClusterInternal reports a host only a cluster (or this machine) resolves, the one place plain http is acceptable for an autopilot receiver: the hop never leaves the cluster network.
Types ¶
type AutopilotRoute ¶
type AutopilotRoute struct {
// EnvIDs are the environments whose alerts reach it. Empty: none do.
EnvIDs []string
// Severities are the severity label values that reach it; a single "*"
// is every alert.
Severities []string
// AlwaysAlertnames reach it whatever their severity.
AlwaysAlertnames []string
}
AutopilotRoute is the resolved filter of an autopilot receiver.
type Receiver ¶
type Receiver struct {
OrgID string
Name string
Type string
// SecretRef is the file name (inside SecretDir) holding the secret, or "".
SecretRef string
Settings map[string]string
// Autopilot is where a TypeAutopilot receiver's route reaches; nil for
// every other type (and an autopilot receiver without it gets no route).
Autopilot *AutopilotRoute
}
Receiver is one stored receiver.
type Rendered ¶
type Rendered struct {
// YAML is the Alertmanager configuration.
YAML []byte
// Hash identifies the configuration; a syncer compares it to what is live.
Hash string
// Files are the secret files the Secret must contain: name -> the org and
// receiver that need it (the caller fills in the values from its own
// secret storage).
Files []SecretFile
// Skipped says what was left out and why. Never an error: one bad receiver
// must not take every other org's alerting down.
Skipped []string
}
Rendered is the renderer's result.
type Route ¶
type Route struct {
OrgID string
EnvID string
Position int
Matchers map[string]string
Receivers []string
Continue bool
}
Route is one env route: labels the rule author set, mapped to receiver names.
type SMTP ¶
type SMTP struct {
Host string // host:port, e.g. smtp.resend.com:587
From string
Username string // Resend: "resend"
PasswordFile string
}
SMTP is the email relay. The password is a FILE, like every secret.
type SecretFile ¶
SecretFile is one file the mounted Secret must hold.
type Settings ¶
type Settings struct {
// InAppURL is the endpoint the reliant_inapp receivers post to: the
// control plane's in-app notification webhook, or a local stack's alert
// log sink.
InAppURL string
// InAppTokenFile holds the bearer token that endpoint requires.
InAppTokenFile string
// AllowHTTPWebhooks lets a webhook receiver's url be plain http. Only a
// LOCAL stack sets it, where every receiver is the developer's own machine.
// A renderer serving several orgs must leave it false: a customer-supplied http URL
// could name a cluster-internal service, and Alertmanager would post to it
// from inside the cluster.
AllowHTTPWebhooks bool
// SMTP is Resend's relay. Empty Host disables email receivers (they are
// dropped and reported, never rendered half-configured).
SMTP SMTP
// GroupWait / GroupInterval / RepeatInterval default to 30s / 5m / 4h.
GroupWait, GroupInterval, RepeatInterval string
}
Settings are the process-wide parts of the configuration.