mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-16 14:45:28 +00:00
Graceful deletion of resources
This commit adds support to core resources to enable deferred deletion of resources. Clients may optionally specify a time period after which resources must be deleted via an object sent with their DELETE. That object may define an optional grace period in seconds, or allow the default "preferred" value for a resource to be used. Once the object is marked as pending deletion, the deletionTimestamp field will be set and an etcd TTL will be in place. Clients should assume resources that have deletionTimestamp set will be deleted at some point in the future. Other changes will come later to enable graceful deletion on a per resource basis.
This commit is contained in:
@@ -81,19 +81,21 @@ type Etcd struct {
|
||||
// storage of the value in etcd is not appropriate, since they cannot
|
||||
// be watched.
|
||||
Decorator rest.ObjectFunc
|
||||
// Allows extended behavior during creation
|
||||
// Allows extended behavior during creation, required
|
||||
CreateStrategy rest.RESTCreateStrategy
|
||||
// On create of an object, attempt to run a further operation.
|
||||
AfterCreate rest.ObjectFunc
|
||||
// Allows extended behavior during updates
|
||||
// Allows extended behavior during updates, required
|
||||
UpdateStrategy rest.RESTUpdateStrategy
|
||||
// On update of an object, attempt to run a further operation.
|
||||
AfterUpdate rest.ObjectFunc
|
||||
// Allows extended behavior during updates, optional
|
||||
DeleteStrategy rest.RESTDeleteStrategy
|
||||
// On deletion of an object, attempt to run a further operation.
|
||||
AfterDelete rest.ObjectFunc
|
||||
// If true, return the object that was deleted. Otherwise, return a generic
|
||||
// success status response.
|
||||
ReturnDeletedObject bool
|
||||
// On deletion of an object, attempt to run a further operation.
|
||||
AfterDelete rest.ObjectFunc
|
||||
|
||||
// Used for all etcd access functions
|
||||
Helper tools.EtcdHelper
|
||||
@@ -333,8 +335,7 @@ func (e *Etcd) Get(ctx api.Context, name string) (runtime.Object, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = e.Helper.ExtractObj(key, obj, false)
|
||||
if err != nil {
|
||||
if err := e.Helper.ExtractObj(key, obj, false); err != nil {
|
||||
return nil, etcderr.InterpretGetError(err, e.EndpointName, name)
|
||||
}
|
||||
if e.Decorator != nil {
|
||||
@@ -346,26 +347,56 @@ func (e *Etcd) Get(ctx api.Context, name string) (runtime.Object, error) {
|
||||
}
|
||||
|
||||
// Delete removes the item from etcd.
|
||||
func (e *Etcd) Delete(ctx api.Context, name string) (runtime.Object, error) {
|
||||
func (e *Etcd) Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error) {
|
||||
key, err := e.KeyFunc(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj := e.NewFunc()
|
||||
if err := e.Helper.DeleteObj(key, obj); err != nil {
|
||||
if err := e.Helper.ExtractObj(key, obj, false); err != nil {
|
||||
return nil, etcderr.InterpretDeleteError(err, e.EndpointName, name)
|
||||
}
|
||||
if e.AfterDelete != nil {
|
||||
|
||||
// support older consumers of delete by treating "nil" as delete immediately
|
||||
if options == nil {
|
||||
options = api.NewDeleteOptions(0)
|
||||
}
|
||||
graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, obj, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pendingGraceful {
|
||||
return e.finalizeDelete(obj, false)
|
||||
}
|
||||
if graceful && *options.GracePeriodSeconds != 0 {
|
||||
out := e.NewFunc()
|
||||
if err := e.Helper.SetObj(key, obj, out, uint64(*options.GracePeriodSeconds)); err != nil {
|
||||
return nil, etcderr.InterpretUpdateError(err, e.EndpointName, name)
|
||||
}
|
||||
return e.finalizeDelete(out, true)
|
||||
}
|
||||
|
||||
// delete immediately, or no graceful deletion supported
|
||||
out := e.NewFunc()
|
||||
if err := e.Helper.DeleteObj(key, out); err != nil {
|
||||
return nil, etcderr.InterpretDeleteError(err, e.EndpointName, name)
|
||||
}
|
||||
return e.finalizeDelete(out, true)
|
||||
}
|
||||
|
||||
func (e *Etcd) finalizeDelete(obj runtime.Object, runHooks bool) (runtime.Object, error) {
|
||||
if runHooks && e.AfterDelete != nil {
|
||||
if err := e.AfterDelete(obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if e.Decorator != nil {
|
||||
if err := e.Decorator(obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if e.ReturnDeletedObject {
|
||||
if e.Decorator != nil {
|
||||
if err := e.Decorator(obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
return &api.Status{Status: api.StatusSuccess}, nil
|
||||
|
@@ -631,7 +631,7 @@ func TestEtcdDelete(t *testing.T) {
|
||||
for name, item := range table {
|
||||
fakeClient, registry := NewTestGenericEtcdRegistry(t)
|
||||
fakeClient.Data[path] = item.existing
|
||||
obj, err := registry.Delete(api.NewContext(), key)
|
||||
obj, err := registry.Delete(api.NewContext(), key, nil)
|
||||
if !item.errOK(err) {
|
||||
t.Errorf("%v: unexpected error: %v (%#v)", name, err, obj)
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ type Registry interface {
|
||||
CreateWithName(ctx api.Context, id string, obj runtime.Object) error
|
||||
UpdateWithName(ctx api.Context, id string, obj runtime.Object) error
|
||||
Get(ctx api.Context, id string) (runtime.Object, error)
|
||||
Delete(ctx api.Context, id string) (runtime.Object, error)
|
||||
Delete(ctx api.Context, id string, options *api.DeleteOptions) (runtime.Object, error)
|
||||
WatchPredicate(ctx api.Context, m Matcher, resourceVersion string) (watch.Interface, error)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user