mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Receivers API (read only endpoints) (#81751)
* Add single receiver method * Add receiver permissions * Add single/multi GET endpoints for receivers * Remove stable tag from time intervals See end of PR description here: https://github.com/grafana/grafana/pull/81672
This commit is contained in:
@@ -64,6 +64,7 @@ type API struct {
|
||||
StateManager *state.Manager
|
||||
AccessControl ac.AccessControl
|
||||
Policies *provisioning.NotificationPolicyService
|
||||
ReceiverService *notifier.ReceiverService
|
||||
ContactPointService *provisioning.ContactPointService
|
||||
Templates *provisioning.TemplateService
|
||||
MuteTimings *provisioning.MuteTimingService
|
||||
@@ -152,7 +153,11 @@ func (api *API) RegisterAPIEndpoints(m *metrics.API) {
|
||||
hist: api.Historian,
|
||||
}), m)
|
||||
|
||||
api.RegisterNotificationsApiEndpoints(NewNotificationsApi(api.MuteTimings), m)
|
||||
api.RegisterNotificationsApiEndpoints(NewNotificationsApi(&NotificationSrv{
|
||||
logger: logger,
|
||||
receiverService: api.ReceiverService,
|
||||
muteTimingService: api.MuteTimings,
|
||||
}), m)
|
||||
|
||||
// Inject upgrade endpoints if legacy alerting is enabled and the feature flag is enabled.
|
||||
if !api.Cfg.UnifiedAlerting.IsEnabled() && api.FeatureManager.IsEnabledGlobally(featuremgmt.FlagAlertingPreviewUpgrade) {
|
||||
|
||||
83
pkg/services/ngalert/api/api_notifications.go
Normal file
83
pkg/services/ngalert/api/api_notifications.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"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/notifier"
|
||||
)
|
||||
|
||||
type NotificationSrv struct {
|
||||
logger log.Logger
|
||||
receiverService ReceiverService
|
||||
muteTimingService MuteTimingService // defined in api_provisioning.go
|
||||
}
|
||||
|
||||
type ReceiverService interface {
|
||||
GetReceiver(ctx context.Context, q models.GetReceiverQuery, u identity.Requester) (definitions.GettableApiReceiver, error)
|
||||
GetReceivers(ctx context.Context, q models.GetReceiversQuery, u identity.Requester) ([]definitions.GettableApiReceiver, error)
|
||||
}
|
||||
|
||||
func (srv *NotificationSrv) RouteGetTimeInterval(c *contextmodel.ReqContext, name string) response.Response {
|
||||
muteTimeInterval, err := srv.muteTimingService.GetMuteTiming(c.Req.Context(), name, c.OrgID)
|
||||
if err != nil {
|
||||
return errorToResponse(err)
|
||||
}
|
||||
return response.JSON(http.StatusOK, muteTimeInterval) // TODO convert to timing interval
|
||||
}
|
||||
|
||||
func (srv *NotificationSrv) RouteGetTimeIntervals(c *contextmodel.ReqContext) response.Response {
|
||||
muteTimeIntervals, err := srv.muteTimingService.GetMuteTimings(c.Req.Context(), c.OrgID)
|
||||
if err != nil {
|
||||
return errorToResponse(err)
|
||||
}
|
||||
return response.JSON(http.StatusOK, muteTimeIntervals) // TODO convert to timing interval
|
||||
}
|
||||
|
||||
func (srv *NotificationSrv) RouteGetReceiver(c *contextmodel.ReqContext, name string) response.Response {
|
||||
q := models.GetReceiverQuery{
|
||||
OrgID: c.SignedInUser.OrgID,
|
||||
Name: name,
|
||||
Decrypt: c.QueryBool("decrypt"),
|
||||
}
|
||||
|
||||
receiver, err := srv.receiverService.GetReceiver(c.Req.Context(), q, c.SignedInUser)
|
||||
if err != nil {
|
||||
if errors.Is(err, notifier.ErrNotFound) {
|
||||
return ErrResp(http.StatusNotFound, err, "receiver not found")
|
||||
}
|
||||
if errors.Is(err, notifier.ErrPermissionDenied) {
|
||||
return ErrResp(http.StatusForbidden, err, "permission denied")
|
||||
}
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to get receiver")
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, receiver)
|
||||
}
|
||||
|
||||
func (srv *NotificationSrv) RouteGetReceivers(c *contextmodel.ReqContext) response.Response {
|
||||
q := models.GetReceiversQuery{
|
||||
OrgID: c.SignedInUser.OrgID,
|
||||
Names: c.QueryStrings("names"),
|
||||
Limit: c.QueryInt("limit"),
|
||||
Offset: c.QueryInt("offset"),
|
||||
Decrypt: c.QueryBool("decrypt"),
|
||||
}
|
||||
|
||||
receivers, err := srv.receiverService.GetReceivers(c.Req.Context(), q, c.SignedInUser)
|
||||
if err != nil {
|
||||
if errors.Is(err, notifier.ErrPermissionDenied) {
|
||||
return ErrResp(http.StatusForbidden, err, "permission denied")
|
||||
}
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to get receiver groups")
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, receivers)
|
||||
}
|
||||
188
pkg/services/ngalert/api/api_notifications_test.go
Normal file
188
pkg/services/ngalert/api/api_notifications_test.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/log/logtest"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
"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/notifier"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/tests/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
|
||||
am_config "github.com/prometheus/alertmanager/config"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRouteGetReceiver(t *testing.T) {
|
||||
fakeReceiverSvc := fakes.NewFakeReceiverService()
|
||||
|
||||
t.Run("returns expected model", func(t *testing.T) {
|
||||
expected := definitions.GettableApiReceiver{
|
||||
Receiver: am_config.Receiver{
|
||||
Name: "receiver1",
|
||||
},
|
||||
GettableGrafanaReceivers: definitions.GettableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definitions.GettableGrafanaReceiver{
|
||||
{
|
||||
UID: "uid1",
|
||||
Name: "receiver1",
|
||||
Type: "slack",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
fakeReceiverSvc.GetReceiverFn = func(ctx context.Context, q models.GetReceiverQuery, u identity.Requester) (definitions.GettableApiReceiver, error) {
|
||||
return expected, nil
|
||||
}
|
||||
handler := NewNotificationsApi(newNotificationSrv(fakeReceiverSvc))
|
||||
rc := testReqCtx("GET")
|
||||
resp := handler.handleRouteGetReceiver(&rc, "receiver1")
|
||||
require.Equal(t, http.StatusOK, resp.Status())
|
||||
json, err := json.Marshal(expected)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, json, resp.Body())
|
||||
})
|
||||
|
||||
t.Run("builds query from request context and url param", func(t *testing.T) {
|
||||
fakeReceiverSvc.GetReceiverFn = func(ctx context.Context, q models.GetReceiverQuery, u identity.Requester) (definitions.GettableApiReceiver, error) {
|
||||
return definitions.GettableApiReceiver{}, nil
|
||||
}
|
||||
handler := NewNotificationsApi(newNotificationSrv(fakeReceiverSvc))
|
||||
rc := testReqCtx("GET")
|
||||
rc.Context.Req.Form.Set("decrypt", "true")
|
||||
resp := handler.handleRouteGetReceiver(&rc, "receiver1")
|
||||
require.Equal(t, http.StatusOK, resp.Status())
|
||||
|
||||
call := fakeReceiverSvc.PopMethodCall()
|
||||
require.Equal(t, "GetReceiver", call.Method)
|
||||
expectedQ := models.GetReceiverQuery{
|
||||
Name: "receiver1",
|
||||
Decrypt: true,
|
||||
OrgID: 1,
|
||||
}
|
||||
require.Equal(t, expectedQ, call.Args[1])
|
||||
})
|
||||
|
||||
t.Run("should pass along not found response", func(t *testing.T) {
|
||||
fakeReceiverSvc.GetReceiverFn = func(ctx context.Context, q models.GetReceiverQuery, u identity.Requester) (definitions.GettableApiReceiver, error) {
|
||||
return definitions.GettableApiReceiver{}, notifier.ErrNotFound
|
||||
}
|
||||
handler := NewNotificationsApi(newNotificationSrv(fakeReceiverSvc))
|
||||
rc := testReqCtx("GET")
|
||||
resp := handler.handleRouteGetReceiver(&rc, "receiver1")
|
||||
require.Equal(t, http.StatusNotFound, resp.Status())
|
||||
})
|
||||
|
||||
t.Run("should pass along permission denied response", func(t *testing.T) {
|
||||
fakeReceiverSvc.GetReceiverFn = func(ctx context.Context, q models.GetReceiverQuery, u identity.Requester) (definitions.GettableApiReceiver, error) {
|
||||
return definitions.GettableApiReceiver{}, notifier.ErrPermissionDenied
|
||||
}
|
||||
handler := NewNotificationsApi(newNotificationSrv(fakeReceiverSvc))
|
||||
rc := testReqCtx("GET")
|
||||
resp := handler.handleRouteGetReceiver(&rc, "receiver1")
|
||||
require.Equal(t, http.StatusForbidden, resp.Status())
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouteGetReceivers(t *testing.T) {
|
||||
fakeReceiverSvc := fakes.NewFakeReceiverService()
|
||||
|
||||
t.Run("returns expected model", func(t *testing.T) {
|
||||
expected := []definitions.GettableApiReceiver{
|
||||
{
|
||||
Receiver: am_config.Receiver{
|
||||
Name: "receiver1",
|
||||
},
|
||||
GettableGrafanaReceivers: definitions.GettableGrafanaReceivers{
|
||||
GrafanaManagedReceivers: []*definitions.GettableGrafanaReceiver{
|
||||
{
|
||||
UID: "uid1",
|
||||
Name: "receiver1",
|
||||
Type: "slack",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
fakeReceiverSvc.GetReceiversFn = func(ctx context.Context, q models.GetReceiversQuery, u identity.Requester) ([]definitions.GettableApiReceiver, error) {
|
||||
return expected, nil
|
||||
}
|
||||
handler := NewNotificationsApi(newNotificationSrv(fakeReceiverSvc))
|
||||
rc := testReqCtx("GET")
|
||||
rc.Context.Req.Form.Set("names", "receiver1")
|
||||
resp := handler.handleRouteGetReceivers(&rc)
|
||||
require.Equal(t, http.StatusOK, resp.Status())
|
||||
json, err := json.Marshal(expected)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, json, resp.Body())
|
||||
})
|
||||
|
||||
t.Run("builds query from request context", func(t *testing.T) {
|
||||
fakeReceiverSvc.GetReceiversFn = func(ctx context.Context, q models.GetReceiversQuery, u identity.Requester) ([]definitions.GettableApiReceiver, error) {
|
||||
return []definitions.GettableApiReceiver{}, nil
|
||||
}
|
||||
handler := NewNotificationsApi(newNotificationSrv(fakeReceiverSvc))
|
||||
rc := testReqCtx("GET")
|
||||
rc.Context.Req.Form.Set("names", "receiver1")
|
||||
rc.Context.Req.Form.Add("names", "receiver2")
|
||||
rc.Context.Req.Form.Set("limit", "1")
|
||||
rc.Context.Req.Form.Set("offset", "2")
|
||||
rc.Context.Req.Form.Set("decrypt", "true")
|
||||
resp := handler.handleRouteGetReceivers(&rc)
|
||||
require.Equal(t, http.StatusOK, resp.Status())
|
||||
|
||||
call := fakeReceiverSvc.PopMethodCall()
|
||||
require.Equal(t, "GetReceivers", call.Method)
|
||||
expectedQ := models.GetReceiversQuery{
|
||||
Names: []string{"receiver1", "receiver2"},
|
||||
Limit: 1,
|
||||
Offset: 2,
|
||||
Decrypt: true,
|
||||
OrgID: 1,
|
||||
}
|
||||
require.Equal(t, expectedQ, call.Args[1])
|
||||
})
|
||||
|
||||
t.Run("should pass along permission denied response", func(t *testing.T) {
|
||||
fakeReceiverSvc.GetReceiversFn = func(ctx context.Context, q models.GetReceiversQuery, u identity.Requester) ([]definitions.GettableApiReceiver, error) {
|
||||
return nil, notifier.ErrPermissionDenied
|
||||
}
|
||||
handler := NewNotificationsApi(newNotificationSrv(fakeReceiverSvc))
|
||||
rc := testReqCtx("GET")
|
||||
resp := handler.handleRouteGetReceivers(&rc)
|
||||
require.Equal(t, http.StatusForbidden, resp.Status())
|
||||
})
|
||||
}
|
||||
|
||||
func newNotificationSrv(receiverService ReceiverService) *NotificationSrv {
|
||||
return &NotificationSrv{
|
||||
logger: log.NewNopLogger(),
|
||||
receiverService: receiverService,
|
||||
}
|
||||
}
|
||||
|
||||
func testReqCtx(method string) contextmodel.ReqContext {
|
||||
return contextmodel.ReqContext{
|
||||
Context: &web.Context{
|
||||
Req: &http.Request{
|
||||
Header: make(http.Header),
|
||||
Form: make(url.Values),
|
||||
},
|
||||
Resp: web.NewResponseWriter(method, httptest.NewRecorder()),
|
||||
},
|
||||
SignedInUser: &user.SignedInUser{
|
||||
OrgID: 1,
|
||||
},
|
||||
Logger: &logtest.Fake{},
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -1363,9 +1364,13 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("decrypt true without alert.provisioning.secrets:read permissions returns 403", func(t *testing.T) {
|
||||
recPermCheck := false
|
||||
env := createTestEnv(t, testConfig)
|
||||
env.ac = &recordingAccessControlFake{
|
||||
Callback: func(user *user.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
if strings.Contains(evaluator.String(), accesscontrol.ActionAlertingProvisioningReadSecrets) {
|
||||
recPermCheck = true
|
||||
}
|
||||
return false, nil
|
||||
},
|
||||
}
|
||||
@@ -1377,16 +1382,18 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
|
||||
|
||||
response := sut.RouteGetContactPointsExport(&rc)
|
||||
|
||||
require.True(t, recPermCheck)
|
||||
require.Equal(t, 403, response.Status())
|
||||
require.Len(t, env.ac.EvaluateRecordings, 1)
|
||||
require.Equal(t, accesscontrol.ActionAlertingProvisioningReadSecrets, env.ac.EvaluateRecordings[0].Evaluator.String())
|
||||
})
|
||||
|
||||
t.Run("decrypt true with admin returns 200", func(t *testing.T) {
|
||||
recPermCheck := false
|
||||
env := createTestEnv(t, testConfig)
|
||||
env.ac = &recordingAccessControlFake{
|
||||
Callback: func(user *user.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
|
||||
require.Equal(t, accesscontrol.ActionAlertingProvisioningReadSecrets, evaluator.String())
|
||||
if strings.Contains(evaluator.String(), accesscontrol.ActionAlertingProvisioningReadSecrets) {
|
||||
recPermCheck = true
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
}
|
||||
@@ -1399,9 +1406,8 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
|
||||
response := sut.RouteGetContactPointsExport(&rc)
|
||||
response.WriteTo(&rc)
|
||||
|
||||
require.True(t, recPermCheck)
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Len(t, env.ac.EvaluateRecordings, 1)
|
||||
require.Equal(t, accesscontrol.ActionAlertingProvisioningReadSecrets, env.ac.EvaluateRecordings[0].Evaluator.String())
|
||||
})
|
||||
|
||||
t.Run("json body content is as expected", func(t *testing.T) {
|
||||
|
||||
@@ -43,10 +43,27 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
ac.EvalPermission(ac.ActionAlertingRuleCreate, scope),
|
||||
ac.EvalPermission(ac.ActionAlertingRuleDelete, scope),
|
||||
)
|
||||
// Grafana rule state history paths
|
||||
|
||||
// Grafana rule state history paths
|
||||
case http.MethodGet + "/api/v1/rules/history":
|
||||
eval = ac.EvalPermission(ac.ActionAlertingRuleRead)
|
||||
|
||||
// Grafana receivers paths
|
||||
case http.MethodGet + "/api/v1/notifications/receivers":
|
||||
// additional authorization is done at the service level
|
||||
eval = ac.EvalAny(
|
||||
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversList),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversRead),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets),
|
||||
)
|
||||
case http.MethodGet + "/api/v1/notifications/receivers/{Name}":
|
||||
// TODO: scope to :Name
|
||||
eval = ac.EvalAny(
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversRead),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets),
|
||||
)
|
||||
|
||||
// Grafana unified alerting upgrade paths
|
||||
case http.MethodGet + "/api/v1/upgrade/org":
|
||||
return middleware.ReqOrgAdmin
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestAuthorize(t *testing.T) {
|
||||
}
|
||||
paths[p] = methods
|
||||
}
|
||||
require.Len(t, paths, 62)
|
||||
require.Len(t, paths, 64)
|
||||
|
||||
ac := acmock.New()
|
||||
api := &API{AccessControl: ac}
|
||||
|
||||
@@ -19,10 +19,20 @@ import (
|
||||
)
|
||||
|
||||
type NotificationsApi interface {
|
||||
RouteGetReceiver(*contextmodel.ReqContext) response.Response
|
||||
RouteGetReceivers(*contextmodel.ReqContext) response.Response
|
||||
RouteNotificationsGetTimeInterval(*contextmodel.ReqContext) response.Response
|
||||
RouteNotificationsGetTimeIntervals(*contextmodel.ReqContext) response.Response
|
||||
}
|
||||
|
||||
func (f *NotificationsApiHandler) RouteGetReceiver(ctx *contextmodel.ReqContext) response.Response {
|
||||
// Parse Path Parameters
|
||||
nameParam := web.Params(ctx.Req)[":name"]
|
||||
return f.handleRouteGetReceiver(ctx, nameParam)
|
||||
}
|
||||
func (f *NotificationsApiHandler) RouteGetReceivers(ctx *contextmodel.ReqContext) response.Response {
|
||||
return f.handleRouteGetReceivers(ctx)
|
||||
}
|
||||
func (f *NotificationsApiHandler) RouteNotificationsGetTimeInterval(ctx *contextmodel.ReqContext) response.Response {
|
||||
// Parse Path Parameters
|
||||
nameParam := web.Params(ctx.Req)[":name"]
|
||||
@@ -34,6 +44,30 @@ func (f *NotificationsApiHandler) RouteNotificationsGetTimeIntervals(ctx *contex
|
||||
|
||||
func (api *API) RegisterNotificationsApiEndpoints(srv NotificationsApi, m *metrics.API) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister) {
|
||||
group.Get(
|
||||
toMacaronPath("/api/v1/notifications/receivers/{Name}"),
|
||||
requestmeta.SetOwner(requestmeta.TeamAlerting),
|
||||
requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow),
|
||||
api.authorize(http.MethodGet, "/api/v1/notifications/receivers/{Name}"),
|
||||
metrics.Instrument(
|
||||
http.MethodGet,
|
||||
"/api/v1/notifications/receivers/{Name}",
|
||||
api.Hooks.Wrap(srv.RouteGetReceiver),
|
||||
m,
|
||||
),
|
||||
)
|
||||
group.Get(
|
||||
toMacaronPath("/api/v1/notifications/receivers"),
|
||||
requestmeta.SetOwner(requestmeta.TeamAlerting),
|
||||
requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow),
|
||||
api.authorize(http.MethodGet, "/api/v1/notifications/receivers"),
|
||||
metrics.Instrument(
|
||||
http.MethodGet,
|
||||
"/api/v1/notifications/receivers",
|
||||
api.Hooks.Wrap(srv.RouteGetReceivers),
|
||||
m,
|
||||
),
|
||||
)
|
||||
group.Get(
|
||||
toMacaronPath("/api/v1/notifications/time-intervals/{name}"),
|
||||
requestmeta.SetOwner(requestmeta.TeamAlerting),
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
)
|
||||
|
||||
type NotificationsApiHandler struct {
|
||||
muteTimingService MuteTimingService
|
||||
notificationSrv *NotificationSrv
|
||||
}
|
||||
|
||||
func NewNotificationsApi(muteTimingService MuteTimingService) NotificationsApi {
|
||||
func NewNotificationsApi(notificationSrv *NotificationSrv) *NotificationsApiHandler {
|
||||
return &NotificationsApiHandler{
|
||||
muteTimingService: muteTimingService,
|
||||
notificationSrv: notificationSrv,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *NotificationsApiHandler) handleRouteNotificationsGetTimeInterval(ctx *contextmodel.ReqContext, name string) response.Response {
|
||||
model, err := f.muteTimingService.GetMuteTiming(ctx.Req.Context(), name, ctx.OrgID)
|
||||
if err != nil {
|
||||
return errorToResponse(err)
|
||||
}
|
||||
return response.JSON(http.StatusOK, model) // TODO convert to timing interval
|
||||
return f.notificationSrv.RouteGetTimeInterval(ctx, name)
|
||||
}
|
||||
|
||||
func (f *NotificationsApiHandler) handleRouteNotificationsGetTimeIntervals(ctx *contextmodel.ReqContext) response.Response {
|
||||
model, err := f.muteTimingService.GetMuteTimings(ctx.Req.Context(), ctx.OrgID)
|
||||
if err != nil {
|
||||
return errorToResponse(err)
|
||||
}
|
||||
return response.JSON(http.StatusOK, model) // TODO convert to timing interval
|
||||
return f.notificationSrv.RouteGetTimeIntervals(ctx)
|
||||
}
|
||||
|
||||
func (f *NotificationsApiHandler) handleRouteGetReceiver(ctx *contextmodel.ReqContext, name string) response.Response {
|
||||
return f.notificationSrv.RouteGetReceiver(ctx, name)
|
||||
}
|
||||
|
||||
func (f *NotificationsApiHandler) handleRouteGetReceivers(ctx *contextmodel.ReqContext) response.Response {
|
||||
return f.notificationSrv.RouteGetReceivers(ctx)
|
||||
}
|
||||
|
||||
@@ -4511,7 +4511,6 @@
|
||||
"type": "object"
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"properties": {
|
||||
"alerts": {
|
||||
"description": "alerts",
|
||||
@@ -4535,7 +4534,6 @@
|
||||
"type": "object"
|
||||
},
|
||||
"alertGroups": {
|
||||
"description": "AlertGroups alert groups",
|
||||
"items": {
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
},
|
||||
@@ -4695,13 +4693,13 @@
|
||||
"type": "object"
|
||||
},
|
||||
"gettableAlerts": {
|
||||
"description": "GettableAlerts gettable alerts",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gettableAlert"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"gettableSilence": {
|
||||
"description": "GettableSilence gettable silence",
|
||||
"properties": {
|
||||
"comment": {
|
||||
"description": "comment",
|
||||
@@ -4750,6 +4748,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"gettableSilences": {
|
||||
"description": "GettableSilences gettable silences",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gettableSilence"
|
||||
},
|
||||
@@ -4900,7 +4899,6 @@
|
||||
"type": "array"
|
||||
},
|
||||
"postableSilence": {
|
||||
"description": "PostableSilence postable silence",
|
||||
"properties": {
|
||||
"comment": {
|
||||
"description": "comment",
|
||||
@@ -5057,61 +5055,6 @@
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/v1/notifications/time-intervals": {
|
||||
"get": {
|
||||
"description": "Get all the time intervals",
|
||||
"operationId": "RouteNotificationsGetTimeIntervals",
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/GetAllIntervalsResponse"
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ForbiddenError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"notifications"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/notifications/time-intervals/{name}": {
|
||||
"get": {
|
||||
"operationId": "RouteNotificationsGetTimeInterval",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Time interval name",
|
||||
"in": "path",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/GetIntervalsByNameResponse"
|
||||
},
|
||||
"403": {
|
||||
"description": "ForbiddenError",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ForbiddenError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "NotFound",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NotFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Get a time interval by name.",
|
||||
"tags": [
|
||||
"notifications"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/provisioning/alert-rules": {
|
||||
"get": {
|
||||
"operationId": "RouteGetAlertRules",
|
||||
@@ -6168,6 +6111,21 @@
|
||||
"$ref": "#/definitions/GettableTimeIntervals"
|
||||
}
|
||||
},
|
||||
"GetReceiverResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/GettableApiReceiver"
|
||||
}
|
||||
},
|
||||
"GetReceiversResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/GettableApiReceiver"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"GettableHistoricUserConfigs": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
|
||||
56
pkg/services/ngalert/api/tooling/definitions/receivers.go
Normal file
56
pkg/services/ngalert/api/tooling/definitions/receivers.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package definitions
|
||||
|
||||
// swagger:route GET /v1/notifications/receivers/{Name} notifications RouteGetReceiver
|
||||
//
|
||||
// Get a receiver by name.
|
||||
//
|
||||
// Responses:
|
||||
// 200: GetReceiverResponse
|
||||
// 403: PermissionDenied
|
||||
// 404: NotFound
|
||||
|
||||
// swagger:route GET /v1/notifications/receivers notifications RouteGetReceivers
|
||||
//
|
||||
// Get all receivers.
|
||||
//
|
||||
// Responses:
|
||||
// 200: GetReceiversResponse
|
||||
// 403: PermissionDenied
|
||||
|
||||
// swagger:parameters RouteGetReceiver
|
||||
type GetReceiverParams struct {
|
||||
// in:path
|
||||
// required: true
|
||||
Name string `json:"name"`
|
||||
// in:query
|
||||
// required: false
|
||||
Decrypt bool `json:"decrypt"`
|
||||
}
|
||||
|
||||
// swagger:parameters RouteGetReceivers
|
||||
type GetReceiversParams struct {
|
||||
// in:query
|
||||
// required: false
|
||||
Names []string `json:"names"`
|
||||
// in:query
|
||||
// required: false
|
||||
Limit int `json:"limit"`
|
||||
// in:query
|
||||
// required: false
|
||||
Offset int `json:"offset"`
|
||||
// in:query
|
||||
// required: false
|
||||
Decrypt bool `json:"decrypt"`
|
||||
}
|
||||
|
||||
// swagger:response GetReceiverResponse
|
||||
type GetReceiverResponse struct {
|
||||
// in:body
|
||||
Body GettableApiReceiver
|
||||
}
|
||||
|
||||
// swagger:response GetReceiversResponse
|
||||
type GetReceiversResponse struct {
|
||||
// in:body
|
||||
Body []GettableApiReceiver
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package definitions
|
||||
|
||||
// swagger:route GET /v1/notifications/time-intervals notifications stable RouteNotificationsGetTimeIntervals
|
||||
// swagger:route GET /v1/notifications/time-intervals notifications RouteNotificationsGetTimeIntervals
|
||||
//
|
||||
// Get all the time intervals
|
||||
//
|
||||
@@ -8,7 +8,7 @@ package definitions
|
||||
// 200: GetAllIntervalsResponse
|
||||
// 403: ForbiddenError
|
||||
|
||||
// swagger:route GET /v1/notifications/time-intervals/{name} notifications stable RouteNotificationsGetTimeInterval
|
||||
// swagger:route GET /v1/notifications/time-intervals/{name} notifications RouteNotificationsGetTimeInterval
|
||||
//
|
||||
// Get a time interval by name.
|
||||
//
|
||||
@@ -17,7 +17,7 @@ package definitions
|
||||
// 404: NotFound
|
||||
// 403: ForbiddenError
|
||||
|
||||
// swagger:parameters stable RouteNotificationsGetTimeInterval
|
||||
// swagger:parameters RouteNotificationsGetTimeInterval
|
||||
type RouteTimeIntervalNameParam struct {
|
||||
// Time interval name
|
||||
// in:path
|
||||
|
||||
@@ -4512,7 +4512,6 @@
|
||||
"type": "object"
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"properties": {
|
||||
"alerts": {
|
||||
"description": "alerts",
|
||||
@@ -4536,6 +4535,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"alertGroups": {
|
||||
"description": "AlertGroups alert groups",
|
||||
"items": {
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
},
|
||||
@@ -4640,6 +4640,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"gettableAlert": {
|
||||
"description": "GettableAlert gettable alert",
|
||||
"properties": {
|
||||
"annotations": {
|
||||
"$ref": "#/definitions/labelSet"
|
||||
@@ -4701,7 +4702,6 @@
|
||||
"type": "array"
|
||||
},
|
||||
"gettableSilence": {
|
||||
"description": "GettableSilence gettable silence",
|
||||
"properties": {
|
||||
"comment": {
|
||||
"description": "comment",
|
||||
@@ -4756,6 +4756,7 @@
|
||||
"type": "array"
|
||||
},
|
||||
"integration": {
|
||||
"description": "Integration integration",
|
||||
"properties": {
|
||||
"lastNotifyAttempt": {
|
||||
"description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.\nFormat: date-time",
|
||||
@@ -4936,7 +4937,6 @@
|
||||
"type": "object"
|
||||
},
|
||||
"receiver": {
|
||||
"description": "Receiver receiver",
|
||||
"properties": {
|
||||
"active": {
|
||||
"description": "active",
|
||||
@@ -7046,6 +7046,86 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/notifications/receivers": {
|
||||
"get": {
|
||||
"operationId": "RouteGetReceivers",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": "names",
|
||||
"type": "array"
|
||||
},
|
||||
{
|
||||
"format": "int64",
|
||||
"in": "query",
|
||||
"name": "limit",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"format": "int64",
|
||||
"in": "query",
|
||||
"name": "offset",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "decrypt",
|
||||
"type": "boolean"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/GetReceiversResponse"
|
||||
},
|
||||
"403": {
|
||||
"description": "PermissionDenied",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/PermissionDenied"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Get all receivers.",
|
||||
"tags": [
|
||||
"notifications"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/notifications/receivers/{Name}": {
|
||||
"get": {
|
||||
"operationId": "RouteGetReceiver",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "decrypt",
|
||||
"type": "boolean"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/GetReceiverResponse"
|
||||
},
|
||||
"404": {
|
||||
"description": "NotFound",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NotFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Get a receiver by name.",
|
||||
"tags": [
|
||||
"notifications"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/notifications/time-intervals": {
|
||||
"get": {
|
||||
"description": "Get all the time intervals",
|
||||
@@ -8507,6 +8587,21 @@
|
||||
"$ref": "#/definitions/GettableTimeIntervals"
|
||||
}
|
||||
},
|
||||
"GetReceiverResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/GettableApiReceiver"
|
||||
}
|
||||
},
|
||||
"GetReceiversResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/GettableApiReceiver"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"GettableHistoricUserConfigs": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
|
||||
@@ -2007,12 +2007,91 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/notifications/receivers": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"notifications"
|
||||
],
|
||||
"summary": "Get all receivers.",
|
||||
"operationId": "RouteGetReceivers",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": "names",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "decrypt",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/GetReceiversResponse"
|
||||
},
|
||||
"403": {
|
||||
"description": "PermissionDenied",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/PermissionDenied"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/notifications/receivers/{Name}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"notifications"
|
||||
],
|
||||
"summary": "Get a receiver by name.",
|
||||
"operationId": "RouteGetReceiver",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "decrypt",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/GetReceiverResponse"
|
||||
},
|
||||
"404": {
|
||||
"description": "NotFound",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NotFound"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/notifications/time-intervals": {
|
||||
"get": {
|
||||
"description": "Get all the time intervals",
|
||||
"tags": [
|
||||
"notifications",
|
||||
"stable"
|
||||
"notifications"
|
||||
],
|
||||
"operationId": "RouteNotificationsGetTimeIntervals",
|
||||
"responses": {
|
||||
@@ -2031,8 +2110,7 @@
|
||||
"/v1/notifications/time-intervals/{name}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"notifications",
|
||||
"stable"
|
||||
"notifications"
|
||||
],
|
||||
"summary": "Get a time interval by name.",
|
||||
"operationId": "RouteNotificationsGetTimeInterval",
|
||||
@@ -7994,7 +8072,6 @@
|
||||
}
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"alerts",
|
||||
@@ -8019,6 +8096,7 @@
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
},
|
||||
"alertGroups": {
|
||||
"description": "AlertGroups alert groups",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
@@ -8124,6 +8202,7 @@
|
||||
}
|
||||
},
|
||||
"gettableAlert": {
|
||||
"description": "GettableAlert gettable alert",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"labels",
|
||||
@@ -8187,7 +8266,6 @@
|
||||
"$ref": "#/definitions/gettableAlerts"
|
||||
},
|
||||
"gettableSilence": {
|
||||
"description": "GettableSilence gettable silence",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"comment",
|
||||
@@ -8244,6 +8322,7 @@
|
||||
"$ref": "#/definitions/gettableSilences"
|
||||
},
|
||||
"integration": {
|
||||
"description": "Integration integration",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
@@ -8426,7 +8505,6 @@
|
||||
"$ref": "#/definitions/postableSilence"
|
||||
},
|
||||
"receiver": {
|
||||
"description": "Receiver receiver",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"active",
|
||||
@@ -8557,6 +8635,21 @@
|
||||
"$ref": "#/definitions/GettableTimeIntervals"
|
||||
}
|
||||
},
|
||||
"GetReceiverResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/GettableApiReceiver"
|
||||
}
|
||||
},
|
||||
"GetReceiversResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/GettableApiReceiver"
|
||||
}
|
||||
}
|
||||
},
|
||||
"GettableHistoricUserConfigs": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
|
||||
Reference in New Issue
Block a user