Alerting: Send information about alert rule to data source in headers (#90344)

* add support of metadata to condition and adding it to request headers
* support for additional metadata when condition is built
* add additionall context to conditions: source and folder title
* add version
* use percent-encoding for header values
This commit is contained in:
Yuri Tseretyan
2024-07-17 22:55:12 +03:00
committed by GitHub
parent b825700343
commit c3b9c9b239
7 changed files with 139 additions and 20 deletions
+23 -15
View File
@@ -6,6 +6,7 @@ import (
"context"
"errors"
"fmt"
"net/url"
"runtime/debug"
"sort"
"strconv"
@@ -43,13 +44,18 @@ type ConditionEvaluator interface {
Evaluate(ctx context.Context, now time.Time) (Results, error)
}
type expressionService interface {
type expressionExecutor interface {
ExecutePipeline(ctx context.Context, now time.Time, pipeline expr.DataPipeline) (*backend.QueryDataResponse, error)
}
type expressionBuilder interface {
expressionExecutor
BuildPipeline(req *expr.Request) (expr.DataPipeline, error)
}
type conditionEvaluator struct {
pipeline expr.DataPipeline
expressionService expressionService
expressionService expressionExecutor
condition models.Condition
evalTimeout time.Duration
evalResultLimit int
@@ -105,7 +111,7 @@ type evaluatorImpl struct {
evaluationTimeout time.Duration
evaluationResultLimit int
dataSourceCache datasources.CacheService
expressionService *expr.Service
expressionService expressionBuilder
pluginsStore pluginstore.Store
}
@@ -324,22 +330,24 @@ func ParseStateString(repr string) (State, error) {
}
}
func buildDatasourceHeaders(ctx context.Context) map[string]string {
headers := map[string]string{
// Many data sources check this in query method as sometimes alerting needs special considerations.
// Several existing systems also compare against the value of this header. Altering this constitutes a breaking change.
//
// Note: The spelling of this headers is intentionally degenerate from the others for compatibility reasons.
// When sent over a network, the key of this header is canonicalized to "Fromalert".
// However, some datasources still compare against the string "FromAlert".
models.FromAlertHeaderName: "true",
func buildDatasourceHeaders(ctx context.Context, metadata map[string]string) map[string]string {
headers := make(map[string]string, len(metadata)+3)
models.CacheSkipHeaderName: "true",
for key, value := range metadata {
headers[fmt.Sprintf("X-Rule-%s", key)] = url.QueryEscape(value)
}
// Many data sources check this in query method as sometimes alerting needs special considerations.
// Several existing systems also compare against the value of this header. Altering this constitutes a breaking change.
//
// Note: The spelling of this headers is intentionally degenerate from the others for compatibility reasons.
// When sent over a network, the key of this header is canonicalized to "Fromalert".
// However, some datasources still compare against the string "FromAlert".
headers[models.FromAlertHeaderName] = "true"
headers[models.CacheSkipHeaderName] = "true"
key, ok := models.RuleKeyFromContext(ctx)
if ok {
headers["X-Rule-Uid"] = key.UID
headers["X-Grafana-Org-Id"] = strconv.FormatInt(key.OrgID, 10)
}
@@ -350,7 +358,7 @@ func buildDatasourceHeaders(ctx context.Context) map[string]string {
func getExprRequest(ctx EvaluationContext, condition models.Condition, dsCacheService datasources.CacheService, reader AlertingResultsReader) (*expr.Request, error) {
req := &expr.Request{
OrgId: ctx.User.GetOrgID(),
Headers: buildDatasourceHeaders(ctx.Ctx),
Headers: buildDatasourceHeaders(ctx.Ctx, condition.Metadata),
User: ctx.User,
}
datasources := make(map[string]*datasources.DataSource, len(condition.Data))