diff --git a/pkg/services/apiserver/appinstaller/installer.go b/pkg/services/apiserver/appinstaller/installer.go index 9817f7513bc..e5ad34168c4 100644 --- a/pkg/services/apiserver/appinstaller/installer.go +++ b/pkg/services/apiserver/appinstaller/installer.go @@ -2,6 +2,7 @@ package appinstaller import ( "context" + "errors" "fmt" "maps" "time" @@ -11,6 +12,7 @@ import ( "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" genericapiserver "k8s.io/apiserver/pkg/server" @@ -58,27 +60,31 @@ func AddToScheme( return additionalGroupVersions, nil } -// RegisterAdmissionPlugins registers admission plugins for app installers -func RegisterAdmissionPlugins( - ctx context.Context, +// RegisterAdmission combines the existing admission control from builders. +func RegisterAdmission( + existingAdmission admission.Interface, appInstallers []appsdkapiserver.AppInstaller, - options *grafanaapiserveroptions.Options, -) error { - logger := logging.FromContext(ctx) +) (admission.Interface, error) { + controllers := []admission.Interface{} for _, installer := range appInstallers { - plugin := installer.AdmissionPlugin() - if plugin != nil { - md := installer.ManifestData() - if md == nil { - return fmt.Errorf("manifest is not initialized for installer for GroupVersions %v", installer.GroupVersions()) - } - pluginName := md.AppName + " admission" - options.RecommendedOptions.Admission.Plugins.Register(pluginName, plugin) - logger.Info("Registered admission plugin", "app", md.AppName) + factory := installer.AdmissionPlugin() + if factory == nil { + continue } + + admissionInterface, err := factory(nil) + if err != nil { + return nil, fmt.Errorf("failed to create admission plugin: %w", err) + } + controllers = append(controllers, admissionInterface) } - return nil + + if existingAdmission != nil { + controllers = append(controllers, existingAdmission) + } + + return admission.NewChainHandler(controllers...), nil } type AuthorizerRegistrar interface { @@ -179,7 +185,7 @@ func createPostStartHook( logger := logging.FromContext(hookContext.Context) logger.Debug("Initializing app", "app", installer.ManifestData().AppName) - if err := installer.InitializeApp(*hookContext.LoopbackClientConfig); err != nil { + if err := installer.InitializeApp(*hookContext.LoopbackClientConfig); err != nil && !errors.Is(err, appsdkapiserver.ErrAppAlreadyInitialized) { logger.Error("Failed to initialize app", "app", installer.ManifestData().AppName, "error", err) return fmt.Errorf("failed to initialize app %s: %w", installer.ManifestData().AppName, err) } diff --git a/pkg/services/apiserver/service.go b/pkg/services/apiserver/service.go index 31777f82a65..23d5b63e20f 100644 --- a/pkg/services/apiserver/service.go +++ b/pkg/services/apiserver/service.go @@ -2,6 +2,7 @@ package apiserver import ( "context" + "errors" "fmt" "net/http" "path" @@ -291,11 +292,6 @@ func (s *service) start(ctx context.Context) error { o := grafanaapiserveroptions.NewOptions(s.codecs.LegacyCodec(groupVersions...)) - // Register admission plugins from app installers after options are created - if err := appinstaller.RegisterAdmissionPlugins(ctx, s.appInstallers, o); err != nil { - return err - } - // Register authorizers from app installers appinstaller.RegisterAuthorizers(ctx, s.appInstallers, s.authorizer) @@ -367,6 +363,14 @@ func (s *service) start(ctx context.Context) error { return err } + serverConfig.AdmissionControl, err = appinstaller.RegisterAdmission( + serverConfig.AdmissionControl, + s.appInstallers, + ) + if err != nil { + return err + } + notFoundHandler := notfoundhandler.New(s.codecs, genericapifilters.NoMuxAndDiscoveryIncompleteKey) if err := appinstaller.RegisterPostStartHooks(s.appInstallers, serverConfig); err != nil { @@ -469,6 +473,13 @@ func (s *service) start(ctx context.Context) error { // used by local clients to make requests to the server s.restConfig = runningServer.LoopbackClientConfig + for _, installer := range s.appInstallers { + err := installer.InitializeApp(*s.restConfig) + if err != nil && !errors.Is(err, appsdkapiserver.ErrAppAlreadyInitialized) { + return err + } + } + return nil }