mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -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"
|
||||
"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/rest"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
@ -28,6 +29,7 @@ import (
|
||||
)
|
||||
|
||||
var _ builder.APIGroupBuilder = (*FolderAPIBuilder)(nil)
|
||||
var _ builder.APIGroupValidation = (*FolderAPIBuilder)(nil)
|
||||
|
||||
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) {
|
||||
verb := attr.GetVerb()
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"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"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
)
|
||||
|
||||
@ -46,6 +47,10 @@ type APIGroupBuilder interface {
|
||||
GetAuthorizer() authorizer.Authorizer
|
||||
}
|
||||
|
||||
type APIGroupValidation interface {
|
||||
Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error)
|
||||
}
|
||||
|
||||
type APIGroupOptions struct {
|
||||
Scheme *runtime.Scheme
|
||||
OptsGetter generic.RESTOptionsGetter
|
||||
|
@ -103,6 +103,7 @@ func SetupConfig(
|
||||
buildBranch string,
|
||||
buildHandlerChainFunc func(delegateHandler http.Handler, c *genericapiserver.Config) http.Handler,
|
||||
) error {
|
||||
serverConfig.AdmissionControl = NewAdmissionFromBuilders(builders)
|
||||
defsGetter := GetOpenAPIDefinitions(builders)
|
||||
serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(
|
||||
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
|
||||
|
Loading…
Reference in New Issue
Block a user