// Create inserts a new item according to the unique key from the object. func (e *Store) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil { return nil, err } name, err := e.ObjectNameFunc(obj) if err != nil { return nil, err } key, err := e.KeyFunc(ctx, name) if err != nil { return nil, err } ttl, err := e.calculateTTL(obj, 0, false) if err != nil { return nil, err } out := e.NewFunc() if err := e.Storage.Create(ctx, key, obj, out, ttl); err != nil { err = storeerr.InterpretCreateError(err, e.QualifiedResource, name) err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj) return nil, err } if e.AfterCreate != nil { if err := e.AfterCreate(out); err != nil { return nil, err } } if e.Decorator != nil { if err := e.Decorator(obj); err != nil { return nil, err } } return out, nil }
// Create inserts a new item according to the unique key from the object. func (e *Store) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil { return nil, err } name, err := e.ObjectNameFunc(obj) if err != nil { return nil, err } key, err := e.KeyFunc(ctx, name) if err != nil { return nil, err } ttl, err := e.calculateTTL(obj, 0, false) if err != nil { return nil, err } out := e.NewFunc() if err := e.Storage.Create(ctx, key, obj, out, ttl); err != nil { err = storeerr.InterpretCreateError(err, e.QualifiedResource, name) err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj) if !kubeerr.IsAlreadyExists(err) { return nil, err } if errGet := e.Storage.Get(ctx, key, out, false); errGet != nil { return nil, err } accessor, errGetAcc := meta.Accessor(out) if errGetAcc != nil { return nil, err } if accessor.GetDeletionTimestamp() != nil { msg := &err.(*kubeerr.StatusError).ErrStatus.Message *msg = fmt.Sprintf("object is being deleted: %s", *msg) // TODO: remove this block after 1.6 userAgent, _ := api.UserAgentFrom(ctx) if !isOldKubectl(userAgent) { return nil, err } if e.QualifiedResource.Resource != "replicationcontrollers" { return nil, err } *msg = fmt.Sprintf("%s: if you're using \"kubectl rolling-update\" with kubectl version older than v1.4.0, your rolling update has failed, though the pods are correctly updated. Please see https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG.md#kubectl-rolling-update for a workaround", *msg) } return nil, err } if e.AfterCreate != nil { if err := e.AfterCreate(out); err != nil { return nil, err } } if e.Decorator != nil { if err := e.Decorator(obj); err != nil { return nil, err } } return out, nil }
// Create inserts a new item according to the unique key from the object. func (e *Store) Create(ctx genericapirequest.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil { return nil, err } name, err := e.ObjectNameFunc(obj) if err != nil { return nil, err } key, err := e.KeyFunc(ctx, name) if err != nil { return nil, err } ttl, err := e.calculateTTL(obj, 0, false) if err != nil { return nil, err } out := e.NewFunc() if err := e.Storage.Create(ctx, key, obj, out, ttl); err != nil { err = storeerr.InterpretCreateError(err, e.QualifiedResource, name) err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj) if !kubeerr.IsAlreadyExists(err) { return nil, err } if errGet := e.Storage.Get(ctx, key, "", out, false); errGet != nil { return nil, err } accessor, errGetAcc := meta.Accessor(out) if errGetAcc != nil { return nil, err } if accessor.GetDeletionTimestamp() != nil { msg := &err.(*kubeerr.StatusError).ErrStatus.Message *msg = fmt.Sprintf("object is being deleted: %s", *msg) } return nil, err } if e.AfterCreate != nil { if err := e.AfterCreate(out); err != nil { return nil, err } } if e.Decorator != nil { if err := e.Decorator(obj); err != nil { return nil, err } } return out, nil }
// 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. // A bool is returned along with the object and any errors, to indicate object creation. func (e *Store) Update(ctx api.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { key, err := e.KeyFunc(ctx, name) if err != nil { return nil, false, err } var ( creatingObj runtime.Object creating = false ) storagePreconditions := &storage.Preconditions{} if preconditions := objInfo.Preconditions(); preconditions != nil { storagePreconditions.UID = preconditions.UID } out := e.NewFunc() // deleteObj is only used in case a deletion is carried out var deleteObj runtime.Object err = e.Storage.GuaranteedUpdate(ctx, key, out, true, storagePreconditions, func(existing runtime.Object, res storage.ResponseMeta) (runtime.Object, *uint64, error) { // Given the existing object, get the new object obj, err := objInfo.UpdatedObject(ctx, existing) if err != nil { return nil, nil, err } // If AllowUnconditionalUpdate() is true and the object specified by the user does not have a resource version, // then we populate it with the latest version. // Else, we check that the version specified by the user matches the version of latest storage object. resourceVersion, err := e.Storage.Versioner().ObjectResourceVersion(obj) if err != nil { return nil, nil, err } doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate() version, err := e.Storage.Versioner().ObjectResourceVersion(existing) if err != nil { return nil, nil, err } if version == 0 { if !e.UpdateStrategy.AllowCreateOnUpdate() { return nil, nil, kubeerr.NewNotFound(e.QualifiedResource, name) } creating = true creatingObj = obj if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil { return nil, nil, err } ttl, err := e.calculateTTL(obj, 0, false) if err != nil { return nil, nil, err } return obj, &ttl, nil } creating = false creatingObj = nil if doUnconditionalUpdate { // Update the object's resource version to match the latest storage object's resource version. err = e.Storage.Versioner().UpdateObject(obj, res.ResourceVersion) if err != nil { return nil, nil, err } } else { // Check if the object's resource version matches the latest resource version. newVersion, err := e.Storage.Versioner().ObjectResourceVersion(obj) if err != nil { return nil, nil, err } if newVersion == 0 { // TODO: The Invalid error should has a field for Resource. // After that field is added, we should fill the Resource and // leave the Kind field empty. See the discussion in #18526. qualifiedKind := unversioned.GroupKind{Group: e.QualifiedResource.Group, Kind: e.QualifiedResource.Resource} fieldErrList := field.ErrorList{field.Invalid(field.NewPath("metadata").Child("resourceVersion"), newVersion, "must be specified for an update")} return nil, nil, kubeerr.NewInvalid(qualifiedKind, name, fieldErrList) } if newVersion != version { return nil, nil, kubeerr.NewConflict(e.QualifiedResource, name, fmt.Errorf(OptimisticLockErrorMsg)) } } if err := rest.BeforeUpdate(e.UpdateStrategy, ctx, obj, existing); err != nil { return nil, nil, err } delete := e.shouldDelete(ctx, key, obj, existing) if delete { deleteObj = obj return nil, nil, errEmptiedFinalizers } ttl, err := e.calculateTTL(obj, res.TTL, true) if err != nil { return nil, nil, err } if int64(ttl) != res.TTL { return obj, &ttl, nil } return obj, nil, nil }) if err != nil { // delete the object if err == errEmptiedFinalizers { return e.deleteForEmptyFinalizers(ctx, name, key, deleteObj, storagePreconditions) } if creating { err = storeerr.InterpretCreateError(err, e.QualifiedResource, name) err = rest.CheckGeneratedNameError(e.CreateStrategy, err, creatingObj) } else { err = storeerr.InterpretUpdateError(err, e.QualifiedResource, name) } return nil, false, err } if creating { if e.AfterCreate != nil { if err := e.AfterCreate(out); err != nil { return nil, false, err } } } else { if e.AfterUpdate != nil { if err := e.AfterUpdate(out); err != nil { return nil, false, err } } } if e.Decorator != nil { if err := e.Decorator(out); err != nil { return nil, false, err } } return out, creating, nil }
// 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. // A bool is returned along with the object and any errors, to indicate object creation. func (e *Store) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { name, err := e.ObjectNameFunc(obj) if err != nil { return nil, false, err } key, err := e.KeyFunc(ctx, name) if err != nil { return nil, false, err } // If AllowUnconditionalUpdate() is true and the object specified by the user does not have a resource version, // then we populate it with the latest version. // Else, we check that the version specified by the user matches the version of latest storage object. resourceVersion, err := e.Storage.Versioner().ObjectResourceVersion(obj) if err != nil { return nil, false, err } doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate() // TODO: expose TTL creating := false out := e.NewFunc() meta, err := api.ObjectMetaFor(obj) if err != nil { return nil, false, kubeerr.NewInternalError(err) } var preconditions *storage.Preconditions // If the UID of the new object is specified, we use it as an Update precondition. if len(meta.UID) != 0 { UIDCopy := meta.UID preconditions = &storage.Preconditions{UID: &UIDCopy} } err = e.Storage.GuaranteedUpdate(ctx, key, out, true, preconditions, func(existing runtime.Object, res storage.ResponseMeta) (runtime.Object, *uint64, error) { // Since we return 'obj' from this function and it can be modified outside this // function, we are resetting resourceVersion to the initial value here. // // TODO: In fact, we should probably return a DeepCopy of obj in all places. err := e.Storage.Versioner().UpdateObject(obj, resourceVersion) if err != nil { return nil, nil, err } version, err := e.Storage.Versioner().ObjectResourceVersion(existing) if err != nil { return nil, nil, err } if version == 0 { if !e.UpdateStrategy.AllowCreateOnUpdate() { return nil, nil, kubeerr.NewNotFound(e.QualifiedResource, name) } creating = true if err := rest.BeforeCreate(e.CreateStrategy, ctx, obj); err != nil { return nil, nil, err } ttl, err := e.calculateTTL(obj, 0, false) if err != nil { return nil, nil, err } return obj, &ttl, nil } creating = false if doUnconditionalUpdate { // Update the object's resource version to match the latest storage object's resource version. err = e.Storage.Versioner().UpdateObject(obj, res.ResourceVersion) if err != nil { return nil, nil, err } } else { // Check if the object's resource version matches the latest resource version. newVersion, err := e.Storage.Versioner().ObjectResourceVersion(obj) if err != nil { return nil, nil, err } if newVersion == 0 { // TODO: The Invalid error should has a field for Resource. // After that field is added, we should fill the Resource and // leave the Kind field empty. See the discussion in #18526. qualifiedKind := unversioned.GroupKind{Group: e.QualifiedResource.Group, Kind: e.QualifiedResource.Resource} fieldErrList := field.ErrorList{field.Invalid(field.NewPath("metadata").Child("resourceVersion"), newVersion, "must be specified for an update")} return nil, nil, kubeerr.NewInvalid(qualifiedKind, name, fieldErrList) } if newVersion != version { return nil, nil, kubeerr.NewConflict(e.QualifiedResource, name, fmt.Errorf("the object has been modified; please apply your changes to the latest version and try again")) } } if err := rest.BeforeUpdate(e.UpdateStrategy, ctx, obj, existing); err != nil { return nil, nil, err } ttl, err := e.calculateTTL(obj, res.TTL, true) if err != nil { return nil, nil, err } if int64(ttl) != res.TTL { return obj, &ttl, nil } return obj, nil, nil }) if err != nil { if creating { err = storeerr.InterpretCreateError(err, e.QualifiedResource, name) err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj) } else { err = storeerr.InterpretUpdateError(err, e.QualifiedResource, name) } return nil, false, err } if creating { if e.AfterCreate != nil { if err := e.AfterCreate(out); err != nil { return nil, false, err } } } else { if e.AfterUpdate != nil { if err := e.AfterUpdate(out); err != nil { return nil, false, err } } } if e.Decorator != nil { if err := e.Decorator(obj); err != nil { return nil, false, err } } return out, creating, nil }