mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Add method to provisioning API for obtaining a group and its rules (#51398)
* Generate shell for new route * Propagate path parameters * Implement route logic * Add a couple simple tests * Use NotFound error for not found, avoid returning pointer * Regenerate
This commit is contained in:
parent
e64cde8727
commit
b9c7eb1380
@ -54,6 +54,7 @@ type AlertRuleService interface {
|
|||||||
CreateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error)
|
CreateAlertRule(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)
|
UpdateAlertRule(ctx context.Context, rule alerting_models.AlertRule, provenance alerting_models.Provenance) (alerting_models.AlertRule, error)
|
||||||
DeleteAlertRule(ctx context.Context, orgID int64, ruleUID string, provenance alerting_models.Provenance) error
|
DeleteAlertRule(ctx context.Context, orgID int64, ruleUID string, provenance alerting_models.Provenance) error
|
||||||
|
GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (definitions.AlertRuleGroup, error)
|
||||||
UpdateRuleGroup(ctx context.Context, orgID int64, folderUID, rulegroup string, interval int64) error
|
UpdateRuleGroup(ctx context.Context, orgID int64, folderUID, rulegroup string, interval int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +285,18 @@ func (srv *ProvisioningSrv) RouteDeleteAlertRule(c *models.ReqContext, UID strin
|
|||||||
return response.JSON(http.StatusNoContent, "")
|
return response.JSON(http.StatusNoContent, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag definitions.AlertRuleGroup, folderUID string, group string) response.Response {
|
func (srv *ProvisioningSrv) RouteGetAlertRuleGroup(c *models.ReqContext, folder string, group string) response.Response {
|
||||||
|
g, err := srv.alertRules.GetRuleGroup(c.Req.Context(), c.OrgId, folder, group)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, store.ErrAlertRuleGroupNotFound) {
|
||||||
|
return ErrResp(http.StatusNotFound, err, "")
|
||||||
|
}
|
||||||
|
return ErrResp(http.StatusInternalServerError, err, "")
|
||||||
|
}
|
||||||
|
return response.JSON(http.StatusOK, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *ProvisioningSrv) RoutePutAlertRuleGroup(c *models.ReqContext, ag definitions.AlertRuleGroupMetadata, folderUID string, group string) response.Response {
|
||||||
err := srv.alertRules.UpdateRuleGroup(c.Req.Context(), c.OrgId, folderUID, group, ag.Interval)
|
err := srv.alertRules.UpdateRuleGroup(c.Req.Context(), c.OrgId, folderUID, group, ag.Interval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, store.ErrOptimisticLock) {
|
if errors.Is(err, store.ErrOptimisticLock) {
|
||||||
|
@ -239,6 +239,28 @@ func TestProvisioningApi(t *testing.T) {
|
|||||||
require.Equal(t, 404, response.Status())
|
require.Equal(t, 404, response.Status())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("alert rule groups", func(t *testing.T) {
|
||||||
|
t.Run("are present, GET returns 200", func(t *testing.T) {
|
||||||
|
sut := createProvisioningSrvSut(t)
|
||||||
|
rc := createTestRequestCtx()
|
||||||
|
insertRule(t, sut, createTestAlertRule("rule", 1))
|
||||||
|
|
||||||
|
response := sut.RouteGetAlertRuleGroup(&rc, "folder-uid", "my-cool-group")
|
||||||
|
|
||||||
|
require.Equal(t, 200, response.Status())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("are missing, GET returns 404", func(t *testing.T) {
|
||||||
|
sut := createProvisioningSrvSut(t)
|
||||||
|
rc := createTestRequestCtx()
|
||||||
|
insertRule(t, sut, createTestAlertRule("rule", 1))
|
||||||
|
|
||||||
|
response := sut.RouteGetAlertRuleGroup(&rc, "folder-uid", "does not exist")
|
||||||
|
|
||||||
|
require.Equal(t, 404, response.Status())
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func createProvisioningSrvSut(t *testing.T) ProvisioningSrv {
|
func createProvisioningSrvSut(t *testing.T) ProvisioningSrv {
|
||||||
@ -382,6 +404,7 @@ func createTestAlertRule(title string, orgID int64) definitions.AlertRule {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
RuleGroup: "my-cool-group",
|
RuleGroup: "my-cool-group",
|
||||||
|
FolderUID: "folder-uid",
|
||||||
For: time.Second * 60,
|
For: time.Second * 60,
|
||||||
NoDataState: models.OK,
|
NoDataState: models.OK,
|
||||||
ExecErrState: models.OkErrState,
|
ExecErrState: models.OkErrState,
|
||||||
|
@ -185,7 +185,8 @@ func (api *API) authorize(method, path string) web.Handler {
|
|||||||
http.MethodGet + "/api/v1/provisioning/templates/{name}",
|
http.MethodGet + "/api/v1/provisioning/templates/{name}",
|
||||||
http.MethodGet + "/api/v1/provisioning/mute-timings",
|
http.MethodGet + "/api/v1/provisioning/mute-timings",
|
||||||
http.MethodGet + "/api/v1/provisioning/mute-timings/{name}",
|
http.MethodGet + "/api/v1/provisioning/mute-timings/{name}",
|
||||||
http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}":
|
http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}",
|
||||||
|
http.MethodGet + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}":
|
||||||
fallback = middleware.ReqOrgAdmin
|
fallback = middleware.ReqOrgAdmin
|
||||||
eval = ac.EvalPermission(ac.ActionAlertingProvisioningRead) // organization scope
|
eval = ac.EvalPermission(ac.ActionAlertingProvisioningRead) // organization scope
|
||||||
|
|
||||||
|
@ -95,6 +95,10 @@ func (f *ForkedProvisioningApi) forkRouteDeleteAlertRule(ctx *models.ReqContext,
|
|||||||
return f.svc.RouteDeleteAlertRule(ctx, UID)
|
return f.svc.RouteDeleteAlertRule(ctx, UID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ForkedProvisioningApi) forkRoutePutAlertRuleGroup(ctx *models.ReqContext, ag apimodels.AlertRuleGroup, folder, group string) response.Response {
|
func (f *ForkedProvisioningApi) forkRouteGetAlertRuleGroup(ctx *models.ReqContext, folder, group string) response.Response {
|
||||||
|
return f.svc.RouteGetAlertRuleGroup(ctx, folder, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ForkedProvisioningApi) forkRoutePutAlertRuleGroup(ctx *models.ReqContext, ag apimodels.AlertRuleGroupMetadata, folder, group string) response.Response {
|
||||||
return f.svc.RoutePutAlertRuleGroup(ctx, ag, folder, group)
|
return f.svc.RoutePutAlertRuleGroup(ctx, ag, folder, group)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ type ProvisioningApiForkingService interface {
|
|||||||
RouteDeleteMuteTiming(*models.ReqContext) response.Response
|
RouteDeleteMuteTiming(*models.ReqContext) response.Response
|
||||||
RouteDeleteTemplate(*models.ReqContext) response.Response
|
RouteDeleteTemplate(*models.ReqContext) response.Response
|
||||||
RouteGetAlertRule(*models.ReqContext) response.Response
|
RouteGetAlertRule(*models.ReqContext) response.Response
|
||||||
|
RouteGetAlertRuleGroup(*models.ReqContext) response.Response
|
||||||
RouteGetContactpoints(*models.ReqContext) response.Response
|
RouteGetContactpoints(*models.ReqContext) response.Response
|
||||||
RouteGetMuteTiming(*models.ReqContext) response.Response
|
RouteGetMuteTiming(*models.ReqContext) response.Response
|
||||||
RouteGetMuteTimings(*models.ReqContext) response.Response
|
RouteGetMuteTimings(*models.ReqContext) response.Response
|
||||||
@ -61,6 +62,11 @@ func (f *ForkedProvisioningApi) RouteGetAlertRule(ctx *models.ReqContext) respon
|
|||||||
uIDParam := web.Params(ctx.Req)[":UID"]
|
uIDParam := web.Params(ctx.Req)[":UID"]
|
||||||
return f.forkRouteGetAlertRule(ctx, uIDParam)
|
return f.forkRouteGetAlertRule(ctx, uIDParam)
|
||||||
}
|
}
|
||||||
|
func (f *ForkedProvisioningApi) RouteGetAlertRuleGroup(ctx *models.ReqContext) response.Response {
|
||||||
|
folderUIDParam := web.Params(ctx.Req)[":FolderUID"]
|
||||||
|
groupParam := web.Params(ctx.Req)[":Group"]
|
||||||
|
return f.forkRouteGetAlertRuleGroup(ctx, folderUIDParam, groupParam)
|
||||||
|
}
|
||||||
func (f *ForkedProvisioningApi) RouteGetContactpoints(ctx *models.ReqContext) response.Response {
|
func (f *ForkedProvisioningApi) RouteGetContactpoints(ctx *models.ReqContext) response.Response {
|
||||||
return f.forkRouteGetContactpoints(ctx)
|
return f.forkRouteGetContactpoints(ctx)
|
||||||
}
|
}
|
||||||
@ -113,7 +119,7 @@ func (f *ForkedProvisioningApi) RoutePutAlertRule(ctx *models.ReqContext) respon
|
|||||||
func (f *ForkedProvisioningApi) RoutePutAlertRuleGroup(ctx *models.ReqContext) response.Response {
|
func (f *ForkedProvisioningApi) RoutePutAlertRuleGroup(ctx *models.ReqContext) response.Response {
|
||||||
folderUIDParam := web.Params(ctx.Req)[":FolderUID"]
|
folderUIDParam := web.Params(ctx.Req)[":FolderUID"]
|
||||||
groupParam := web.Params(ctx.Req)[":Group"]
|
groupParam := web.Params(ctx.Req)[":Group"]
|
||||||
conf := apimodels.AlertRuleGroup{}
|
conf := apimodels.AlertRuleGroupMetadata{}
|
||||||
if err := web.Bind(ctx.Req, &conf); err != nil {
|
if err := web.Bind(ctx.Req, &conf); err != nil {
|
||||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||||
}
|
}
|
||||||
@ -203,6 +209,16 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApiForkingServi
|
|||||||
m,
|
m,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
group.Get(
|
||||||
|
toMacaronPath("/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}"),
|
||||||
|
api.authorize(http.MethodGet, "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}"),
|
||||||
|
metrics.Instrument(
|
||||||
|
http.MethodGet,
|
||||||
|
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}",
|
||||||
|
srv.RouteGetAlertRuleGroup,
|
||||||
|
m,
|
||||||
|
),
|
||||||
|
)
|
||||||
group.Get(
|
group.Get(
|
||||||
toMacaronPath("/api/v1/provisioning/contact-points"),
|
toMacaronPath("/api/v1/provisioning/contact-points"),
|
||||||
api.authorize(http.MethodGet, "/api/v1/provisioning/contact-points"),
|
api.authorize(http.MethodGet, "/api/v1/provisioning/contact-points"),
|
||||||
|
@ -308,7 +308,7 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"AlertRuleGroup": {
|
"AlertRuleGroupMetadata": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"interval": {
|
"interval": {
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
@ -470,30 +470,6 @@
|
|||||||
},
|
},
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"DashboardAclUpdateItem": {
|
|
||||||
"properties": {
|
|
||||||
"permission": {
|
|
||||||
"$ref": "#/definitions/PermissionType"
|
|
||||||
},
|
|
||||||
"role": {
|
|
||||||
"enum": [
|
|
||||||
"Viewer",
|
|
||||||
"Editor",
|
|
||||||
"Admin"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"teamId": {
|
|
||||||
"format": "int64",
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"userId": {
|
|
||||||
"format": "int64",
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"DateTime": {
|
"DateTime": {
|
||||||
"description": "DateTime is a time but it serializes to ISO8601 format with millis\nIt knows how to read 3 different variations of a RFC3339 date time.\nMost APIs we encounter want either millisecond or second precision times.\nThis just tries to make it worry-free.",
|
"description": "DateTime is a time but it serializes to ISO8601 format with millis\nIt knows how to read 3 different variations of a RFC3339 date time.\nMost APIs we encounter want either millisecond or second precision times.\nThis just tries to make it worry-free.",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@ -1336,48 +1312,6 @@
|
|||||||
},
|
},
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"MetricRequest": {
|
|
||||||
"properties": {
|
|
||||||
"debug": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"from": {
|
|
||||||
"description": "From Start time in epoch timestamps in milliseconds or relative using Grafana time units.",
|
|
||||||
"example": "now-1h",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"queries": {
|
|
||||||
"description": "queries.refId – Specifies an identifier of the query. Is optional and default to “A”.\nqueries.datasourceId – Specifies the data source to be queried. Each query in the request must have an unique datasourceId.\nqueries.maxDataPoints - Species maximum amount of data points that dashboard panel can render. Is optional and default to 100.\nqueries.intervalMs - Specifies the time interval in milliseconds of time series. Is optional and defaults to 1000.",
|
|
||||||
"example": [
|
|
||||||
{
|
|
||||||
"datasource": {
|
|
||||||
"uid": "PD8C576611E62080A"
|
|
||||||
},
|
|
||||||
"format": "table",
|
|
||||||
"intervalMs": 86400000,
|
|
||||||
"maxDataPoints": 1092,
|
|
||||||
"rawSql": "SELECT 1 as valueOne, 2 as valueTwo",
|
|
||||||
"refId": "A"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/Json"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"description": "To End time in epoch timestamps in milliseconds or relative using Grafana time units.",
|
|
||||||
"example": "now",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"from",
|
|
||||||
"to",
|
|
||||||
"queries"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"MonthRange": {
|
"MonthRange": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"Begin": {
|
"Begin": {
|
||||||
@ -1425,34 +1359,6 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"NavLink": {
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"target": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"text": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"NavbarPreference": {
|
|
||||||
"properties": {
|
|
||||||
"savedItems": {
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/NavLink"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"NotFound": {
|
"NotFound": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
@ -1668,53 +1574,9 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"PatchPrefsCmd": {
|
|
||||||
"properties": {
|
|
||||||
"homeDashboardId": {
|
|
||||||
"default": 0,
|
|
||||||
"description": "The numerical :id of a favorited dashboard",
|
|
||||||
"format": "int64",
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"homeDashboardUID": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"locale": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"navbar": {
|
|
||||||
"$ref": "#/definitions/NavbarPreference"
|
|
||||||
},
|
|
||||||
"queryHistory": {
|
|
||||||
"$ref": "#/definitions/QueryHistoryPreference"
|
|
||||||
},
|
|
||||||
"theme": {
|
|
||||||
"enum": [
|
|
||||||
"light",
|
|
||||||
"dark"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timezone": {
|
|
||||||
"enum": [
|
|
||||||
"utc",
|
|
||||||
"browser"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"weekStart": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"PermissionDenied": {
|
"PermissionDenied": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"PermissionType": {
|
|
||||||
"format": "int64",
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"Point": {
|
"Point": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"T": {
|
"T": {
|
||||||
@ -2036,14 +1898,6 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"QueryHistoryPreference": {
|
|
||||||
"properties": {
|
|
||||||
"homeTab": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"Receiver": {
|
"Receiver": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"email_configs": {
|
"email_configs": {
|
||||||
@ -2738,6 +2592,7 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"URL": {
|
"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": {
|
"properties": {
|
||||||
"ForceQuery": {
|
"ForceQuery": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -2770,58 +2625,7 @@
|
|||||||
"$ref": "#/definitions/Userinfo"
|
"$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"
|
|
||||||
},
|
|
||||||
"UpdateDashboardAclCommand": {
|
|
||||||
"properties": {
|
|
||||||
"items": {
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/DashboardAclUpdateItem"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"UpdatePrefsCmd": {
|
|
||||||
"properties": {
|
|
||||||
"homeDashboardId": {
|
|
||||||
"default": 0,
|
|
||||||
"description": "The numerical :id of a favorited dashboard",
|
|
||||||
"format": "int64",
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"homeDashboardUID": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"locale": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"navbar": {
|
|
||||||
"$ref": "#/definitions/NavbarPreference"
|
|
||||||
},
|
|
||||||
"queryHistory": {
|
|
||||||
"$ref": "#/definitions/QueryHistoryPreference"
|
|
||||||
},
|
|
||||||
"theme": {
|
|
||||||
"enum": [
|
|
||||||
"light",
|
|
||||||
"dark"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"timezone": {
|
|
||||||
"enum": [
|
|
||||||
"utc",
|
|
||||||
"browser"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"weekStart": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"Userinfo": {
|
"Userinfo": {
|
||||||
@ -2991,7 +2795,6 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"alertGroup": {
|
"alertGroup": {
|
||||||
"description": "AlertGroup alert group",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"alerts": {
|
"alerts": {
|
||||||
"description": "alerts",
|
"description": "alerts",
|
||||||
@ -3015,7 +2818,6 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"alertGroups": {
|
"alertGroups": {
|
||||||
"description": "AlertGroups alert groups",
|
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/alertGroup"
|
"$ref": "#/definitions/alertGroup"
|
||||||
},
|
},
|
||||||
@ -3123,6 +2925,7 @@
|
|||||||
"$ref": "#/definitions/Duration"
|
"$ref": "#/definitions/Duration"
|
||||||
},
|
},
|
||||||
"gettableAlert": {
|
"gettableAlert": {
|
||||||
|
"description": "GettableAlert gettable alert",
|
||||||
"properties": {
|
"properties": {
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"$ref": "#/definitions/labelSet"
|
"$ref": "#/definitions/labelSet"
|
||||||
@ -3184,7 +2987,6 @@
|
|||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"gettableSilence": {
|
"gettableSilence": {
|
||||||
"description": "GettableSilence gettable silence",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"comment": {
|
"comment": {
|
||||||
"description": "comment",
|
"description": "comment",
|
||||||
@ -3344,7 +3146,6 @@
|
|||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"postableSilence": {
|
"postableSilence": {
|
||||||
"description": "PostableSilence postable silence",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"comment": {
|
"comment": {
|
||||||
"description": "comment",
|
"description": "comment",
|
||||||
@ -3382,6 +3183,7 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"receiver": {
|
"receiver": {
|
||||||
|
"description": "Receiver receiver",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"description": "name",
|
"description": "name",
|
||||||
@ -3730,6 +3532,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}": {
|
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "RouteGetAlertRuleGroup",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "FolderUID",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "Group",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/AlertRuleGroup"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": " Not found."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Get a rule group.",
|
||||||
|
"tags": [
|
||||||
|
"provisioning"
|
||||||
|
]
|
||||||
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
@ -3752,15 +3583,15 @@
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"name": "Body",
|
"name": "Body",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/AlertRuleGroup"
|
"$ref": "#/definitions/AlertRuleGroupMetadata"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "AlertRuleGroup",
|
"description": "AlertRuleGroupMetadata",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/AlertRuleGroup"
|
"$ref": "#/definitions/AlertRuleGroupMetadata"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
|
@ -135,6 +135,14 @@ func NewAlertRule(rule models.AlertRule, provenance models.Provenance) AlertRule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swagger:route GET /api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group} provisioning stable RouteGetAlertRuleGroup
|
||||||
|
//
|
||||||
|
// Get a rule group.
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: AlertRuleGroup
|
||||||
|
// 404: description: Not found.
|
||||||
|
|
||||||
// swagger:route PUT /api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group} provisioning stable RoutePutAlertRuleGroup
|
// swagger:route PUT /api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group} provisioning stable RoutePutAlertRuleGroup
|
||||||
//
|
//
|
||||||
// Update the interval of a rule group.
|
// Update the interval of a rule group.
|
||||||
@ -143,16 +151,16 @@ func NewAlertRule(rule models.AlertRule, provenance models.Provenance) AlertRule
|
|||||||
// - application/json
|
// - application/json
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: AlertRuleGroup
|
// 200: AlertRuleGroupMetadata
|
||||||
// 400: ValidationError
|
// 400: ValidationError
|
||||||
|
|
||||||
// swagger:parameters RoutePutAlertRuleGroup
|
// swagger:parameters RouteGetAlertRuleGroup RoutePutAlertRuleGroup
|
||||||
type FolderUIDPathParam struct {
|
type FolderUIDPathParam struct {
|
||||||
// in:path
|
// in:path
|
||||||
FolderUID string `json:"FolderUID"`
|
FolderUID string `json:"FolderUID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:parameters RoutePutAlertRuleGroup
|
// swagger:parameters RouteGetAlertRuleGroup RoutePutAlertRuleGroup
|
||||||
type RuleGroupPathParam struct {
|
type RuleGroupPathParam struct {
|
||||||
// in:path
|
// in:path
|
||||||
Group string `json:"Group"`
|
Group string `json:"Group"`
|
||||||
@ -161,9 +169,16 @@ type RuleGroupPathParam struct {
|
|||||||
// swagger:parameters RoutePutAlertRuleGroup
|
// swagger:parameters RoutePutAlertRuleGroup
|
||||||
type AlertRuleGroupPayload struct {
|
type AlertRuleGroupPayload struct {
|
||||||
// in:body
|
// in:body
|
||||||
Body AlertRuleGroup
|
Body AlertRuleGroupMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlertRuleGroupMetadata struct {
|
||||||
|
Interval int64 `json:"interval"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlertRuleGroup struct {
|
type AlertRuleGroup struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
FolderUID string `json:"folderUid"`
|
||||||
Interval int64 `json:"interval"`
|
Interval int64 `json:"interval"`
|
||||||
|
Rules []models.AlertRule `json:"rules"`
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"AlertRuleGroup": {
|
"AlertRuleGroupMetadata": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"interval": {
|
"interval": {
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
@ -2592,6 +2592,7 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"URL": {
|
"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": {
|
"properties": {
|
||||||
"ForceQuery": {
|
"ForceQuery": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -2624,7 +2625,7 @@
|
|||||||
"$ref": "#/definitions/Userinfo"
|
"$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"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"Userinfo": {
|
"Userinfo": {
|
||||||
@ -2794,6 +2795,7 @@
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"alertGroup": {
|
"alertGroup": {
|
||||||
|
"description": "AlertGroup alert group",
|
||||||
"properties": {
|
"properties": {
|
||||||
"alerts": {
|
"alerts": {
|
||||||
"description": "alerts",
|
"description": "alerts",
|
||||||
@ -2988,6 +2990,7 @@
|
|||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"gettableSilence": {
|
"gettableSilence": {
|
||||||
|
"description": "GettableSilence gettable silence",
|
||||||
"properties": {
|
"properties": {
|
||||||
"comment": {
|
"comment": {
|
||||||
"description": "comment",
|
"description": "comment",
|
||||||
@ -3146,6 +3149,7 @@
|
|||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"postableSilence": {
|
"postableSilence": {
|
||||||
|
"description": "PostableSilence postable silence",
|
||||||
"properties": {
|
"properties": {
|
||||||
"comment": {
|
"comment": {
|
||||||
"description": "comment",
|
"description": "comment",
|
||||||
@ -5157,6 +5161,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}": {
|
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "RouteGetAlertRuleGroup",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "FolderUID",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "Group",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/AlertRuleGroup"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": " Not found."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Get a rule group.",
|
||||||
|
"tags": [
|
||||||
|
"provisioning"
|
||||||
|
]
|
||||||
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
@ -5179,15 +5212,15 @@
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"name": "Body",
|
"name": "Body",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/AlertRuleGroup"
|
"$ref": "#/definitions/AlertRuleGroupMetadata"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "AlertRuleGroup",
|
"description": "AlertRuleGroupMetadata",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/AlertRuleGroup"
|
"$ref": "#/definitions/AlertRuleGroupMetadata"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
|
@ -1893,6 +1893,36 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}": {
|
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"provisioning",
|
||||||
|
"stable"
|
||||||
|
],
|
||||||
|
"summary": "Get a rule group.",
|
||||||
|
"operationId": "RouteGetAlertRuleGroup",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "FolderUID",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "Group",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/AlertRuleGroup"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": " Not found."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
@ -1920,15 +1950,15 @@
|
|||||||
"name": "Body",
|
"name": "Body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/AlertRuleGroup"
|
"$ref": "#/definitions/AlertRuleGroupMetadata"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "AlertRuleGroup",
|
"description": "AlertRuleGroupMetadata",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/AlertRuleGroup"
|
"$ref": "#/definitions/AlertRuleGroupMetadata"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
@ -2629,7 +2659,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AlertRuleGroup": {
|
"AlertRuleGroupMetadata": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"interval": {
|
"interval": {
|
||||||
@ -4917,8 +4947,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"URL": {
|
"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.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"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).",
|
||||||
"properties": {
|
"properties": {
|
||||||
"ForceQuery": {
|
"ForceQuery": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -5119,6 +5150,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"alertGroup": {
|
"alertGroup": {
|
||||||
|
"description": "AlertGroup alert group",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"alerts",
|
"alerts",
|
||||||
@ -5143,7 +5175,6 @@
|
|||||||
"$ref": "#/definitions/alertGroup"
|
"$ref": "#/definitions/alertGroup"
|
||||||
},
|
},
|
||||||
"alertGroups": {
|
"alertGroups": {
|
||||||
"description": "AlertGroups alert groups",
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/alertGroup"
|
"$ref": "#/definitions/alertGroup"
|
||||||
@ -5252,7 +5283,6 @@
|
|||||||
"$ref": "#/definitions/Duration"
|
"$ref": "#/definitions/Duration"
|
||||||
},
|
},
|
||||||
"gettableAlert": {
|
"gettableAlert": {
|
||||||
"description": "GettableAlert gettable alert",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"labels",
|
"labels",
|
||||||
@ -5309,7 +5339,6 @@
|
|||||||
"$ref": "#/definitions/gettableAlert"
|
"$ref": "#/definitions/gettableAlert"
|
||||||
},
|
},
|
||||||
"gettableAlerts": {
|
"gettableAlerts": {
|
||||||
"description": "GettableAlerts gettable alerts",
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/gettableAlert"
|
"$ref": "#/definitions/gettableAlert"
|
||||||
@ -5515,6 +5544,7 @@
|
|||||||
"$ref": "#/definitions/postableSilence"
|
"$ref": "#/definitions/postableSilence"
|
||||||
},
|
},
|
||||||
"receiver": {
|
"receiver": {
|
||||||
|
"description": "Receiver receiver",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"name"
|
"name"
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"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/models"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
@ -89,6 +90,32 @@ func (service *AlertRuleService) CreateAlertRule(ctx context.Context, rule model
|
|||||||
return rule, nil
|
return rule, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (service *AlertRuleService) GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (definitions.AlertRuleGroup, error) {
|
||||||
|
q := models.ListAlertRulesQuery{
|
||||||
|
OrgID: orgID,
|
||||||
|
NamespaceUIDs: []string{folder},
|
||||||
|
RuleGroup: group,
|
||||||
|
}
|
||||||
|
if err := service.ruleStore.ListAlertRules(ctx, &q); err != nil {
|
||||||
|
return definitions.AlertRuleGroup{}, err
|
||||||
|
}
|
||||||
|
if len(q.Result) == 0 {
|
||||||
|
return definitions.AlertRuleGroup{}, store.ErrAlertRuleGroupNotFound
|
||||||
|
}
|
||||||
|
res := definitions.AlertRuleGroup{
|
||||||
|
Title: q.Result[0].RuleGroup,
|
||||||
|
FolderUID: q.Result[0].NamespaceUID,
|
||||||
|
Interval: q.Result[0].IntervalSeconds,
|
||||||
|
Rules: []models.AlertRule{},
|
||||||
|
}
|
||||||
|
for _, r := range q.Result {
|
||||||
|
if r != nil {
|
||||||
|
res.Rules = append(res.Rules, *r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateRuleGroup will update the interval for all rules in the group.
|
// UpdateRuleGroup will update the interval for all rules in the group.
|
||||||
func (service *AlertRuleService) UpdateRuleGroup(ctx context.Context, orgID int64, namespaceUID string, ruleGroup string, interval int64) error {
|
func (service *AlertRuleService) UpdateRuleGroup(ctx context.Context, orgID int64, namespaceUID string, ruleGroup string, interval int64) error {
|
||||||
if err := models.ValidateRuleGroupInterval(interval, service.baseIntervalSeconds); err != nil {
|
if err := models.ValidateRuleGroupInterval(interval, service.baseIntervalSeconds); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user