diff --git a/pkg/services/ngalert/api/api_alertmanager_guards.go b/pkg/services/ngalert/api/api_alertmanager_guards.go index 735b823a6f5..5c30d76c110 100644 --- a/pkg/services/ngalert/api/api_alertmanager_guards.go +++ b/pkg/services/ngalert/api/api_alertmanager_guards.go @@ -34,7 +34,7 @@ func checkRoutes(currentConfig apimodels.GettableUserConfig, newConfig apimodels reporter := cmputil.DiffReporter{} options := []cmp.Option{cmp.Reporter(&reporter), cmpopts.EquateEmpty(), cmpopts.IgnoreUnexported(labels.Matcher{})} routesEqual := cmp.Equal(currentConfig.AlertmanagerConfig.Route, newConfig.AlertmanagerConfig.Route, options...) - if !routesEqual && currentConfig.AlertmanagerConfig.Route.Provenance != ngmodels.ProvenanceNone { + if !routesEqual && currentConfig.AlertmanagerConfig.Route.Provenance != apimodels.Provenance(ngmodels.ProvenanceNone) { return fmt.Errorf("policies were provisioned and cannot be changed through the UI") } return nil @@ -44,7 +44,7 @@ func checkTemplates(currentConfig apimodels.GettableUserConfig, newConfig apimod for name, template := range currentConfig.TemplateFiles { provenance := ngmodels.ProvenanceNone if prov, present := currentConfig.TemplateFileProvenances[name]; present { - provenance = prov + provenance = ngmodels.Provenance(prov) } if provenance == ngmodels.ProvenanceNone { continue // we are only interested in non none @@ -76,7 +76,7 @@ func checkContactPoints(currReceivers []*apimodels.GettableApiReceiver, newRecei } for _, existingReceiver := range currReceivers { for _, contactPoint := range existingReceiver.GrafanaManagedReceivers { - if contactPoint.Provenance == ngmodels.ProvenanceNone { + if contactPoint.Provenance == apimodels.Provenance(ngmodels.ProvenanceNone) { continue // we are only interested in non none } postedContactPoint, present := newCPs[contactPoint.UID] @@ -133,7 +133,7 @@ func checkMuteTimes(currentConfig apimodels.GettableUserConfig, newConfig apimod for _, muteTime := range currentConfig.AlertmanagerConfig.MuteTimeIntervals { provenance := ngmodels.ProvenanceNone if prov, present := currentConfig.AlertmanagerConfig.MuteTimeProvenances[muteTime.Name]; present { - provenance = prov + provenance = ngmodels.Provenance(prov) } if provenance == ngmodels.ProvenanceNone { continue // we are only interested in non none diff --git a/pkg/services/ngalert/api/api_alertmanager_guards_test.go b/pkg/services/ngalert/api/api_alertmanager_guards_test.go index a4a43b01182..07906c0b597 100644 --- a/pkg/services/ngalert/api/api_alertmanager_guards_test.go +++ b/pkg/services/ngalert/api/api_alertmanager_guards_test.go @@ -65,7 +65,7 @@ func gettableRoute(t *testing.T, provenance models.Provenance) definitions.Getta AlertmanagerConfig: definitions.GettableApiAlertingConfig{ Config: definitions.Config{ Route: &definitions.Route{ - Provenance: provenance, + Provenance: definitions.Provenance(provenance), Continue: true, GroupBy: []model.LabelName{ "...", @@ -100,7 +100,7 @@ func postableRoute(t *testing.T, provenace models.Provenance) definitions.Postab AlertmanagerConfig: definitions.PostableApiAlertingConfig{ Config: definitions.Config{ Route: &definitions.Route{ - Provenance: provenace, + Provenance: definitions.Provenance(provenace), Continue: true, GroupBy: []model.LabelName{ "...", @@ -199,8 +199,8 @@ func gettableTemplates(t *testing.T, name string, provenance models.Provenance) TemplateFiles: map[string]string{ name: "some-template", }, - TemplateFileProvenances: map[string]models.Provenance{ - name: provenance, + TemplateFileProvenances: map[string]definitions.Provenance{ + name: definitions.Provenance(provenance), }, } } @@ -315,7 +315,7 @@ func defaultGettableReceiver(t *testing.T, uid string, provenance models.Provena Name: "yeah", Type: "slack", DisableResolveMessage: true, - Provenance: provenance, + Provenance: definitions.Provenance(provenance), SecureFields: map[string]bool{ "url": true, }, @@ -368,8 +368,8 @@ func TestCheckMuteTimes(t *testing.T) { TimeIntervals: defaultInterval(t), }, }, - map[string]models.Provenance{ - "test-1": models.ProvenanceNone, + map[string]definitions.Provenance{ + "test-1": definitions.Provenance(models.ProvenanceNone), }), newConfig: postableMuteIntervals(t, []amConfig.MuteTimeInterval{ @@ -393,8 +393,8 @@ func TestCheckMuteTimes(t *testing.T) { TimeIntervals: defaultInterval(t), }, }, - map[string]models.Provenance{ - "test-1": models.ProvenanceNone, + map[string]definitions.Provenance{ + "test-1": definitions.Provenance(models.ProvenanceNone), }), newConfig: postableMuteIntervals(t, []amConfig.MuteTimeInterval{}), }, @@ -412,8 +412,8 @@ func TestCheckMuteTimes(t *testing.T) { TimeIntervals: defaultInterval(t), }, }, - map[string]models.Provenance{ - "test-1": models.ProvenanceAPI, + map[string]definitions.Provenance{ + "test-1": definitions.Provenance(models.ProvenanceAPI), }), newConfig: postableMuteIntervals(t, []amConfig.MuteTimeInterval{ { @@ -432,8 +432,8 @@ func TestCheckMuteTimes(t *testing.T) { TimeIntervals: defaultInterval(t), }, }, - map[string]models.Provenance{ - "test-1": models.ProvenanceNone, + map[string]definitions.Provenance{ + "test-1": definitions.Provenance(models.ProvenanceNone), }), newConfig: postableMuteIntervals(t, []amConfig.MuteTimeInterval{ @@ -457,8 +457,8 @@ func TestCheckMuteTimes(t *testing.T) { TimeIntervals: defaultInterval(t), }, }, - map[string]models.Provenance{ - "test-1": models.ProvenanceNone, + map[string]definitions.Provenance{ + "test-1": definitions.Provenance(models.ProvenanceNone), }), newConfig: postableMuteIntervals(t, []amConfig.MuteTimeInterval{ @@ -487,8 +487,8 @@ func TestCheckMuteTimes(t *testing.T) { TimeIntervals: defaultInterval(t), }, }, - map[string]models.Provenance{ - "test-1": models.ProvenanceAPI, + map[string]definitions.Provenance{ + "test-1": definitions.Provenance(models.ProvenanceAPI), }), newConfig: postableMuteIntervals(t, []amConfig.MuteTimeInterval{ @@ -520,7 +520,7 @@ func TestCheckMuteTimes(t *testing.T) { } } -func gettableMuteIntervals(t *testing.T, muteTimeIntervals []amConfig.MuteTimeInterval, provenances map[string]models.Provenance) definitions.GettableUserConfig { +func gettableMuteIntervals(t *testing.T, muteTimeIntervals []amConfig.MuteTimeInterval, provenances map[string]definitions.Provenance) definitions.GettableUserConfig { return definitions.GettableUserConfig{ AlertmanagerConfig: definitions.GettableApiAlertingConfig{ MuteTimeProvenances: provenances, diff --git a/pkg/services/ngalert/api/api_alertmanager_test.go b/pkg/services/ngalert/api/api_alertmanager_test.go index 0cfc6bbaab8..6b253b0a029 100644 --- a/pkg/services/ngalert/api/api_alertmanager_test.go +++ b/pkg/services/ngalert/api/api_alertmanager_test.go @@ -223,7 +223,7 @@ func TestAlertmanagerConfig(t *testing.T) { response := sut.RouteGetAlertingConfig(rc) body := asGettableUserConfig(t, response) - require.Equal(t, ngmodels.ProvenanceNone, body.AlertmanagerConfig.Route.Provenance) + require.Equal(t, apimodels.Provenance(ngmodels.ProvenanceNone), body.AlertmanagerConfig.Route.Provenance) }) t.Run("contact point from GET config has no provenance", func(t *testing.T) { sut := createSut(t, nil) @@ -232,7 +232,7 @@ func TestAlertmanagerConfig(t *testing.T) { response := sut.RouteGetAlertingConfig(rc) body := asGettableUserConfig(t, response) - require.Equal(t, ngmodels.ProvenanceNone, body.AlertmanagerConfig.Receivers[0].GrafanaManagedReceivers[0].Provenance) + require.Equal(t, apimodels.Provenance(ngmodels.ProvenanceNone), body.AlertmanagerConfig.Receivers[0].GrafanaManagedReceivers[0].Provenance) }) t.Run("templates from GET config have no provenance", func(t *testing.T) { sut := createSut(t, nil) @@ -254,7 +254,7 @@ func TestAlertmanagerConfig(t *testing.T) { response := sut.RouteGetAlertingConfig(rc) body := asGettableUserConfig(t, response) - require.Equal(t, ngmodels.ProvenanceAPI, body.AlertmanagerConfig.Route.Provenance) + require.Equal(t, apimodels.Provenance(ngmodels.ProvenanceAPI), body.AlertmanagerConfig.Route.Provenance) }) t.Run("contact point from GET config has expected provenance", func(t *testing.T) { sut := createSut(t, nil) @@ -274,7 +274,7 @@ func TestAlertmanagerConfig(t *testing.T) { response = sut.RouteGetAlertingConfig(rc) body = asGettableUserConfig(t, response) - require.Equal(t, ngmodels.ProvenanceAPI, body.AlertmanagerConfig.Receivers[0].GrafanaManagedReceivers[0].Provenance) + require.Equal(t, apimodels.Provenance(ngmodels.ProvenanceAPI), body.AlertmanagerConfig.Receivers[0].GrafanaManagedReceivers[0].Provenance) }) t.Run("templates from GET config have expected provenance", func(t *testing.T) { sut := createSut(t, nil) @@ -286,7 +286,7 @@ func TestAlertmanagerConfig(t *testing.T) { body := asGettableUserConfig(t, response) require.NotNil(t, body.TemplateFileProvenances) require.Len(t, body.TemplateFileProvenances, 1) - require.Equal(t, ngmodels.ProvenanceAPI, body.TemplateFileProvenances["a"]) + require.Equal(t, apimodels.Provenance(ngmodels.ProvenanceAPI), body.TemplateFileProvenances["a"]) }) }) } diff --git a/pkg/services/ngalert/api/api_provisioning.go b/pkg/services/ngalert/api/api_provisioning.go index 297200cfa9a..2a834a3f8c5 100644 --- a/pkg/services/ngalert/api/api_provisioning.go +++ b/pkg/services/ngalert/api/api_provisioning.go @@ -177,7 +177,7 @@ func (srv *ProvisioningSrv) RoutePutTemplate(c *contextmodel.ReqContext, body de tmpl := definitions.NotificationTemplate{ Name: name, Template: body.Template, - Provenance: alerting_models.ProvenanceAPI, + Provenance: definitions.Provenance(alerting_models.ProvenanceAPI), } modified, err := srv.templates.SetTemplate(c.Req.Context(), c.OrgID, tmpl) if err != nil { @@ -219,7 +219,7 @@ func (srv *ProvisioningSrv) RouteGetMuteTimings(c *contextmodel.ReqContext) resp } func (srv *ProvisioningSrv) RoutePostMuteTiming(c *contextmodel.ReqContext, mt definitions.MuteTimeInterval) response.Response { - mt.Provenance = alerting_models.ProvenanceAPI + mt.Provenance = definitions.Provenance(alerting_models.ProvenanceAPI) created, err := srv.muteTimings.CreateMuteTiming(c.Req.Context(), mt, c.OrgID) if err != nil { if errors.Is(err, provisioning.ErrValidation) { @@ -232,7 +232,7 @@ func (srv *ProvisioningSrv) RoutePostMuteTiming(c *contextmodel.ReqContext, mt d func (srv *ProvisioningSrv) RoutePutMuteTiming(c *contextmodel.ReqContext, mt definitions.MuteTimeInterval, name string) response.Response { mt.Name = name - mt.Provenance = alerting_models.ProvenanceAPI + mt.Provenance = definitions.Provenance(alerting_models.ProvenanceAPI) updated, err := srv.muteTimings.UpdateMuteTiming(c.Req.Context(), mt, c.OrgID) if err != nil { if errors.Is(err, provisioning.ErrValidation) { @@ -259,7 +259,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRules(c *contextmodel.ReqContext) respo if err != nil { return ErrResp(http.StatusInternalServerError, err, "") } - return response.JSON(http.StatusOK, definitions.NewAlertRules(rules)) + return response.JSON(http.StatusOK, ProvisionedAlertRuleFromAlertRules(rules)) } func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *contextmodel.ReqContext, UID string) response.Response { @@ -267,11 +267,11 @@ func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *contextmodel.ReqContext, U if err != nil { return ErrResp(http.StatusInternalServerError, err, "") } - return response.JSON(http.StatusOK, definitions.NewAlertRule(rule, provenace)) + return response.JSON(http.StatusOK, ProvisionedAlertRuleFromAlertRule(rule, provenace)) } func (srv *ProvisioningSrv) RoutePostAlertRule(c *contextmodel.ReqContext, ar definitions.ProvisionedAlertRule) response.Response { - upstreamModel, err := ar.UpstreamModel() + upstreamModel, err := AlertRuleFromProvisionedAlertRule(ar) upstreamModel.OrgID = c.OrgID if err != nil { return ErrResp(http.StatusBadRequest, err, "") @@ -291,12 +291,12 @@ func (srv *ProvisioningSrv) RoutePostAlertRule(c *contextmodel.ReqContext, ar de return ErrResp(http.StatusInternalServerError, err, "") } - resp := definitions.NewAlertRule(createdAlertRule, provenance) + resp := ProvisionedAlertRuleFromAlertRule(createdAlertRule, provenance) return response.JSON(http.StatusCreated, resp) } func (srv *ProvisioningSrv) RoutePutAlertRule(c *contextmodel.ReqContext, ar definitions.ProvisionedAlertRule, UID string) response.Response { - updated, err := ar.UpstreamModel() + updated, err := AlertRuleFromProvisionedAlertRule(ar) if err != nil { ErrResp(http.StatusBadRequest, err, "") } @@ -317,7 +317,7 @@ func (srv *ProvisioningSrv) RoutePutAlertRule(c *contextmodel.ReqContext, ar def return ErrResp(http.StatusInternalServerError, err, "") } - resp := definitions.NewAlertRule(updatedAlertRule, provenance) + resp := ProvisionedAlertRuleFromAlertRule(updatedAlertRule, provenance) return response.JSON(http.StatusOK, resp) } @@ -337,7 +337,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleGroup(c *contextmodel.ReqContext, f } return ErrResp(http.StatusInternalServerError, err, "") } - return response.JSON(http.StatusOK, definitions.NewAlertRuleGroupFromModel(g)) + return response.JSON(http.StatusOK, AlertRuleGroupToApi(g)) } // RouteGetAlertRulesExport retrieves all alert rules in a format compatible with file provisioning. @@ -403,7 +403,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleExport(c *contextmodel.ReqContext, func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *contextmodel.ReqContext, ag definitions.AlertRuleGroup, folderUID string, group string) response.Response { ag.FolderUID = folderUID ag.Title = group - groupModel, err := ag.ToModel() + groupModel, err := AlertRuleGroupFromApi(ag) if err != nil { ErrResp(http.StatusBadRequest, err, "") } diff --git a/pkg/services/ngalert/api/api_provisioning_test.go b/pkg/services/ngalert/api/api_provisioning_test.go index 4b63f046706..2e9f3097a2b 100644 --- a/pkg/services/ngalert/api/api_provisioning_test.go +++ b/pkg/services/ngalert/api/api_provisioning_test.go @@ -274,7 +274,7 @@ func TestProvisioningApi(t *testing.T) { require.Equal(t, 201, response.Status()) created := deserializeRule(t, response.Body()) require.Equal(t, int64(3), created.OrgID) - require.Equal(t, models.ProvenanceNone, created.Provenance) + require.Equal(t, definitions.Provenance(models.ProvenanceNone), created.Provenance) }) t.Run("PUT sets expected fields with no provenance", func(t *testing.T) { @@ -293,7 +293,7 @@ func TestProvisioningApi(t *testing.T) { require.Equal(t, 200, response.Status()) created := deserializeRule(t, response.Body()) require.Equal(t, int64(3), created.OrgID) - require.Equal(t, models.ProvenanceNone, created.Provenance) + require.Equal(t, definitions.Provenance(models.ProvenanceNone), created.Provenance) }) }) @@ -921,7 +921,7 @@ func (f *fakeNotificationPolicyService) GetPolicyTree(ctx context.Context, orgID return definitions.Route{}, store.ErrNoAlertmanagerConfiguration } result := f.tree - result.Provenance = f.prov + result.Provenance = definitions.Provenance(f.prov) return result, nil } diff --git a/pkg/services/ngalert/api/api_ruler.go b/pkg/services/ngalert/api/api_ruler.go index 8a9632f898f..6f73cd98fce 100644 --- a/pkg/services/ngalert/api/api_ruler.go +++ b/pkg/services/ngalert/api/api_ruler.go @@ -481,7 +481,7 @@ func toGettableExtendedRuleNode(r ngmodels.AlertRule, namespaceID int64, provena RuleGroup: r.RuleGroup, NoDataState: apimodels.NoDataState(r.NoDataState), ExecErrState: apimodels.ExecutionErrorState(r.ExecErrState), - Provenance: provenance, + Provenance: apimodels.Provenance(provenance), IsPaused: r.IsPaused, }, } diff --git a/pkg/services/ngalert/api/api_ruler_test.go b/pkg/services/ngalert/api/api_ruler_test.go index 43ee46caa8e..bace6d77e34 100644 --- a/pkg/services/ngalert/api/api_ruler_test.go +++ b/pkg/services/ngalert/api/api_ruler_test.go @@ -367,10 +367,10 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) { for _, group := range groups { for _, actualRule := range group.Rules { if actualRule.GrafanaManagedAlert.UID == expectedRules[0].UID { - require.Equal(t, models.ProvenanceAPI, actualRule.GrafanaManagedAlert.Provenance) + require.Equal(t, apimodels.Provenance(models.ProvenanceAPI), actualRule.GrafanaManagedAlert.Provenance) found = true } else { - require.Equal(t, models.ProvenanceNone, actualRule.GrafanaManagedAlert.Provenance) + require.Equal(t, apimodels.Provenance(models.ProvenanceNone), actualRule.GrafanaManagedAlert.Provenance) } } } diff --git a/pkg/services/ngalert/api/compat.go b/pkg/services/ngalert/api/compat.go new file mode 100644 index 00000000000..1c37c9c0786 --- /dev/null +++ b/pkg/services/ngalert/api/compat.go @@ -0,0 +1,91 @@ +package api + +import ( + "time" + + "github.com/prometheus/common/model" + + "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" + "github.com/grafana/grafana/pkg/services/ngalert/models" +) + +// AlertRuleFromProvisionedAlertRule converts definitions.ProvisionedAlertRule to models.AlertRule +func AlertRuleFromProvisionedAlertRule(a definitions.ProvisionedAlertRule) (models.AlertRule, error) { + return models.AlertRule{ + ID: a.ID, + UID: a.UID, + OrgID: a.OrgID, + NamespaceUID: a.FolderUID, + RuleGroup: a.RuleGroup, + Title: a.Title, + Condition: a.Condition, + Data: a.Data, + Updated: a.Updated, + NoDataState: a.NoDataState, + ExecErrState: a.ExecErrState, + For: time.Duration(a.For), + Annotations: a.Annotations, + Labels: a.Labels, + IsPaused: a.IsPaused, + }, nil +} + +// ProvisionedAlertRuleFromAlertRule converts models.AlertRule to definitions.ProvisionedAlertRule and sets provided provenance status +func ProvisionedAlertRuleFromAlertRule(rule models.AlertRule, provenance models.Provenance) definitions.ProvisionedAlertRule { + return definitions.ProvisionedAlertRule{ + ID: rule.ID, + UID: rule.UID, + OrgID: rule.OrgID, + FolderUID: rule.NamespaceUID, + RuleGroup: rule.RuleGroup, + Title: rule.Title, + For: model.Duration(rule.For), + Condition: rule.Condition, + Data: rule.Data, + Updated: rule.Updated, + NoDataState: rule.NoDataState, + ExecErrState: rule.ExecErrState, + Annotations: rule.Annotations, + Labels: rule.Labels, + Provenance: definitions.Provenance(provenance), // TODO validate enum conversion? + IsPaused: rule.IsPaused, + } +} + +// ProvisionedAlertRuleFromAlertRules converts a collection of models.AlertRule to definitions.ProvisionedAlertRules with provenance status models.ProvenanceNone +func ProvisionedAlertRuleFromAlertRules(rules []*models.AlertRule) definitions.ProvisionedAlertRules { + result := make([]definitions.ProvisionedAlertRule, 0, len(rules)) + for _, r := range rules { + result = append(result, ProvisionedAlertRuleFromAlertRule(*r, models.ProvenanceNone)) + } + return result +} + +func AlertRuleGroupFromApi(a definitions.AlertRuleGroup) (models.AlertRuleGroup, error) { + ruleGroup := models.AlertRuleGroup{ + Title: a.Title, + FolderUID: a.FolderUID, + Interval: a.Interval, + } + for i := range a.Rules { + converted, err := AlertRuleFromProvisionedAlertRule(a.Rules[i]) + if err != nil { + return models.AlertRuleGroup{}, err + } + ruleGroup.Rules = append(ruleGroup.Rules, converted) + } + return ruleGroup, nil +} + +func AlertRuleGroupToApi(d models.AlertRuleGroup) definitions.AlertRuleGroup { + rules := make([]definitions.ProvisionedAlertRule, 0, len(d.Rules)) + for i := range d.Rules { + rules = append(rules, ProvisionedAlertRuleFromAlertRule(d.Rules[i], d.Provenance)) + } + return definitions.AlertRuleGroup{ + Title: d.Title, + FolderUID: d.FolderUID, + Interval: d.Interval, + Rules: rules, + } +} diff --git a/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules_test.go b/pkg/services/ngalert/api/compat_test.go similarity index 63% rename from pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules_test.go rename to pkg/services/ngalert/api/compat_test.go index fd8845e41c4..42fcfca87e5 100644 --- a/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules_test.go +++ b/pkg/services/ngalert/api/compat_test.go @@ -1,34 +1,36 @@ -package definitions +package api import ( "testing" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" ) func TestToModel(t *testing.T) { t.Run("if no rules are provided the rule field should be nil", func(t *testing.T) { - ruleGroup := AlertRuleGroup{ + ruleGroup := definitions.AlertRuleGroup{ Title: "123", FolderUID: "123", Interval: 10, } - tm, err := ruleGroup.ToModel() + tm, err := AlertRuleGroupFromApi(ruleGroup) require.NoError(t, err) require.Nil(t, tm.Rules) }) t.Run("if rules are provided the rule field should be not nil", func(t *testing.T) { - ruleGroup := AlertRuleGroup{ + ruleGroup := definitions.AlertRuleGroup{ Title: "123", FolderUID: "123", Interval: 10, - Rules: []ProvisionedAlertRule{ + Rules: []definitions.ProvisionedAlertRule{ { UID: "1", }, }, } - tm, err := ruleGroup.ToModel() + tm, err := AlertRuleGroupFromApi(ruleGroup) require.NoError(t, err) require.Len(t, tm.Rules, 1) }) diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index ce0ddc37285..d883f169990 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -17,7 +17,6 @@ import ( "github.com/prometheus/common/model" "gopkg.in/yaml.v3" - "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/util" ) @@ -567,11 +566,13 @@ func (c *PostableUserConfig) UnmarshalYAML(value *yaml.Node) error { return nil } +type Provenance string + // swagger:model type GettableUserConfig struct { - TemplateFiles map[string]string `yaml:"template_files" json:"template_files"` - TemplateFileProvenances map[string]models.Provenance `yaml:"template_file_provenances,omitempty" json:"template_file_provenances,omitempty"` - AlertmanagerConfig GettableApiAlertingConfig `yaml:"alertmanager_config" json:"alertmanager_config"` + TemplateFiles map[string]string `yaml:"template_files" json:"template_files"` + TemplateFileProvenances map[string]Provenance `yaml:"template_file_provenances,omitempty" json:"template_file_provenances,omitempty"` + AlertmanagerConfig GettableApiAlertingConfig `yaml:"alertmanager_config" json:"alertmanager_config"` // amSimple stores a map[string]interface of the decoded alertmanager config. // This enables circumventing the underlying alertmanager secret type @@ -635,7 +636,7 @@ func (c *GettableUserConfig) GetGrafanaReceiverMap() map[string]*GettableGrafana type GettableApiAlertingConfig struct { Config `yaml:",inline"` - MuteTimeProvenances map[string]models.Provenance `yaml:"muteTimeProvenances,omitempty" json:"muteTimeProvenances,omitempty"` + MuteTimeProvenances map[string]Provenance `yaml:"muteTimeProvenances,omitempty" json:"muteTimeProvenances,omitempty"` // Override with our superset receiver type Receivers []*GettableApiReceiver `yaml:"receivers,omitempty" json:"receivers,omitempty"` } @@ -722,7 +723,7 @@ type Route struct { GroupInterval *model.Duration `yaml:"group_interval,omitempty" json:"group_interval,omitempty"` RepeatInterval *model.Duration `yaml:"repeat_interval,omitempty" json:"repeat_interval,omitempty"` - Provenance models.Provenance `yaml:"provenance,omitempty" json:"provenance,omitempty"` + Provenance Provenance `yaml:"provenance,omitempty" json:"provenance,omitempty"` } // UnmarshalYAML implements the yaml.Unmarshaler interface for Route. This is a copy of alertmanager's upstream except it removes validation on the label key. @@ -1006,13 +1007,13 @@ func (r RawMessage) MarshalYAML() (interface{}, error) { } type GettableGrafanaReceiver struct { - UID string `json:"uid"` - Name string `json:"name"` - Type string `json:"type"` - DisableResolveMessage bool `json:"disableResolveMessage"` - Settings RawMessage `json:"settings,omitempty"` - SecureFields map[string]bool `json:"secureFields"` - Provenance models.Provenance `json:"provenance,omitempty"` + UID string `json:"uid"` + Name string `json:"name"` + Type string `json:"type"` + DisableResolveMessage bool `json:"disableResolveMessage"` + Settings RawMessage `json:"settings,omitempty"` + SecureFields map[string]bool `json:"secureFields"` + Provenance Provenance `json:"provenance,omitempty"` } type PostableGrafanaReceiver struct { diff --git a/pkg/services/ngalert/api/tooling/definitions/cortex-ruler.go b/pkg/services/ngalert/api/tooling/definitions/cortex-ruler.go index 4a96c98a188..6fe7c99cb1d 100644 --- a/pkg/services/ngalert/api/tooling/definitions/cortex-ruler.go +++ b/pkg/services/ngalert/api/tooling/definitions/cortex-ruler.go @@ -393,6 +393,6 @@ type GettableGrafanaRule struct { RuleGroup string `json:"rule_group" yaml:"rule_group"` NoDataState NoDataState `json:"no_data_state" yaml:"no_data_state"` ExecErrState ExecutionErrorState `json:"exec_err_state" yaml:"exec_err_state"` - Provenance models.Provenance `json:"provenance,omitempty" yaml:"provenance,omitempty"` + Provenance Provenance `json:"provenance,omitempty" yaml:"provenance,omitempty"` IsPaused bool `json:"is_paused" yaml:"is_paused"` } diff --git a/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go b/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go index 75ff2bb6619..94704fb5f38 100644 --- a/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go +++ b/pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go @@ -133,60 +133,11 @@ type ProvisionedAlertRule struct { // example: {"team": "sre-team-1"} Labels map[string]string `json:"labels,omitempty"` // readonly: true - Provenance models.Provenance `json:"provenance,omitempty"` + Provenance Provenance `json:"provenance,omitempty"` // example: false IsPaused bool `json:"isPaused"` } -func (a *ProvisionedAlertRule) UpstreamModel() (models.AlertRule, error) { - return models.AlertRule{ - ID: a.ID, - UID: a.UID, - OrgID: a.OrgID, - NamespaceUID: a.FolderUID, - RuleGroup: a.RuleGroup, - Title: a.Title, - Condition: a.Condition, - Data: a.Data, - Updated: a.Updated, - NoDataState: a.NoDataState, - ExecErrState: a.ExecErrState, - For: time.Duration(a.For), - Annotations: a.Annotations, - Labels: a.Labels, - IsPaused: a.IsPaused, - }, nil -} - -func NewAlertRule(rule models.AlertRule, provenance models.Provenance) ProvisionedAlertRule { - return ProvisionedAlertRule{ - ID: rule.ID, - UID: rule.UID, - OrgID: rule.OrgID, - FolderUID: rule.NamespaceUID, - RuleGroup: rule.RuleGroup, - Title: rule.Title, - For: model.Duration(rule.For), - Condition: rule.Condition, - Data: rule.Data, - Updated: rule.Updated, - NoDataState: rule.NoDataState, - ExecErrState: rule.ExecErrState, - Annotations: rule.Annotations, - Labels: rule.Labels, - Provenance: provenance, - IsPaused: rule.IsPaused, - } -} - -func NewAlertRules(rules []*models.AlertRule) ProvisionedAlertRules { - result := make([]ProvisionedAlertRule, 0, len(rules)) - for _, r := range rules { - result = append(result, NewAlertRule(*r, models.ProvenanceNone)) - } - return result -} - // swagger:route GET /api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group} provisioning stable RouteGetAlertRuleGroup // // Get a rule group. @@ -268,32 +219,3 @@ type AlertRuleGroup struct { // AlertingFileExport is the full provisioned file export. // swagger:model type AlertingFileExport = file.AlertingFileExport - -func (a *AlertRuleGroup) ToModel() (models.AlertRuleGroup, error) { - ruleGroup := models.AlertRuleGroup{ - Title: a.Title, - FolderUID: a.FolderUID, - Interval: a.Interval, - } - for i := range a.Rules { - converted, err := a.Rules[i].UpstreamModel() - if err != nil { - return models.AlertRuleGroup{}, err - } - ruleGroup.Rules = append(ruleGroup.Rules, converted) - } - return ruleGroup, nil -} - -func NewAlertRuleGroupFromModel(d models.AlertRuleGroup) AlertRuleGroup { - rules := make([]ProvisionedAlertRule, 0, len(d.Rules)) - for i := range d.Rules { - rules = append(rules, NewAlertRule(d.Rules[i], d.Provenance)) - } - return AlertRuleGroup{ - Title: d.Title, - FolderUID: d.FolderUID, - Interval: d.Interval, - Rules: rules, - } -} diff --git a/pkg/services/ngalert/api/tooling/definitions/provisioning_mute_timings.go b/pkg/services/ngalert/api/tooling/definitions/provisioning_mute_timings.go index 99d15fd2989..ae61889a0d8 100644 --- a/pkg/services/ngalert/api/tooling/definitions/provisioning_mute_timings.go +++ b/pkg/services/ngalert/api/tooling/definitions/provisioning_mute_timings.go @@ -2,8 +2,6 @@ package definitions import ( "github.com/prometheus/alertmanager/config" - - "github.com/grafana/grafana/pkg/services/ngalert/models" ) // swagger:route GET /api/v1/provisioning/mute-timings provisioning stable RouteGetMuteTimings @@ -71,7 +69,7 @@ type MuteTimingPayload struct { // swagger:model type MuteTimeInterval struct { config.MuteTimeInterval `json:",inline" yaml:",inline"` - Provenance models.Provenance `json:"provenance,omitempty"` + Provenance Provenance `json:"provenance,omitempty"` } func (mt *MuteTimeInterval) ResourceType() string { diff --git a/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go b/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go index 5d34e563e6e..d91c47193b7 100644 --- a/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go +++ b/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go @@ -1,9 +1,5 @@ package definitions -import ( - "github.com/grafana/grafana/pkg/services/ngalert/models" -) - // swagger:route GET /api/v1/provisioning/templates provisioning stable RouteGetTemplates // // Get all notification templates. @@ -47,9 +43,9 @@ type RouteGetTemplateParam struct { // swagger:model type NotificationTemplate struct { - Name string `json:"name"` - Template string `json:"template"` - Provenance models.Provenance `json:"provenance,omitempty"` + Name string `json:"name"` + Template string `json:"template"` + Provenance Provenance `json:"provenance,omitempty"` } // swagger:model diff --git a/pkg/services/ngalert/notifier/alertmanager_config.go b/pkg/services/ngalert/notifier/alertmanager_config.go index eb7b9c02d4b..5ca9ea840d6 100644 --- a/pkg/services/ngalert/notifier/alertmanager_config.go +++ b/pkg/services/ngalert/notifier/alertmanager_config.go @@ -129,7 +129,7 @@ func (moa *MultiOrgAlertmanager) mergeProvenance(ctx context.Context, config def if err != nil { return definitions.GettableUserConfig{}, err } - config.AlertmanagerConfig.Route.Provenance = provenance + config.AlertmanagerConfig.Route.Provenance = definitions.Provenance(provenance) } cp := definitions.EmbeddedContactPoint{} @@ -140,7 +140,7 @@ func (moa *MultiOrgAlertmanager) mergeProvenance(ctx context.Context, config def for _, receiver := range config.AlertmanagerConfig.Receivers { for _, contactPoint := range receiver.GrafanaManagedReceivers { if provenance, exists := cpProvs[contactPoint.UID]; exists { - contactPoint.Provenance = provenance + contactPoint.Provenance = definitions.Provenance(provenance) } } } @@ -150,14 +150,20 @@ func (moa *MultiOrgAlertmanager) mergeProvenance(ctx context.Context, config def if err != nil { return definitions.GettableUserConfig{}, nil } - config.TemplateFileProvenances = tmplProvs + config.TemplateFileProvenances = make(map[string]definitions.Provenance, len(tmplProvs)) + for key, provenance := range tmplProvs { + config.TemplateFileProvenances[key] = definitions.Provenance(provenance) + } mt := definitions.MuteTimeInterval{} mtProvs, err := moa.ProvStore.GetProvenances(ctx, org, mt.ResourceType()) if err != nil { return definitions.GettableUserConfig{}, nil } - config.AlertmanagerConfig.MuteTimeProvenances = mtProvs + config.AlertmanagerConfig.MuteTimeProvenances = make(map[string]definitions.Provenance, len(mtProvs)) + for key, provenance := range mtProvs { + config.AlertmanagerConfig.MuteTimeProvenances[key] = definitions.Provenance(provenance) + } return config, nil } diff --git a/pkg/services/ngalert/provisioning/mute_timings.go b/pkg/services/ngalert/provisioning/mute_timings.go index ef65d70dffe..54d4b7d4294 100644 --- a/pkg/services/ngalert/provisioning/mute_timings.go +++ b/pkg/services/ngalert/provisioning/mute_timings.go @@ -82,7 +82,7 @@ func (svc *MuteTimingService) CreateMuteTiming(ctx context.Context, mt definitio if err != nil { return err } - err = svc.prov.SetProvenance(ctx, &mt, orgID, mt.Provenance) + err = svc.prov.SetProvenance(ctx, &mt, orgID, models.Provenance(mt.Provenance)) if err != nil { return err } @@ -137,7 +137,7 @@ func (svc *MuteTimingService) UpdateMuteTiming(ctx context.Context, mt definitio if err != nil { return err } - err = svc.prov.SetProvenance(ctx, &mt, orgID, mt.Provenance) + err = svc.prov.SetProvenance(ctx, &mt, orgID, models.Provenance(mt.Provenance)) if err != nil { return err } diff --git a/pkg/services/ngalert/provisioning/notification_policies.go b/pkg/services/ngalert/provisioning/notification_policies.go index f9e71ef8683..55d6cb39c76 100644 --- a/pkg/services/ngalert/provisioning/notification_policies.go +++ b/pkg/services/ngalert/provisioning/notification_policies.go @@ -57,7 +57,7 @@ func (nps *NotificationPolicyService) GetPolicyTree(ctx context.Context, orgID i } result := *cfg.AlertmanagerConfig.Route - result.Provenance = provenance + result.Provenance = definitions.Provenance(provenance) return result, nil } diff --git a/pkg/services/ngalert/provisioning/notification_policies_test.go b/pkg/services/ngalert/provisioning/notification_policies_test.go index 5ffd39c06d9..b5be44f5c24 100644 --- a/pkg/services/ngalert/provisioning/notification_policies_test.go +++ b/pkg/services/ngalert/provisioning/notification_policies_test.go @@ -146,7 +146,7 @@ func TestNotificationPolicyService(t *testing.T) { tree, err := sut.GetPolicyTree(context.Background(), 1) require.NoError(t, err) - require.Equal(t, models.ProvenanceNone, tree.Provenance) + require.Equal(t, models.ProvenanceNone, models.Provenance(tree.Provenance)) }) t.Run("service returns upgraded provenance value", func(t *testing.T) { @@ -158,7 +158,7 @@ func TestNotificationPolicyService(t *testing.T) { updated, err := sut.GetPolicyTree(context.Background(), 1) require.NoError(t, err) - require.Equal(t, models.ProvenanceAPI, updated.Provenance) + require.Equal(t, models.ProvenanceAPI, models.Provenance(updated.Provenance)) }) t.Run("service respects concurrency token when updating", func(t *testing.T) { diff --git a/pkg/services/ngalert/provisioning/templates.go b/pkg/services/ngalert/provisioning/templates.go index 3cb71e7deaf..a05bb48105b 100644 --- a/pkg/services/ngalert/provisioning/templates.go +++ b/pkg/services/ngalert/provisioning/templates.go @@ -70,7 +70,7 @@ func (t *TemplateService) SetTemplate(ctx context.Context, orgID int64, tmpl def if err != nil { return err } - err = t.prov.SetProvenance(ctx, &tmpl, orgID, tmpl.Provenance) + err = t.prov.SetProvenance(ctx, &tmpl, orgID, models.Provenance(tmpl.Provenance)) if err != nil { return err } diff --git a/pkg/services/provisioning/alerting/mute_times_provisioner.go b/pkg/services/provisioning/alerting/mute_times_provisioner.go index d83f94d5e69..71b8b1a4111 100644 --- a/pkg/services/provisioning/alerting/mute_times_provisioner.go +++ b/pkg/services/provisioning/alerting/mute_times_provisioner.go @@ -42,7 +42,7 @@ func (c *defaultMuteTimesProvisioner) Provision(ctx context.Context, cache[muteTiming.OrgID][interval.Name] = interval } } - muteTiming.MuteTime.Provenance = models.ProvenanceFile + muteTiming.MuteTime.Provenance = definitions.Provenance(models.ProvenanceFile) if _, exists := cache[muteTiming.OrgID][muteTiming.MuteTime.Name]; exists { _, err := c.muteTimingService.UpdateMuteTiming(ctx, muteTiming.MuteTime, muteTiming.OrgID) if err != nil { diff --git a/pkg/services/provisioning/alerting/text_templates.go b/pkg/services/provisioning/alerting/text_templates.go index 9d3f7dc1887..4b60b3912e2 100644 --- a/pkg/services/provisioning/alerting/text_templates.go +++ b/pkg/services/provisioning/alerting/text_templates.go @@ -4,6 +4,7 @@ import ( "context" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/provisioning" ) @@ -30,7 +31,7 @@ func (c *defaultTextTemplateProvisioner) Provision(ctx context.Context, files []*AlertingFile) error { for _, file := range files { for _, template := range file.Templates { - template.Data.Provenance = models.ProvenanceFile + template.Data.Provenance = definitions.Provenance(models.ProvenanceFile) _, err := c.templateService.SetTemplate(ctx, template.OrgID, template.Data) if err != nil { return err