Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alerting: Allow none provenance alert rule creation from provisioning API #58410

Merged
19 changes: 15 additions & 4 deletions pkg/services/ngalert/api/api_provisioning.go
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/grafana/grafana/pkg/util"
)

const disableProvenanceHeaderName = "X-Disable-Provenance"

type ProvisioningSrv struct {
log log.Logger
policies NotificationPolicyService
Expand Down Expand Up @@ -259,7 +261,8 @@ func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar definiti
if err != nil {
return ErrResp(http.StatusBadRequest, err, "")
}
createdAlertRule, err := srv.alertRules.CreateAlertRule(c.Req.Context(), upstreamModel, alerting_models.ProvenanceAPI, c.UserID)
provenance := determineProvenance(c)
createdAlertRule, err := srv.alertRules.CreateAlertRule(c.Req.Context(), upstreamModel, provenance, c.UserID)
if errors.Is(err, alerting_models.ErrAlertRuleFailedValidation) {
return ErrResp(http.StatusBadRequest, err, "")
}
Expand All @@ -273,7 +276,7 @@ func (srv *ProvisioningSrv) RoutePostAlertRule(c *models.ReqContext, ar definiti
return ErrResp(http.StatusInternalServerError, err, "")
}

resp := definitions.NewAlertRule(createdAlertRule, alerting_models.ProvenanceAPI)
resp := definitions.NewAlertRule(createdAlertRule, provenance)
return response.JSON(http.StatusCreated, resp)
}

Expand All @@ -284,7 +287,8 @@ func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar definitio
}
updated.OrgID = c.OrgID
updated.UID = UID
updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), updated, alerting_models.ProvenanceAPI)
provenance := determineProvenance(c)
updatedAlertRule, err := srv.alertRules.UpdateAlertRule(c.Req.Context(), updated, provenance)
if errors.Is(err, alerting_models.ErrAlertRuleNotFound) {
return response.Empty(http.StatusNotFound)
}
Expand All @@ -298,7 +302,7 @@ func (srv *ProvisioningSrv) RoutePutAlertRule(c *models.ReqContext, ar definitio
return ErrResp(http.StatusInternalServerError, err, "")
}

resp := definitions.NewAlertRule(updatedAlertRule, alerting_models.ProvenanceAPI)
resp := definitions.NewAlertRule(updatedAlertRule, provenance)
return response.JSON(http.StatusOK, resp)
}

Expand Down Expand Up @@ -340,3 +344,10 @@ func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag defi
}
return response.JSON(http.StatusOK, ag)
}

func determineProvenance(ctx *models.ReqContext) alerting_models.Provenance {
if _, disabled := ctx.Req.Header[disableProvenanceHeaderName]; disabled {
return alerting_models.ProvenanceNone
}
return alerting_models.ProvenanceAPI
}
12 changes: 8 additions & 4 deletions pkg/services/ngalert/api/api_provisioning_test.go
Expand Up @@ -229,7 +229,7 @@ func TestProvisioningApi(t *testing.T) {

t.Run("alert rules", func(t *testing.T) {
t.Run("are invalid", func(t *testing.T) {
t.Run("POST returns 400", func(t *testing.T) {
t.Run("POST returns 400 on wrong body params", func(t *testing.T) {
sut := createProvisioningSrvSut(t)
rc := createTestRequestCtx()
rule := createInvalidAlertRule()
Expand All @@ -241,7 +241,7 @@ func TestProvisioningApi(t *testing.T) {
require.Contains(t, string(response.Body()), "invalid alert rule")
})

t.Run("PUT returns 400", func(t *testing.T) {
t.Run("PUT returns 400 on wrong body params", func(t *testing.T) {
sut := createProvisioningSrvSut(t)
rc := createTestRequestCtx()
uid := "123123"
Expand All @@ -258,9 +258,10 @@ func TestProvisioningApi(t *testing.T) {
})

t.Run("exist in non-default orgs", func(t *testing.T) {
t.Run("POST sets expected fields", func(t *testing.T) {
t.Run("POST sets expected fields with no provenance", func(t *testing.T) {
sut := createProvisioningSrvSut(t)
rc := createTestRequestCtx()
rc.Req.Header = map[string][]string{"X-Disable-Provenance": {"true"}}
rc.OrgID = 3
rule := createTestAlertRule("rule", 1)

Expand All @@ -269,15 +270,17 @@ 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)
})

t.Run("PUT sets expected fields", func(t *testing.T) {
t.Run("PUT sets expected fields with no provenance", func(t *testing.T) {
sut := createProvisioningSrvSut(t)
uid := t.Name()
rule := createTestAlertRule("rule", 1)
rule.UID = uid
insertRuleInOrg(t, sut, rule, 3)
rc := createTestRequestCtx()
rc.Req.Header = map[string][]string{"X-Disable-Provenance": {"hello"}}
rc.OrgID = 3
rule.OrgID = 1 // Set the org back to something wrong, we should still prefer the value from the req context.

Expand All @@ -286,6 +289,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)
})
})

Expand Down
29 changes: 25 additions & 4 deletions pkg/services/ngalert/api/tooling/api.json
Expand Up @@ -364,11 +364,14 @@
"description": "A map of RefIDs (unique query identifiers) to this type makes up the Responses property of a QueryDataResponse.\nThe Error property is used to allow for partial success responses from the containing QueryDataResponse.",
"properties": {
"Error": {
"description": "Error is a property to be set if the the corresponding DataQuery has an error.",
"description": "Error is a property to be set if the corresponding DataQuery has an error.",
"type": "string"
},
"Frames": {
"$ref": "#/definitions/Frames"
},
"Status": {
"$ref": "#/definitions/Status"
}
},
"title": "DataResponse contains the results from a DataQuery.",
Expand Down Expand Up @@ -2816,6 +2819,10 @@
"SmtpNotEnabled": {
"$ref": "#/definitions/ResponseDetails"
},
"Status": {
"format": "int64",
"type": "integer"
},
"Success": {
"$ref": "#/definitions/ResponseDetails"
},
Expand Down Expand Up @@ -3070,6 +3077,7 @@
"type": "object"
},
"URL": {
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
"properties": {
"ForceQuery": {
"type": "boolean"
Expand Down Expand Up @@ -3102,7 +3110,7 @@
"$ref": "#/definitions/Userinfo"
}
},
"title": "URL is a custom URL type that allows validation at configuration load time.",
"title": "A URL represents a parsed URL (technically, a URI reference).",
"type": "object"
},
"Userinfo": {
Expand Down Expand Up @@ -3258,6 +3266,7 @@
"type": "object"
},
"alertGroup": {
"description": "AlertGroup alert group",
"properties": {
"alerts": {
"description": "alerts",
Expand All @@ -3281,6 +3290,7 @@
"type": "object"
},
"alertGroups": {
"description": "AlertGroups alert groups",
"items": {
"$ref": "#/definitions/alertGroup"
},
Expand Down Expand Up @@ -3385,7 +3395,6 @@
"type": "object"
},
"gettableAlert": {
"description": "GettableAlert gettable alert",
"properties": {
"annotations": {
"$ref": "#/definitions/labelSet"
Expand Down Expand Up @@ -3441,12 +3450,14 @@
"type": "object"
},
"gettableAlerts": {
"description": "GettableAlerts gettable alerts",
"items": {
"$ref": "#/definitions/gettableAlert"
},
"type": "array"
},
"gettableSilence": {
"description": "GettableSilence gettable silence",
"properties": {
"comment": {
"description": "comment",
Expand Down Expand Up @@ -3495,6 +3506,7 @@
"type": "object"
},
"gettableSilences": {
"description": "GettableSilences gettable silences",
"items": {
"$ref": "#/definitions/gettableSilence"
},
Expand Down Expand Up @@ -3683,7 +3695,6 @@
"type": "object"
},
"receiver": {
"description": "Receiver receiver",
"properties": {
"active": {
"description": "active",
Expand Down Expand Up @@ -3816,6 +3827,11 @@
"schema": {
"$ref": "#/definitions/ProvisionedAlertRule"
}
},
{
"in": "header",
"name": "X-Disable-Provenance",
"type": "string"
}
],
"responses": {
Expand Down Expand Up @@ -3906,6 +3922,11 @@
"schema": {
"$ref": "#/definitions/ProvisionedAlertRule"
}
},
{
"in": "header",
"name": "X-Disable-Provenance",
"type": "string"
}
],
"responses": {
Expand Down
Expand Up @@ -57,6 +57,12 @@ type AlertRulePayload struct {
Body ProvisionedAlertRule
}

// swagger:parameters RoutePostAlertRule RoutePutAlertRule
type AlertRuleHeaders struct {
// in:header
XDisableProvenance string `json:"X-Disable-Provenance"`
}

type ProvisionedAlertRule struct {
ID int64 `json:"id"`
UID string `json:"uid"`
Expand Down
22 changes: 20 additions & 2 deletions pkg/services/ngalert/api/tooling/post.json
Expand Up @@ -364,11 +364,14 @@
"description": "A map of RefIDs (unique query identifiers) to this type makes up the Responses property of a QueryDataResponse.\nThe Error property is used to allow for partial success responses from the containing QueryDataResponse.",
"properties": {
"Error": {
"description": "Error is a property to be set if the the corresponding DataQuery has an error.",
"description": "Error is a property to be set if the corresponding DataQuery has an error.",
"type": "string"
},
"Frames": {
"$ref": "#/definitions/Frames"
},
"Status": {
"$ref": "#/definitions/Status"
}
},
"title": "DataResponse contains the results from a DataQuery.",
Expand Down Expand Up @@ -2816,6 +2819,10 @@
"SmtpNotEnabled": {
"$ref": "#/definitions/ResponseDetails"
},
"Status": {
"format": "int64",
"type": "integer"
},
"Success": {
"$ref": "#/definitions/ResponseDetails"
},
Expand Down Expand Up @@ -3283,7 +3290,6 @@
"type": "object"
},
"alertGroups": {
"description": "AlertGroups alert groups",
"items": {
"$ref": "#/definitions/alertGroup"
},
Expand Down Expand Up @@ -3443,6 +3449,7 @@
"type": "object"
},
"gettableAlerts": {
"description": "GettableAlerts gettable alerts",
"items": {
"$ref": "#/definitions/gettableAlert"
},
Expand Down Expand Up @@ -3685,6 +3692,7 @@
"type": "object"
},
"receiver": {
"description": "Receiver receiver",
"properties": {
"active": {
"description": "active",
Expand Down Expand Up @@ -5489,6 +5497,11 @@
"schema": {
"$ref": "#/definitions/ProvisionedAlertRule"
}
},
{
"in": "header",
"name": "X-Disable-Provenance",
"type": "string"
}
],
"responses": {
Expand Down Expand Up @@ -5579,6 +5592,11 @@
"schema": {
"$ref": "#/definitions/ProvisionedAlertRule"
}
},
{
"in": "header",
"name": "X-Disable-Provenance",
"type": "string"
}
],
"responses": {
Expand Down