Merge pull request #99375 from ehashman/probe-kep-2238

Add Probe-level terminationGracePeriodSeconds
This commit is contained in:
Kubernetes Prow Robot 2021-03-11 23:10:18 -08:00 committed by GitHub
commit faa5c8ccd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 18088 additions and 17260 deletions

View File

@ -8957,7 +8957,7 @@
"type": "string" "type": "string"
}, },
"terminationGracePeriodSeconds": { "terminationGracePeriodSeconds": {
"description": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.", "description": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.",
"format": "int64", "format": "int64",
"type": "integer" "type": "integer"
}, },
@ -9249,6 +9249,11 @@
"$ref": "#/definitions/io.k8s.api.core.v1.TCPSocketAction", "$ref": "#/definitions/io.k8s.api.core.v1.TCPSocketAction",
"description": "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported" "description": "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported"
}, },
"terminationGracePeriodSeconds": {
"description": "Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate.",
"format": "int64",
"type": "integer"
},
"timeoutSeconds": { "timeoutSeconds": {
"description": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes", "description": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
"format": "int32", "format": "int32",

View File

@ -551,6 +551,20 @@ func dropDisabledFields(
}) })
} }
if !utilfeature.DefaultFeatureGate.Enabled(features.ProbeTerminationGracePeriod) && !probeGracePeriodInUse(oldPodSpec) {
// Set pod-level terminationGracePeriodSeconds to nil if the feature is disabled and it is not used
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
if c.LivenessProbe != nil {
c.LivenessProbe.TerminationGracePeriodSeconds = nil
}
if c.StartupProbe != nil {
c.StartupProbe.TerminationGracePeriodSeconds = nil
}
// cannot be set for readiness probes
return true
})
}
dropDisabledFSGroupFields(podSpec, oldPodSpec) dropDisabledFSGroupFields(podSpec, oldPodSpec)
if !utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) && !overheadInUse(oldPodSpec) { if !utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) && !overheadInUse(oldPodSpec) {
@ -811,6 +825,27 @@ func subpathExprInUse(podSpec *api.PodSpec) bool {
return inUse return inUse
} }
// probeGracePeriodInUse returns true if the pod spec is non-nil and has a probe that makes use
// of the probe-level terminationGracePeriodSeconds feature
func probeGracePeriodInUse(podSpec *api.PodSpec) bool {
if podSpec == nil {
return false
}
var inUse bool
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
// cannot be set for readiness probes
if (c.LivenessProbe != nil && c.LivenessProbe.TerminationGracePeriodSeconds != nil) ||
(c.StartupProbe != nil && c.StartupProbe.TerminationGracePeriodSeconds != nil) {
inUse = true
return false
}
return true
})
return inUse
}
// csiInUse returns true if any pod's spec include inline CSI volumes. // csiInUse returns true if any pod's spec include inline CSI volumes.
func csiInUse(podSpec *api.PodSpec) bool { func csiInUse(podSpec *api.PodSpec) bool {
if podSpec == nil { if podSpec == nil {

View File

@ -1140,6 +1140,103 @@ func TestDropSubPathExpr(t *testing.T) {
} }
} }
func TestDropProbeGracePeriod(t *testing.T) {
gracePeriod := int64(10)
probe := api.Probe{TerminationGracePeriodSeconds: &gracePeriod}
podWithProbeGracePeriod := func() *api.Pod {
return &api.Pod{
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyNever,
Containers: []api.Container{{Name: "container1", Image: "testimage", LivenessProbe: &probe, StartupProbe: &probe}},
},
}
}
podWithoutProbeGracePeriod := func() *api.Pod {
p := podWithProbeGracePeriod()
p.Spec.Containers[0].LivenessProbe.TerminationGracePeriodSeconds = nil
p.Spec.Containers[0].StartupProbe.TerminationGracePeriodSeconds = nil
return p
}
podInfo := []struct {
description string
hasGracePeriod bool
pod func() *api.Pod
}{
{
description: "has probe-level terminationGracePeriod",
hasGracePeriod: true,
pod: podWithProbeGracePeriod,
},
{
description: "does not have probe-level terminationGracePeriod",
hasGracePeriod: false,
pod: podWithoutProbeGracePeriod,
},
{
description: "only has liveness probe-level terminationGracePeriod",
hasGracePeriod: true,
pod: func() *api.Pod {
p := podWithProbeGracePeriod()
p.Spec.Containers[0].StartupProbe.TerminationGracePeriodSeconds = nil
return p
},
},
{
description: "is nil",
hasGracePeriod: false,
pod: func() *api.Pod { return nil },
},
}
enabled := true
for _, oldPodInfo := range podInfo {
for _, newPodInfo := range podInfo {
oldPodHasGracePeriod, oldPod := oldPodInfo.hasGracePeriod, oldPodInfo.pod()
newPodHasGracePeriod, newPod := newPodInfo.hasGracePeriod, newPodInfo.pod()
if newPod == nil {
continue
}
t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
var oldPodSpec *api.PodSpec
if oldPod != nil {
oldPodSpec = &oldPod.Spec
}
dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
// old pod should never be changed
if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
t.Errorf("old pod changed: %v", diff.ObjectReflectDiff(oldPod, oldPodInfo.pod()))
}
switch {
case enabled || oldPodHasGracePeriod:
// new pod should not be changed if the feature is enabled, or if the old pod had subpaths
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodInfo.pod()))
}
case newPodHasGracePeriod:
// new pod should be changed
if reflect.DeepEqual(newPod, newPodInfo.pod()) {
t.Errorf("new pod was not changed")
}
// new pod should not have subpaths
if !reflect.DeepEqual(newPod, podWithoutProbeGracePeriod()) {
t.Errorf("new pod had probe-level terminationGracePeriod: %v", diff.ObjectReflectDiff(newPod, podWithoutProbeGracePeriod()))
}
default:
// new pod should not need to be changed
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodInfo.pod()))
}
}
})
}
}
}
// helper creates a podStatus with list of PodIPs // helper creates a podStatus with list of PodIPs
func makePodStatus(podIPs []api.PodIP) *api.PodStatus { func makePodStatus(podIPs []api.PodIP) *api.PodStatus {
return &api.PodStatus{ return &api.PodStatus{

View File

@ -2020,6 +2020,17 @@ type Probe struct {
// Minimum consecutive failures for the probe to be considered failed after having succeeded. // Minimum consecutive failures for the probe to be considered failed after having succeeded.
// +optional // +optional
FailureThreshold int32 FailureThreshold int32
// Optional duration in seconds the pod needs to terminate gracefully upon probe failure.
// The grace period is the duration in seconds after the processes running in the pod are sent
// a termination signal and the time when the processes are forcibly halted with a kill signal.
// Set this value longer than the expected cleanup time for your process.
// If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this
// value overrides the value provided by the pod spec.
// Value must be non-negative integer. The value zero indicates stop immediately via
// the kill signal (no opportunity to shut down).
// This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate.
// +optional
TerminationGracePeriodSeconds *int64
} }
// PullPolicy describes a policy for if/when to pull a container image // PullPolicy describes a policy for if/when to pull a container image
@ -2719,7 +2730,8 @@ type PodSpec struct {
// +optional // +optional
RestartPolicy RestartPolicy RestartPolicy RestartPolicy
// Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. // Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request.
// Value must be non-negative integer. The value zero indicates delete immediately. // Value must be non-negative integer. The value zero indicates stop immediately via the kill
// signal (no opportunity to shut down).
// If this value is nil, the default grace period will be used instead. // If this value is nil, the default grace period will be used instead.
// The grace period is the duration in seconds after the processes running in the pod are sent // The grace period is the duration in seconds after the processes running in the pod are sent
// a termination signal and the time when the processes are forcibly halted with a kill signal. // a termination signal and the time when the processes are forcibly halted with a kill signal.

View File

@ -6467,6 +6467,7 @@ func autoConvert_v1_Probe_To_core_Probe(in *v1.Probe, out *core.Probe, s convers
out.PeriodSeconds = in.PeriodSeconds out.PeriodSeconds = in.PeriodSeconds
out.SuccessThreshold = in.SuccessThreshold out.SuccessThreshold = in.SuccessThreshold
out.FailureThreshold = in.FailureThreshold out.FailureThreshold = in.FailureThreshold
out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds))
return nil return nil
} }
@ -6484,6 +6485,7 @@ func autoConvert_core_Probe_To_v1_Probe(in *core.Probe, out *v1.Probe, s convers
out.PeriodSeconds = in.PeriodSeconds out.PeriodSeconds = in.PeriodSeconds
out.SuccessThreshold = in.SuccessThreshold out.SuccessThreshold = in.SuccessThreshold
out.FailureThreshold = in.FailureThreshold out.FailureThreshold = in.FailureThreshold
out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds))
return nil return nil
} }

