mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s: Add validation support to builder (#95502)
This commit is contained in:
parent
e0163c93c2
commit
5533b30135
@ -8,6 +8,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||||
@ -28,6 +29,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var _ builder.APIGroupBuilder = (*FolderAPIBuilder)(nil)
|
var _ builder.APIGroupBuilder = (*FolderAPIBuilder)(nil)
|
||||||
|
var _ builder.APIGroupValidation = (*FolderAPIBuilder)(nil)
|
||||||
|
|
||||||
var resourceInfo = v0alpha1.FolderResourceInfo
|
var resourceInfo = v0alpha1.FolderResourceInfo
|
||||||
|
|
||||||
@ -181,6 +183,10 @@ func (b *FolderAPIBuilder) GetAuthorizer() authorizer.Authorizer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorizerParams, error) {
|
func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorizerParams, error) {
|
||||||
verb := attr.GetVerb()
|
verb := attr.GetVerb()
|
||||||
name := attr.GetName()
|
name := attr.GetName()
|
||||||
|
43
pkg/services/apiserver/builder/admission.go
Normal file
43
pkg/services/apiserver/builder/admission.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package builder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
|
)
|
||||||
|
|
||||||
|
const PluginName = "GrafanaAdmission"
|
||||||
|
|
||||||
|
type builderAdmission struct {
|
||||||
|
validators map[schema.GroupVersion]APIGroupValidation
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ admission.ValidationInterface = (*builderAdmission)(nil)
|
||||||
|
|
||||||
|
func (b *builderAdmission) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
|
||||||
|
if v, ok := b.validators[a.GetResource().GroupVersion()]; ok {
|
||||||
|
return v.Validate(ctx, a, o)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *builderAdmission) Handles(operation admission.Operation) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAdmissionFromBuilders(builders []APIGroupBuilder) *builderAdmission {
|
||||||
|
validators := make(map[schema.GroupVersion]APIGroupValidation)
|
||||||
|
for _, builder := range builders {
|
||||||
|
if v, ok := builder.(APIGroupValidation); ok {
|
||||||
|
validators[builder.GetGroupVersion()] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NewAdmission(validators)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAdmission(validators map[schema.GroupVersion]APIGroupValidation) *builderAdmission {
|
||||||
|
return &builderAdmission{
|
||||||
|
validators: validators,
|
||||||
|
}
|
||||||
|
}
|
85
pkg/services/apiserver/builder/admission_test.go
Normal file
85
pkg/services/apiserver/builder/admission_test.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package builder_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuilderAdmission_Validate(t *testing.T) {
|
||||||
|
gvk := schema.GroupVersionKind{
|
||||||
|
Group: "testGroup",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "testKind",
|
||||||
|
}
|
||||||
|
gvr := gvk.GroupVersion().WithResource("testkinds")
|
||||||
|
defaultAttributes := admission.NewAttributesRecord(nil, nil, gvk, "", "", gvr, "", admission.Create, nil, false, nil)
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
validators map[schema.GroupVersion]builder.APIGroupValidation
|
||||||
|
attributes admission.Attributes
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "validator exists - forbidden",
|
||||||
|
validators: map[schema.GroupVersion]builder.APIGroupValidation{
|
||||||
|
{Group: "testGroup", Version: "v1"}: &mockValidator{
|
||||||
|
validateFunc: func(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return admission.NewForbidden(a, errors.New("test error"))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
attributes: defaultAttributes,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "validator exists - allowed",
|
||||||
|
validators: map[schema.GroupVersion]builder.APIGroupValidation{
|
||||||
|
{Group: "testGroup", Version: "v1"}: &mockValidator{
|
||||||
|
validateFunc: func(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
attributes: defaultAttributes,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "validator does not exist",
|
||||||
|
validators: map[schema.GroupVersion]builder.APIGroupValidation{
|
||||||
|
{Group: "testGroup", Version: "v1"}: &mockValidator{
|
||||||
|
validateFunc: func(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
attributes: defaultAttributes,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
b := builder.NewAdmission(tt.validators)
|
||||||
|
err := b.Validate(context.Background(), tt.attributes, nil)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockValidator struct {
|
||||||
|
validateFunc func(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockValidator) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return m.validateFunc(ctx, a, o)
|
||||||
|
}
|
@ -1,18 +1,19 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||||
"k8s.io/kube-openapi/pkg/common"
|
"k8s.io/kube-openapi/pkg/common"
|
||||||
"k8s.io/kube-openapi/pkg/spec3"
|
"k8s.io/kube-openapi/pkg/spec3"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
|
|
||||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,6 +47,10 @@ type APIGroupBuilder interface {
|
|||||||
GetAuthorizer() authorizer.Authorizer
|
GetAuthorizer() authorizer.Authorizer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type APIGroupValidation interface {
|
||||||
|
Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
type APIGroupOptions struct {
|
type APIGroupOptions struct {
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
OptsGetter generic.RESTOptionsGetter
|
OptsGetter generic.RESTOptionsGetter
|
||||||
|
@ -103,6 +103,7 @@ func SetupConfig(
|
|||||||
buildBranch string,
|
buildBranch string,
|
||||||
buildHandlerChainFunc func(delegateHandler http.Handler, c *genericapiserver.Config) http.Handler,
|
buildHandlerChainFunc func(delegateHandler http.Handler, c *genericapiserver.Config) http.Handler,
|
||||||
) error {
|
) error {
|
||||||
|
serverConfig.AdmissionControl = NewAdmissionFromBuilders(builders)
|
||||||
defsGetter := GetOpenAPIDefinitions(builders)
|
defsGetter := GetOpenAPIDefinitions(builders)
|
||||||
serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(
|
serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(
|
||||||
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
|
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
|
||||||
|
Loading…
Reference in New Issue
Block a user