register endpoint
This commit is contained in:
@@ -2,6 +2,8 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
@@ -9,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana-app-sdk/simple"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis"
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1"
|
||||
)
|
||||
|
||||
func New(cfg app.Config) (app.App, error) {
|
||||
@@ -19,6 +22,14 @@ func New(cfg app.Config) (app.App, error) {
|
||||
}
|
||||
}
|
||||
|
||||
customCfg, ok := cfg.SpecificConfig.(*Config)
|
||||
if !ok {
|
||||
return nil, errors.New("no configuration")
|
||||
}
|
||||
if err := customCfg.Validate(); err != nil {
|
||||
return nil, fmt.Errorf("invalid configuration: %w", err)
|
||||
}
|
||||
|
||||
c := simple.AppConfig{
|
||||
Name: "alerting.notification",
|
||||
KubeConfig: cfg.KubeConfig,
|
||||
@@ -30,6 +41,15 @@ func New(cfg app.Config) (app.App, error) {
|
||||
},
|
||||
},
|
||||
ManagedKinds: managedKinds,
|
||||
VersionedCustomRoutes: map[string]simple.AppVersionRouteHandlers{
|
||||
v0alpha1.APIVersion: {
|
||||
simple.AppVersionRoute{
|
||||
Namespaced: true,
|
||||
Path: "testing/integration",
|
||||
Method: "GET",
|
||||
}: customCfg.ReceiverTestingHandler.HandleReceiverTestingRequest,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
a, err := simple.NewApp(c)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ReceiverTestingHandler ReceiverTestingHandler
|
||||
}
|
||||
|
||||
func (c *Config) Validate() error {
|
||||
if c.ReceiverTestingHandler == nil {
|
||||
return errors.New("receiver testing handler is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReceiverTestingHandler interface {
|
||||
HandleReceiverTestingRequest(context.Context, app.CustomRouteResponseWriter, *app.CustomRouteRequest) error
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package receivertesting
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
)
|
||||
|
||||
func Authorize(ctx context.Context, ac accesscontrol.AccessControl, attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return authorizer.DecisionDeny, "valid user is required", err
|
||||
}
|
||||
eval := accesscontrol.EvalAny(
|
||||
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsWrite),
|
||||
accesscontrol.EvalPermission(accesscontrol.ActionAlertingReceiversTest),
|
||||
)
|
||||
ok, err := ac.Evaluate(ctx, user, eval)
|
||||
if ok {
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
return authorizer.DecisionDeny, "", err
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package receivertesting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-app-sdk/app"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1"
|
||||
_ "github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||
)
|
||||
|
||||
type ReceiverTestingHandler struct {
|
||||
testingSvc *notifier.ReceiverTestingSvc
|
||||
}
|
||||
|
||||
func New(ng *ngalert.AlertNG) *ReceiverTestingHandler {
|
||||
testingSvc := notifier.NewReceiverTestingSvc(ng.Api.ReceiverService, ng.MultiOrgAlertmanager, ng.SecretsService)
|
||||
return &ReceiverTestingHandler{
|
||||
testingSvc: testingSvc,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *ReceiverTestingHandler) HandleReceiverTestingRequest(ctx context.Context, w app.CustomRouteResponseWriter, r *app.CustomRouteRequest) error {
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var req v0alpha1.GetIntegrationTestRequestBody
|
||||
err = json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
writeBadRequest(w, err)
|
||||
}
|
||||
|
||||
alert := notifier.Alert{
|
||||
Labels: req.Alert.Labels,
|
||||
Annotations: req.Alert.Annotations,
|
||||
}
|
||||
|
||||
integration, secure, err := receiver.ConvertReceiverIntegrationToIntegration("test-receiver", v0alpha1.ReceiverIntegration(req.Integration))
|
||||
if err != nil {
|
||||
writeBadRequest(w, err)
|
||||
}
|
||||
receiverUID := ""
|
||||
if req.ReceiverRef != nil {
|
||||
receiverUID = *req.ReceiverRef
|
||||
}
|
||||
|
||||
result, err := p.testingSvc.Test(ctx, user, alert, receiverUID, integration, secure)
|
||||
if err != nil {
|
||||
// TODO better error handling
|
||||
writeBadRequest(w, err)
|
||||
}
|
||||
|
||||
response := v0alpha1.GetIntegrationTest{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
GetIntegrationTestBody: v0alpha1.GetIntegrationTestBody{
|
||||
Timestamp: time.Time(result.LastNotifyAttempt),
|
||||
Duration: result.LastNotifyAttemptDuration,
|
||||
},
|
||||
}
|
||||
if result.LastNotifyAttemptError != "" {
|
||||
response.GetIntegrationTestBody.Error = &result.LastNotifyAttemptError
|
||||
}
|
||||
|
||||
json, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal response: %w", err)
|
||||
}
|
||||
|
||||
w.WriteHeader(200)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write(json)
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeBadRequest(w app.CustomRouteResponseWriter, err error) {
|
||||
w.WriteHeader(400)
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/receiver/receivertesting"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/routingtree"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/templategroup"
|
||||
"github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/timeinterval"
|
||||
@@ -53,6 +54,10 @@ func RegisterAppInstaller(
|
||||
ng: ng,
|
||||
}
|
||||
|
||||
customCfg := notificationsApp.Config{
|
||||
ReceiverTestingHandler: receivertesting.New(ng),
|
||||
}
|
||||
|
||||
localManifest := apis.LocalManifest()
|
||||
|
||||
provider := simple.NewAppProvider(localManifest, nil, notificationsApp.New)
|
||||
@@ -60,7 +65,7 @@ func RegisterAppInstaller(
|
||||
appConfig := app.Config{
|
||||
KubeConfig: restclient.Config{}, // this will be overridden by the installer's InitializeApp method
|
||||
ManifestData: *localManifest.ManifestData,
|
||||
SpecificConfig: nil,
|
||||
SpecificConfig: &customCfg,
|
||||
}
|
||||
|
||||
i, err := appsdkapiserver.NewDefaultAppInstaller(provider, appConfig, &apis.GoTypeAssociator{})
|
||||
@@ -85,6 +90,8 @@ func (a AlertingNotificationsAppInstaller) GetAuthorizer() authorizer.Authorizer
|
||||
return receiver.Authorize(ctx, ac.NewReceiverAccess[*ngmodels.Receiver](authz, false), a)
|
||||
case routingtree.ResourceInfo.GroupResource().Resource:
|
||||
return routingtree.Authorize(ctx, authz, a)
|
||||
case "testing":
|
||||
return receivertesting.Authorize(ctx, authz, a)
|
||||
}
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user