Initialize UID earlier in the Create process
Before: Create() BeginCreate() BeforeCreate() init UID <--------------------- strategy code After: Create() init UID <------------------------- BeginCreate() BeforeCreate() strategy code This also wipes UID early (suggested by David) and asserts it is set in BeforeCreate(). Kubernetes-commit: 5615de51f9e768dd01d7fe49a48e8db756bd8ac8
This commit is contained in:
parent
010d9e3ada
commit
970b3ee9bb
|
@ -163,8 +163,10 @@ func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Int
|
|||
|
||||
userInfo, _ := request.UserFrom(ctx)
|
||||
|
||||
// if this object supports namespace info
|
||||
if objectMeta, err := meta.Accessor(obj); err == nil {
|
||||
// Wipe fields which cannot take user-provided values
|
||||
rest.WipeObjectMetaSystemFields(objectMeta)
|
||||
|
||||
// ensure namespace on the object is correct, or error if a conflicting namespace was set in the object
|
||||
if err := rest.EnsureObjectNamespaceMatchesRequestNamespace(rest.ExpectedNamespaceForResource(namespace, scope.Resource), objectMeta); err != nil {
|
||||
scope.err(err, w, req)
|
||||
|
|
|
@ -382,6 +382,13 @@ func finishNothing(context.Context, bool) {}
|
|||
func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
|
||||
var finishCreate FinishFunc = finishNothing
|
||||
|
||||
// Init metadata as early as possible.
|
||||
if objectMeta, err := meta.Accessor(obj); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
rest.FillObjectMetaSystemFields(objectMeta)
|
||||
}
|
||||
|
||||
if e.BeginCreate != nil {
|
||||
fn, err := e.BeginCreate(ctx, obj, options)
|
||||
if err != nil {
|
||||
|
@ -558,6 +565,13 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj
|
|||
doUnconditionalUpdate := newResourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
|
||||
|
||||
if existingResourceVersion == 0 {
|
||||
// Init metadata as early as possible.
|
||||
if objectMeta, err := meta.Accessor(obj); err != nil {
|
||||
return nil, nil, err
|
||||
} else {
|
||||
rest.FillObjectMetaSystemFields(objectMeta)
|
||||
}
|
||||
|
||||
var finishCreate FinishFunc = finishNothing
|
||||
|
||||
if e.BeginCreate != nil {
|
||||
|
|
|
@ -100,6 +100,11 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx context.Context, obj runtime.
|
|||
return kerr
|
||||
}
|
||||
|
||||
// ensure that system-critical metadata has been populated
|
||||
if !metav1.HasObjectMetaSystemFieldValues(objectMeta) {
|
||||
return errors.NewInternalError(fmt.Errorf("system metadata was not initialized"))
|
||||
}
|
||||
|
||||
// ensure namespace on the object is correct, or error if a conflicting namespace was set in the object
|
||||
requestNamespace, ok := genericapirequest.NamespaceFrom(ctx)
|
||||
if !ok {
|
||||
|
@ -109,10 +114,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx context.Context, obj runtime.
|
|||
return err
|
||||
}
|
||||
|
||||
objectMeta.SetDeletionTimestamp(nil)
|
||||
objectMeta.SetDeletionGracePeriodSeconds(nil)
|
||||
strategy.PrepareForCreate(ctx, obj)
|
||||
FillObjectMetaSystemFields(objectMeta)
|
||||
|
||||
if len(objectMeta.GetGenerateName()) > 0 && len(objectMeta.GetName()) == 0 {
|
||||
objectMeta.SetName(strategy.GenerateName(objectMeta.GetGenerateName()))
|
||||
|
|
|
@ -23,11 +23,19 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
)
|
||||
|
||||
// WipeObjectMetaSystemFields erases fields that are managed by the system on ObjectMeta.
|
||||
func WipeObjectMetaSystemFields(meta metav1.Object) {
|
||||
meta.SetCreationTimestamp(metav1.Time{})
|
||||
meta.SetUID("")
|
||||
meta.SetDeletionTimestamp(nil)
|
||||
meta.SetDeletionGracePeriodSeconds(nil)
|
||||
meta.SetSelfLink("")
|
||||
}
|
||||
|
||||
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
||||
func FillObjectMetaSystemFields(meta metav1.Object) {
|
||||
meta.SetCreationTimestamp(metav1.Now())
|
||||
meta.SetUID(uuid.NewUUID())
|
||||
meta.SetSelfLink("")
|
||||
}
|
||||
|
||||
// EnsureObjectNamespaceMatchesRequestNamespace returns an error if obj.Namespace and requestNamespace
|
||||
|
|
|
@ -23,14 +23,33 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// TestWipeObjectMetaSystemFields validates that system populated fields are set on an object
|
||||
func TestWipeObjectMetaSystemFields(t *testing.T) {
|
||||
resource := metav1.ObjectMeta{}
|
||||
WipeObjectMetaSystemFields(&resource)
|
||||
if !resource.CreationTimestamp.Time.IsZero() {
|
||||
t.Errorf("resource.CreationTimestamp is set")
|
||||
}
|
||||
if len(resource.UID) != 0 {
|
||||
t.Errorf("resource.UID is set")
|
||||
}
|
||||
if resource.DeletionTimestamp != nil {
|
||||
t.Errorf("resource.DeletionTimestamp is set")
|
||||
}
|
||||
if resource.DeletionGracePeriodSeconds != nil {
|
||||
t.Errorf("resource.DeletionGracePeriodSeconds is set")
|
||||
}
|
||||
if len(resource.SelfLink) != 0 {
|
||||
t.Errorf("resource.SelfLink is set")
|
||||
}
|
||||
}
|
||||
|
||||
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
|
||||
func TestFillObjectMetaSystemFields(t *testing.T) {
|
||||
resource := metav1.ObjectMeta{}
|
||||
FillObjectMetaSystemFields(&resource)
|
||||
if resource.CreationTimestamp.Time.IsZero() {
|
||||
t.Errorf("resource.CreationTimestamp is zero")
|
||||
} else if len(resource.UID) == 0 {
|
||||
t.Errorf("resource.UID missing")
|
||||
}
|
||||
if len(resource.UID) == 0 {
|
||||
t.Errorf("resource.UID missing")
|
||||
|
|
Loading…
Reference in New Issue