mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 18:24:07 +00:00
implementation
This commit is contained in:
parent
fa01dfdb0a
commit
3a96afdfef
@ -558,6 +558,64 @@ func dropDisabledFields(
|
||||
}
|
||||
// For other types of containers, validateContainers will handle them.
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodLifecycleSleepAction) && !podLifecycleSleepActionInUse(oldPodSpec) {
|
||||
for i := range podSpec.Containers {
|
||||
if podSpec.Containers[i].Lifecycle == nil {
|
||||
continue
|
||||
}
|
||||
if podSpec.Containers[i].Lifecycle.PreStop != nil {
|
||||
podSpec.Containers[i].Lifecycle.PreStop.Sleep = nil
|
||||
}
|
||||
if podSpec.Containers[i].Lifecycle.PostStart != nil {
|
||||
podSpec.Containers[i].Lifecycle.PostStart.Sleep = nil
|
||||
}
|
||||
}
|
||||
for i := range podSpec.InitContainers {
|
||||
if podSpec.InitContainers[i].Lifecycle == nil {
|
||||
continue
|
||||
}
|
||||
if podSpec.InitContainers[i].Lifecycle.PreStop != nil {
|
||||
podSpec.InitContainers[i].Lifecycle.PreStop.Sleep = nil
|
||||
}
|
||||
if podSpec.InitContainers[i].Lifecycle.PostStart != nil {
|
||||
podSpec.InitContainers[i].Lifecycle.PostStart.Sleep = nil
|
||||
}
|
||||
}
|
||||
for i := range podSpec.EphemeralContainers {
|
||||
if podSpec.EphemeralContainers[i].Lifecycle == nil {
|
||||
continue
|
||||
}
|
||||
if podSpec.EphemeralContainers[i].Lifecycle.PreStop != nil {
|
||||
podSpec.EphemeralContainers[i].Lifecycle.PreStop.Sleep = nil
|
||||
}
|
||||
if podSpec.EphemeralContainers[i].Lifecycle.PostStart != nil {
|
||||
podSpec.EphemeralContainers[i].Lifecycle.PostStart.Sleep = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func podLifecycleSleepActionInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
return false
|
||||
}
|
||||
var inUse bool
|
||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
||||
if c.Lifecycle == nil {
|
||||
return true
|
||||
}
|
||||
if c.Lifecycle.PreStop != nil && c.Lifecycle.PreStop.Sleep != nil {
|
||||
inUse = true
|
||||
return false
|
||||
}
|
||||
if c.Lifecycle.PostStart != nil && c.Lifecycle.PostStart.Sleep != nil {
|
||||
inUse = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return inUse
|
||||
}
|
||||
|
||||
// dropDisabledPodStatusFields removes disabled fields from the pod status
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@ -86,6 +87,14 @@ func (hr *handlerRunner) Run(ctx context.Context, containerID kubecontainer.Cont
|
||||
klog.V(1).ErrorS(err, "HTTP lifecycle hook for Container in Pod failed", "path", handler.HTTPGet.Path, "containerName", container.Name, "pod", klog.KObj(pod))
|
||||
}
|
||||
return msg, err
|
||||
case handler.Sleep != nil:
|
||||
err := hr.runSleepHandler(ctx, handler.Sleep.Seconds)
|
||||
var msg string
|
||||
if err != nil {
|
||||
msg = fmt.Sprintf("Sleep lifecycle hook (%d) for Container %q in Pod %q failed - error: %v", handler.Sleep.Seconds, container.Name, format.Pod(pod), err)
|
||||
klog.V(1).ErrorS(err, "Sleep lifecycle hook for Container in Pod failed", "sleepSeconds", handler.Sleep.Seconds, "containerName", container.Name, "pod", klog.KObj(pod))
|
||||
}
|
||||
return msg, err
|
||||
default:
|
||||
err := fmt.Errorf("invalid handler: %v", handler)
|
||||
msg := fmt.Sprintf("Cannot run handler: %v", err)
|
||||
@ -117,6 +126,20 @@ func resolvePort(portReference intstr.IntOrString, container *v1.Container) (int
|
||||
return -1, fmt.Errorf("couldn't find port: %v in %v", portReference, container)
|
||||
}
|
||||
|
||||
func (hr *handlerRunner) runSleepHandler(ctx context.Context, seconds int64) error {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodLifecycleSleepAction) {
|
||||
return nil
|
||||
}
|
||||
c := time.After(time.Duration(seconds) * time.Second)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// unexpected termination
|
||||
return fmt.Errorf("container terminated before sleep hook finished")
|
||||
case <-c:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (hr *handlerRunner) runHTTPHandler(ctx context.Context, pod *v1.Pod, container *v1.Container, handler *v1.LifecycleHandler, eventRecorder record.EventRecorder) error {
|
||||
host := handler.HTTPGet.Host
|
||||
podIP := host
|
||||
|
@ -859,3 +859,59 @@ func TestIsHTTPResponseError(t *testing.T) {
|
||||
t.Errorf("unexpected http response error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunSleepHandler(t *testing.T) {
|
||||
handlerRunner := NewHandlerRunner(&fakeHTTP{}, &fakeContainerCommandRunner{}, nil, nil)
|
||||
containerID := kubecontainer.ContainerID{Type: "test", ID: "abc1234"}
|
||||
containerName := "containerFoo"
|
||||
container := v1.Container{
|
||||
Name: containerName,
|
||||
Lifecycle: &v1.Lifecycle{
|
||||
PreStop: &v1.LifecycleHandler{},
|
||||
},
|
||||
}
|
||||
pod := v1.Pod{}
|
||||
pod.ObjectMeta.Name = "podFoo"
|
||||
pod.ObjectMeta.Namespace = "nsFoo"
|
||||
pod.Spec.Containers = []v1.Container{container}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
sleepSeconds int64
|
||||
terminationGracePeriodSeconds int64
|
||||
expectErr bool
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "valid seconds",
|
||||
sleepSeconds: 5,
|
||||
terminationGracePeriodSeconds: 30,
|
||||
},
|
||||
{
|
||||
name: "longer than TerminationGracePeriodSeconds",
|
||||
sleepSeconds: 3,
|
||||
terminationGracePeriodSeconds: 2,
|
||||
expectErr: true,
|
||||
expectedErr: "container terminated before sleep hook finished",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodLifecycleSleepAction, true)()
|
||||
|
||||
pod.Spec.Containers[0].Lifecycle.PreStop.Sleep = &v1.SleepAction{Seconds: tt.sleepSeconds}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(tt.terminationGracePeriodSeconds)*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, err := handlerRunner.Run(ctx, containerID, &pod, &container, container.Lifecycle.PreStop)
|
||||
|
||||
if !tt.expectErr && err != nil {
|
||||
t.Errorf("unexpected success")
|
||||
}
|
||||
if tt.expectErr && err.Error() != tt.expectedErr {
|
||||
t.Errorf("%s: expected error want %s, got %s", tt.name, tt.expectedErr, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user