Files
podman/test/e2e/pod_stop_test.go
Matt Heon 46d874aa52 Refactor graph traversal & use for pod stop
First, refactor our existing graph traversal code to improve code
sharing. There still isn't much sharing between inward traversal
(stop, remove) and outward traversal (start) but stop and remove
are sharing most of their code, which seems a positive.

Second, add a new graph-traversal function to stop containers.
We already had start and remove; stop uses the newly-refactored
inward-traversal code which it shares with removal.

Third, rework the shared stop/removal inward-traversal code to
add locking. This allows parallel execution of stop and removal,
which should improve the performance of `podman pod rm` and
retain the performance of `podman pod stop` at about what it is
right now.

Fourth and finally, use the new graph-based stop when possible
to solve unordered stop problems with pods - specifically, the
infra container stopping before application containers, leaving
those containers without a working network.

Fixes https://issues.redhat.com/browse/RHEL-76827

Signed-off-by: Matt Heon <mheon@redhat.com>
2025-02-06 18:28:12 -05:00

259 lines
8.7 KiB
Go

//go:build linux || freebsd
package integration
import (
"path/filepath"
"time"
. "github.com/containers/podman/v5/test/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Podman pod stop", func() {
It("podman pod stop bogus pod", func() {
session := podmanTest.Podman([]string{"pod", "stop", "123"})
session.WaitWithDefaultTimeout()
expect := "no pod with name or ID 123 found: no such pod"
if IsRemote() {
expect = `unable to find pod "123": no such pod`
}
Expect(session).Should(ExitWithError(125, expect))
})
It("podman pod stop --ignore bogus pod", func() {
session := podmanTest.Podman([]string{"pod", "stop", "--ignore", "123"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman stop bogus pod and a running pod", func() {
_, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "stop", "bogus", "test1"})
session.WaitWithDefaultTimeout()
expect := "no pod with name or ID bogus found: no such pod"
if IsRemote() {
expect = `unable to find pod "bogus": no such pod`
}
Expect(session).Should(ExitWithError(125, expect))
})
It("podman stop --ignore bogus pod and a running pod", func() {
_, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "stop", "--ignore", "bogus", "test1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "stop", "-t", "-1", "--ignore", "test1", "bogus"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman pod stop single empty pod", func() {
_, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"pod", "stop", podid})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("podman pod stop single pod by name", func() {
_, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "stop", "foobar99"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("podman pod stop multiple pods", func() {
_, ec, podid1 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
_, ec2, podid2 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec2).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "stop", podid1, podid2})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("podman pod stop all pods", func() {
_, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
_, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "stop", "--all"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("podman pod stop latest pod", func() {
_, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
_, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
podid := "--latest"
if IsRemote() {
podid = "foobar100"
}
session = podmanTest.Podman([]string{"pod", "stop", podid})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
})
It("podman pod stop multiple pods with bogus", func() {
_, ec, podid1 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "stop", podid1, "doesnotexist"})
session.WaitWithDefaultTimeout()
expect := "no pod with name or ID doesnotexist found: no such pod"
if IsRemote() {
expect = `unable to find pod "doesnotexist": no such pod`
}
Expect(session).Should(ExitWithError(125, expect))
})
It("podman pod start/stop single pod via --pod-id-file", func() {
podIDFile := filepath.Join(tempdir, "podID")
podName := "rudolph"
// Create a pod with --pod-id-file.
session := podmanTest.Podman([]string{"pod", "create", "--name", podName, "--pod-id-file", podIDFile})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
// Create container inside the pod.
session = podmanTest.Podman([]string{"create", "--pod", podName, ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
session = podmanTest.Podman([]string{"pod", "start", "--pod-id-file", podIDFile})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) // infra+top
session = podmanTest.Podman([]string{"pod", "stop", "--pod-id-file", podIDFile})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("podman pod start/stop multiple pods via --pod-id-file", func() {
podIDFiles := []string{}
for _, i := range "0123456789" {
podIDFile := filepath.Join(tempdir, "cid"+string(i))
podName := "rudolph" + string(i)
// Create a pod with --pod-id-file.
session := podmanTest.Podman([]string{"pod", "create", "--name", podName, "--pod-id-file", podIDFile})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
// Create container inside the pod.
session = podmanTest.Podman([]string{"create", "--pod", podName, ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
// Append the id files along with the command.
podIDFiles = append(podIDFiles, "--pod-id-file")
podIDFiles = append(podIDFiles, podIDFile)
}
cmd := []string{"pod", "start"}
cmd = append(cmd, podIDFiles...)
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(20)) // 10*(infra+top)
cmd = []string{"pod", "stop"}
cmd = append(cmd, podIDFiles...)
session = podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
It("podman pod stop orders container stop", func() {
podName := "testpod"
infraName := "testpod-infra"
podmanTest.PodmanExitCleanly("pod", "create", "--infra-name", infraName, podName)
ctrName := "testctr"
podmanTest.PodmanExitCleanly("run", "-d", "--name", ctrName, "--pod", podName, ALPINE, "top")
podmanTest.PodmanExitCleanly("pod", "stop", podName)
ctrStop := podmanTest.PodmanExitCleanly("inspect", "--format", "{{ .State.FinishedAt }}", ctrName)
infraStop := podmanTest.PodmanExitCleanly("inspect", "--format", "{{ .State.FinishedAt }}", infraName)
timeFormat := "2006-01-02 15:04:05.999999999 -0700 MST"
ctrStopTime, err := time.Parse(timeFormat, ctrStop.OutputToString())
Expect(err).ShouldNot(HaveOccurred())
infraStopTime, err := time.Parse(timeFormat, infraStop.OutputToString())
Expect(err).ShouldNot(HaveOccurred())
Expect(infraStopTime).To(BeTemporally(">", ctrStopTime))
})
})