Code change:
func TestCheckGracefulDelete(t *testing.T) { defaultGracePeriod := int64(30) tcs := []struct { <del> in          *api.Pod gracePeriod int64 </del> <ins> name              string pod               *api.Pod deleteGracePeriod *int64 gracePeriod       int64 </ins> }{ { <del> in: &api.Pod{ </del> <ins> name: "in pending phase with has node name", pod: &api.Pod{ </ins> Spec:   api.PodSpec{NodeName: "something"}, Status: api.PodStatus{Phase: api.PodPending}, }, <del> gracePeriod: defaultGracePeriod, </del> <ins> deleteGracePeriod: &defaultGracePeriod, gracePeriod:       defaultGracePeriod, </ins> }, { <del> in: &api.Pod{ </del> <ins> name: "in failed phase with has node name", pod: &api.Pod{ </ins> Spec:   api.PodSpec{NodeName: "something"}, Status: api.PodStatus{Phase: api.PodFailed}, }, <del> gracePeriod: 0, </del> <ins> deleteGracePeriod: &defaultGracePeriod, gracePeriod:       0, </ins> }, { <del> in: &api.Pod{ </del> <ins> name: "in failed phase", pod: &api.Pod{ </ins> Spec:   api.PodSpec{}, Status: api.PodStatus{Phase: api.PodPending}, }, <del> gracePeriod: 0, </del> <ins> deleteGracePeriod: &defaultGracePeriod, gracePeriod:       0, </ins> }, { <del> in: &api.Pod{ </del> <ins> name: "in succeeded phase", pod: &api.Pod{ </ins> Spec:   api.PodSpec{}, Status: api.PodStatus{Phase: api.PodSucceeded}, }, <del> gracePeriod: 0, </del> <ins> deleteGracePeriod: &defaultGracePeriod, gracePeriod:       0, </ins> }, { <del> in: &api.Pod{ </del> <ins> name: "no phase", pod: &api.Pod{ </ins> Spec:   api.PodSpec{}, Status: api.PodStatus{}, }, <del> gracePeriod: 0, </del> <ins> deleteGracePeriod: &defaultGracePeriod, gracePeriod:       0, }, { name: "has negative grace period", pod: &api.Pod{ Spec: api.PodSpec{ NodeName:                      "something", TerminationGracePeriodSeconds: utilpointer.Int64(-1), }, Status: api.PodStatus{}, }, gracePeriod: 1, </ins> }, } for _, tc := range tcs { <del> out := &metav1.DeleteOptions{GracePeriodSeconds: &defaultGracePeriod} Strategy.CheckGracefulDelete(genericapirequest.NewContext(), tc.in, out) if out.GracePeriodSeconds == nil { t.Errorf("out grace period was nil but supposed to be %v", tc.gracePeriod) } if *(out.GracePeriodSeconds) != tc.gracePeriod { t.Errorf("out grace period was %v but was expected to be %v", *out, tc.gracePeriod) } </del> <ins> t.Run(tc.name, func(t *testing.T) { out := &metav1.DeleteOptions{} if tc.deleteGracePeriod != nil { out.GracePeriodSeconds = utilpointer.Int64(*tc.deleteGracePeriod) } Strategy.CheckGracefulDelete(genericapirequest.NewContext(), tc.pod, out) if out.GracePeriodSeconds == nil { t.Errorf("out grace period was nil but supposed to be %v", tc.gracePeriod) } if *(out.GracePeriodSeconds) != tc.gracePeriod { t.Errorf("out grace period was %v but was expected to be %v", *out, tc.gracePeriod) } }) </ins> } }

Related discussion:
text: In Kube, components are required to calculate the time period from when they observe the event in their local clock (i.e. 30s from now), not use the deletion timestamp. A negative value of deletion grace period should be rejected by the apiserver as an invalid value (bad request / invalid field).
attempts to take a missing or positive deletion grace period negative should be rejected, I agree. if a negative value is already persisted, I'd be inclined to allow a negative value in an update and clip to 0
As I mentioned in the PR, eviction is passing negatives through to the store: In kubectl, we specify the default value for GracePeriod is -1. In the case of delete, we simply don't set the value in the deleteOptions we send to the API. In the case of eviction, we send the -1 value, and that gets passed along to the store.
I don't see the -1 getting sent to the eviction API. It looks like values < 0 result in a nil value being sent to the API: I would not expect the API to accept a negative value as-is.
Looks like you are correct. Do the deletionOptions go through their own validation or through some kind of validation for the evict API? The original bug report mentions 'evict' though it's not clear if the eviction API was used or not.
ValidateDeleteOptions is called inside pod deletion, but did not check that the field was non-negative. I don't see any eviction-specific validation.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-contributor-experience at . /lifecycle stale
Stale issues rot after 30d of inactivity. Mark the issue as fresh with . Rotten issues close after an additional 30d of inactivity. If this issue is safe to close now please do so with . Send feedback to sig-contributor-experience at . /lifecycle rotten
/lifecycle rotten
Im investigating the and . Surprisingly see you here...