Alerting: decouple api models from domain\dto models: separate Provenance status + converters (#63594)

* move conversions of domain models to api models and reverse from definition package to api package
pull/63828/head
Yuri Tseretyan 2 years ago committed by GitHub
parent dc01e1ee6a
commit f561e71de8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      pkg/services/ngalert/api/api_alertmanager_guards.go
  2. 36
      pkg/services/ngalert/api/api_alertmanager_guards_test.go
  3. 10
      pkg/services/ngalert/api/api_alertmanager_test.go
  4. 22
      pkg/services/ngalert/api/api_provisioning.go
  5. 6
      pkg/services/ngalert/api/api_provisioning_test.go
  6. 2
      pkg/services/ngalert/api/api_ruler.go
  7. 4
      pkg/services/ngalert/api/api_ruler_test.go
  8. 91
      pkg/services/ngalert/api/compat.go
  9. 14
      pkg/services/ngalert/api/compat_test.go
  10. 27
      pkg/services/ngalert/api/tooling/definitions/alertmanager.go
  11. 2
      pkg/services/ngalert/api/tooling/definitions/cortex-ruler.go
  12. 80
      pkg/services/ngalert/api/tooling/definitions/provisioning_alert_rules.go
  13. 4
      pkg/services/ngalert/api/tooling/definitions/provisioning_mute_timings.go
  14. 10
      pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go
  15. 14
      pkg/services/ngalert/notifier/alertmanager_config.go
  16. 4
      pkg/services/ngalert/provisioning/mute_timings.go
  17. 2
      pkg/services/ngalert/provisioning/notification_policies.go
  18. 4
      pkg/services/ngalert/provisioning/notification_policies_test.go
  19. 2
      pkg/services/ngalert/provisioning/templates.go
  20. 2
      pkg/services/provisioning/alerting/mute_times_provisioner.go
  21. 3
      pkg/services/provisioning/alerting/text_templates.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

@ -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,

@ -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"])
})
})
}

@ -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, "")
}

@ -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
}

@ -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,
},
}

@ -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)
}
}
}

@ -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,
}
}

@ -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)
})

@ -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 {

@ -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"`
}

@ -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,
}
}

@ -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 {

@ -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

@ -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
}

@ -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
}

@ -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
}

@ -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) {

@ -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
}

@ -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 {

@ -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

Loading…
Cancel
Save