Content-Length: 541936 | pFad | http://github.com/kubernetes/kubernetes/pull/98866/files

70 Fix TerminationGracePeriodSeconds is negative (part 1) by wzshiming · Pull Request #98866 · kubernetes/kubernetes · GitHub
Skip to content

Fix TerminationGracePeriodSeconds is negative (part 1) #98866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion pkg/apis/core/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3973,6 +3973,7 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
// 1. spec.containers[*].image
// 2. spec.initContainers[*].image
// 3. spec.activeDeadlineSeconds
// 4. spec.terminationGracePeriodSeconds

containerErrs, stop := ValidateContainerUpdates(newPod.Spec.Containers, oldPod.Spec.Containers, specPath.Child("containers"))
allErrs = append(allErrs, containerErrs...)
Expand Down Expand Up @@ -4039,11 +4040,17 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
// tolerations are checked before the deep copy, so munge those too
mungedPodSpec.Tolerations = oldPod.Spec.Tolerations // +k8s:verify-mutation:reason=clone

// Relax validation of immutable fields to allow it to be set to 1 if it was previously negative.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this lgtm

if oldPod.Spec.TerminationGracePeriodSeconds != nil && *oldPod.Spec.TerminationGracePeriodSeconds < 0 &&
mungedPodSpec.TerminationGracePeriodSeconds != nil && *mungedPodSpec.TerminationGracePeriodSeconds == 1 {
mungedPodSpec.TerminationGracePeriodSeconds = oldPod.Spec.TerminationGracePeriodSeconds // +k8s:verify-mutation:reason=clone
}

if !apiequality.Semantic.DeepEqual(mungedPodSpec, oldPod.Spec) {
// This diff isn't perfect, but it's a helluva lot better an "I'm not going to tell you what the difference is".
//TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
specDiff := diff.ObjectDiff(mungedPodSpec, oldPod.Spec)
allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing tolerations)\n%v", specDiff)))
allErrs = append(allErrs, field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds`, `spec.tolerations` (only additions to existing tolerations) or `spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)\n%v", specDiff)))
}

return allErrs
Expand Down
40 changes: 40 additions & 0 deletions pkg/apis/core/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9803,6 +9803,46 @@ func TestValidatePodUpdate(t *testing.T) {
"spec: Forbidden: pod updates",
"removed priority class name",
},
{
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
TerminationGracePeriodSeconds: utilpointer.Int64Ptr(1),
},
},
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
TerminationGracePeriodSeconds: utilpointer.Int64Ptr(-1),
},
},
"",
"update termination grace period seconds",
},
{
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
TerminationGracePeriodSeconds: utilpointer.Int64Ptr(0),
},
},
core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
Spec: core.PodSpec{
TerminationGracePeriodSeconds: utilpointer.Int64Ptr(-1),
},
},
"spec: Forbidden: pod updates",
"update termination grace period seconds not 1",
},
}

for _, test := range tests {
Expand Down
5 changes: 5 additions & 0 deletions pkg/registry/core/pod/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ func (podStrategy) CheckGracefulDelete(ctx context.Context, obj runtime.Object,
if pod.Status.Phase == api.PodFailed || pod.Status.Phase == api.PodSucceeded {
period = 0
}

if period < 0 {
period = 1
}

// ensure the options and the pod are in sync
options.GracePeriodSeconds = &period
return true
Expand Down
70 changes: 49 additions & 21 deletions pkg/registry/core/pod/strategy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/client"
utilpointer "k8s.io/utils/pointer"

// ensure types are installed
_ "k8s.io/kubernetes/pkg/apis/core/install"
Expand Down Expand Up @@ -266,55 +267,82 @@ func TestGetPodQOS(t *testing.T) {
func TestCheckGracefulDelete(t *testing.T) {
defaultGracePeriod := int64(30)
tcs := []struct {
in *api.Pod
gracePeriod int64
name string
pod *api.Pod
deleteGracePeriod *int64
gracePeriod int64
}{
{
in: &api.Pod{
name: "in pending phase with has node name",
pod: &api.Pod{
Spec: api.PodSpec{NodeName: "something"},
Status: api.PodStatus{Phase: api.PodPending},
},

gracePeriod: defaultGracePeriod,
deleteGracePeriod: &defaultGracePeriod,
gracePeriod: defaultGracePeriod,
},
{
in: &api.Pod{
name: "in failed phase with has node name",
pod: &api.Pod{
Spec: api.PodSpec{NodeName: "something"},
Status: api.PodStatus{Phase: api.PodFailed},
},
gracePeriod: 0,
deleteGracePeriod: &defaultGracePeriod,
gracePeriod: 0,
},
{
in: &api.Pod{
name: "in failed phase",
pod: &api.Pod{
Spec: api.PodSpec{},
Status: api.PodStatus{Phase: api.PodPending},
},
gracePeriod: 0,
deleteGracePeriod: &defaultGracePeriod,
gracePeriod: 0,
},
{
in: &api.Pod{
name: "in succeeded phase",
pod: &api.Pod{
Spec: api.PodSpec{},
Status: api.PodStatus{Phase: api.PodSucceeded},
},
gracePeriod: 0,
deleteGracePeriod: &defaultGracePeriod,
gracePeriod: 0,
},
{
in: &api.Pod{
name: "no phase",
pod: &api.Pod{
Spec: api.PodSpec{},
Status: api.PodStatus{},
},
gracePeriod: 0,
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,
},
}
for _, tc := range tcs {
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)
}
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)
}
})
}
}

Expand Down
10 changes: 10 additions & 0 deletions staging/src/k8s.io/apiserver/pkg/registry/rest/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/admission"
utilpointer "k8s.io/utils/pointer"
)

// RESTDeleteStrategy defines deletion behavior on an object that follows Kubernetes
Expand Down Expand Up @@ -86,6 +87,15 @@ func BeforeDelete(strategy RESTDeleteStrategy, ctx context.Context, obj runtime.
return false, false, errors.NewConflict(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, objectMeta.GetName(), fmt.Errorf("the ResourceVersion in the precondition (%s) does not match the ResourceVersion in record (%s). The object might have been modified", *options.Preconditions.ResourceVersion, objectMeta.GetResourceVersion()))
}
}

// Negative values will be treated as the value `1s` on the delete path.
if gracePeriodSeconds := options.GracePeriodSeconds; gracePeriodSeconds != nil && *gracePeriodSeconds < 0 {
options.GracePeriodSeconds = utilpointer.Int64(1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding another options mutation looks like it will exacerbate the issue being fixed in #100101

@deads2k, is that PR close? is there something this PR should do differently to avoid that issue?

}
if deletionGracePeriodSeconds := objectMeta.GetDeletionGracePeriodSeconds(); deletionGracePeriodSeconds != nil && *deletionGracePeriodSeconds < 0 {
objectMeta.SetDeletionGracePeriodSeconds(utilpointer.Int64(1))
}

gracefulStrategy, ok := strategy.(RESTGracefulDeleteStrategy)
if !ok {
// If we're not deleting gracefully there's no point in updating Generation, as we won't update
Expand Down
Loading








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/kubernetes/kubernetes/pull/98866/files

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy