Alerting: Add provenance field to /api/v1/provisioning/alert-rules (#76252)

This commit adds the missing Provenance field to responses for
/api/v1/provisioning/alert-rules.
pull/76372/head
George Robinson 2 years ago committed by GitHub
parent 6b52bb9c27
commit 05e12e787b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      pkg/services/ngalert/api/api_provisioning.go
  2. 4
      pkg/services/ngalert/api/compat.go
  3. 21
      pkg/services/ngalert/provisioning/alert_rules.go
  4. 36
      pkg/tests/api/alerting/api_provisioning_test.go

@ -57,7 +57,7 @@ type MuteTimingService interface {
} }
type AlertRuleService interface { type AlertRuleService interface {
GetAlertRules(ctx context.Context, orgID int64) ([]*alerting_models.AlertRule, error) GetAlertRules(ctx context.Context, orgID int64) ([]*alerting_models.AlertRule, map[string]alerting_models.Provenance, error)
GetAlertRule(ctx context.Context, orgID int64, ruleUID string) (alerting_models.AlertRule, alerting_models.Provenance, error) GetAlertRule(ctx context.Context, orgID int64, ruleUID string) (alerting_models.AlertRule, alerting_models.Provenance, error)
CreateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance, userID int64) (alerting_models.AlertRule, error) CreateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance, userID int64) (alerting_models.AlertRule, error)
UpdateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error) UpdateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error)
@ -300,11 +300,11 @@ func (srv *ProvisioningSrv) RouteDeleteMuteTiming(c *contextmodel.ReqContext, na
} }
func (srv *ProvisioningSrv) RouteGetAlertRules(c *contextmodel.ReqContext) response.Response { func (srv *ProvisioningSrv) RouteGetAlertRules(c *contextmodel.ReqContext) response.Response {
rules, err := srv.alertRules.GetAlertRules(c.Req.Context(), c.SignedInUser.GetOrgID()) rules, provenances, err := srv.alertRules.GetAlertRules(c.Req.Context(), c.SignedInUser.GetOrgID())
if err != nil { if err != nil {
return ErrResp(http.StatusInternalServerError, err, "") return ErrResp(http.StatusInternalServerError, err, "")
} }
return response.JSON(http.StatusOK, ProvisionedAlertRuleFromAlertRules(rules)) return response.JSON(http.StatusOK, ProvisionedAlertRuleFromAlertRules(rules, provenances))
} }
func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *contextmodel.ReqContext, UID string) response.Response { func (srv *ProvisioningSrv) RouteRouteGetAlertRule(c *contextmodel.ReqContext, UID string) response.Response {

@ -55,10 +55,10 @@ func ProvisionedAlertRuleFromAlertRule(rule models.AlertRule, provenance models.
} }
// ProvisionedAlertRuleFromAlertRules converts a collection of models.AlertRule to definitions.ProvisionedAlertRules with provenance status models.ProvenanceNone // ProvisionedAlertRuleFromAlertRules converts a collection of models.AlertRule to definitions.ProvisionedAlertRules with provenance status models.ProvenanceNone
func ProvisionedAlertRuleFromAlertRules(rules []*models.AlertRule) definitions.ProvisionedAlertRules { func ProvisionedAlertRuleFromAlertRules(rules []*models.AlertRule, provenances map[string]models.Provenance) definitions.ProvisionedAlertRules {
result := make([]definitions.ProvisionedAlertRule, 0, len(rules)) result := make([]definitions.ProvisionedAlertRule, 0, len(rules))
for _, r := range rules { for _, r := range rules {
result = append(result, ProvisionedAlertRuleFromAlertRule(*r, models.ProvenanceNone)) result = append(result, ProvisionedAlertRuleFromAlertRule(*r, provenances[r.UID]))
} }
return result return result
} }

@ -45,16 +45,23 @@ func NewAlertRuleService(ruleStore RuleStore,
} }
} }
func (service *AlertRuleService) GetAlertRules(ctx context.Context, orgID int64) ([]*models.AlertRule, error) { func (service *AlertRuleService) GetAlertRules(ctx context.Context, orgID int64) ([]*models.AlertRule, map[string]models.Provenance, error) {
q := models.ListAlertRulesQuery{ q := models.ListAlertRulesQuery{
OrgID: orgID, OrgID: orgID,
} }
rules, err := service.ruleStore.ListAlertRules(ctx, &q) rules, err := service.ruleStore.ListAlertRules(ctx, &q)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
// TODO: GET provenance provenances := make(map[string]models.Provenance)
return rules, nil if len(rules) > 0 {
resourceType := rules[0].ResourceType()
provenances, err = service.provenanceStore.GetProvenances(ctx, orgID, resourceType)
if err != nil {
return nil, nil, err
}
}
return rules, provenances, nil
} }
func (service *AlertRuleService) GetAlertRule(ctx context.Context, orgID int64, ruleUID string) (models.AlertRule, models.Provenance, error) { func (service *AlertRuleService) GetAlertRule(ctx context.Context, orgID int64, ruleUID string) (models.AlertRule, models.Provenance, error) {
@ -62,15 +69,15 @@ func (service *AlertRuleService) GetAlertRule(ctx context.Context, orgID int64,
OrgID: orgID, OrgID: orgID,
UID: ruleUID, UID: ruleUID,
} }
rules, err := service.ruleStore.GetAlertRuleByUID(ctx, query) rule, err := service.ruleStore.GetAlertRuleByUID(ctx, query)
if err != nil { if err != nil {
return models.AlertRule{}, models.ProvenanceNone, err return models.AlertRule{}, models.ProvenanceNone, err
} }
provenance, err := service.provenanceStore.GetProvenance(ctx, rules, orgID) provenance, err := service.provenanceStore.GetProvenance(ctx, rule, orgID)
if err != nil { if err != nil {
return models.AlertRule{}, models.ProvenanceNone, err return models.AlertRule{}, models.ProvenanceNone, err
} }
return *rules, provenance, nil return *rule, provenance, nil
} }
type AlertRuleWithFolderTitle struct { type AlertRuleWithFolderTitle struct {

@ -2,13 +2,16 @@ package alerting
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"sort"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/tests/testinfra" "github.com/grafana/grafana/pkg/tests/testinfra"
@ -43,6 +46,11 @@ func TestIntegrationProvisioning(t *testing.T) {
Login: "admin", Login: "admin",
}) })
apiClient := newAlertingApiClient(grafanaListedAddr, "editor", "editor")
// Create the namespace we'll save our alerts to.
namespaceUID := "default"
apiClient.CreateFolder(t, namespaceUID, namespaceUID)
t.Run("when provisioning notification policies", func(t *testing.T) { t.Run("when provisioning notification policies", func(t *testing.T) {
url := fmt.Sprintf("http://%s/api/v1/provisioning/policies", grafanaListedAddr) url := fmt.Sprintf("http://%s/api/v1/provisioning/policies", grafanaListedAddr)
body := ` body := `
@ -333,6 +341,34 @@ func TestIntegrationProvisioning(t *testing.T) {
require.Equal(t, 200, resp.StatusCode) require.Equal(t, 200, resp.StatusCode)
}) })
}) })
t.Run("when provisioning alert rules", func(t *testing.T) {
url := fmt.Sprintf("http://%s/api/v1/provisioning/alert-rules", grafanaListedAddr)
body := `{"orgID":1,"folderUID":"default","ruleGroup":"Test Group","title":"Provisioned","condition":"A","data":[{"refId":"A","queryType":"","relativeTimeRange":{"from":600,"to":0},"datasourceUid":"f558c85f-66ad-4fd1-b31d-7979e6c93db4","model":{"editorMode":"code","exemplar":false,"expr":"sum(rate(low_card[5m])) \u003e 0","format":"time_series","instant":true,"intervalMs":1000,"legendFormat":"__auto","maxDataPoints":43200,"range":false,"refId":"A"}}],"noDataState":"NoData","execErrState":"Error","for":"0s"}`
req := createTestRequest("POST", url, "admin", body)
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err)
require.NoError(t, resp.Body.Close())
require.Equal(t, 201, resp.StatusCode)
// We want to check the provenances of both provisioned and non-provisioned rules
createRule(t, apiClient, namespaceUID)
req = createTestRequest("GET", url, "admin", "")
resp, err = http.DefaultClient.Do(req)
require.NoError(t, err)
var rules definitions.ProvisionedAlertRules
require.NoError(t, json.NewDecoder(resp.Body).Decode(&rules))
require.NoError(t, resp.Body.Close())
require.Len(t, rules, 2)
sort.Slice(rules, func(i, j int) bool {
return rules[i].ID < rules[j].ID
})
require.Equal(t, definitions.Provenance("api"), rules[0].Provenance)
require.Equal(t, definitions.Provenance(""), rules[1].Provenance)
})
} }
func createTestRequest(method string, url string, user string, body string) *http.Request { func createTestRequest(method string, url string, user string, body string) *http.Request {

Loading…
Cancel
Save