mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 03:57:41 +00:00
prevent deletionTimestamp from moving into the past
This commit is contained in:
parent
4114a9b4e4
commit
88090c4973
@ -126,9 +126,22 @@ func BeforeDelete(strategy RESTDeleteStrategy, ctx context.Context, obj runtime.
|
|||||||
if period >= *objectMeta.GetDeletionGracePeriodSeconds() {
|
if period >= *objectMeta.GetDeletionGracePeriodSeconds() {
|
||||||
return false, true, nil
|
return false, true, nil
|
||||||
}
|
}
|
||||||
|
// Move the existing deletionTimestamp back by existing object.DeletionGracePeriod, then forward by options.DeletionGracePeriod.
|
||||||
|
// This moves the deletionTimestamp back, since the grace period can only be shortened in this code path.
|
||||||
newDeletionTimestamp := metav1.NewTime(
|
newDeletionTimestamp := metav1.NewTime(
|
||||||
objectMeta.GetDeletionTimestamp().Add(-time.Second * time.Duration(*objectMeta.GetDeletionGracePeriodSeconds())).
|
objectMeta.GetDeletionTimestamp().Add(-time.Second * time.Duration(*objectMeta.GetDeletionGracePeriodSeconds())).
|
||||||
Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
|
Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
|
||||||
|
// Prevent shortening the grace period moving deletionTimestamp into the past
|
||||||
|
if now := metav1Now(); newDeletionTimestamp.Before(&now) {
|
||||||
|
newDeletionTimestamp = now
|
||||||
|
if period != 0 {
|
||||||
|
// Since a graceful deletion was requested (options.GracePeriodSeconds != 0), but the entire grace period has already expired,
|
||||||
|
// shorten to the minimum period possible while still treating this as a graceful delete.
|
||||||
|
// This means the API server updates the object, another actor observes the update
|
||||||
|
// and is still responsible for the final delete with options.GracePeriodSeconds == 0.
|
||||||
|
period = int64(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
objectMeta.SetDeletionTimestamp(&newDeletionTimestamp)
|
objectMeta.SetDeletionTimestamp(&newDeletionTimestamp)
|
||||||
objectMeta.SetDeletionGracePeriodSeconds(&period)
|
objectMeta.SetDeletionGracePeriodSeconds(&period)
|
||||||
return true, false, nil
|
return true, false, nil
|
||||||
@ -147,8 +160,8 @@ func BeforeDelete(strategy RESTDeleteStrategy, ctx context.Context, obj runtime.
|
|||||||
return false, false, errors.NewInternalError(fmt.Errorf("options.GracePeriodSeconds should not be nil"))
|
return false, false, errors.NewInternalError(fmt.Errorf("options.GracePeriodSeconds should not be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
now := metav1.NewTime(metav1.Now().Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
|
requestedDeletionTimestamp := metav1.NewTime(metav1Now().Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
|
||||||
objectMeta.SetDeletionTimestamp(&now)
|
objectMeta.SetDeletionTimestamp(&requestedDeletionTimestamp)
|
||||||
objectMeta.SetDeletionGracePeriodSeconds(options.GracePeriodSeconds)
|
objectMeta.SetDeletionGracePeriodSeconds(options.GracePeriodSeconds)
|
||||||
// If it's the first graceful deletion we are going to set the DeletionTimestamp to non-nil.
|
// If it's the first graceful deletion we are going to set the DeletionTimestamp to non-nil.
|
||||||
// Controllers of the object that's being deleted shouldn't take any nontrivial actions, hence its behavior changes.
|
// Controllers of the object that's being deleted shouldn't take any nontrivial actions, hence its behavior changes.
|
||||||
|
@ -18,7 +18,9 @@ package rest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -52,15 +54,32 @@ func TestBeforeDelete(t *testing.T) {
|
|||||||
options *metav1.DeleteOptions
|
options *metav1.DeleteOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
makePod := func(deletionGracePeriodSeconds int64) *v1.Pod {
|
// snapshot and restore real metav1Now function
|
||||||
|
originalMetav1Now := metav1Now
|
||||||
|
t.Cleanup(func() {
|
||||||
|
metav1Now = originalMetav1Now
|
||||||
|
})
|
||||||
|
|
||||||
|
// make now refer to a fixed point in time
|
||||||
|
now := metav1.Time{Time: time.Now().Truncate(time.Second)}
|
||||||
|
metav1Now = func() metav1.Time {
|
||||||
|
return now
|
||||||
|
}
|
||||||
|
|
||||||
|
makePodWithDeletionTimestamp := func(deletionTimestamp *metav1.Time, deletionGracePeriodSeconds int64) *v1.Pod {
|
||||||
return &v1.Pod{
|
return &v1.Pod{
|
||||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
|
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
DeletionTimestamp: &metav1.Time{},
|
DeletionTimestamp: deletionTimestamp,
|
||||||
DeletionGracePeriodSeconds: &deletionGracePeriodSeconds,
|
DeletionGracePeriodSeconds: &deletionGracePeriodSeconds,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
makePod := func(deletionGracePeriodSeconds int64) *v1.Pod {
|
||||||
|
deletionTimestamp := now
|
||||||
|
deletionTimestamp.Time = deletionTimestamp.Time.Add(time.Duration(deletionGracePeriodSeconds) * time.Second)
|
||||||
|
return makePodWithDeletionTimestamp(&deletionTimestamp, deletionGracePeriodSeconds)
|
||||||
|
}
|
||||||
makeOption := func(gracePeriodSeconds int64) *metav1.DeleteOptions {
|
makeOption := func(gracePeriodSeconds int64) *metav1.DeleteOptions {
|
||||||
return &metav1.DeleteOptions{
|
return &metav1.DeleteOptions{
|
||||||
GracePeriodSeconds: &gracePeriodSeconds,
|
GracePeriodSeconds: &gracePeriodSeconds,
|
||||||
@ -74,6 +93,7 @@ func TestBeforeDelete(t *testing.T) {
|
|||||||
wantGracefulPending bool
|
wantGracefulPending bool
|
||||||
wantGracePeriodSeconds *int64
|
wantGracePeriodSeconds *int64
|
||||||
wantDeletionGracePeriodSeconds *int64
|
wantDeletionGracePeriodSeconds *int64
|
||||||
|
wantDeletionTimestamp *metav1.Time
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -271,6 +291,28 @@ func TestBeforeDelete(t *testing.T) {
|
|||||||
wantGraceful: false,
|
wantGraceful: false,
|
||||||
wantGracefulPending: true,
|
wantGracefulPending: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "when a shorter non-zero grace period would move into the past",
|
||||||
|
args: args{
|
||||||
|
pod: makePodWithDeletionTimestamp(&metav1.Time{Time: now.Time.Add(-time.Minute)}, 60),
|
||||||
|
options: makeOption(50),
|
||||||
|
},
|
||||||
|
wantDeletionTimestamp: &now,
|
||||||
|
wantDeletionGracePeriodSeconds: utilpointer.Int64(1),
|
||||||
|
wantGracePeriodSeconds: utilpointer.Int64(50),
|
||||||
|
wantGraceful: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when a zero grace period would move into the past",
|
||||||
|
args: args{
|
||||||
|
pod: makePodWithDeletionTimestamp(&metav1.Time{Time: now.Time.Add(-time.Minute)}, 60),
|
||||||
|
options: makeOption(0),
|
||||||
|
},
|
||||||
|
wantDeletionTimestamp: &now,
|
||||||
|
wantDeletionGracePeriodSeconds: utilpointer.Int64(0),
|
||||||
|
wantGracePeriodSeconds: utilpointer.Int64(0),
|
||||||
|
wantGraceful: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@ -301,6 +343,11 @@ func TestBeforeDelete(t *testing.T) {
|
|||||||
if !utilpointer.Int64Equal(tt.args.options.GracePeriodSeconds, tt.wantGracePeriodSeconds) {
|
if !utilpointer.Int64Equal(tt.args.options.GracePeriodSeconds, tt.wantGracePeriodSeconds) {
|
||||||
t.Errorf("options.GracePeriodSeconds = %v, want %v", ptr.Deref(tt.args.options.GracePeriodSeconds, 0), ptr.Deref(tt.wantGracePeriodSeconds, 0))
|
t.Errorf("options.GracePeriodSeconds = %v, want %v", ptr.Deref(tt.args.options.GracePeriodSeconds, 0), ptr.Deref(tt.wantGracePeriodSeconds, 0))
|
||||||
}
|
}
|
||||||
|
if tt.wantDeletionTimestamp != nil {
|
||||||
|
if !reflect.DeepEqual(tt.args.pod.DeletionTimestamp, tt.wantDeletionTimestamp) {
|
||||||
|
t.Errorf("pod.deletionTimestamp = %v, want %v", tt.args.pod.DeletionTimestamp, tt.wantDeletionTimestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// metav1Now returns metav1.Now(), but allows override for unit testing
|
||||||
|
var metav1Now = func() metav1.Time { return metav1.Now() }
|
||||||
|
|
||||||
// WipeObjectMetaSystemFields erases fields that are managed by the system on ObjectMeta.
|
// WipeObjectMetaSystemFields erases fields that are managed by the system on ObjectMeta.
|
||||||
func WipeObjectMetaSystemFields(meta metav1.Object) {
|
func WipeObjectMetaSystemFields(meta metav1.Object) {
|
||||||
meta.SetCreationTimestamp(metav1.Time{})
|
meta.SetCreationTimestamp(metav1.Time{})
|
||||||
@ -34,7 +37,7 @@ func WipeObjectMetaSystemFields(meta metav1.Object) {
|
|||||||
|
|
||||||
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
||||||
func FillObjectMetaSystemFields(meta metav1.Object) {
|
func FillObjectMetaSystemFields(meta metav1.Object) {
|
||||||
meta.SetCreationTimestamp(metav1.Now())
|
meta.SetCreationTimestamp(metav1Now())
|
||||||
meta.SetUID(uuid.NewUUID())
|
meta.SetUID(uuid.NewUUID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user