mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Provisioning: Setup server and storage (#99757)
feat: setup server and storage This simply sets up the API server and its storage for `provisioning.grafana.app`. Features will be added eventually.
This commit is contained in:
parent
3c0383f0d5
commit
0c120db84d
@ -29,3 +29,9 @@ func NewRegistryStore(scheme *runtime.Scheme, resourceInfo utils.ResourceInfo, o
|
||||
}
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func NewRegistryStatusStore(scheme *runtime.Scheme, specStore *registry.Store) *StatusREST {
|
||||
gv := specStore.New().GetObjectKind().GroupVersionKind().GroupVersion()
|
||||
strategy := NewStatusStrategy(scheme, gv)
|
||||
return NewStatusREST(specStore, strategy)
|
||||
}
|
||||
|
@ -26,7 +26,10 @@ type StatusREST struct {
|
||||
store *genericregistry.Store
|
||||
}
|
||||
|
||||
var _ = rest.Patcher(&StatusREST{})
|
||||
var (
|
||||
_ rest.Patcher = (*StatusREST)(nil)
|
||||
_ rest.Storage = (*StatusREST)(nil)
|
||||
)
|
||||
|
||||
// New creates a new DataPlaneService object.
|
||||
func (r *StatusREST) New() runtime.Object {
|
||||
|
160
pkg/registry/apis/provisioning/register.go
Normal file
160
pkg/registry/apis/provisioning/register.go
Normal file
@ -0,0 +1,160 @@
|
||||
package provisioning
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
)
|
||||
|
||||
var (
|
||||
_ builder.APIGroupBuilder = (*APIBuilder)(nil)
|
||||
)
|
||||
|
||||
type APIBuilder struct{}
|
||||
|
||||
// NewAPIBuilder creates an API builder.
|
||||
// It avoids anything that is core to Grafana, such that it can be used in a multi-tenant service down the line.
|
||||
// This means there are no hidden dependencies, and no use of e.g. *settings.Cfg.
|
||||
func NewAPIBuilder() *APIBuilder {
|
||||
return &APIBuilder{}
|
||||
}
|
||||
|
||||
// RegisterAPIService returns an API builder, from [NewAPIBuilder]. It is called by Wire.
|
||||
// This function happily uses services core to Grafana, and does not need to be multi-tenancy-compatible.
|
||||
func RegisterAPIService(
|
||||
features featuremgmt.FeatureToggles,
|
||||
apiregistration builder.APIRegistrar,
|
||||
) (*APIBuilder, error) {
|
||||
if !features.IsEnabledGlobally(featuremgmt.FlagProvisioning) &&
|
||||
!features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) {
|
||||
return nil, nil // skip registration unless opting into experimental apis OR the feature specifically
|
||||
}
|
||||
|
||||
builder := NewAPIBuilder()
|
||||
apiregistration.RegisterAPI(builder)
|
||||
return builder, nil
|
||||
}
|
||||
|
||||
func (b *APIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
return authorizer.AuthorizerFunc(
|
||||
func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
// TODO: Implement a webhook authoriser somehow.
|
||||
|
||||
// fallback to the standard authorizer
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
})
|
||||
}
|
||||
|
||||
func (b *APIBuilder) GetGroupVersion() schema.GroupVersion {
|
||||
return provisioning.SchemeGroupVersion
|
||||
}
|
||||
|
||||
func (b *APIBuilder) InstallSchema(scheme *runtime.Scheme) error {
|
||||
err := provisioning.AddToScheme(scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This is required for --server-side apply
|
||||
err = provisioning.AddKnownTypes(provisioning.InternalGroupVersion, scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
metav1.AddToGroupVersion(scheme, provisioning.SchemeGroupVersion)
|
||||
// Only 1 version (for now?)
|
||||
return scheme.SetVersionPriority(provisioning.SchemeGroupVersion)
|
||||
}
|
||||
|
||||
func (b *APIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, opts builder.APIGroupOptions) error {
|
||||
repositoryStorage, err := grafanaregistry.NewRegistryStore(opts.Scheme, provisioning.RepositoryResourceInfo, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create repository storage: %w", err)
|
||||
}
|
||||
|
||||
repositoryStatusStorage := grafanaregistry.NewRegistryStatusStore(opts.Scheme, repositoryStorage)
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
storage[provisioning.RepositoryResourceInfo.StoragePath()] = repositoryStorage
|
||||
storage[provisioning.RepositoryResourceInfo.StoragePath("status")] = repositoryStatusStorage
|
||||
apiGroupInfo.VersionedResourcesStorageMap[provisioning.VERSION] = storage
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *APIBuilder) Mutate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||
obj := a.GetObject()
|
||||
|
||||
if obj == nil || a.GetOperation() == admission.Connect {
|
||||
return nil // This is normal for sub-resource
|
||||
}
|
||||
|
||||
r, ok := obj.(*provisioning.Repository)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected repository configuration")
|
||||
}
|
||||
|
||||
// TODO: Do something based on the resource we got.
|
||||
_ = r
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *APIBuilder) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||
obj := a.GetObject()
|
||||
if obj == nil || a.GetOperation() == admission.Connect {
|
||||
return nil // This is normal for sub-resource
|
||||
}
|
||||
|
||||
var list field.ErrorList
|
||||
// TODO: Fill the list with validation errors.
|
||||
|
||||
if len(list) > 0 {
|
||||
return apierrors.NewInvalid(
|
||||
provisioning.RepositoryResourceInfo.GroupVersionKind().GroupKind(),
|
||||
a.GetName(), list)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *APIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {
|
||||
return provisioning.GetOpenAPIDefinitions
|
||||
}
|
||||
|
||||
func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartHookFunc, error) {
|
||||
postStartHooks := map[string]genericapiserver.PostStartHookFunc{
|
||||
"grafana-provisioning": func(postStartHookCtx genericapiserver.PostStartHookContext) error {
|
||||
// TODO: Set up a shared informer for a controller and a watcher with workers.
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return postStartHooks, nil
|
||||
}
|
||||
|
||||
func (b *APIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
|
||||
oas.Info.Description = "Provisioning"
|
||||
|
||||
root := "/apis/" + b.GetGroupVersion().String() + "/"
|
||||
|
||||
// The root API discovery list
|
||||
sub := oas.Paths.Paths[root]
|
||||
if sub != nil && sub.Get != nil {
|
||||
sub.Get.Tags = []string{"API Discovery"} // sorts first in the list
|
||||
}
|
||||
|
||||
return oas, nil
|
||||
}
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apis/folders"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/peakq"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/scope"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/service"
|
||||
@ -40,6 +41,7 @@ var WireSet = wire.NewSet(
|
||||
folders.RegisterAPIService,
|
||||
iam.RegisterAPIService,
|
||||
peakq.RegisterAPIService,
|
||||
provisioning.RegisterAPIService,
|
||||
service.RegisterAPIService,
|
||||
query.RegisterAPIService,
|
||||
scope.RegisterAPIService,
|
||||
|
Loading…
Reference in New Issue
Block a user