mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	implementation
This commit is contained in:
		@@ -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())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user