mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-06 16:06:51 +00:00
add common fields validation before updaing a resource; make the repair of malformed update request flippable by a flag.
This commit is contained in:
@@ -19,6 +19,7 @@ package rest
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/fielderrors"
|
||||
)
|
||||
@@ -44,6 +45,22 @@ type RESTUpdateStrategy interface {
|
||||
AllowUnconditionalUpdate() bool
|
||||
}
|
||||
|
||||
// TODO: add other common fields that require global validation.
|
||||
func validateCommonFields(obj, old runtime.Object) fielderrors.ValidationErrorList {
|
||||
allErrs := fielderrors.ValidationErrorList{}
|
||||
objectMeta, err := api.ObjectMetaFor(obj)
|
||||
if err != nil {
|
||||
return append(allErrs, errors.NewInternalError(err))
|
||||
}
|
||||
oldObjectMeta, err := api.ObjectMetaFor(old)
|
||||
if err != nil {
|
||||
return append(allErrs, errors.NewInternalError(err))
|
||||
}
|
||||
allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(objectMeta, oldObjectMeta)...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// BeforeUpdate ensures that common operations for all resources are performed on update. It only returns
|
||||
// errors that can be converted to api.Status. It will invoke update validation with the provided existing
|
||||
// and updated objects.
|
||||
@@ -59,8 +76,14 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx api.Context, obj, old runtime
|
||||
} else {
|
||||
objectMeta.Namespace = api.NamespaceNone
|
||||
}
|
||||
|
||||
strategy.PrepareForUpdate(obj, old)
|
||||
if errs := strategy.ValidateUpdate(ctx, obj, old); len(errs) > 0 {
|
||||
|
||||
// Ensure some common fields, like UID, are validated for all resources.
|
||||
errs := validateCommonFields(obj, old)
|
||||
|
||||
errs = append(errs, strategy.ValidateUpdate(ctx, obj, old)...)
|
||||
if len(errs) > 0 {
|
||||
return errors.NewInvalid(kind, objectMeta.Name, errs)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -38,6 +38,10 @@ import (
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// TODO: delete this global variable when we enable the validation of common
|
||||
// fields by default.
|
||||
var RepairMalformedUpdates bool = true
|
||||
|
||||
const cIdentifierErrorMsg string = `must be a C identifier (matching regex ` + validation.CIdentifierFmt + `): e.g. "my_name" or "MyName"`
|
||||
const isNegativeErrorMsg string = `must be non-negative`
|
||||
|
||||
@@ -231,6 +235,7 @@ func ValidatePositiveQuantity(value resource.Quantity, fieldName string) errs.Va
|
||||
|
||||
// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
|
||||
// been performed.
|
||||
// TODO: Remove calls to this method scattered in validations of specific resources, e.g., ValidatePodUpdate.
|
||||
func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
|
||||
@@ -273,23 +278,32 @@ func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn Val
|
||||
func ValidateObjectMetaUpdate(new, old *api.ObjectMeta) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
|
||||
if !RepairMalformedUpdates && new.UID != old.UID {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("uid", new.UID, "field is immutable"))
|
||||
}
|
||||
// in the event it is left empty, set it, to allow clients more flexibility
|
||||
if len(new.UID) == 0 {
|
||||
new.UID = old.UID
|
||||
}
|
||||
// ignore changes to timestamp
|
||||
if old.CreationTimestamp.IsZero() {
|
||||
old.CreationTimestamp = new.CreationTimestamp
|
||||
} else {
|
||||
new.CreationTimestamp = old.CreationTimestamp
|
||||
}
|
||||
// an object can never remove a deletion timestamp or clear/change grace period seconds
|
||||
if !old.DeletionTimestamp.IsZero() {
|
||||
new.DeletionTimestamp = old.DeletionTimestamp
|
||||
}
|
||||
if old.DeletionGracePeriodSeconds != nil && new.DeletionGracePeriodSeconds == nil {
|
||||
new.DeletionGracePeriodSeconds = old.DeletionGracePeriodSeconds
|
||||
// TODO: remove the following code that repairs the update request when we retire the clients that modify the immutable fields.
|
||||
// Please do not copy this pattern elsewhere; validation functions should not be modifying the objects they are passed!
|
||||
if RepairMalformedUpdates {
|
||||
if len(new.UID) == 0 {
|
||||
new.UID = old.UID
|
||||
}
|
||||
// ignore changes to timestamp
|
||||
if old.CreationTimestamp.IsZero() {
|
||||
old.CreationTimestamp = new.CreationTimestamp
|
||||
} else {
|
||||
new.CreationTimestamp = old.CreationTimestamp
|
||||
}
|
||||
// an object can never remove a deletion timestamp or clear/change grace period seconds
|
||||
if !old.DeletionTimestamp.IsZero() {
|
||||
new.DeletionTimestamp = old.DeletionTimestamp
|
||||
}
|
||||
if old.DeletionGracePeriodSeconds != nil && new.DeletionGracePeriodSeconds == nil {
|
||||
new.DeletionGracePeriodSeconds = old.DeletionGracePeriodSeconds
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: needs to check if new==nil && old !=nil after the repair logic is removed.
|
||||
if new.DeletionGracePeriodSeconds != nil && old.DeletionGracePeriodSeconds != nil && *new.DeletionGracePeriodSeconds != *old.DeletionGracePeriodSeconds {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("deletionGracePeriodSeconds", new.DeletionGracePeriodSeconds, "field is immutable; may only be changed via deletion"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user