K8s: Add API Enablement for apps (#109019)
This commit is contained in:
@@ -8,17 +8,19 @@ import (
|
||||
|
||||
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
grafanaapiserveroptions "github.com/grafana/grafana/pkg/services/apiserver/options"
|
||||
"github.com/grafana/grafana/pkg/storage/legacysql/dualwrite"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
serverstore "k8s.io/apiserver/pkg/server/storage"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
grafanaapiserveroptions "github.com/grafana/grafana/pkg/services/apiserver/options"
|
||||
)
|
||||
|
||||
type LegacyStorageGetterFunc func(schema.GroupVersionResource) grafanarest.Storage
|
||||
@@ -31,13 +33,6 @@ type AuthorizerProvider interface {
|
||||
GetAuthorizer() authorizer.Authorizer
|
||||
}
|
||||
|
||||
type APIEnablementProvider interface {
|
||||
// Do not implement this unless you have special circumstances! This is a list of resources that are allowed to be accessed in v0alpha1,
|
||||
// to prevent accidental exposure of experimental APIs. While developing, use the feature flag `grafanaAPIServerWithExperimentalAPIs`.
|
||||
// And then, when you're ready to expose this to the end user, go to v1beta1 instead.
|
||||
GetAllowedV0Alpha1Resources() []string
|
||||
}
|
||||
|
||||
type AppInstallerConfig struct {
|
||||
CustomConfig any
|
||||
AllowedV0Alpha1Resources []string
|
||||
@@ -132,6 +127,7 @@ func InstallAPIs(
|
||||
dualWriteService dualwrite.Service,
|
||||
dualWriterMetrics *grafanarest.DualWriterMetrics,
|
||||
builderMetrics *builder.BuilderMetrics,
|
||||
apiResourceConfig *serverstore.ResourceConfig,
|
||||
) error {
|
||||
logger := logging.FromContext(ctx)
|
||||
for _, installer := range appInstallers {
|
||||
@@ -148,6 +144,7 @@ func InstallAPIs(
|
||||
dualWriteService: dualWriteService,
|
||||
dualWriterMetrics: dualWriterMetrics,
|
||||
builderMetrics: builderMetrics,
|
||||
apiResourceConfig: apiResourceConfig,
|
||||
}
|
||||
if err := installer.InstallAPIs(wrapper, restOpsGetter); err != nil {
|
||||
return fmt.Errorf("failed to install APIs for app %s: %w", installer.ManifestData().AppName, err)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package appinstaller
|
||||
|
||||
import (
|
||||
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
)
|
||||
|
||||
func NewAPIResourceConfig(installers []appsdkapiserver.AppInstaller) *serverstorage.ResourceConfig {
|
||||
ret := serverstorage.NewResourceConfig()
|
||||
enable := []schema.GroupVersion{}
|
||||
disable := []schema.GroupVersion{}
|
||||
|
||||
for _, installer := range installers {
|
||||
for _, version := range installer.ManifestData().Versions {
|
||||
gv := schema.GroupVersion{
|
||||
Group: installer.ManifestData().Group,
|
||||
Version: version.Name,
|
||||
}
|
||||
if version.Served {
|
||||
enable = append(enable, gv)
|
||||
} else {
|
||||
disable = append(disable, gv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret.EnableVersions(enable...)
|
||||
ret.DisableVersions(disable...)
|
||||
|
||||
return ret
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
genericrest "k8s.io/apiserver/pkg/registry/rest"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
|
||||
appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||
"github.com/grafana/grafana-app-sdk/logging"
|
||||
@@ -35,6 +36,7 @@ type serverWrapper struct {
|
||||
dualWriteService dualwrite.Service
|
||||
dualWriterMetrics *grafanarest.DualWriterMetrics
|
||||
builderMetrics *builder.BuilderMetrics
|
||||
apiResourceConfig *serverstorage.ResourceConfig
|
||||
}
|
||||
|
||||
func (s *serverWrapper) InstallAPIGroup(apiGroupInfo *genericapiserver.APIGroupInfo) error {
|
||||
@@ -50,6 +52,12 @@ func (s *serverWrapper) InstallAPIGroup(apiGroupInfo *genericapiserver.APIGroupI
|
||||
Group: s.installer.ManifestData().Group,
|
||||
Resource: resource,
|
||||
}
|
||||
gvr := gr.WithVersion(v)
|
||||
if s.apiResourceConfig != nil && !s.apiResourceConfig.ResourceEnabled(gvr) {
|
||||
log.Debug("Skipping storage for disabled resource", "gvr", gvr.String(), "storagePath", storagePath)
|
||||
delete(apiGroupInfo.VersionedResourcesStorageMap[v], storagePath)
|
||||
continue
|
||||
}
|
||||
storage := s.configureStorage(gr, dualWriteSupported, restStorage)
|
||||
if unifiedStorage, ok := storage.(grafanarest.Storage); ok && dualWriteSupported {
|
||||
log.Debug("Configuring dual writer for storage", "resource", gr.String(), "version", v, "storagePath", storagePath)
|
||||
|
||||
@@ -39,6 +39,13 @@ func applyGrafanaConfig(cfg *setting.Cfg, features featuremgmt.FeatureToggles, o
|
||||
|
||||
apiserverCfg := cfg.SectionWithEnvOverrides("grafana-apiserver")
|
||||
|
||||
runtimeConfig := apiserverCfg.Key("runtime_config").String()
|
||||
if runtimeConfig != "" {
|
||||
if err := o.APIEnablementOptions.RuntimeConfig.Set(runtimeConfig); err != nil {
|
||||
return fmt.Errorf("failed to set runtime config: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
o.RecommendedOptions.Etcd.StorageConfig.Transport.ServerList = apiserverCfg.Key("etcd_servers").Strings(",")
|
||||
|
||||
o.RecommendedOptions.SecureServing.BindAddress = ip
|
||||
|
||||
@@ -21,6 +21,7 @@ const defaultEtcdPathPrefix = "/registry/grafana.app"
|
||||
|
||||
type Options struct {
|
||||
RecommendedOptions *genericoptions.RecommendedOptions
|
||||
APIEnablementOptions *genericoptions.APIEnablementOptions
|
||||
GrafanaAggregatorOptions *GrafanaAggregatorOptions
|
||||
StorageOptions *StorageOptions
|
||||
ExtraOptions *ExtraOptions
|
||||
@@ -30,6 +31,7 @@ type Options struct {
|
||||
func NewOptions(codec runtime.Codec) *Options {
|
||||
return &Options{
|
||||
RecommendedOptions: NewRecommendedOptions(codec),
|
||||
APIEnablementOptions: genericoptions.NewAPIEnablementOptions(),
|
||||
GrafanaAggregatorOptions: NewGrafanaAggregatorOptions(),
|
||||
StorageOptions: NewStorageOptions(),
|
||||
ExtraOptions: NewExtraOptions(),
|
||||
@@ -38,6 +40,7 @@ func NewOptions(codec runtime.Codec) *Options {
|
||||
|
||||
func (o *Options) AddFlags(fs *pflag.FlagSet) {
|
||||
o.RecommendedOptions.AddFlags(fs)
|
||||
o.APIEnablementOptions.AddFlags(fs)
|
||||
o.GrafanaAggregatorOptions.AddFlags(fs)
|
||||
o.StorageOptions.AddFlags(fs)
|
||||
o.ExtraOptions.AddFlags(fs)
|
||||
|
||||
@@ -304,11 +304,19 @@ func (s *service) start(ctx context.Context) error {
|
||||
return errs[0]
|
||||
}
|
||||
|
||||
if errs := o.APIEnablementOptions.Validate(s.scheme); len(errs) != 0 {
|
||||
return errs[0]
|
||||
}
|
||||
|
||||
serverConfig := genericapiserver.NewRecommendedConfig(s.codecs)
|
||||
if err := o.ApplyTo(serverConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := o.APIEnablementOptions.ApplyTo(&serverConfig.Config, appinstaller.NewAPIResourceConfig(s.appInstallers), s.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverConfig.Authorization.Authorizer = s.authorizer
|
||||
serverConfig.Authentication.Authenticator = authenticator.NewAuthenticator(serverConfig.Authentication.Authenticator)
|
||||
serverConfig.TracerProvider = s.tracing.GetTracerProvider()
|
||||
@@ -395,6 +403,7 @@ func (s *service) start(ctx context.Context) error {
|
||||
s.storageStatus,
|
||||
s.dualWriterMetrics,
|
||||
s.builderMetrics,
|
||||
serverConfig.MergedResourceConfig,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user