mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 11:13:48 +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.
|
// 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
|
// dropDisabledPodStatusFields removes disabled fields from the pod status
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"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))
|
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
|
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:
|
default:
|
||||||
err := fmt.Errorf("invalid handler: %v", handler)
|
err := fmt.Errorf("invalid handler: %v", handler)
|
||||||
msg := fmt.Sprintf("Cannot run handler: %v", err)
|
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)
|
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 {
|
func (hr *handlerRunner) runHTTPHandler(ctx context.Context, pod *v1.Pod, container *v1.Container, handler *v1.LifecycleHandler, eventRecorder record.EventRecorder) error {
|
||||||
host := handler.HTTPGet.Host
|
host := handler.HTTPGet.Host
|
||||||
podIP := host
|
podIP := host
|
||||||
|
@ -859,3 +859,59 @@ func TestIsHTTPResponseError(t *testing.T) {
|
|||||||
t.Errorf("unexpected http response error: %v", err)
|
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