mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
admission: complete plumbing of validation admission
This commit is contained in:
parent
d4f48c9313
commit
74b4223ab8
@ -38,6 +38,11 @@ func (AlwaysAdmit) Admit(a admission.Attributes) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatingAdmit makes an admission decision based on the request attributes. It is NOT allowed to mutate
|
||||||
|
func (AlwaysAdmit) ValidatingAdmit(a admission.Attributes) (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Handles returns true if this admission controller can handle the given operation
|
// Handles returns true if this admission controller can handle the given operation
|
||||||
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
|
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
|
||||||
func (AlwaysAdmit) Handles(operation admission.Operation) bool {
|
func (AlwaysAdmit) Handles(operation admission.Operation) bool {
|
||||||
|
@ -67,6 +67,8 @@ type MutationInterface interface {
|
|||||||
|
|
||||||
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
|
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
|
||||||
type ValidationInterface interface {
|
type ValidationInterface interface {
|
||||||
|
Interface
|
||||||
|
|
||||||
// ValidatingAdmit makes an admission decision based on the request attributes. It is NOT allowed to mutate
|
// ValidatingAdmit makes an admission decision based on the request attributes. It is NOT allowed to mutate
|
||||||
ValidatingAdmit(a Attributes) (err error)
|
ValidatingAdmit(a Attributes) (err error)
|
||||||
}
|
}
|
||||||
|
@ -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, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface, includeName bool) http.HandlerFunc {
|
func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface, 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)
|
||||||
@ -95,7 +95,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
|
|||||||
|
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)
|
admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)
|
||||||
if mutatingAdmission != nil && mutatingAdmission.Handles(admission.Create) {
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) {
|
||||||
err = mutatingAdmission.Admit(admissionAttributes)
|
err = mutatingAdmission.Admit(admissionAttributes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
@ -112,7 +112,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.Object
|
|||||||
ctx,
|
ctx,
|
||||||
name,
|
name,
|
||||||
obj,
|
obj,
|
||||||
rest.AdmissionToValidateObjectFunc(validatingAdmission, admissionAttributes),
|
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes),
|
||||||
includeUninitialized,
|
includeUninitialized,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -150,13 +150,13 @@ 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, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
func CreateNamedResource(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admission admission.Interface) http.HandlerFunc {
|
||||||
return createHandler(r, scope, typer, mutatingAdmission, validatingAdmission, true)
|
return createHandler(r, scope, typer, admission, 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, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
func CreateResource(r rest.Creater, scope RequestScope, typer runtime.ObjectTyper, admission admission.Interface) http.HandlerFunc {
|
||||||
return createHandler(&namedCreaterAdapter{r}, scope, typer, mutatingAdmission, validatingAdmission, false)
|
return createHandler(&namedCreaterAdapter{r}, scope, typer, admission, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
type namedCreaterAdapter struct {
|
type namedCreaterAdapter struct {
|
||||||
|
@ -35,7 +35,7 @@ import (
|
|||||||
|
|
||||||
// DeleteResource returns a function that will handle a resource deletion
|
// DeleteResource returns a function that will handle a resource deletion
|
||||||
// TODO admission here becomes solely validating admission
|
// TODO admission here becomes solely validating admission
|
||||||
func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, admit admission.Interface) 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)
|
||||||
@ -94,7 +94,7 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
|||||||
}
|
}
|
||||||
|
|
||||||
trace.Step("About to check admission control")
|
trace.Step("About to check admission control")
|
||||||
if mutatingAdmission != nil && mutatingAdmission.Handles(admission.Delete) {
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Delete) {
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
err = mutatingAdmission.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))
|
||||||
@ -103,7 +103,8 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if validatingAdmission != nil && validatingAdmission.Handles(admission.Delete) {
|
// TODO: avoid calling Handles twice
|
||||||
|
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok && validatingAdmission.Handles(admission.Delete) {
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
err = validatingAdmission.ValidatingAdmit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
err = validatingAdmission.ValidatingAdmit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
@ -167,7 +168,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, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestScope, admit admission.Interface) 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"))
|
||||||
@ -181,7 +182,7 @@ 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 mutatingAdmission != nil && mutatingAdmission.Handles(admission.Delete) {
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Delete) {
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
err = mutatingAdmission.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))
|
||||||
@ -190,7 +191,8 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if validatingAdmission != nil && validatingAdmission.Handles(admission.Delete) {
|
// TODO: avoid calling Handles twice
|
||||||
|
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok && validatingAdmission.Handles(admission.Delete) {
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
|
||||||
err = validatingAdmission.ValidatingAdmit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
err = validatingAdmission.ValidatingAdmit(admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, userInfo))
|
||||||
|
@ -92,16 +92,25 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
|
|||||||
scope.Serializer.DecoderToVersion(s.Serializer, schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal}),
|
scope.Serializer.DecoderToVersion(s.Serializer, schema.GroupVersion{Group: gv.Group, Version: runtime.APIVersionInternal}),
|
||||||
)
|
)
|
||||||
|
|
||||||
updateAdmit := func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
if admit != nil && admit.Handles(admission.Update) {
|
staticAdmissionAttributes := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
updateMutation := func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
return admit.Admit(admission.NewAttributesRecord(updatedObject, currentObject, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && admit.Handles(admission.Update) {
|
||||||
|
return mutatingAdmission.Admit(admission.NewAttributesRecord(updatedObject, currentObject, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := patchResource(ctx, updateAdmit, timeout, versionedObj, r, name, patchType, patchJS,
|
result, err := patchResource(
|
||||||
|
ctx,
|
||||||
|
updateMutation,
|
||||||
|
rest.AdmissionToValidateObjectFunc(admit, staticAdmissionAttributes),
|
||||||
|
rest.AdmissionToValidateObjectUpdateFunc(admit, staticAdmissionAttributes),
|
||||||
|
timeout, versionedObj,
|
||||||
|
r,
|
||||||
|
name,
|
||||||
|
patchType,
|
||||||
|
patchJS,
|
||||||
scope.Namer, scope.Creater, scope.Defaulter, scope.UnsafeConvertor, scope.Kind, scope.Resource, codec)
|
scope.Namer, scope.Creater, scope.Defaulter, scope.UnsafeConvertor, scope.Kind, scope.Resource, codec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scope.err(err, w, req)
|
scope.err(err, w, req)
|
||||||
@ -122,12 +131,14 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateAdmissionFunc func(updatedObject runtime.Object, currentObject runtime.Object) error
|
type mutateObjectUpdateFunc func(obj, old runtime.Object) error
|
||||||
|
|
||||||
// patchResource divides PatchResource for easier unit testing
|
// patchResource divides PatchResource for easier unit testing
|
||||||
func patchResource(
|
func patchResource(
|
||||||
ctx request.Context,
|
ctx request.Context,
|
||||||
admit updateAdmissionFunc,
|
updateMutation mutateObjectUpdateFunc,
|
||||||
|
createValidation rest.ValidateObjectFunc,
|
||||||
|
updateValidation rest.ValidateObjectUpdateFunc,
|
||||||
timeout time.Duration,
|
timeout time.Duration,
|
||||||
versionedObj runtime.Object,
|
versionedObj runtime.Object,
|
||||||
patcher rest.Patcher,
|
patcher rest.Patcher,
|
||||||
@ -341,16 +352,15 @@ func patchResource(
|
|||||||
// applyAdmission is called every time GuaranteedUpdate asks for the updated object,
|
// applyAdmission is called every time GuaranteedUpdate asks for the updated object,
|
||||||
// and is given the currently persisted object and the patched object as input.
|
// and is given the currently persisted object and the patched object as input.
|
||||||
applyAdmission := func(ctx request.Context, patchedObject runtime.Object, currentObject runtime.Object) (runtime.Object, error) {
|
applyAdmission := func(ctx request.Context, patchedObject runtime.Object, currentObject runtime.Object) (runtime.Object, error) {
|
||||||
return patchedObject, admit(patchedObject, currentObject)
|
return patchedObject, updateMutation(patchedObject, currentObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedObjectInfo := rest.DefaultUpdatedObjectInfo(nil, applyPatch, applyAdmission)
|
updatedObjectInfo := rest.DefaultUpdatedObjectInfo(nil, applyPatch, applyAdmission)
|
||||||
|
|
||||||
return finishRequest(timeout, func() (runtime.Object, error) {
|
return finishRequest(timeout, func() (runtime.Object, error) {
|
||||||
updateObject, _, updateErr := patcher.Update(ctx, name, updatedObjectInfo)
|
updateObject, _, updateErr := patcher.Update(ctx, name, updatedObjectInfo, createValidation, updateValidation)
|
||||||
for i := 0; i < MaxRetryWhenPatchConflicts && (errors.IsConflict(updateErr)); i++ {
|
for i := 0; i < MaxRetryWhenPatchConflicts && (errors.IsConflict(updateErr)); i++ {
|
||||||
lastConflictErr = updateErr
|
lastConflictErr = updateErr
|
||||||
updateObject, _, updateErr = patcher.Update(ctx, name, updatedObjectInfo)
|
updateObject, _, updateErr = patcher.Update(ctx, name, updatedObjectInfo, createValidation, updateValidation)
|
||||||
}
|
}
|
||||||
return updateObject, updateErr
|
return updateObject, updateErr
|
||||||
})
|
})
|
||||||
|
@ -117,11 +117,20 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
|
|||||||
ResourcePath: restPath,
|
ResourcePath: restPath,
|
||||||
}
|
}
|
||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
|
// TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT
|
||||||
err = admit.Admit(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo))
|
if mutatingAdmit, ok := admit.(admission.MutationInterface); ok {
|
||||||
if err != nil {
|
err = mutatingAdmit.Admit(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo))
|
||||||
scope.err(err, w, req)
|
if err != nil {
|
||||||
return
|
scope.err(err, w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mutatingAdmit, ok := admit.(admission.ValidationInterface); ok {
|
||||||
|
err = mutatingAdmit.Validate(admission.NewAttributesRecord(connectRequest, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, userInfo))
|
||||||
|
if err != nil {
|
||||||
|
scope.err(err, w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestInfo, _ := request.RequestInfoFrom(ctx)
|
requestInfo, _ := request.RequestInfoFrom(ctx)
|
||||||
|
@ -137,7 +137,7 @@ func (p *testPatcher) New() runtime.Object {
|
|||||||
return &example.Pod{}
|
return &example.Pod{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPatcher) Update(ctx request.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
|
func (p *testPatcher) Update(ctx request.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
|
||||||
currentPod := p.startingPod
|
currentPod := p.startingPod
|
||||||
if p.numUpdates > 0 {
|
if p.numUpdates > 0 {
|
||||||
currentPod = p.updatePod
|
currentPod = p.updatePod
|
||||||
@ -202,7 +202,8 @@ type patchTestCase struct {
|
|||||||
name string
|
name string
|
||||||
|
|
||||||
// admission chain to use, nil is fine
|
// admission chain to use, nil is fine
|
||||||
admit updateAdmissionFunc
|
admissionMutation mutateObjectUpdateFunc
|
||||||
|
admissionValidation rest.ValidateObjectUpdateFunc // TODO: add test for this
|
||||||
|
|
||||||
// startingPod is used as the starting point for the first Update
|
// startingPod is used as the starting point for the first Update
|
||||||
startingPod *example.Pod
|
startingPod *example.Pod
|
||||||
@ -224,9 +225,16 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
name := tc.startingPod.Name
|
name := tc.startingPod.Name
|
||||||
|
|
||||||
codec := codecs.LegacyCodec(examplev1.SchemeGroupVersion)
|
codec := codecs.LegacyCodec(examplev1.SchemeGroupVersion)
|
||||||
admit := tc.admit
|
|
||||||
if admit == nil {
|
admissionMutation := tc.admissionMutation
|
||||||
admit = func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
if admissionMutation == nil {
|
||||||
|
admissionMutation = func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
admissionValidation := tc.admissionValidation
|
||||||
|
if admissionValidation == nil {
|
||||||
|
admissionValidation = func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,7 +296,18 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resultObj, err := patchResource(ctx, admit, 1*time.Second, versionedObj, testPatcher, name, patchType, patch, namer, creater, defaulter, convertor, kind, resource, codec)
|
resultObj, err := patchResource(
|
||||||
|
ctx,
|
||||||
|
admissionMutation,
|
||||||
|
rest.ValidateAllObjectFunc,
|
||||||
|
admissionValidation,
|
||||||
|
1*time.Second,
|
||||||
|
versionedObj,
|
||||||
|
testPatcher,
|
||||||
|
name,
|
||||||
|
patchType,
|
||||||
|
patch,
|
||||||
|
namer, creater, defaulter, convertor, kind, resource, codec)
|
||||||
if len(tc.expectedError) != 0 {
|
if len(tc.expectedError) != 0 {
|
||||||
if err == nil || err.Error() != tc.expectedError {
|
if err == nil || err.Error() != tc.expectedError {
|
||||||
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
|
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
|
||||||
@ -511,7 +530,7 @@ func TestPatchWithAdmissionRejection(t *testing.T) {
|
|||||||
tc := &patchTestCase{
|
tc := &patchTestCase{
|
||||||
name: "TestPatchWithAdmissionRejection",
|
name: "TestPatchWithAdmissionRejection",
|
||||||
|
|
||||||
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
return errors.New("admission failure")
|
return errors.New("admission failure")
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -550,7 +569,7 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) {
|
|||||||
tc := &patchTestCase{
|
tc := &patchTestCase{
|
||||||
name: "TestPatchWithVersionConflictThenAdmissionFailure",
|
name: "TestPatchWithVersionConflictThenAdmissionFailure",
|
||||||
|
|
||||||
admit: func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error {
|
||||||
if seen {
|
if seen {
|
||||||
return errors.New("admission failure")
|
return errors.New("admission failure")
|
||||||
}
|
}
|
||||||
|
@ -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, mutatingAdmission admission.Interface, validatingAdmission admission.ValidationInterface) http.HandlerFunc {
|
func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) 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)
|
||||||
@ -89,7 +89,7 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
|
|||||||
userInfo, _ := request.UserFrom(ctx)
|
userInfo, _ := request.UserFrom(ctx)
|
||||||
staticAdmissionAttributes := admission.NewAttributesRecord(nil, nil, 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
|
var transformers []rest.TransformFunc
|
||||||
if mutatingAdmission != nil && mutatingAdmission.Handles(admission.Update) {
|
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Update) {
|
||||||
transformers = append(transformers, func(ctx request.Context, newObj, oldObj runtime.Object) (runtime.Object, error) {
|
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))
|
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo))
|
||||||
})
|
})
|
||||||
@ -102,8 +102,8 @@ func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectType
|
|||||||
ctx,
|
ctx,
|
||||||
name,
|
name,
|
||||||
rest.DefaultUpdatedObjectInfo(obj, transformers...),
|
rest.DefaultUpdatedObjectInfo(obj, transformers...),
|
||||||
rest.AdmissionToValidateObjectFunc(validatingAdmission, staticAdmissionAttributes),
|
rest.AdmissionToValidateObjectFunc(admit, staticAdmissionAttributes),
|
||||||
rest.AdmissionToValidateObjectUpdateFunc(validatingAdmission, staticAdmissionAttributes),
|
rest.AdmissionToValidateObjectUpdateFunc(admit, staticAdmissionAttributes),
|
||||||
)
|
)
|
||||||
wasCreated = created
|
wasCreated = created
|
||||||
return obj, err
|
return obj, err
|
||||||
|
@ -52,16 +52,6 @@ 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
|
||||||
@ -315,7 +305,7 @@ 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, createValidation ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
|
func (e *Store) Create(ctx genericapirequest.Context, obj runtime.Object, createValidation rest.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
|
||||||
}
|
}
|
||||||
@ -514,7 +504,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, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc) (runtime.Object, bool, error) {
|
func (e *Store) Update(ctx genericapirequest.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.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
|
||||||
|
@ -154,7 +154,11 @@ type NamespaceScopedStrategy interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
|
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
|
||||||
func AdmissionToValidateObjectFunc(validatingAdmission admission.ValidationInterface, staticAttributes admission.Attributes) ValidateObjectFunc {
|
func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectFunc {
|
||||||
|
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
||||||
|
if !ok {
|
||||||
|
return func(obj runtime.Object) error { return nil }
|
||||||
|
}
|
||||||
return func(obj runtime.Object) error {
|
return func(obj runtime.Object) error {
|
||||||
finalAttributes := admission.NewAttributesRecord(
|
finalAttributes := admission.NewAttributesRecord(
|
||||||
obj,
|
obj,
|
||||||
@ -170,6 +174,6 @@ func AdmissionToValidateObjectFunc(validatingAdmission admission.ValidationInter
|
|||||||
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return validatingAdmission.Validate(finalAttributes)
|
return validatingAdmission.ValidatingAdmit(finalAttributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,11 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx genericapirequest.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
|
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
|
||||||
func AdmissionToValidateObjectUpdateFunc(validatingAdmission admission.ValidationInterface, staticAttributes admission.Attributes) ValidateObjectUpdateFunc {
|
func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectUpdateFunc {
|
||||||
|
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
||||||
|
if !ok {
|
||||||
|
return func(obj, old runtime.Object) error { return nil }
|
||||||
|
}
|
||||||
return func(obj, old runtime.Object) error {
|
return func(obj, old runtime.Object) error {
|
||||||
finalAttributes := admission.NewAttributesRecord(
|
finalAttributes := admission.NewAttributesRecord(
|
||||||
obj,
|
obj,
|
||||||
@ -248,6 +252,6 @@ func AdmissionToValidateObjectUpdateFunc(validatingAdmission admission.Validatio
|
|||||||
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return validatingAdmission.Validate(finalAttributes)
|
return validatingAdmission.ValidatingAdmit(finalAttributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user