mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
Alerting: indicate whether an alertrule is provisioned (#48458)
This commit is contained in:
parent
7048bf9f0d
commit
9e21e4d1c1
@ -52,6 +52,7 @@ Scopes must have an order to ensure consistency and ease of search, this helps u
|
||||
- `grafana_alerting_ticker_interval_seconds`
|
||||
- [FEATURE] Indicate whether routes are provisioned when GETting Alertmanager configuration #47857
|
||||
- [FEATURE] Indicate whether contact point is provisioned when GETting Alertmanager configuration #48323
|
||||
- [FEATURE] Indicate whether alert rule is provisioned when GETting the rule #48458
|
||||
|
||||
## 8.5.1
|
||||
|
||||
|
@ -67,6 +67,7 @@ type API struct {
|
||||
QuotaService *quota.QuotaService
|
||||
Schedule schedule.ScheduleService
|
||||
TransactionManager provisioning.TransactionManager
|
||||
ProvenanceStore provisioning.ProvisioningStore
|
||||
RuleStore store.RuleStore
|
||||
InstanceStore store.InstanceStore
|
||||
AlertingStore AlertingStore
|
||||
@ -109,6 +110,7 @@ func (api *API) RegisterAPIEndpoints(m *metrics.API) {
|
||||
QuotaService: api.QuotaService,
|
||||
scheduleService: api.Schedule,
|
||||
store: api.RuleStore,
|
||||
provenanceStore: api.ProvenanceStore,
|
||||
xactManager: api.TransactionManager,
|
||||
log: logger,
|
||||
cfg: &api.Cfg.UnifiedAlerting,
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
|
||||
type RulerSrv struct {
|
||||
xactManager provisioning.TransactionManager
|
||||
provenanceStore provisioning.ProvisioningStore
|
||||
store store.RuleStore
|
||||
DatasourceCache datasources.CacheService
|
||||
QuotaService *quota.QuotaService
|
||||
@ -143,6 +144,11 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqSignedIn, evaluator)
|
||||
}
|
||||
|
||||
provenanceRecords, err := srv.provenanceStore.GetProvenances(c.Req.Context(), c.SignedInUser.OrgId, (&ngmodels.AlertRule{}).ResourceType())
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to get provenance for rule group")
|
||||
}
|
||||
|
||||
for _, r := range q.Result {
|
||||
if !authorizeDatasourceAccessForRule(r, hasAccess) {
|
||||
continue
|
||||
@ -154,11 +160,11 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.
|
||||
Name: r.RuleGroup,
|
||||
Interval: ruleGroupInterval,
|
||||
Rules: []apimodels.GettableExtendedRuleNode{
|
||||
toGettableExtendedRuleNode(*r, namespace.Id),
|
||||
toGettableExtendedRuleNode(*r, namespace.Id, provenanceRecords),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
ruleGroupConfig.Rules = append(ruleGroupConfig.Rules, toGettableExtendedRuleNode(*r, namespace.Id))
|
||||
ruleGroupConfig.Rules = append(ruleGroupConfig.Rules, toGettableExtendedRuleNode(*r, namespace.Id, provenanceRecords))
|
||||
ruleGroupConfigs[r.RuleGroup] = ruleGroupConfig
|
||||
}
|
||||
}
|
||||
@ -170,7 +176,7 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.
|
||||
return response.JSON(http.StatusAccepted, result)
|
||||
}
|
||||
|
||||
func (srv RulerSrv) RouteGetRulegGroupConfig(c *models.ReqContext) response.Response {
|
||||
func (srv RulerSrv) RouteGetRulesGroupConfig(c *models.ReqContext) response.Response {
|
||||
namespaceTitle := web.Params(c.Req)[":Namespace"]
|
||||
namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, false)
|
||||
if err != nil {
|
||||
@ -194,12 +200,17 @@ func (srv RulerSrv) RouteGetRulegGroupConfig(c *models.ReqContext) response.Resp
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqSignedIn, evaluator)
|
||||
}
|
||||
|
||||
provenanceRecords, err := srv.provenanceStore.GetProvenances(c.Req.Context(), c.SignedInUser.OrgId, (&ngmodels.AlertRule{}).ResourceType())
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to get group alert rules")
|
||||
}
|
||||
|
||||
for _, r := range q.Result {
|
||||
if !authorizeDatasourceAccessForRule(r, hasAccess) {
|
||||
continue
|
||||
}
|
||||
ruleGroupInterval = model.Duration(time.Duration(r.IntervalSeconds) * time.Second)
|
||||
ruleNodes = append(ruleNodes, toGettableExtendedRuleNode(*r, namespace.Id))
|
||||
ruleNodes = append(ruleNodes, toGettableExtendedRuleNode(*r, namespace.Id, provenanceRecords))
|
||||
}
|
||||
|
||||
result := apimodels.RuleGroupConfigResponse{
|
||||
@ -255,6 +266,11 @@ func (srv RulerSrv) RouteGetRulesConfig(c *models.ReqContext) response.Response
|
||||
return accesscontrol.HasAccess(srv.ac, c)(accesscontrol.ReqSignedIn, evaluator)
|
||||
}
|
||||
|
||||
provenanceRecords, err := srv.provenanceStore.GetProvenances(c.Req.Context(), c.SignedInUser.OrgId, (&ngmodels.AlertRule{}).ResourceType())
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to get alert rules")
|
||||
}
|
||||
|
||||
for _, r := range q.Result {
|
||||
if !authorizeDatasourceAccessForRule(r, hasAccess) {
|
||||
continue
|
||||
@ -273,7 +289,7 @@ func (srv RulerSrv) RouteGetRulesConfig(c *models.ReqContext) response.Response
|
||||
Name: r.RuleGroup,
|
||||
Interval: ruleGroupInterval,
|
||||
Rules: []apimodels.GettableExtendedRuleNode{
|
||||
toGettableExtendedRuleNode(*r, folder.Id),
|
||||
toGettableExtendedRuleNode(*r, folder.Id, provenanceRecords),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
@ -284,11 +300,11 @@ func (srv RulerSrv) RouteGetRulesConfig(c *models.ReqContext) response.Response
|
||||
Name: r.RuleGroup,
|
||||
Interval: ruleGroupInterval,
|
||||
Rules: []apimodels.GettableExtendedRuleNode{
|
||||
toGettableExtendedRuleNode(*r, folder.Id),
|
||||
toGettableExtendedRuleNode(*r, folder.Id, provenanceRecords),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
ruleGroupConfig.Rules = append(ruleGroupConfig.Rules, toGettableExtendedRuleNode(*r, folder.Id))
|
||||
ruleGroupConfig.Rules = append(ruleGroupConfig.Rules, toGettableExtendedRuleNode(*r, folder.Id, provenanceRecords))
|
||||
configs[namespace][r.RuleGroup] = ruleGroupConfig
|
||||
}
|
||||
}
|
||||
@ -437,7 +453,11 @@ func (srv RulerSrv) updateAlertRulesInGroup(c *models.ReqContext, namespace *mod
|
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "rule group updated successfully"})
|
||||
}
|
||||
|
||||
func toGettableExtendedRuleNode(r ngmodels.AlertRule, namespaceID int64) apimodels.GettableExtendedRuleNode {
|
||||
func toGettableExtendedRuleNode(r ngmodels.AlertRule, namespaceID int64, provenanceRecords map[string]ngmodels.Provenance) apimodels.GettableExtendedRuleNode {
|
||||
provenance := ngmodels.ProvenanceNone
|
||||
if prov, exists := provenanceRecords[r.ResourceID()]; exists {
|
||||
provenance = prov
|
||||
}
|
||||
gettableExtendedRuleNode := apimodels.GettableExtendedRuleNode{
|
||||
GrafanaManagedAlert: &apimodels.GettableGrafanaRule{
|
||||
ID: r.ID,
|
||||
@ -454,6 +474,7 @@ func toGettableExtendedRuleNode(r ngmodels.AlertRule, namespaceID int64) apimode
|
||||
RuleGroup: r.RuleGroup,
|
||||
NoDataState: apimodels.NoDataState(r.NoDataState),
|
||||
ExecErrState: apimodels.ExecutionErrorState(r.ExecErrState),
|
||||
Provenance: provenance,
|
||||
},
|
||||
}
|
||||
gettableExtendedRuleNode.ApiRuleNode = &apimodels.ApiRuleNode{
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
apimodels "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"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/schedule"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@ -550,6 +551,48 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) {
|
||||
assert.Emptyf(t, expectedRules, "not all expected rules were returned")
|
||||
})
|
||||
})
|
||||
t.Run("should return the provenance of the alert rules", func(t *testing.T) {
|
||||
orgID := rand.Int63()
|
||||
folder := randFolder()
|
||||
ruleStore := store.NewFakeRuleStore(t)
|
||||
ruleStore.Folders[orgID] = append(ruleStore.Folders[orgID], folder)
|
||||
expectedRules := models.GenerateAlertRules(rand.Intn(4)+2, models.AlertRuleGen(withOrgID(orgID), withNamespace(folder)))
|
||||
ruleStore.PutRule(context.Background(), expectedRules...)
|
||||
ac := acMock.New().WithDisabled()
|
||||
|
||||
svc := createService(ac, ruleStore, nil)
|
||||
|
||||
// add provenance to the first generated rule
|
||||
rule := &models.AlertRule{
|
||||
UID: expectedRules[0].UID,
|
||||
}
|
||||
err := svc.provenanceStore.SetProvenance(context.Background(), rule, orgID, models.ProvenanceAPI)
|
||||
require.NoError(t, err)
|
||||
|
||||
response := svc.RouteGetNamespaceRulesConfig(createRequestContext(orgID, "", map[string]string{
|
||||
":Namespace": folder.Title,
|
||||
}))
|
||||
|
||||
require.Equal(t, http.StatusAccepted, response.Status())
|
||||
result := &apimodels.NamespaceConfigResponse{}
|
||||
require.NoError(t, json.Unmarshal(response.Body(), result))
|
||||
require.NotNil(t, result)
|
||||
found := false
|
||||
for namespace, groups := range *result {
|
||||
require.Equal(t, folder.Title, namespace)
|
||||
for _, group := range groups {
|
||||
for _, actualRule := range group.Rules {
|
||||
if actualRule.GrafanaManagedAlert.UID == expectedRules[0].UID {
|
||||
require.Equal(t, models.ProvenanceAPI, actualRule.GrafanaManagedAlert.Provenance)
|
||||
found = true
|
||||
} else {
|
||||
require.Equal(t, models.ProvenanceNone, actualRule.GrafanaManagedAlert.Provenance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
require.True(t, found)
|
||||
})
|
||||
}
|
||||
|
||||
func createService(ac *acMock.Mock, store *store.FakeRuleStore, scheduler schedule.ScheduleService) *RulerSrv {
|
||||
@ -558,6 +601,7 @@ func createService(ac *acMock.Mock, store *store.FakeRuleStore, scheduler schedu
|
||||
store: store,
|
||||
DatasourceCache: nil,
|
||||
QuotaService: nil,
|
||||
provenanceStore: provisioning.NewFakeProvisioningStore(),
|
||||
scheduleService: scheduler,
|
||||
log: log.New("test"),
|
||||
cfg: nil,
|
||||
|
@ -122,7 +122,7 @@ func (f *ForkedRulerApi) forkRouteGetNamespaceGrafanaRulesConfig(ctx *models.Req
|
||||
}
|
||||
|
||||
func (f *ForkedRulerApi) forkRouteGetGrafanaRuleGroupConfig(ctx *models.ReqContext) response.Response {
|
||||
return f.GrafanaRuler.RouteGetRulegGroupConfig(ctx)
|
||||
return f.GrafanaRuler.RouteGetRulesGroupConfig(ctx)
|
||||
}
|
||||
|
||||
func (f *ForkedRulerApi) forkRouteGetGrafanaRulesConfig(ctx *models.ReqContext) response.Response {
|
||||
|
@ -386,4 +386,5 @@ 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"`
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ func (ng *AlertNG) init() error {
|
||||
RuleStore: store,
|
||||
AlertingStore: store,
|
||||
AdminConfigStore: store,
|
||||
ProvenanceStore: store,
|
||||
MultiOrgAlertmanager: ng.MultiOrgAlertmanager,
|
||||
StateManager: ng.stateManager,
|
||||
AccessControl: ng.accesscontrol,
|
||||
|
Loading…
Reference in New Issue
Block a user