Alerting: Fix export of imported Prometheus-style recording rules to terraform (#115661)
Alerting: Fix export imported Prometheus-style recording rules to terraform
This commit is contained in:
@@ -189,42 +189,11 @@ func AlertRuleExportFromAlertRule(rule models.AlertRule) (definitions.AlertRuleE
|
||||
data = append(data, query)
|
||||
}
|
||||
|
||||
cPtr := &rule.Condition
|
||||
if rule.Condition == "" {
|
||||
cPtr = nil
|
||||
}
|
||||
|
||||
noDataState := definitions.NoDataState(rule.NoDataState)
|
||||
ndsPtr := &noDataState
|
||||
if noDataState == "" {
|
||||
ndsPtr = nil
|
||||
}
|
||||
execErrorState := definitions.ExecutionErrorState(rule.ExecErrState)
|
||||
eesPtr := &execErrorState
|
||||
if execErrorState == "" {
|
||||
eesPtr = nil
|
||||
}
|
||||
|
||||
result := definitions.AlertRuleExport{
|
||||
UID: rule.UID,
|
||||
Title: rule.Title,
|
||||
For: model.Duration(rule.For),
|
||||
KeepFiringFor: model.Duration(rule.KeepFiringFor),
|
||||
Condition: cPtr,
|
||||
Data: data,
|
||||
DashboardUID: rule.DashboardUID,
|
||||
PanelID: rule.PanelID,
|
||||
NoDataState: ndsPtr,
|
||||
ExecErrState: eesPtr,
|
||||
IsPaused: rule.IsPaused,
|
||||
NotificationSettings: AlertRuleNotificationSettingsExportFromNotificationSettings(rule.NotificationSettings),
|
||||
Record: AlertRuleRecordExportFromRecord(rule.Record),
|
||||
}
|
||||
if rule.For.Seconds() > 0 {
|
||||
result.ForString = util.Pointer(model.Duration(rule.For).String())
|
||||
}
|
||||
if rule.KeepFiringFor.Seconds() > 0 {
|
||||
result.KeepFiringForString = util.Pointer(model.Duration(rule.KeepFiringFor).String())
|
||||
UID: rule.UID,
|
||||
Title: rule.Title,
|
||||
Data: data,
|
||||
IsPaused: rule.IsPaused,
|
||||
}
|
||||
if rule.Annotations != nil {
|
||||
result.Annotations = &rule.Annotations
|
||||
@@ -232,13 +201,54 @@ func AlertRuleExportFromAlertRule(rule models.AlertRule) (definitions.AlertRuleE
|
||||
if rule.Labels != nil {
|
||||
result.Labels = &rule.Labels
|
||||
}
|
||||
if rule.MissingSeriesEvalsToResolve != nil && *rule.MissingSeriesEvalsToResolve != -1 {
|
||||
result.MissingSeriesEvalsToResolve = rule.MissingSeriesEvalsToResolve
|
||||
|
||||
if rule.Type() == models.RuleTypeRecording {
|
||||
populateRecordingRuleExportFields(rule, &result)
|
||||
} else {
|
||||
populateAlertingRuleExportFields(rule, &result)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func populateRecordingRuleExportFields(rule models.AlertRule, result *definitions.AlertRuleExport) {
|
||||
result.Record = AlertRuleRecordExportFromRecord(rule.Record)
|
||||
}
|
||||
|
||||
func populateAlertingRuleExportFields(rule models.AlertRule, result *definitions.AlertRuleExport) {
|
||||
result.DashboardUID = rule.DashboardUID
|
||||
result.PanelID = rule.PanelID
|
||||
result.NotificationSettings = AlertRuleNotificationSettingsExportFromNotificationSettings(rule.NotificationSettings)
|
||||
|
||||
if rule.Condition != "" {
|
||||
result.Condition = &rule.Condition
|
||||
}
|
||||
|
||||
if rule.NoDataState != "" {
|
||||
noDataState := definitions.NoDataState(rule.NoDataState)
|
||||
result.NoDataState = &noDataState
|
||||
}
|
||||
|
||||
if rule.ExecErrState != "" {
|
||||
execErrorState := definitions.ExecutionErrorState(rule.ExecErrState)
|
||||
result.ExecErrState = &execErrorState
|
||||
}
|
||||
|
||||
result.For = model.Duration(rule.For)
|
||||
if rule.For > 0 {
|
||||
result.ForString = util.Pointer(model.Duration(rule.For).String())
|
||||
}
|
||||
|
||||
result.KeepFiringFor = model.Duration(rule.KeepFiringFor)
|
||||
if rule.KeepFiringFor > 0 {
|
||||
result.KeepFiringForString = util.Pointer(model.Duration(rule.KeepFiringFor).String())
|
||||
}
|
||||
|
||||
if rule.MissingSeriesEvalsToResolve != nil && *rule.MissingSeriesEvalsToResolve != -1 {
|
||||
result.MissingSeriesEvalsToResolve = rule.MissingSeriesEvalsToResolve
|
||||
}
|
||||
}
|
||||
|
||||
func encodeQueryModel(m map[string]any) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
enc := json.NewEncoder(&buf)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func TestToModel(t *testing.T) {
|
||||
@@ -115,6 +116,102 @@ func TestToModel(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestAlertRuleExportFromAlertRule(t *testing.T) {
|
||||
alertingRule := models.RuleGen.With(
|
||||
models.RuleGen.WithNotEmptyLabels(2, "lbl-"),
|
||||
models.RuleGen.WithAnnotations(map[string]string{"ann-key": "ann-value"}),
|
||||
models.RuleGen.WithFor(2*time.Minute),
|
||||
models.RuleGen.WithKeepFiringFor(5*time.Minute),
|
||||
models.RuleGen.WithNotificationSettingsGen(models.NotificationSettingsGen()),
|
||||
).Generate()
|
||||
recordingRule := models.RuleGen.With(
|
||||
models.RuleGen.WithAllRecordingRules(),
|
||||
models.RuleGen.WithNotEmptyLabels(2, "lbl-"),
|
||||
models.RuleGen.WithAnnotations(map[string]string{"ann-key": "ann-value"}),
|
||||
).Generate()
|
||||
|
||||
// Build expected exported recording rule
|
||||
recordingRuleData, err := AlertQueryExportFromAlertQuery(recordingRule.Data[0])
|
||||
require.NoError(t, err)
|
||||
expectedRecordingRuleExport := definitions.AlertRuleExport{
|
||||
UID: recordingRule.UID,
|
||||
Title: recordingRule.Title,
|
||||
Data: []definitions.AlertQueryExport{recordingRuleData},
|
||||
Annotations: &recordingRule.Annotations,
|
||||
Labels: &recordingRule.Labels,
|
||||
Record: &definitions.AlertRuleRecordExport{
|
||||
Metric: recordingRule.Record.Metric,
|
||||
From: recordingRule.Record.From,
|
||||
TargetDatasourceUID: util.Pointer(recordingRule.Record.TargetDatasourceUID),
|
||||
},
|
||||
}
|
||||
|
||||
// Build expected exported alerting rule
|
||||
alertingRuleData, err := AlertQueryExportFromAlertQuery(alertingRule.Data[0])
|
||||
require.NoError(t, err)
|
||||
noDataState := definitions.NoDataState(alertingRule.NoDataState)
|
||||
execErrState := definitions.ExecutionErrorState(alertingRule.ExecErrState)
|
||||
expectedAlertingRuleExport := definitions.AlertRuleExport{
|
||||
UID: alertingRule.UID,
|
||||
Title: alertingRule.Title,
|
||||
Condition: &alertingRule.Condition,
|
||||
Data: []definitions.AlertQueryExport{alertingRuleData},
|
||||
DashboardUID: alertingRule.DashboardUID,
|
||||
PanelID: alertingRule.PanelID,
|
||||
NoDataState: &noDataState,
|
||||
ExecErrState: &execErrState,
|
||||
For: prommodel.Duration(alertingRule.For),
|
||||
KeepFiringFor: prommodel.Duration(alertingRule.KeepFiringFor),
|
||||
ForString: util.Pointer(prommodel.Duration(alertingRule.For).String()),
|
||||
KeepFiringForString: util.Pointer(prommodel.Duration(alertingRule.KeepFiringFor).String()),
|
||||
Annotations: &alertingRule.Annotations,
|
||||
Labels: &alertingRule.Labels,
|
||||
NotificationSettings: AlertRuleNotificationSettingsExportFromNotificationSettings(alertingRule.NotificationSettings),
|
||||
MissingSeriesEvalsToResolve: alertingRule.MissingSeriesEvalsToResolve,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
rule models.AlertRule
|
||||
expected definitions.AlertRuleExport
|
||||
}{
|
||||
{
|
||||
name: "export recording rule",
|
||||
rule: recordingRule,
|
||||
expected: expectedRecordingRuleExport,
|
||||
},
|
||||
{
|
||||
name: "export alerting rule",
|
||||
rule: alertingRule,
|
||||
expected: expectedAlertingRuleExport,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
exported, err := AlertRuleExportFromAlertRule(tc.rule)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expected, exported)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertQueryExportFromAlertQuery(t *testing.T) {
|
||||
query := models.RuleGen.GenerateQuery()
|
||||
|
||||
exported, err := AlertQueryExportFromAlertQuery(query)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, query.RefID, exported.RefID)
|
||||
require.Equal(t, query.DatasourceUID, exported.DatasourceUID)
|
||||
require.Equal(t, int64(time.Duration(query.RelativeTimeRange.From).Seconds()), exported.RelativeTimeRange.FromSeconds)
|
||||
require.Equal(t, int64(time.Duration(query.RelativeTimeRange.To).Seconds()), exported.RelativeTimeRange.ToSeconds)
|
||||
require.NotNil(t, exported.QueryType)
|
||||
require.Equal(t, query.QueryType, *exported.QueryType)
|
||||
require.NotNil(t, exported.Model)
|
||||
require.NotEmpty(t, exported.ModelString)
|
||||
}
|
||||
|
||||
func TestAlertRuleMetadataFromModelMetadata(t *testing.T) {
|
||||
t.Run("should convert model metadata to api metadata", func(t *testing.T) {
|
||||
modelMetadata := models.AlertRuleMetadata{
|
||||
|
||||
Reference in New Issue
Block a user