Merge pull request #119179 from gjkim42/add-prestop-e2e-test
node-e2e: Add container lifecycle e2e tests for preStop hook
This commit is contained in:
		@@ -38,6 +38,9 @@ type execCommand struct {
 | 
				
			|||||||
	StartDelay int
 | 
						StartDelay int
 | 
				
			||||||
	// Delay is how long the container should delay before exiting
 | 
						// Delay is how long the container should delay before exiting
 | 
				
			||||||
	Delay int
 | 
						Delay int
 | 
				
			||||||
 | 
						// TerminationSeconds is the time it takes for the container before
 | 
				
			||||||
 | 
						// terminating if it catches SIGTERM.
 | 
				
			||||||
 | 
						TerminationSeconds int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ExecCommand returns the command to execute in the container that implements execCommand and logs activities to a container
 | 
					// ExecCommand returns the command to execute in the container that implements execCommand and logs activities to a container
 | 
				
			||||||
@@ -57,21 +60,30 @@ func ExecCommand(name string, c execCommand) []string {
 | 
				
			|||||||
	fmt.Fprintf(&cmd, "cat %s >> /dev/termination-log; ", containerLog)
 | 
						fmt.Fprintf(&cmd, "cat %s >> /dev/termination-log; ", containerLog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fmt.Fprintf(&cmd, "echo %s '%s Starting %d' | tee -a %s >> /dev/termination-log; ", timeCmd, name, c.StartDelay, containerLog)
 | 
						fmt.Fprintf(&cmd, "echo %s '%s Starting %d' | tee -a %s >> /dev/termination-log; ", timeCmd, name, c.StartDelay, containerLog)
 | 
				
			||||||
 | 
						fmt.Fprintf(&cmd, "_term() { sleep %d; echo %s '%s Exiting' | tee -a %s >> /dev/termination-log; exit %d; }; ", c.TerminationSeconds, timeCmd, name, containerLog, c.ExitCode)
 | 
				
			||||||
 | 
						fmt.Fprintf(&cmd, "trap _term TERM; ")
 | 
				
			||||||
	if c.StartDelay != 0 {
 | 
						if c.StartDelay != 0 {
 | 
				
			||||||
		fmt.Fprintf(&cmd, "sleep %d; ", c.StartDelay)
 | 
							fmt.Fprint(&cmd, sleepCommand(c.StartDelay))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// You can check started file to see if the container has started
 | 
						// You can check started file to see if the container has started
 | 
				
			||||||
	fmt.Fprintf(&cmd, "touch started; ")
 | 
						fmt.Fprintf(&cmd, "touch started; ")
 | 
				
			||||||
	fmt.Fprintf(&cmd, "echo %s '%s Started' | tee -a %s >> /dev/termination-log; ", timeCmd, name, containerLog)
 | 
						fmt.Fprintf(&cmd, "echo %s '%s Started' | tee -a %s >> /dev/termination-log; ", timeCmd, name, containerLog)
 | 
				
			||||||
	fmt.Fprintf(&cmd, "echo %s '%s Delaying %d' | tee -a %s >> /dev/termination-log; ", timeCmd, name, c.Delay, containerLog)
 | 
						fmt.Fprintf(&cmd, "echo %s '%s Delaying %d' | tee -a %s >> /dev/termination-log; ", timeCmd, name, c.Delay, containerLog)
 | 
				
			||||||
	if c.Delay != 0 {
 | 
						if c.Delay != 0 {
 | 
				
			||||||
		fmt.Fprintf(&cmd, "sleep %d; ", c.Delay)
 | 
							fmt.Fprint(&cmd, sleepCommand(c.Delay))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fmt.Fprintf(&cmd, "echo %s '%s Exiting'  | tee -a %s >> /dev/termination-log; ", timeCmd, name, containerLog)
 | 
						fmt.Fprintf(&cmd, "echo %s '%s Exiting'  | tee -a %s >> /dev/termination-log; ", timeCmd, name, containerLog)
 | 
				
			||||||
	fmt.Fprintf(&cmd, "exit %d", c.ExitCode)
 | 
						fmt.Fprintf(&cmd, "exit %d", c.ExitCode)
 | 
				
			||||||
	return []string{"sh", "-c", cmd.String()}
 | 
						return []string{"sh", "-c", cmd.String()}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// sleepCommand returns a command that sleeps for the given number of seconds
 | 
				
			||||||
 | 
					// in background and waits for it to finish so that the parent process can
 | 
				
			||||||
 | 
					// handle signals.
 | 
				
			||||||
 | 
					func sleepCommand(seconds int) string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("exec sleep %d & wait $!; ", seconds)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type containerOutput struct {
 | 
					type containerOutput struct {
 | 
				
			||||||
	// time the message was seen to the nearest second
 | 
						// time the message was seen to the nearest second
 | 
				
			||||||
	timestamp time.Time
 | 
						timestamp time.Time
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	PostStartPrefix = "PostStart"
 | 
						PostStartPrefix = "PostStart"
 | 
				
			||||||
 | 
						PreStopPrefix   = "PreStop"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var containerRestartPolicyAlways = v1.ContainerRestartPolicyAlways
 | 
					var containerRestartPolicyAlways = v1.ContainerRestartPolicyAlways
 | 
				
			||||||
@@ -596,6 +597,138 @@ var _ = SIGDescribe("[NodeConformance] Containers Lifecycle ", func() {
 | 
				
			|||||||
			framework.ExpectNoError(err)
 | 
								framework.ExpectNoError(err)
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ginkgo.It("should call the container's preStop hook and terminate it if its startup probe fails", func() {
 | 
				
			||||||
 | 
							regular1 := "regular-1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							podSpec := &v1.Pod{
 | 
				
			||||||
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
									Name: "test-pod",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Spec: v1.PodSpec{
 | 
				
			||||||
 | 
									RestartPolicy: v1.RestartPolicyNever,
 | 
				
			||||||
 | 
									Containers: []v1.Container{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:  regular1,
 | 
				
			||||||
 | 
											Image: busyboxImage,
 | 
				
			||||||
 | 
											Command: ExecCommand(regular1, execCommand{
 | 
				
			||||||
 | 
												Delay:              100,
 | 
				
			||||||
 | 
												TerminationSeconds: 15,
 | 
				
			||||||
 | 
												ExitCode:           0,
 | 
				
			||||||
 | 
											}),
 | 
				
			||||||
 | 
											StartupProbe: &v1.Probe{
 | 
				
			||||||
 | 
												ProbeHandler: v1.ProbeHandler{
 | 
				
			||||||
 | 
													Exec: &v1.ExecAction{
 | 
				
			||||||
 | 
														Command: []string{
 | 
				
			||||||
 | 
															"sh",
 | 
				
			||||||
 | 
															"-c",
 | 
				
			||||||
 | 
															"exit 1",
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												InitialDelaySeconds: 10,
 | 
				
			||||||
 | 
												FailureThreshold:    1,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Lifecycle: &v1.Lifecycle{
 | 
				
			||||||
 | 
												PreStop: &v1.LifecycleHandler{
 | 
				
			||||||
 | 
													Exec: &v1.ExecAction{
 | 
				
			||||||
 | 
														Command: ExecCommand(prefixedName(PreStopPrefix, regular1), execCommand{
 | 
				
			||||||
 | 
															Delay:    1,
 | 
				
			||||||
 | 
															ExitCode: 0,
 | 
				
			||||||
 | 
														}),
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							preparePod(podSpec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							client := e2epod.NewPodClient(f)
 | 
				
			||||||
 | 
							podSpec = client.Create(context.TODO(), podSpec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Waiting for the pod to complete")
 | 
				
			||||||
 | 
							err := e2epod.WaitForPodNoLongerRunningInNamespace(context.TODO(), f.ClientSet, podSpec.Name, podSpec.Namespace)
 | 
				
			||||||
 | 
							framework.ExpectNoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Parsing results")
 | 
				
			||||||
 | 
							podSpec, err = client.Get(context.TODO(), podSpec.Name, metav1.GetOptions{})
 | 
				
			||||||
 | 
							framework.ExpectNoError(err)
 | 
				
			||||||
 | 
							results := parseOutput(podSpec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Analyzing results")
 | 
				
			||||||
 | 
							framework.ExpectNoError(results.RunTogether(regular1, prefixedName(PreStopPrefix, regular1)))
 | 
				
			||||||
 | 
							framework.ExpectNoError(results.Starts(prefixedName(PreStopPrefix, regular1)))
 | 
				
			||||||
 | 
							framework.ExpectNoError(results.Exits(regular1))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ginkgo.It("should call the container's preStop hook and terminate it if its liveness probe fails", func() {
 | 
				
			||||||
 | 
							regular1 := "regular-1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							podSpec := &v1.Pod{
 | 
				
			||||||
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
									Name: "test-pod",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Spec: v1.PodSpec{
 | 
				
			||||||
 | 
									RestartPolicy: v1.RestartPolicyNever,
 | 
				
			||||||
 | 
									Containers: []v1.Container{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:  regular1,
 | 
				
			||||||
 | 
											Image: busyboxImage,
 | 
				
			||||||
 | 
											Command: ExecCommand(regular1, execCommand{
 | 
				
			||||||
 | 
												Delay:              100,
 | 
				
			||||||
 | 
												TerminationSeconds: 15,
 | 
				
			||||||
 | 
												ExitCode:           0,
 | 
				
			||||||
 | 
											}),
 | 
				
			||||||
 | 
											LivenessProbe: &v1.Probe{
 | 
				
			||||||
 | 
												ProbeHandler: v1.ProbeHandler{
 | 
				
			||||||
 | 
													Exec: &v1.ExecAction{
 | 
				
			||||||
 | 
														Command: []string{
 | 
				
			||||||
 | 
															"sh",
 | 
				
			||||||
 | 
															"-c",
 | 
				
			||||||
 | 
															"exit 1",
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												InitialDelaySeconds: 10,
 | 
				
			||||||
 | 
												FailureThreshold:    1,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											Lifecycle: &v1.Lifecycle{
 | 
				
			||||||
 | 
												PreStop: &v1.LifecycleHandler{
 | 
				
			||||||
 | 
													Exec: &v1.ExecAction{
 | 
				
			||||||
 | 
														Command: ExecCommand(prefixedName(PreStopPrefix, regular1), execCommand{
 | 
				
			||||||
 | 
															Delay:    1,
 | 
				
			||||||
 | 
															ExitCode: 0,
 | 
				
			||||||
 | 
														}),
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							preparePod(podSpec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							client := e2epod.NewPodClient(f)
 | 
				
			||||||
 | 
							podSpec = client.Create(context.TODO(), podSpec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Waiting for the pod to complete")
 | 
				
			||||||
 | 
							err := e2epod.WaitForPodNoLongerRunningInNamespace(context.TODO(), f.ClientSet, podSpec.Name, podSpec.Namespace)
 | 
				
			||||||
 | 
							framework.ExpectNoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Parsing results")
 | 
				
			||||||
 | 
							podSpec, err = client.Get(context.TODO(), podSpec.Name, metav1.GetOptions{})
 | 
				
			||||||
 | 
							framework.ExpectNoError(err)
 | 
				
			||||||
 | 
							results := parseOutput(podSpec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ginkgo.By("Analyzing results")
 | 
				
			||||||
 | 
							framework.ExpectNoError(results.RunTogether(regular1, prefixedName(PreStopPrefix, regular1)))
 | 
				
			||||||
 | 
							framework.ExpectNoError(results.Starts(prefixedName(PreStopPrefix, regular1)))
 | 
				
			||||||
 | 
							framework.ExpectNoError(results.Exits(regular1))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ = SIGDescribe("[NodeAlphaFeature:SidecarContainers] Containers Lifecycle ", func() {
 | 
					var _ = SIGDescribe("[NodeAlphaFeature:SidecarContainers] Containers Lifecycle ", func() {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user