mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
add wiring for validating admission
This commit is contained in:
parent
c3f31376da
commit
02e16cb253
@ -61,6 +61,16 @@ type Interface interface {
|
|||||||
Handles(operation Operation) bool
|
Handles(operation Operation) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
|
||||||
|
type ValidationInterface interface {
|
||||||
|
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate
|
||||||
|
Validate(a Attributes) (err error)
|
||||||
|
|
||||||
|
// Handles returns true if this admission controller can handle the given operation
|
||||||
|
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
|
||||||
|
Handles(operation Operation) bool
|
||||||
|
}
|
||||||
|
|
||||||
// Operation is the type of resource operation being checked for admission control
|
// Operation is the type of resource operation being checked for admission control
|
||||||
type Operation string
|
type Operation string
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
utiltrace "k8s.io/apiserver/pkg/util/trace"
|
utiltrace "k8s.io/apiserver/pkg/util/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface, includeName bool) http.HandlerFunc {
|
func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface, includeName bool) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
// For performance tracking purposes.
|
// For performance tracking purposes.
|
||||||
trace := utiltrace.New("Create " + req.URL.Path)
|
trace := utiltrace.New("Create " + req.URL.Path)
|
||||||
@ -93,10 +93,10 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
|
|||||||
ae := request.AuditEventFrom(ctx)
|
ae := request.AuditEventFrom(ctx)
|
||||||
audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer)
|
audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer)
|
||||||
|
|
||||||
if admit != nil && admit.Handles(admission.Create) {
|
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)
|
||||||
err = admit.Admit(admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo))
|
if mutatingAdmission != nil && mutatingAdmission.Handles(admission.Create) {
|
||||||
|
err = mutatingAdmission.Admit(admissionAttributes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
@ -108,7 +108,13 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
|
|||||||
|
|
||||||
trace.Step("About to store object in database")
|
trace.Step("About to store object in database")
|
||||||
result, err := finishRequest(timeout, func() (runtime.Object, error) {
|
result, err := finishRequest(timeout, func() (runtime.Object, error) {
|
||||||
return r.Create(ctx, name, obj, includeUninitialized)
|
return r.Create(
|
||||||
|
ctx,
|
||||||
|
name,
|
||||||
|
obj,
|
||||||
|
rest.AdmissionToValidateObjectFunc(validatingAdmission, admissionAttributes),
|
||||||
|
includeUninitialized,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
@ -144,19 +150,19 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateNamedResource returns a function that will handle a resource creation with name.
|
// CreateNamedResource returns a function that will handle a resource creation with name.
|
||||||
func CreateNamedResource(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) http.HandlerFunc {
|
func CreateNamedResource(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
||||||
return createHandler(r, scope, typer, admit, true)
|
return createHandler(r, scope, typer, mutatingAdmission, validatingAdmission, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateResource returns a function that will handle a resource creation.
|
// CreateResource returns a function that will handle a resource creation.
|
||||||
func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) http.HandlerFunc {
|
func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectTyper, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
||||||
return createHandler(&namedCreaterAdapter{r}, scope, typer, admit, false)
|
return createHandler(&namedCreaterAdapter{r}, scope, typer, mutatingAdmission, validatingAdmission, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
type namedCreaterAdapter struct {
|
type namedCreaterAdapter struct {
|
||||||
rest.Creater
|
rest.Creater
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *namedCreaterAdapter) Create(ctx request.Context, name string, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) {
|
func (c *namedCreaterAdapter) Create(ctx request.Context, name string, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
|
||||||
return c.Creater.Create(ctx, obj, includeUninitialized)
|
return c.Creater.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DeleteResource returns a function that will handle a resource deletion
|
// DeleteResource returns a function that will handle a resource deletion
|
||||||
func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, admit admission.Interface) http.HandlerFunc {
|
// TODO admission here becomes solely validating admission
|
||||||
|
func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
// For performance tracking purposes.
|
// For performance tracking purposes.
|
||||||
trace := utiltrace.New("Delete " + req.URL.Path)
|
trace := utiltrace.New("Delete " + req.URL.Path)
|
||||||
@ -93,10 +94,19 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
|||||||
}
|
}
|
||||||
|
|
||||||
trace.Step("About to check admission control")
|
trace.Step("About to check admission control")
|
||||||
if admit != nil && admit.Handles(admission.Delete) {
|
if mutatingAdmission != nil && mutatingAdmission.Handles(admission.Delete) {
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
err = mutatingAdmission.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
|
if err != nil {
|
||||||
|
scope.err(err, w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if validatingAdmission != nil && validatingAdmission.Handles(admission.Delete) {
|
||||||
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
|
err = validatingAdmission.Validate(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
@ -157,7 +167,7 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteCollection returns a function that will handle a collection deletion
|
// DeleteCollection returns a function that will handle a collection deletion
|
||||||
func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestScope, admit admission.Interface) http.HandlerFunc {
|
func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestScope, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
// TODO: we either want to remove timeout or document it (if we document, move timeout out of this function and declare it in api_installer)
|
// TODO: we either want to remove timeout or document it (if we document, move timeout out of this function and declare it in api_installer)
|
||||||
timeout := parseTimeout(req.URL.Query().Get("timeout"))
|
timeout := parseTimeout(req.URL.Query().Get("timeout"))
|
||||||
@ -171,10 +181,19 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
|||||||
ctx := scope.ContextFunc(req)
|
ctx := scope.ContextFunc(req)
|
||||||
ctx = request.WithNamespace(ctx, namespace)
|
ctx = request.WithNamespace(ctx, namespace)
|
||||||
|
|
||||||
if admit != nil && admit.Handles(admission.Delete) {
|
if mutatingAdmission != nil && mutatingAdmission.Handles(admission.Delete) {
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
err = admit.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
err = mutatingAdmission.Admit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
|
if err != nil {
|
||||||
|
scope.err(err, w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if validatingAdmission != nil && validatingAdmission.Handles(admission.Delete) {
|
||||||
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
|
err = validatingAdmission.Validate(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
return
|
return
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// UpdateResource returns a function that will handle a resource update
|
// UpdateResource returns a function that will handle a resource update
|
||||||
func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) http.HandlerFunc {
|
func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectTyper, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
// For performance tracking purposes.
|
// For performance tracking purposes.
|
||||||
trace := utiltrace.New("Update " + req.URL.Path)
|
trace := utiltrace.New("Update " + req.URL.Path)
|
||||||
@ -86,18 +86,25 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var transformers []rest.TransformFunc
|
|
||||||
if admit != nil && admit.Handles(admission.Update) {
|
|
||||||
transformers = append(transformers, func(ctx request.Context, newObj, oldObj runtime.Object) (runtime.Object, error) {
|
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
return newObj, admit.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
staticAdmissionAttributes := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)
|
||||||
|
var transformers []rest.TransformFunc
|
||||||
|
if mutatingAdmission != nil && mutatingAdmission.Handles(admission.Update) {
|
||||||
|
transformers = append(transformers, func(ctx request.Context, newObj, oldObj runtime.Object) (runtime.Object, error) {
|
||||||
|
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
trace.Step("About to store object in database")
|
trace.Step("About to store object in database")
|
||||||
wasCreated := false
|
wasCreated := false
|
||||||
result, err := finishRequest(timeout, func() (runtime.Object, error) {
|
result, err := finishRequest(timeout, func() (runtime.Object, error) {
|
||||||
obj, created, err := r.Update(ctx, name, rest.DefaultUpdatedObjectInfo(obj, transformers...))
|
obj, created, err := r.Update(
|
||||||
|
ctx,
|
||||||
|
name,
|
||||||
|
rest.DefaultUpdatedObjectInfo(obj, transformers...),
|
||||||
|
rest.AdmissionToValidateObjectFunc(validatingAdmission, staticAdmissionAttributes),
|
||||||
|
rest.AdmissionToValidateObjectUpdateFunc(validatingAdmission, staticAdmissionAttributes),
|
||||||
|
)
|
||||||
wasCreated = created
|
wasCreated = created
|
||||||
return obj, err
|
return obj, err
|
||||||
})
|
})
|
||||||
|
@ -52,6 +52,16 @@ import (
|
|||||||
// object.
|
// object.
|
||||||
type ObjectFunc func(obj runtime.Object) error
|
type ObjectFunc func(obj runtime.Object) error
|
||||||
|
|
||||||
|
// ValidateObjectFunc is a function to act on a given object. An error may be returned
|
||||||
|
// if the hook cannot be completed. An ObjectFunc may NOT transform the provided
|
||||||
|
// object.
|
||||||
|
type ValidateObjectFunc func(obj runtime.Object) error
|
||||||
|
|
||||||
|
// ValidateObjectUpdateFunc is a function to act on a given object and its predecessor.
|
||||||
|
// An error may be returned if the hook cannot be completed. An UpdateObjectFunc
|
||||||
|
// may NOT transform the provided object.
|
||||||
|
type ValidateObjectUpdateFunc func(obj, old runtime.Object) error
|
||||||
|
|
||||||
// GenericStore interface can be used for type assertions when we need to access the underlying strategies.
|
// GenericStore interface can be used for type assertions when we need to access the underlying strategies.
|
||||||
type GenericStore interface {
|
type GenericStore interface {
|
||||||
GetCreateStrategy() rest.RESTCreateStrategy
|
GetCreateStrategy() rest.RESTCreateStrategy
|
||||||
@ -148,11 +158,13 @@ type Store struct {
|
|||||||
// AfterCreate implements a further operation to run after a resource is
|
// AfterCreate implements a further operation to run after a resource is
|
||||||
// created and before it is decorated, optional.
|
// created and before it is decorated, optional.
|
||||||
AfterCreate ObjectFunc
|
AfterCreate ObjectFunc
|
||||||
|
|
||||||
// UpdateStrategy implements resource-specific behavior during updates.
|
// UpdateStrategy implements resource-specific behavior during updates.
|
||||||
UpdateStrategy rest.RESTUpdateStrategy
|
UpdateStrategy rest.RESTUpdateStrategy
|
||||||
// AfterUpdate implements a further operation to run after a resource is
|
// AfterUpdate implements a further operation to run after a resource is
|
||||||
// updated and before it is decorated, optional.
|
// updated and before it is decorated, optional.
|
||||||
AfterUpdate ObjectFunc
|
AfterUpdate ObjectFunc
|
||||||
|
|
||||||
// DeleteStrategy implements resource-specific behavior during deletion.
|
// DeleteStrategy implements resource-specific behavior during deletion.
|
||||||
DeleteStrategy rest.RESTDeleteStrategy
|
DeleteStrategy rest.RESTDeleteStrategy
|
||||||
// AfterDelete implements a further operation to run after a resource is
|
// AfterDelete implements a further operation to run after a resource is
|
||||||
@ -303,10 +315,18 @@ func (e *Store) ListPredicate(ctx genericapirequest.Context, p storage.Selection
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create inserts a new item according to the unique key from the object.
|
// Create inserts a new item according to the unique key from the object.
|
||||||
func (e *Store) Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error) {
|
func (e *Store) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
|
||||||
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
|
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// at this point we have a fully formed object. It is time to call the validators that the apiserver
|
||||||
|
// handling chain wants to enforce.
|
||||||
|
if createValidation != nil {
|
||||||
|
if err := createValidation(obj.DeepCopyObject()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
name, err := e.ObjectNameFunc(obj)
|
name, err := e.ObjectNameFunc(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -494,7 +514,7 @@ func (e *Store) deleteWithoutFinalizers(ctx genericapirequest.Context, name, key
|
|||||||
// Update performs an atomic update and set of the object. Returns the result of the update
|
// Update performs an atomic update and set of the object. Returns the result of the update
|
||||||
// or an error. If the registry allows create-on-update, the create flow will be executed.
|
// or an error. If the registry allows create-on-update, the create flow will be executed.
|
||||||
// A bool is returned along with the object and any errors, to indicate object creation.
|
// A bool is returned along with the object and any errors, to indicate object creation.
|
||||||
func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
|
||||||
key, err := e.KeyFunc(ctx, name)
|
key, err := e.KeyFunc(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@ -544,10 +564,18 @@ func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.
|
|||||||
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
|
if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
// at this point we have a fully formed object. It is time to call the validators that the apiserver
|
||||||
|
// handling chain wants to enforce.
|
||||||
|
if createValidation != nil {
|
||||||
|
if err := createValidation(obj.DeepCopyObject()); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
ttl, err := e.calculateTTL(obj, 0, false)
|
ttl, err := e.calculateTTL(obj, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj, &ttl, nil
|
return obj, &ttl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,6 +610,13 @@ func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.
|
|||||||
if err := rest.BeforeUpdate(e.UpdateStrategy, ctx, obj, existing); err != nil {
|
if err := rest.BeforeUpdate(e.UpdateStrategy, ctx, obj, existing); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
// at this point we have a fully formed object. It is time to call the validators that the apiserver
|
||||||
|
// handling chain wants to enforce.
|
||||||
|
if updateValidation != nil {
|
||||||
|
if err := updateValidation(obj.DeepCopyObject(), existing.DeepCopyObject()); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
if e.shouldDeleteDuringUpdate(ctx, key, obj, existing) {
|
if e.shouldDeleteDuringUpdate(ctx, key, obj, existing) {
|
||||||
deleteObj = obj
|
deleteObj = obj
|
||||||
return nil, nil, errEmptiedFinalizers
|
return nil, nil, errEmptiedFinalizers
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
"k8s.io/apiserver/pkg/storage/names"
|
"k8s.io/apiserver/pkg/storage/names"
|
||||||
@ -151,3 +152,24 @@ type NamespaceScopedStrategy interface {
|
|||||||
// NamespaceScoped returns if the object must be in a namespace.
|
// NamespaceScoped returns if the object must be in a namespace.
|
||||||
NamespaceScoped() bool
|
NamespaceScoped() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
|
||||||
|
func AdmissionToValidateObjectFunc(validatingAdmission admission.ValidationInterface, staticAttributes admission.Attributes) ValidateObjectFunc {
|
||||||
|
return func(obj runtime.Object) error {
|
||||||
|
finalAttributes := admission.NewAttributesRecord(
|
||||||
|
obj,
|
||||||
|
staticAttributes.GetOldObject(),
|
||||||
|
staticAttributes.GetKind(),
|
||||||
|
staticAttributes.GetNamespace(),
|
||||||
|
staticAttributes.GetName(),
|
||||||
|
staticAttributes.GetResource(),
|
||||||
|
staticAttributes.GetSubresource(),
|
||||||
|
staticAttributes.GetOperation(),
|
||||||
|
staticAttributes.GetUserInfo(),
|
||||||
|
)
|
||||||
|
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return validatingAdmission.Validate(finalAttributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -192,7 +192,7 @@ type Creater interface {
|
|||||||
|
|
||||||
// Create creates a new version of a resource. If includeUninitialized is set, the object may be returned
|
// Create creates a new version of a resource. If includeUninitialized is set, the object may be returned
|
||||||
// without completing initialization.
|
// without completing initialization.
|
||||||
Create(ctx genericapirequest.Context, obj runtime.Object, includeUninitialized bool) (runtime.Object, error)
|
Create(ctx genericapirequest.Context, obj runtime.Object, createValidation ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamedCreater is an object that can create an instance of a RESTful object using a name parameter.
|
// NamedCreater is an object that can create an instance of a RESTful object using a name parameter.
|
||||||
@ -205,7 +205,7 @@ type NamedCreater interface {
|
|||||||
// This is needed for create operations on subresources which include the name of the parent
|
// This is needed for create operations on subresources which include the name of the parent
|
||||||
// resource in the path. If includeUninitialized is set, the object may be returned without
|
// resource in the path. If includeUninitialized is set, the object may be returned without
|
||||||
// completing initialization.
|
// completing initialization.
|
||||||
Create(ctx genericapirequest.Context, name string, obj runtime.Object, includeUninitialized bool) (runtime.Object, error)
|
Create(ctx genericapirequest.Context, name string, obj runtime.Object, createValidation ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedObjectInfo provides information about an updated object to an Updater.
|
// UpdatedObjectInfo provides information about an updated object to an Updater.
|
||||||
@ -221,6 +221,16 @@ type UpdatedObjectInfo interface {
|
|||||||
UpdatedObject(ctx genericapirequest.Context, oldObj runtime.Object) (newObj runtime.Object, err error)
|
UpdatedObject(ctx genericapirequest.Context, oldObj runtime.Object) (newObj runtime.Object, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateObjectFunc is a function to act on a given object. An error may be returned
|
||||||
|
// if the hook cannot be completed. An ObjectFunc may NOT transform the provided
|
||||||
|
// object.
|
||||||
|
type ValidateObjectFunc func(obj runtime.Object) error
|
||||||
|
|
||||||
|
// ValidateObjectUpdateFunc is a function to act on a given object and its predecessor.
|
||||||
|
// An error may be returned if the hook cannot be completed. An UpdateObjectFunc
|
||||||
|
// may NOT transform the provided object.
|
||||||
|
type ValidateObjectUpdateFunc func(obj, old runtime.Object) error
|
||||||
|
|
||||||
// Updater is an object that can update an instance of a RESTful object.
|
// Updater is an object that can update an instance of a RESTful object.
|
||||||
type Updater interface {
|
type Updater interface {
|
||||||
// New returns an empty object that can be used with Update after request data has been put into it.
|
// New returns an empty object that can be used with Update after request data has been put into it.
|
||||||
@ -230,14 +240,14 @@ type Updater interface {
|
|||||||
// Update finds a resource in the storage and updates it. Some implementations
|
// Update finds a resource in the storage and updates it. Some implementations
|
||||||
// may allow updates creates the object - they should set the created boolean
|
// may allow updates creates the object - they should set the created boolean
|
||||||
// to true.
|
// to true.
|
||||||
Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo) (runtime.Object, bool, error)
|
Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc) (runtime.Object, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreaterUpdater is a storage object that must support both create and update.
|
// CreaterUpdater is a storage object that must support both create and update.
|
||||||
// Go prevents embedded interfaces that implement the same method.
|
// Go prevents embedded interfaces that implement the same method.
|
||||||
type CreaterUpdater interface {
|
type CreaterUpdater interface {
|
||||||
Creater
|
Creater
|
||||||
Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo) (runtime.Object, bool, error)
|
Update(ctx genericapirequest.Context, name string, objInfo UpdatedObjectInfo, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc) (runtime.Object, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreaterUpdater must satisfy the Updater interface.
|
// CreaterUpdater must satisfy the Updater interface.
|
||||||
|
@ -26,6 +26,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/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
@ -229,3 +230,24 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx genericapirequest.Context,
|
|||||||
|
|
||||||
return newObj, nil
|
return newObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
|
||||||
|
func AdmissionToValidateObjectUpdateFunc(validatingAdmission admission.ValidationInterface, staticAttributes admission.Attributes) ValidateObjectUpdateFunc {
|
||||||
|
return func(obj, old runtime.Object) error {
|
||||||
|
finalAttributes := admission.NewAttributesRecord(
|
||||||
|
obj,
|
||||||
|
old,
|
||||||
|
staticAttributes.GetKind(),
|
||||||
|
staticAttributes.GetNamespace(),
|
||||||
|
staticAttributes.GetName(),
|
||||||
|
staticAttributes.GetResource(),
|
||||||
|
staticAttributes.GetSubresource(),
|
||||||
|
staticAttributes.GetOperation(),
|
||||||
|
staticAttributes.GetUserInfo(),
|
||||||
|
)
|
||||||
|
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return validatingAdmission.Validate(finalAttributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user