View File

@ -2859,6 +2859,11 @@ func validateContainers(containers []core.Container, isInitContainers bool, volu
allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, idxPath.Child("lifecycle"))...) allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, idxPath.Child("lifecycle"))...)
} }
allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, idxPath.Child("livenessProbe"))...) allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, idxPath.Child("livenessProbe"))...)
// Readiness-specific validation
if ctr.ReadinessProbe != nil && ctr.ReadinessProbe.TerminationGracePeriodSeconds != nil {
allErrs = append(allErrs, field.Invalid(idxPath.Child("readinessProbe", "terminationGracePeriodSeconds"), ctr.ReadinessProbe.TerminationGracePeriodSeconds, "must not be set for readinessProbes"))
}
allErrs = append(allErrs, validateProbe(ctr.StartupProbe, idxPath.Child("startupProbe"))...)
// Liveness-specific validation // Liveness-specific validation
if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 { if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 {
allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1")) allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1"))

View File

@ -6284,6 +6284,20 @@ func TestValidateContainers(t *testing.T) {
TerminationMessagePolicy: "File", TerminationMessagePolicy: "File",
}, },
}, },
"invalid readiness probe, terminationGracePeriodSeconds set.": {
{
Name: "life-123",
Image: "image",
ReadinessProbe: &core.Probe{
Handler: core.Handler{
TCPSocket: &core.TCPSocketAction{},
},
TerminationGracePeriodSeconds: utilpointer.Int64Ptr(10),
},
ImagePullPolicy: "IfNotPresent",
TerminationMessagePolicy: "File",
},
},
"invalid liveness probe, no tcp socket port.": { "invalid liveness probe, no tcp socket port.": {
{ {
Name: "life-123", Name: "life-123",

View File

@ -4192,6 +4192,11 @@ func (in *PreferredSchedulingTerm) DeepCopy() *PreferredSchedulingTerm {
func (in *Probe) DeepCopyInto(out *Probe) { func (in *Probe) DeepCopyInto(out *Probe) {
*out = *in *out = *in
in.Handler.DeepCopyInto(&out.Handler) in.Handler.DeepCopyInto(&out.Handler)
if in.TerminationGracePeriodSeconds != nil {
in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
*out = new(int64)
**out = **in
}
return return
} }

View File

@ -696,6 +696,12 @@ const (
// Enables topology aware hints for EndpointSlices // Enables topology aware hints for EndpointSlices
TopologyAwareHints featuregate.Feature = "TopologyAwareHints" TopologyAwareHints featuregate.Feature = "TopologyAwareHints"
// owner: @ehashman
// alpha: v1.21
//
// Allows user to override pod-level terminationGracePeriod for probes
ProbeTerminationGracePeriod featuregate.Feature = "ProbeTerminationGracePeriod"
// owner: @ahg-g // owner: @ahg-g
// alpha: v1.21 // alpha: v1.21
// //
@ -850,6 +856,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
MixedProtocolLBService: {Default: false, PreRelease: featuregate.Alpha}, MixedProtocolLBService: {Default: false, PreRelease: featuregate.Alpha},
VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha}, VolumeCapacityPriority: {Default: false, PreRelease: featuregate.Alpha},
PreferNominatedNode: {Default: false, PreRelease: featuregate.Alpha}, PreferNominatedNode: {Default: false, PreRelease: featuregate.Alpha},
ProbeTerminationGracePeriod: {Default: false, PreRelease: featuregate.Alpha},
RunAsGroup: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22 RunAsGroup: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.22
PodDeletionCost: {Default: false, PreRelease: featuregate.Alpha}, PodDeletionCost: {Default: false, PreRelease: featuregate.Alpha},
TopologyAwareHints: {Default: false, PreRelease: featuregate.Alpha}, TopologyAwareHints: {Default: false, PreRelease: featuregate.Alpha},

View File

@ -227,7 +227,7 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb
msg, handlerErr := m.runner.Run(kubeContainerID, pod, container, container.Lifecycle.PostStart) msg, handlerErr := m.runner.Run(kubeContainerID, pod, container, container.Lifecycle.PostStart)
if handlerErr != nil { if handlerErr != nil {
m.recordContainerEvent(pod, container, kubeContainerID.ID, v1.EventTypeWarning, events.FailedPostStartHook, msg) m.recordContainerEvent(pod, container, kubeContainerID.ID, v1.EventTypeWarning, events.FailedPostStartHook, msg)
if err := m.killContainer(pod, kubeContainerID, container.Name, "FailedPostStartHook", nil); err != nil { if err := m.killContainer(pod, kubeContainerID, container.Name, "FailedPostStartHook", reasonFailedPostStartHook, nil); err != nil {
klog.ErrorS(fmt.Errorf("%s: %v", ErrPostStartHook, handlerErr), "Failed to kill container", "pod", klog.KObj(pod), klog.ErrorS(fmt.Errorf("%s: %v", ErrPostStartHook, handlerErr), "Failed to kill container", "pod", klog.KObj(pod),
"podUID", pod.UID, "containerName", container.Name, "containerID", kubeContainerID.String()) "podUID", pod.UID, "containerName", container.Name, "containerID", kubeContainerID.String())
} }
@ -596,7 +596,7 @@ func (m *kubeGenericRuntimeManager) restoreSpecsFromContainerLabels(containerID
// killContainer kills a container through the following steps: // killContainer kills a container through the following steps:
// * Run the pre-stop lifecycle hooks (if applicable). // * Run the pre-stop lifecycle hooks (if applicable).
// * Stop the container. // * Stop the container.
func (m *kubeGenericRuntimeManager) killContainer(pod *v1.Pod, containerID kubecontainer.ContainerID, containerName string, message string, gracePeriodOverride *int64) error { func (m *kubeGenericRuntimeManager) killContainer(pod *v1.Pod, containerID kubecontainer.ContainerID, containerName string, message string, reason containerKillReason, gracePeriodOverride *int64) error {
var containerSpec *v1.Container var containerSpec *v1.Container
if pod != nil { if pod != nil {
if containerSpec = kubecontainer.GetContainerSpec(pod, containerName); containerSpec == nil { if containerSpec = kubecontainer.GetContainerSpec(pod, containerName); containerSpec == nil {
@ -619,6 +619,19 @@ func (m *kubeGenericRuntimeManager) killContainer(pod *v1.Pod, containerID kubec
gracePeriod = *pod.DeletionGracePeriodSeconds gracePeriod = *pod.DeletionGracePeriodSeconds
case pod.Spec.TerminationGracePeriodSeconds != nil: case pod.Spec.TerminationGracePeriodSeconds != nil:
gracePeriod = *pod.Spec.TerminationGracePeriodSeconds gracePeriod = *pod.Spec.TerminationGracePeriodSeconds
if utilfeature.DefaultFeatureGate.Enabled(features.ProbeTerminationGracePeriod) {
switch reason {
case reasonStartupProbe:
if containerSpec.StartupProbe != nil && containerSpec.StartupProbe.TerminationGracePeriodSeconds != nil {
gracePeriod = *containerSpec.StartupProbe.TerminationGracePeriodSeconds
}
case reasonLivenessProbe:
if containerSpec.LivenessProbe != nil && containerSpec.LivenessProbe.TerminationGracePeriodSeconds != nil {
gracePeriod = *containerSpec.LivenessProbe.TerminationGracePeriodSeconds
}
}
}
} }
if len(message) == 0 { if len(message) == 0 {
@ -672,7 +685,7 @@ func (m *kubeGenericRuntimeManager) killContainersWithSyncResult(pod *v1.Pod, ru
defer wg.Done() defer wg.Done()
killContainerResult := kubecontainer.NewSyncResult(kubecontainer.KillContainer, container.Name) killContainerResult := kubecontainer.NewSyncResult(kubecontainer.KillContainer, container.Name)
if err := m.killContainer(pod, container.ID, container.Name, "", gracePeriodOverride); err != nil { if err := m.killContainer(pod, container.ID, container.Name, "", reasonUnknown, gracePeriodOverride); err != nil {
killContainerResult.Fail(kubecontainer.ErrKillContainer, err.Error()) killContainerResult.Fail(kubecontainer.ErrKillContainer, err.Error())
klog.ErrorS(err, "Kill container failed", "pod", klog.KObj(pod), "podUID", pod.UID, klog.ErrorS(err, "Kill container failed", "pod", klog.KObj(pod), "podUID", pod.UID,
"containerName", container.Name, "containerID", container.ID) "containerName", container.Name, "containerID", container.ID)

View File

@ -120,7 +120,7 @@ func TestKillContainer(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
err := m.killContainer(test.pod, test.containerID, test.containerName, test.reason, &test.gracePeriodOverride) err := m.killContainer(test.pod, test.containerID, test.containerName, test.reason, "", &test.gracePeriodOverride)
if test.succeed != (err == nil) { if test.succeed != (err == nil) {
t.Errorf("%s: expected %v, got %v (%v)", test.caseName, test.succeed, (err == nil), err) t.Errorf("%s: expected %v, got %v (%v)", test.caseName, test.succeed, (err == nil), err)
} }
@ -290,7 +290,7 @@ func TestLifeCycleHook(t *testing.T) {
// Configured and works as expected // Configured and works as expected
t.Run("PreStop-CMDExec", func(t *testing.T) { t.Run("PreStop-CMDExec", func(t *testing.T) {
testPod.Spec.Containers[0].Lifecycle = cmdLifeCycle testPod.Spec.Containers[0].Lifecycle = cmdLifeCycle
m.killContainer(testPod, cID, "foo", "testKill", &gracePeriod) m.killContainer(testPod, cID, "foo", "testKill", "", &gracePeriod)
if fakeRunner.Cmd[0] != cmdLifeCycle.PreStop.Exec.Command[0] { if fakeRunner.Cmd[0] != cmdLifeCycle.PreStop.Exec.Command[0] {
t.Errorf("CMD Prestop hook was not invoked") t.Errorf("CMD Prestop hook was not invoked")
} }
@ -300,7 +300,7 @@ func TestLifeCycleHook(t *testing.T) {
t.Run("PreStop-HTTPGet", func(t *testing.T) { t.Run("PreStop-HTTPGet", func(t *testing.T) {
defer func() { fakeHTTP.url = "" }() defer func() { fakeHTTP.url = "" }()
testPod.Spec.Containers[0].Lifecycle = httpLifeCycle testPod.Spec.Containers[0].Lifecycle = httpLifeCycle
m.killContainer(testPod, cID, "foo", "testKill", &gracePeriod) m.killContainer(testPod, cID, "foo", "testKill", "", &gracePeriod)
if !strings.Contains(fakeHTTP.url, httpLifeCycle.PreStop.HTTPGet.Host) { if !strings.Contains(fakeHTTP.url, httpLifeCycle.PreStop.HTTPGet.Host) {
t.Errorf("HTTP Prestop hook was not invoked") t.Errorf("HTTP Prestop hook was not invoked")
@ -314,7 +314,7 @@ func TestLifeCycleHook(t *testing.T) {
testPod.DeletionGracePeriodSeconds = &gracePeriodLocal testPod.DeletionGracePeriodSeconds = &gracePeriodLocal
testPod.Spec.TerminationGracePeriodSeconds = &gracePeriodLocal testPod.Spec.TerminationGracePeriodSeconds = &gracePeriodLocal
m.killContainer(testPod, cID, "foo", "testKill", &gracePeriodLocal) m.killContainer(testPod, cID, "foo", "testKill", "", &gracePeriodLocal)
if strings.Contains(fakeHTTP.url, httpLifeCycle.PreStop.HTTPGet.Host) { if strings.Contains(fakeHTTP.url, httpLifeCycle.PreStop.HTTPGet.Host) {
t.Errorf("HTTP Should not execute when gracePeriod is 0") t.Errorf("HTTP Should not execute when gracePeriod is 0")

View File

@ -137,7 +137,7 @@ func (cgc *containerGC) removeOldestN(containers []containerGCInfo, toRemove int
ID: containers[i].id, ID: containers[i].id,
} }
message := "Container is in unknown state, try killing it before removal" message := "Container is in unknown state, try killing it before removal"
if err := cgc.manager.killContainer(nil, id, containers[i].name, message, nil); err != nil { if err := cgc.manager.killContainer(nil, id, containers[i].name, message, reasonUnknown, nil); err != nil {
klog.Errorf("Failed to stop container %q: %v", containers[i].id, err) klog.Errorf("Failed to stop container %q: %v", containers[i].id, err)
continue continue
} }

View File

@ -403,6 +403,16 @@ func (m *kubeGenericRuntimeManager) GetPods(all bool) ([]*kubecontainer.Pod, err
return result, nil return result, nil
} }
// containerKillReason explains what killed a given container
type containerKillReason string
const (
reasonStartupProbe containerKillReason = "StartupProbe"
reasonLivenessProbe containerKillReason = "LivenessProbe"
reasonFailedPostStartHook containerKillReason = "FailedPostStartHook"
reasonUnknown containerKillReason = "Unknown"
)
// containerToKillInfo contains necessary information to kill a container. // containerToKillInfo contains necessary information to kill a container.
type containerToKillInfo struct { type containerToKillInfo struct {
// The spec of the container. // The spec of the container.
@ -411,6 +421,9 @@ type containerToKillInfo struct {
name string name string
// The message indicates why the container will be killed. // The message indicates why the container will be killed.
message string message string
// The reason is a clearer source of info on why a container will be killed
// TODO: replace message with reason?
reason containerKillReason
} }
// podActions keeps information what to do for a pod. // podActions keeps information what to do for a pod.
@ -582,6 +595,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku
container: next, container: next,
message: fmt.Sprintf("Init container is in %q state, try killing it before restart", message: fmt.Sprintf("Init container is in %q state, try killing it before restart",
initLastStatus.State), initLastStatus.State),
reason: reasonUnknown,
} }
} }
changes.NextInitContainerToStart = next changes.NextInitContainerToStart = next
@ -623,6 +637,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku
container: &pod.Spec.Containers[idx], container: &pod.Spec.Containers[idx],
message: fmt.Sprintf("Container is in %q state, try killing it before restart", message: fmt.Sprintf("Container is in %q state, try killing it before restart",
containerStatus.State), containerStatus.State),
reason: reasonUnknown,
} }
} }
} }
@ -630,6 +645,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku
} }
// The container is running, but kill the container if any of the following condition is met. // The container is running, but kill the container if any of the following condition is met.
var message string var message string
var reason containerKillReason
restart := shouldRestartOnFailure(pod) restart := shouldRestartOnFailure(pod)
if _, _, changed := containerChanged(&container, containerStatus); changed { if _, _, changed := containerChanged(&container, containerStatus); changed {
message = fmt.Sprintf("Container %s definition changed", container.Name) message = fmt.Sprintf("Container %s definition changed", container.Name)
@ -639,9 +655,11 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku
} else if liveness, found := m.livenessManager.Get(containerStatus.ID); found && liveness == proberesults.Failure { } else if liveness, found := m.livenessManager.Get(containerStatus.ID); found && liveness == proberesults.Failure {
// If the container failed the liveness probe, we should kill it. // If the container failed the liveness probe, we should kill it.
message = fmt.Sprintf("Container %s failed liveness probe", container.Name) message = fmt.Sprintf("Container %s failed liveness probe", container.Name)
reason = reasonLivenessProbe
} else if startup, found := m.startupManager.Get(containerStatus.ID); found && startup == proberesults.Failure { } else if startup, found := m.startupManager.Get(containerStatus.ID); found && startup == proberesults.Failure {
// If the container failed the startup probe, we should kill it. // If the container failed the startup probe, we should kill it.
message = fmt.Sprintf("Container %s failed startup probe", container.Name) message = fmt.Sprintf("Container %s failed startup probe", container.Name)
reason = reasonStartupProbe
} else { } else {
// Keep the container. // Keep the container.
keepCount++ keepCount++
@ -660,6 +678,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku
name: containerStatus.Name, name: containerStatus.Name,
container: &pod.Spec.Containers[idx], container: &pod.Spec.Containers[idx],
message: message, message: message,
reason: reason,
} }
klog.V(2).InfoS("Message for Container of pod", "containerName", container.Name, "containerStatusID", containerStatus.ID, "pod", klog.KObj(pod), "containerMessage", message) klog.V(2).InfoS("Message for Container of pod", "containerName", container.Name, "containerStatusID", containerStatus.ID, "pod", klog.KObj(pod), "containerMessage", message)
} }
@ -720,7 +739,7 @@ func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontaine
klog.V(3).InfoS("Killing unwanted container for pod", "containerName", containerInfo.name, "containerID", containerID, "pod", klog.KObj(pod)) klog.V(3).InfoS("Killing unwanted container for pod", "containerName", containerInfo.name, "containerID", containerID, "pod", klog.KObj(pod))
killContainerResult := kubecontainer.NewSyncResult(kubecontainer.KillContainer, containerInfo.name) killContainerResult := kubecontainer.NewSyncResult(kubecontainer.KillContainer, containerInfo.name)
result.AddSyncResult(killContainerResult) result.AddSyncResult(killContainerResult)
if err := m.killContainer(pod, containerID, containerInfo.name, containerInfo.message, nil); err != nil { if err := m.killContainer(pod, containerID, containerInfo.name, containerInfo.message, containerInfo.reason, nil); err != nil {
killContainerResult.Fail(kubecontainer.ErrKillContainer, err.Error()) killContainerResult.Fail(kubecontainer.ErrKillContainer, err.Error())
klog.ErrorS(err, "killContainer for pod failed", "containerName", containerInfo.name, "containerID", containerID, "pod", klog.KObj(pod)) klog.ErrorS(err, "killContainer for pod failed", "containerName", containerInfo.name, "containerID", containerID, "pod", klog.KObj(pod))
return return

View File

@ -1002,9 +1002,10 @@ func getKillMapWithInitContainers(pod *v1.Pod, status *kubecontainer.PodStatus,
func verifyActions(t *testing.T, expected, actual *podActions, desc string) { func verifyActions(t *testing.T, expected, actual *podActions, desc string) {
if actual.ContainersToKill != nil { if actual.ContainersToKill != nil {
// Clear the message field since we don't need to verify the message. // Clear the message and reason fields since we don't need to verify them.
for k, info := range actual.ContainersToKill { for k, info := range actual.ContainersToKill {
info.message = "" info.message = ""
info.reason = ""
actual.ContainersToKill[k] = info actual.ContainersToKill[k] = info
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -3421,7 +3421,8 @@ message PodSpec {
optional string restartPolicy = 3; optional string restartPolicy = 3;
// Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. // Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request.
// Value must be non-negative integer. The value zero indicates delete immediately. // Value must be non-negative integer. The value zero indicates stop immediately via
// the kill signal (no opportunity to shut down).
// If this value is nil, the default grace period will be used instead. // If this value is nil, the default grace period will be used instead.
// The grace period is the duration in seconds after the processes running in the pod are sent // The grace period is the duration in seconds after the processes running in the pod are sent
// a termination signal and the time when the processes are forcibly halted with a kill signal. // a termination signal and the time when the processes are forcibly halted with a kill signal.
@ -3883,6 +3884,18 @@ message Probe {
// Defaults to 3. Minimum value is 1. // Defaults to 3. Minimum value is 1.
// +optional // +optional
optional int32 failureThreshold = 6; optional int32 failureThreshold = 6;
// Optional duration in seconds the pod needs to terminate gracefully upon probe failure.
// The grace period is the duration in seconds after the processes running in the pod are sent
// a termination signal and the time when the processes are forcibly halted with a kill signal.
// Set this value longer than the expected cleanup time for your process.
// If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this
// value overrides the value provided by the pod spec.
// Value must be non-negative integer. The value zero indicates stop immediately via
// the kill signal (no opportunity to shut down).
// This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate.
// +optional
optional int64 terminationGracePeriodSeconds = 7;
} }
// Represents a projected volume source // Represents a projected volume source

View File

@ -2117,6 +2117,17 @@ type Probe struct {
// Defaults to 3. Minimum value is 1. // Defaults to 3. Minimum value is 1.
// +optional // +optional
FailureThreshold int32 `json:"failureThreshold,omitempty" protobuf:"varint,6,opt,name=failureThreshold"` FailureThreshold int32 `json:"failureThreshold,omitempty" protobuf:"varint,6,opt,name=failureThreshold"`
// Optional duration in seconds the pod needs to terminate gracefully upon probe failure.
// The grace period is the duration in seconds after the processes running in the pod are sent
// a termination signal and the time when the processes are forcibly halted with a kill signal.
// Set this value longer than the expected cleanup time for your process.
// If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this
// value overrides the value provided by the pod spec.
// Value must be non-negative integer. The value zero indicates stop immediately via
// the kill signal (no opportunity to shut down).
// This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate.
// +optional
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty" protobuf:"varint,7,opt,name=terminationGracePeriodSeconds"`
} }
// PullPolicy describes a policy for if/when to pull a container image // PullPolicy describes a policy for if/when to pull a container image
@ -2968,7 +2979,8 @@ type PodSpec struct {
// +optional // +optional
RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,3,opt,name=restartPolicy,casttype=RestartPolicy"` RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,3,opt,name=restartPolicy,casttype=RestartPolicy"`
// Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. // Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request.
// Value must be non-negative integer. The value zero indicates delete immediately. // Value must be non-negative integer. The value zero indicates stop immediately via
// the kill signal (no opportunity to shut down).
// If this value is nil, the default grace period will be used instead. // If this value is nil, the default grace period will be used instead.
// The grace period is the duration in seconds after the processes running in the pod are sent // The grace period is the duration in seconds after the processes running in the pod are sent
// a termination signal and the time when the processes are forcibly halted with a kill signal. // a termination signal and the time when the processes are forcibly halted with a kill signal.

View File

@ -1627,7 +1627,7 @@ var map_PodSpec = map[string]string{
"containers": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated.", "containers": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated.",
"ephemeralContainers": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.", "ephemeralContainers": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.",
"restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy", "restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy",
"terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.", "terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.",
"activeDeadlineSeconds": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.", "activeDeadlineSeconds": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.",
"dnsPolicy": "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", "dnsPolicy": "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.",
"nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", "nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/",
@ -1777,12 +1777,13 @@ func (PreferredSchedulingTerm) SwaggerDoc() map[string]string {
} }
var map_Probe = map[string]string{ var map_Probe = map[string]string{
"": "Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.", "": "Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.",
"initialDelaySeconds": "Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes", "initialDelaySeconds": "Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
"timeoutSeconds": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes", "timeoutSeconds": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
"periodSeconds": "How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1.", "periodSeconds": "How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1.",
"successThreshold": "Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1.", "successThreshold": "Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1.",
"failureThreshold": "Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1.", "failureThreshold": "Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1.",
"terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate.",
} }
func (Probe) SwaggerDoc() map[string]string { func (Probe) SwaggerDoc() map[string]string {

View File

@ -4190,6 +4190,11 @@ func (in *PreferredSchedulingTerm) DeepCopy() *PreferredSchedulingTerm {
func (in *Probe) DeepCopyInto(out *Probe) { func (in *Probe) DeepCopyInto(out *Probe) {
*out = *in *out = *in
in.Handler.DeepCopyInto(&out.Handler) in.Handler.DeepCopyInto(&out.Handler)
if in.TerminationGracePeriodSeconds != nil {
in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
*out = new(int64)
**out = **in
}
return return
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -148,7 +148,8 @@
"timeoutSeconds": 1563658126, "timeoutSeconds": 1563658126,
"periodSeconds": -1771047449, "periodSeconds": -1771047449,
"successThreshold": -1280107919, "successThreshold": -1280107919,
"failureThreshold": -54954325 "failureThreshold": -54954325,
"terminationGracePeriodSeconds": 8559948711650432497
}, },
"readinessProbe": { "readinessProbe": {
"exec": { "exec": {
@ -158,138 +159,141 @@
}, },
"httpGet": { "httpGet": {
"path": "53", "path": "53",
"port": "54", "port": -1395989138,
"host": "55", "host": "54",
"scheme": "OŖ樅尷", "scheme": "斎AO6ĴC浔Ű壝ž",
"httpHeaders": [ "httpHeaders": [
{ {
"name": "56", "name": "55",
"value": "57" "value": "56"
} }
] ]
}, },
"tcpSocket": { "tcpSocket": {
"port": 2136826132, "port": 180803110,
"host": "58" "host": "57"
}, },
"initialDelaySeconds": 819364842, "initialDelaySeconds": -2014231015,
"timeoutSeconds": 933484239, "timeoutSeconds": 1488277679,
"periodSeconds": -983896210, "periodSeconds": -1679907303,
"successThreshold": 552512122, "successThreshold": -1051545416,
"failureThreshold": -833209928 "failureThreshold": 1305372099,
"terminationGracePeriodSeconds": -1220632347188845753
}, },
"startupProbe": { "startupProbe": {
"exec": { "exec": {
"command": [ "command": [
"59" "58"
] ]
}, },
"httpGet": { "httpGet": {
"path": "60", "path": "59",
"port": 180803110, "port": 1229400382,
"host": "61", "host": "60",
"scheme": "ņ錕?øēƺ", "scheme": "3ƆìQ喞艋涽託仭",
"httpHeaders": [ "httpHeaders": [
{ {
"name": "62", "name": "61",
"value": "63" "value": "62"
} }
] ]
}, },
"tcpSocket": { "tcpSocket": {
"port": "64", "port": "63",
"host": "65" "host": "64"
}, },
"initialDelaySeconds": -816398166, "initialDelaySeconds": 2076966617,
"timeoutSeconds": 1229400382, "timeoutSeconds": 202362764,
"periodSeconds": -1583208879, "periodSeconds": -560446848,
"successThreshold": 1088264954, "successThreshold": -1098992377,
"failureThreshold": 13573196 "failureThreshold": -1009864962,
"terminationGracePeriodSeconds": 2618170937706035036
}, },
"lifecycle": { "lifecycle": {
"postStart": { "postStart": {
"exec": { "exec": {
"command": [ "command": [
"66" "65"
] ]
}, },
"httpGet": { "httpGet": {
"path": "67", "path": "66",
"port": -1293912096, "port": -503563033,
"host": "68", "host": "67",
"scheme": "託仭", "scheme": "趕ã/鈱$-议}ȧ外ĺ稥氹Ç|¶鎚¡ ",
"httpHeaders": [ "httpHeaders": [
{ {
"name": "69", "name": "68",
"value": "70" "value": "69"
} }
] ]
}, },
"tcpSocket": { "tcpSocket": {
"port": "71", "port": "70",
"host": "72" "host": "71"
} }
}, },
"preStop": { "preStop": {
"exec": { "exec": {
"command": [ "command": [
"73" "72"
] ]
}, },
"httpGet": { "httpGet": {
"path": "74", "path": "73",
"port": "75", "port": 991085362,
"host": "76", "host": "74",
"scheme": "鴜Ł%Ũ", "scheme": "磩窮秳ķ蟒苾h^樅燴壩卄",
"httpHeaders": [ "httpHeaders": [
{ {
"name": "77", "name": "75",
"value": "78" "value": "76"
} }
] ]
}, },
"tcpSocket": { "tcpSocket": {
"port": "79", "port": -479087071,
"host": "80" "host": "77"
} }
} }
}, },
"terminationMessagePath": "81", "terminationMessagePath": "78",
"terminationMessagePolicy": "Ņ£", "terminationMessagePolicy": "?讦ĭÐ",
"imagePullPolicy": "/C龷ȪÆl殛瓷雼浢Ü礽绅",
"securityContext": { "securityContext": {
"capabilities": { "capabilities": {
"add": [ "add": [
"2Ō¾\\ĒP鄸靇杧ž" "\"ŵw^Ü郀叚Fi皬择,Q"
], ],
"drop": [ "drop": [
"娲瘹ɭȊɚɎ(dɅ囥糷磩窮秳ķ蟒苾h^" "ȸ{+"
] ]
}, },
"privileged": false, "privileged": false,
"seLinuxOptions": { "seLinuxOptions": {
"user": "82", "user": "79",
"role": "83", "role": "80",
"type": "84", "type": "81",
"level": "85" "level": "82"
}, },
"windowsOptions": { "windowsOptions": {
"gmsaCredentialSpecName": "86", "gmsaCredentialSpecName": "83",
"gmsaCredentialSpec": "87", "gmsaCredentialSpec": "84",
"runAsUserName": "88" "runAsUserName": "85"
}, },
"runAsUser": 4491726672505793472, "runAsUser": -1466062763730980131,
"runAsGroup": -5441351197948631872, "runAsGroup": 8360795821384820753,
"runAsNonRoot": true, "runAsNonRoot": false,
"readOnlyRootFilesystem": true, "readOnlyRootFilesystem": true,
"allowPrivilegeEscalation": true, "allowPrivilegeEscalation": true,
"procMount": "ĭÐl恕ɍȇ廄裭4懙", "procMount": "Ƙq/",
"seccompProfile": { "seccompProfile": {
"type": "嵒ƫS捕ɷD¡轫n", "type": " u衲\u003c¿燥",
"localhostProfile": "89" "localhostProfile": "86"
} }
}, },
"stdin": true, "tty": true,
"targetContainerName": "90" "targetContainerName": "87"
} }
] ]
} }

View File

@ -32,37 +32,38 @@ ephemeralContainers:
name: "28" name: "28"
optional: false optional: false
image: "20" image: "20"
imagePullPolicy: /C龷ȪÆl殛瓷雼浢Ü礽绅
lifecycle: lifecycle:
postStart: postStart:
exec: exec:
command: command:
- "66" - "65"
httpGet: httpGet:
host: "68" host: "67"
httpHeaders: httpHeaders:
- name: "69" - name: "68"
value: "70" value: "69"
path: "67" path: "66"
port: -1293912096 port: -503563033
scheme: 託仭 scheme: '趕ã/鈱$-议}ȧ外ĺ稥氹Ç|¶鎚¡ '
tcpSocket: tcpSocket:
host: "72" host: "71"
port: "71" port: "70"
preStop: preStop:
exec: exec:
command: command:
- "73" - "72"
httpGet: httpGet:
host: "76" host: "74"
httpHeaders: httpHeaders:
- name: "77" - name: "75"
value: "78" value: "76"
path: "74" path: "73"
port: "75" port: 991085362
scheme: 鴜Ł%Ũ scheme: 磩窮秳ķ蟒苾h^樅燴壩卄
tcpSocket: tcpSocket:
host: "80" host: "77"
port: "79" port: -479087071
livenessProbe: livenessProbe:
exec: exec:
command: command:
@ -82,6 +83,7 @@ ephemeralContainers:
tcpSocket: tcpSocket:
host: "51" host: "51"
port: 1366345526 port: 1366345526
terminationGracePeriodSeconds: 8559948711650432497
timeoutSeconds: 1563658126 timeoutSeconds: 1563658126
name: "19" name: "19"
ports: ports:
@ -93,22 +95,23 @@ ephemeralContainers:
exec: exec:
command: command:
- "52" - "52"
failureThreshold: -833209928 failureThreshold: 1305372099
httpGet: httpGet:
host: "55" host: "54"
httpHeaders: httpHeaders:
- name: "56" - name: "55"
value: "57" value: "56"
path: "53" path: "53"
port: "54" port: -1395989138
scheme: OŖ樅尷 scheme: 斎AO6ĴC浔Ű壝ž
initialDelaySeconds: 819364842 initialDelaySeconds: -2014231015
periodSeconds: -983896210 periodSeconds: -1679907303
successThreshold: 552512122 successThreshold: -1051545416
tcpSocket: tcpSocket:
host: "58" host: "57"
port: 2136826132 port: 180803110
timeoutSeconds: 933484239 terminationGracePeriodSeconds: -1220632347188845753
timeoutSeconds: 1488277679
resources: resources:
limits: limits:
V夸eɑ: "420" V夸eɑ: "420"
@ -118,51 +121,52 @@ ephemeralContainers:
allowPrivilegeEscalation: true allowPrivilegeEscalation: true
capabilities: capabilities:
add: add:
- 2Ō¾\ĒP鄸靇杧ž - '"ŵw^Ü郀叚Fi皬择,Q'
drop: drop:
- 娲瘹ɭȊɚɎ(dɅ囥糷磩窮秳ķ蟒苾h^ - ȸ{+
privileged: false privileged: false
procMount: ĭÐl恕ɍȇ廄裭4懙 procMount: Ƙq/
readOnlyRootFilesystem: true readOnlyRootFilesystem: true
runAsGroup: -5441351197948631872 runAsGroup: 8360795821384820753
runAsNonRoot: true runAsNonRoot: false
runAsUser: 4491726672505793472 runAsUser: -1466062763730980131
seLinuxOptions: seLinuxOptions:
level: "85" level: "82"
role: "83" role: "80"
type: "84" type: "81"
user: "82" user: "79"
seccompProfile: seccompProfile:
localhostProfile: "89" localhostProfile: "86"
type: 嵒ƫS捕ɷD¡轫n type: ' u衲<¿燥'
windowsOptions: windowsOptions:
gmsaCredentialSpec: "87" gmsaCredentialSpec: "84"
gmsaCredentialSpecName: "86" gmsaCredentialSpecName: "83"
runAsUserName: "88" runAsUserName: "85"
startupProbe: startupProbe:
exec: exec:
command: command:
- "59" - "58"
failureThreshold: 13573196 failureThreshold: -1009864962
httpGet: httpGet:
host: "61" host: "60"
httpHeaders: httpHeaders:
- name: "62" - name: "61"
value: "63" value: "62"
path: "60" path: "59"
port: 180803110 port: 1229400382
scheme: ņ錕?øēƺ scheme: 3ƆìQ喞艋涽託仭
initialDelaySeconds: -816398166 initialDelaySeconds: 2076966617
periodSeconds: -1583208879 periodSeconds: -560446848
successThreshold: 1088264954 successThreshold: -1098992377
tcpSocket: tcpSocket:
host: "65" host: "64"
port: "64" port: "63"
timeoutSeconds: 1229400382 terminationGracePeriodSeconds: 2618170937706035036
stdin: true timeoutSeconds: 202362764
targetContainerName: "90" targetContainerName: "87"
terminationMessagePath: "81" terminationMessagePath: "78"
terminationMessagePolicy: Ņ£ terminationMessagePolicy: ?讦ĭÐ
tty: true
volumeDevices: volumeDevices:
- devicePath: "44" - devicePath: "44"
name: "43" name: "43"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -21,12 +21,13 @@ package v1
// ProbeApplyConfiguration represents an declarative configuration of the Probe type for use // ProbeApplyConfiguration represents an declarative configuration of the Probe type for use
// with apply. // with apply.
type ProbeApplyConfiguration struct { type ProbeApplyConfiguration struct {
HandlerApplyConfiguration `json:",inline"` HandlerApplyConfiguration `json:",inline"`
InitialDelaySeconds *int32 `json:"initialDelaySeconds,omitempty"` InitialDelaySeconds *int32 `json:"initialDelaySeconds,omitempty"`
TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty"` TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty"`
PeriodSeconds *int32 `json:"periodSeconds,omitempty"` PeriodSeconds *int32 `json:"periodSeconds,omitempty"`
SuccessThreshold *int32 `json:"successThreshold,omitempty"` SuccessThreshold *int32 `json:"successThreshold,omitempty"`
FailureThreshold *int32 `json:"failureThreshold,omitempty"` FailureThreshold *int32 `json:"failureThreshold,omitempty"`
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
} }
// ProbeApplyConfiguration constructs an declarative configuration of the Probe type for use with // ProbeApplyConfiguration constructs an declarative configuration of the Probe type for use with
@ -98,3 +99,11 @@ func (b *ProbeApplyConfiguration) WithFailureThreshold(value int32) *ProbeApplyC
b.FailureThreshold = &value b.FailureThreshold = &value
return b return b
} }
// WithTerminationGracePeriodSeconds sets the TerminationGracePeriodSeconds field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the TerminationGracePeriodSeconds field is set to the value of the last call.
func (b *ProbeApplyConfiguration) WithTerminationGracePeriodSeconds(value int64) *ProbeApplyConfiguration {
b.TerminationGracePeriodSeconds = &value
return b
}

View File

@ -5514,6 +5514,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: tcpSocket - name: tcpSocket
type: type:
namedType: io.k8s.api.core.v1.TCPSocketAction namedType: io.k8s.api.core.v1.TCPSocketAction
- name: terminationGracePeriodSeconds
type:
scalar: numeric
- name: timeoutSeconds - name: timeoutSeconds
type: type:
scalar: numeric scalar: numeric

View File

@ -420,6 +420,67 @@ var _ = SIGDescribe("Probing container", func() {
framework.Failf("Pod became ready in %v, more than 5s after startupProbe succeeded. It means that the delay readiness probes were not initiated immediately after startup finished.", readyIn) framework.Failf("Pod became ready in %v, more than 5s after startupProbe succeeded. It means that the delay readiness probes were not initiated immediately after startup finished.", readyIn)
} }
}) })
/*
Release: v1.21
Testname: Set terminationGracePeriodSeconds for livenessProbe
Description: A pod with a long terminationGracePeriod is created with a shorter livenessProbe-level terminationGracePeriodSeconds. We confirm the shorter termination period is used.
*/
ginkgo.It("should override timeoutGracePeriodSeconds when LivenessProbe field is set [Feature:ProbeTerminationGracePeriod]", func() {
pod := e2epod.NewAgnhostPod(f.Namespace.Name, "liveness-override-"+string(uuid.NewUUID()), nil, nil, nil, "/bin/sh", "-c", "sleep 1000")
longGracePeriod := int64(500)
pod.Spec.TerminationGracePeriodSeconds = &longGracePeriod
// probe will fail since pod has no http endpoints
shortGracePeriod := int64(5)
pod.Spec.Containers[0].LivenessProbe = &v1.Probe{
Handler: v1.Handler{
HTTPGet: &v1.HTTPGetAction{
Path: "/healthz",
Port: intstr.FromInt(8080),
},
},
InitialDelaySeconds: 10,
FailureThreshold: 1,
TerminationGracePeriodSeconds: &shortGracePeriod,
}
// 10s delay + 10s period + 5s grace period = 25s < 30s << pod-level timeout 500
RunLivenessTest(f, pod, 1, time.Second*30)
})
/*
Release: v1.21
Testname: Set terminationGracePeriodSeconds for startupProbe
Description: A pod with a long terminationGracePeriod is created with a shorter startupProbe-level terminationGracePeriodSeconds. We confirm the shorter termination period is used.
*/
ginkgo.It("should override timeoutGracePeriodSeconds when StartupProbe field is set [Feature:ProbeTerminationGracePeriod]", func() {
pod := e2epod.NewAgnhostPod(f.Namespace.Name, "startup-override-"+string(uuid.NewUUID()), nil, nil, nil, "/bin/sh", "-c", "sleep 1000")
longGracePeriod := int64(500)
pod.Spec.TerminationGracePeriodSeconds = &longGracePeriod
// startup probe will fail since pod will sleep for 1000s before becoming ready
shortGracePeriod := int64(5)
pod.Spec.Containers[0].StartupProbe = &v1.Probe{
Handler: execHandler([]string{"/bin/cat", "/tmp/startup"}),
InitialDelaySeconds: 10,
FailureThreshold: 1,
TerminationGracePeriodSeconds: &shortGracePeriod,
}
// liveness probe always succeeds
pod.Spec.Containers[0].LivenessProbe = &v1.Probe{
Handler: v1.Handler{
Exec: &v1.ExecAction{
Command: []string{"/bin/true"},
},
},
InitialDelaySeconds: 15,
FailureThreshold: 1,
}
// 10s delay + 10s period + 5s grace period = 25s < 30s << pod-level timeout 500
RunLivenessTest(f, pod, 1, time.Second*30)
})
}) })
// GetContainerStartedTime returns the time when the given container started and error if any // GetContainerStartedTime returns the time when the given container started and error if any