mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-13 22:05:59 +00:00
node-e2e: Add container lifecycle e2e tests for preStop hook
This ensures that the container's pre-stop hook is invoked if the startup or liveness probe fails.
This commit is contained in:
parent
0e14098333
commit
8fb5b6eb4c
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user