Alerting: Implement setting of version message in convert API. (#114331)

Part 2 of adding version messages to the `alert_rule_version` able. This allows
setting the message via a header when using the Prometheus conversion API,
which can be useful for e.g. linking changes back to source control.
This commit is contained in:
Steve Simpson
2025-11-25 11:20:28 +01:00
committed by GitHub
parent b57e6383e4
commit d50e2a94a3
16 changed files with 212 additions and 101 deletions
@@ -63,6 +63,9 @@ const (
// configIdentifierHeader is the header that specifies the identifier for imported Alertmanager config.
configIdentifierHeader = "X-Grafana-Alerting-Config-Identifier"
defaultConfigIdentifier = "default"
// versionMessageHeader is the header that specifies an optional message for rule versions.
versionMessageHeader = "X-Grafana-Alerting-Version-Message"
)
var (
@@ -407,6 +410,11 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusPostRuleGroups(c *context
return errorToResponse(err)
}
versionMessage, err := parseVersionMessageHeader(c)
if err != nil {
logger.Error("Failed to parse version message header", "error", err)
return errorToResponse(err)
}
// 2. Convert Prometheus Rules to GMA
grafanaGroups := make([]*models.AlertRuleGroup, 0, len(promNamespaces))
for ns, rgs := range promNamespaces {
@@ -444,12 +452,13 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusPostRuleGroups(c *context
logger.Error("Failed to convert Prometheus rules to Grafana rules", "error", err)
return errorToResponse(err)
}
grafanaGroups = append(grafanaGroups, grafanaGroup)
}
}
// 3. Update the GMA Rules in the DB
err = srv.alertRuleService.ReplaceRuleGroups(c.Req.Context(), c.SignedInUser, grafanaGroups, provenance)
err = srv.alertRuleService.ReplaceRuleGroups(c.Req.Context(), c.SignedInUser, grafanaGroups, provenance, versionMessage)
if err != nil {
logger.Error("Failed to replace rule groups", "error", err)
return errorToResponse(err)
@@ -856,6 +865,16 @@ func parseExtraLabelsHeader(c *contextmodel.ReqContext) (map[string]string, erro
return parseKeyValuePairs(labelsStr, extraLabelsHeader)
}
// parseVersionMessageHeader obtains and validates the message header value.
func parseVersionMessageHeader(c *contextmodel.ReqContext) (string, error) {
str := strings.TrimSpace(c.Req.Header.Get(versionMessageHeader))
// Limit message to the same as the dashboards message.
if len(str) > 500 {
return "", errInvalidHeaderValue(versionMessageHeader, errors.New("must be less than 500 characters"))
}
return str, nil
}
func formatMergeMatchers(matchers amconfig.Matchers) string {
var pairs []string
for _, matcher := range matchers {