f7aa17f2e4
What is this feature? Prometheus conversion: ensures that AlertRule.Data queries always have default parameters set (intervalMs, maxDataPoints). Without this, updates of the same rule can cause version increments. Why do we need this feature? Currently, when converting Prometheus rules to Grafana alerts, some default parameters are not explicitly set in the query model. This creates a problem during rule updates: When a user updates a rule that hasn't changed, we still detect differences in the AlertQuery.Model because the newly converted rules are missing the default fields, such as intervalMs and maxDataPoints. This causes unnecessary version increments of alert rules.
126 lines
3.2 KiB
Go
126 lines
3.2 KiB
Go
package prom
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/expr"
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
)
|
|
|
|
type CommonQueryModel struct {
|
|
Datasource datasources.DataSource `json:"datasource"`
|
|
RefID string `json:"refId"`
|
|
Type expr.QueryType `json:"type"`
|
|
}
|
|
|
|
// createAlertQueryWithDefaults creates an AlertQuery with default values initialized.
|
|
func createAlertQueryWithDefaults(datasourceUID string, modelData any, refID string, relTimeRange *models.RelativeTimeRange, queryType string) (models.AlertQuery, error) {
|
|
modelJSON, err := json.Marshal(modelData)
|
|
if err != nil {
|
|
return models.AlertQuery{}, fmt.Errorf("failed to marshal query model: %w", err)
|
|
}
|
|
|
|
query := models.AlertQuery{
|
|
DatasourceUID: datasourceUID,
|
|
Model: modelJSON,
|
|
RefID: refID,
|
|
QueryType: queryType,
|
|
}
|
|
|
|
// Set relative time range if provided
|
|
if relTimeRange != nil {
|
|
query.RelativeTimeRange = *relTimeRange
|
|
}
|
|
|
|
if err := query.InitDefaults(); err != nil {
|
|
return models.AlertQuery{}, err
|
|
}
|
|
|
|
return query, nil
|
|
}
|
|
|
|
func createQueryNode(datasourceUID, datasourceType, expr string, fromTimeRange, evaluationOffset time.Duration) (models.AlertQuery, error) {
|
|
modelData := map[string]any{
|
|
"datasource": map[string]any{
|
|
"type": datasourceType,
|
|
"uid": datasourceUID,
|
|
},
|
|
"expr": expr,
|
|
"instant": true,
|
|
"range": false,
|
|
"refId": queryRefID,
|
|
}
|
|
|
|
if datasourceType == datasources.DS_LOKI {
|
|
modelData["queryType"] = "instant"
|
|
}
|
|
|
|
relTimeRange := models.RelativeTimeRange{
|
|
From: models.Duration(fromTimeRange + evaluationOffset),
|
|
To: models.Duration(evaluationOffset),
|
|
}
|
|
|
|
return createAlertQueryWithDefaults(datasourceUID, modelData, queryRefID, &relTimeRange, datasourceType)
|
|
}
|
|
|
|
type MathQueryModel struct {
|
|
expr.MathQuery
|
|
CommonQueryModel
|
|
}
|
|
|
|
func createMathNode() (models.AlertQuery, error) {
|
|
ds, err := expr.DataSourceModelFromNodeType(expr.TypeCMDNode)
|
|
if err != nil {
|
|
return models.AlertQuery{}, err
|
|
}
|
|
|
|
model := MathQueryModel{
|
|
CommonQueryModel: CommonQueryModel{
|
|
Datasource: *ds,
|
|
RefID: prometheusMathRefID,
|
|
Type: expr.QueryTypeMath,
|
|
},
|
|
MathQuery: expr.MathQuery{
|
|
Expression: fmt.Sprintf("is_number($%[1]s) || is_nan($%[1]s) || is_inf($%[1]s)", queryRefID),
|
|
},
|
|
}
|
|
|
|
return createAlertQueryWithDefaults(expr.DatasourceUID, model, prometheusMathRefID, nil, string(expr.QueryTypeMath))
|
|
}
|
|
|
|
type ThresholdQueryModel struct {
|
|
expr.ThresholdQuery
|
|
CommonQueryModel
|
|
}
|
|
|
|
func createThresholdNode() (models.AlertQuery, error) {
|
|
ds, err := expr.DataSourceModelFromNodeType(expr.TypeCMDNode)
|
|
if err != nil {
|
|
return models.AlertQuery{}, err
|
|
}
|
|
|
|
model := ThresholdQueryModel{
|
|
CommonQueryModel: CommonQueryModel{
|
|
Datasource: *ds,
|
|
RefID: thresholdRefID,
|
|
Type: expr.QueryTypeThreshold,
|
|
},
|
|
ThresholdQuery: expr.ThresholdQuery{
|
|
Expression: prometheusMathRefID,
|
|
Conditions: []expr.ThresholdConditionJSON{
|
|
{
|
|
Evaluator: expr.ConditionEvalJSON{
|
|
Type: expr.ThresholdIsAbove,
|
|
Params: []float64{0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
return createAlertQueryWithDefaults(expr.DatasourceUID, model, thresholdRefID, nil, string(expr.QueryTypeThreshold))
|
|
}
|