mirror of
https://github.com/containers/podman.git
synced 2025-07-02 00:30:00 +08:00
Add pod pause/unpause
Added Pause() and Unpause() to libpod/pod.go Added man pages, tests and completions Signed-off-by: haircommander <pehunt@redhat.com> Closes: #1126 Approved by: rhatdan
This commit is contained in:

committed by
Atomic Bot

parent
50fea69fbc
commit
f258e43c7c
@ -12,11 +12,13 @@ Pods are a group of one or more containers sharing the same network, pid and ipc
|
||||
podSubCommands = []cli.Command{
|
||||
podCreateCommand,
|
||||
podKillCommand,
|
||||
podPauseCommand,
|
||||
podPsCommand,
|
||||
podRestartCommand,
|
||||
podRmCommand,
|
||||
podStartCommand,
|
||||
podStopCommand,
|
||||
podUnpauseCommand,
|
||||
}
|
||||
podCommand = cli.Command{
|
||||
Name: "pod",
|
||||
|
73
cmd/podman/pod_pause.go
Normal file
73
cmd/podman/pod_pause.go
Normal file
@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
podPauseFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "pause all running pods",
|
||||
},
|
||||
LatestPodFlag,
|
||||
}
|
||||
podPauseDescription = `
|
||||
Pauses one or more pods. The pod name or ID can be used.
|
||||
`
|
||||
|
||||
podPauseCommand = cli.Command{
|
||||
Name: "pause",
|
||||
Usage: "Pause one or more pods",
|
||||
Description: podPauseDescription,
|
||||
Flags: podPauseFlags,
|
||||
Action: podPauseCmd,
|
||||
ArgsUsage: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]",
|
||||
UseShortOptionHandling: true,
|
||||
}
|
||||
)
|
||||
|
||||
func podPauseCmd(c *cli.Context) error {
|
||||
if err := checkMutuallyExclusiveFlags(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating libpod runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
// getPodsFromContext returns an error when a requested pod
|
||||
// isn't found. The only fatal error scenerio is when there are no pods
|
||||
// in which case the following loop will be skipped.
|
||||
pods, lastError := getPodsFromContext(c, runtime)
|
||||
|
||||
for _, pod := range pods {
|
||||
ctr_errs, err := pod.Pause()
|
||||
if ctr_errs != nil {
|
||||
for ctr, err := range ctr_errs {
|
||||
if lastError != nil {
|
||||
logrus.Errorf("%q", lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to pause container %q on pod %q", ctr, pod.ID())
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
logrus.Errorf("%q", lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to pause pod %q", pod.ID())
|
||||
continue
|
||||
}
|
||||
fmt.Println(pod.ID())
|
||||
}
|
||||
|
||||
return lastError
|
||||
}
|
73
cmd/podman/pod_unpause.go
Normal file
73
cmd/podman/pod_unpause.go
Normal file
@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
podUnpauseFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "unpause all paused pods",
|
||||
},
|
||||
LatestPodFlag,
|
||||
}
|
||||
podUnpauseDescription = `
|
||||
Unpauses one or more pods. The pod name or ID can be used.
|
||||
`
|
||||
|
||||
podUnpauseCommand = cli.Command{
|
||||
Name: "unpause",
|
||||
Usage: "Unpause one or more pods",
|
||||
Description: podUnpauseDescription,
|
||||
Flags: podUnpauseFlags,
|
||||
Action: podUnpauseCmd,
|
||||
ArgsUsage: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]",
|
||||
UseShortOptionHandling: true,
|
||||
}
|
||||
)
|
||||
|
||||
func podUnpauseCmd(c *cli.Context) error {
|
||||
if err := checkMutuallyExclusiveFlags(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating libpod runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
// getPodsFromContext returns an error when a requested pod
|
||||
// isn't found. The only fatal error scenerio is when there are no pods
|
||||
// in which case the following loop will be skipped.
|
||||
pods, lastError := getPodsFromContext(c, runtime)
|
||||
|
||||
for _, pod := range pods {
|
||||
ctr_errs, err := pod.Unpause()
|
||||
if ctr_errs != nil {
|
||||
for ctr, err := range ctr_errs {
|
||||
if lastError != nil {
|
||||
logrus.Errorf("%q", lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to unpause container %q on pod %q", ctr, pod.ID())
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
logrus.Errorf("%q", lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to unpause pod %q", pod.ID())
|
||||
continue
|
||||
}
|
||||
fmt.Println(pod.ID())
|
||||
}
|
||||
|
||||
return lastError
|
||||
}
|
@ -33,10 +33,12 @@
|
||||
| [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod ||
|
||||
| [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. ||
|
||||
| [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system ||
|
||||
| [podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. ||
|
||||
| [podman-pod-restart](/docs/podman-pod-restart.1.md) | Restart one or more pods ||
|
||||
| [podman-pod-rm(1)](/docs/podman-pod-rm.1.md) | Remove one or more pods ||
|
||||
| [podman-pod-start(1)](/docs/podman-pod-start.1.md) | Start one or more pods ||
|
||||
| [podman-pod-stop(1)](/docs/podman-pod-stop.1.md) | Stop one or more pods ||
|
||||
| [podman-pod-unpause(1)](podman-pod-unpause.1.md) | Unpause one or more pods. ||
|
||||
| [podman-port(1)](/docs/podman-port.1.md) | List port mappings for running containers |[]()|
|
||||
| [podman-ps(1)](/docs/podman-ps.1.md) | Prints out information about containers |[](https://asciinema.org/a/bbT41kac6CwZ5giESmZLIaTLR)|
|
||||
| [podman-pull(1)](/docs/podman-pull.1.md) | Pull an image from a registry |[](https://asciinema.org/a/lr4zfoynHJOUNu1KaXa1dwG2X)|
|
||||
|
@ -2193,10 +2193,10 @@ _podman_pod_start() {
|
||||
"
|
||||
|
||||
local boolean_options="
|
||||
all
|
||||
a
|
||||
latest
|
||||
l
|
||||
--all
|
||||
-a
|
||||
--latest
|
||||
-l
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
case "$cur" in
|
||||
@ -2214,11 +2214,53 @@ _podman_pod_stop() {
|
||||
"
|
||||
|
||||
local boolean_options="
|
||||
all
|
||||
a
|
||||
cleanup
|
||||
latest
|
||||
l
|
||||
--all
|
||||
-a
|
||||
--cleanup
|
||||
--latest
|
||||
-l
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__podman_complete_pod_names
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_podman_pod_pause() {
|
||||
local options_with_args="
|
||||
"
|
||||
|
||||
local boolean_options="
|
||||
--all
|
||||
-a
|
||||
--latest
|
||||
-l
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__podman_complete_pod_names
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_podman_pod_unpause() {
|
||||
local options_with_args="
|
||||
"
|
||||
|
||||
local boolean_options="
|
||||
--all
|
||||
-a
|
||||
--latest
|
||||
-l
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
case "$cur" in
|
||||
@ -2244,6 +2286,8 @@ _podman_pod() {
|
||||
rm
|
||||
start
|
||||
stop
|
||||
pause
|
||||
unpause
|
||||
"
|
||||
local aliases="
|
||||
list
|
||||
|
32
docs/podman-pod-pause.1.md
Normal file
32
docs/podman-pod-pause.1.md
Normal file
@ -0,0 +1,32 @@
|
||||
% podman-pod-pause "1"
|
||||
|
||||
## NAME
|
||||
podman\-pod\-pause - Pause one or more pods
|
||||
|
||||
## SYNOPSIS
|
||||
**podman pod pause** [*options*] *pod* ...
|
||||
|
||||
## DESCRIPTION
|
||||
Pauses all the running processes in the containers of one or more pods. You may use pod IDs or names as input.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--all, a**
|
||||
|
||||
Pause all pods.
|
||||
|
||||
**--latest, -l**
|
||||
|
||||
Instead of providing the pod name or ID, pause the last created pod.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
podman pod pause mywebserverpod
|
||||
|
||||
podman pod pause 860a4b23
|
||||
|
||||
## SEE ALSO
|
||||
podman-pod(1), podman-pod-unpause(1), podman-pause(1)
|
||||
|
||||
## HISTORY
|
||||
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>
|
32
docs/podman-pod-unpause.1.md
Normal file
32
docs/podman-pod-unpause.1.md
Normal file
@ -0,0 +1,32 @@
|
||||
% podman-pod-unpause "1"
|
||||
|
||||
## NAME
|
||||
podman\-pod\-unpause - Unpause one or more pods
|
||||
|
||||
## SYNOPSIS
|
||||
**podman pod unpause** [*options*] *pod* ...
|
||||
|
||||
## DESCRIPTION
|
||||
Unpauses all the paused processes in the containers of one or more pods. You may use pod IDs or names as input.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--all, a**
|
||||
|
||||
Unpause all pods.
|
||||
|
||||
**--latest, -l**
|
||||
|
||||
Instead of providing the pod name or ID, unpause the last created pod.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
podman pod unpause mywebserverpod
|
||||
|
||||
podman pod unpause 860a4b23
|
||||
|
||||
## SEE ALSO
|
||||
podman-pod(1), podman-pod-pause(1), podman-unpause(1)
|
||||
|
||||
## HISTORY
|
||||
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>
|
@ -15,10 +15,12 @@ podman pod is a set of subcommands that manage pods, or groups of containers.
|
||||
| ------------------------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| [podman-pod-create(1)](podman-pod-create.1.md) | Create a new pod. |
|
||||
| [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. |
|
||||
| [podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. |
|
||||
| [podman-pod-ps(1)](podman-pod-ps.1.md) | Prints out information about pods. |
|
||||
| [podman-pod-rm(1)](podman-pod-rm.1.md) | Remove one or more pods. |
|
||||
| [podman-pod-start(1)](podman-pod-start.1.md) | Start one or more pods. |
|
||||
| [podman-pod-stop(1)](podman-pod-stop.1.md) | Stop one or more pods. |
|
||||
| [podman-pod-unpause(1)](podman-pod-unpause.1.md) | Unpause one or more pods. |
|
||||
|
||||
## HISTORY
|
||||
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>
|
||||
|
119
libpod/pod.go
119
libpod/pod.go
@ -383,6 +383,124 @@ func (p *Pod) Stop(cleanup bool) (map[string]error, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Pause pauses all containers within a pod that are running.
|
||||
// Only running containers will be paused. Paused, stopped, or created
|
||||
// containers will be ignored.
|
||||
// All containers are paused independently. An error pausing one container
|
||||
// will not prevent other containers being paused.
|
||||
// An error and a map[string]error are returned
|
||||
// If the error is not nil and the map is nil, an error was encountered before
|
||||
// any containers were paused
|
||||
// If map is not nil, an error was encountered when pausing one or more
|
||||
// containers. The container ID is mapped to the error encountered. The error is
|
||||
// set to ErrCtrExists
|
||||
// If both error and the map are nil, all containers were paused without error
|
||||
func (p *Pod) Pause() (map[string]error, error) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if !p.valid {
|
||||
return nil, ErrPodRemoved
|
||||
}
|
||||
|
||||
allCtrs, err := p.runtime.state.PodContainers(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctrErrors := make(map[string]error)
|
||||
|
||||
// Pause to all containers
|
||||
for _, ctr := range allCtrs {
|
||||
ctr.lock.Lock()
|
||||
|
||||
if err := ctr.syncContainer(); err != nil {
|
||||
ctr.lock.Unlock()
|
||||
ctrErrors[ctr.ID()] = err
|
||||
continue
|
||||
}
|
||||
|
||||
// Ignore containers that are not running
|
||||
if ctr.state.State != ContainerStateRunning {
|
||||
ctr.lock.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
if err := ctr.pause(); err != nil {
|
||||
ctr.lock.Unlock()
|
||||
ctrErrors[ctr.ID()] = err
|
||||
continue
|
||||
}
|
||||
|
||||
ctr.lock.Unlock()
|
||||
}
|
||||
|
||||
if len(ctrErrors) > 0 {
|
||||
return ctrErrors, errors.Wrapf(ErrCtrExists, "error pausing some containers")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Unpause unpauses all containers within a pod that are running.
|
||||
// Only paused containers will be unpaused. Running, stopped, or created
|
||||
// containers will be ignored.
|
||||
// All containers are unpaused independently. An error unpausing one container
|
||||
// will not prevent other containers being unpaused.
|
||||
// An error and a map[string]error are returned
|
||||
// If the error is not nil and the map is nil, an error was encountered before
|
||||
// any containers were unpaused
|
||||
// If map is not nil, an error was encountered when unpausing one or more
|
||||
// containers. The container ID is mapped to the error encountered. The error is
|
||||
// set to ErrCtrExists
|
||||
// If both error and the map are nil, all containers were unpaused without error
|
||||
func (p *Pod) Unpause() (map[string]error, error) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if !p.valid {
|
||||
return nil, ErrPodRemoved
|
||||
}
|
||||
|
||||
allCtrs, err := p.runtime.state.PodContainers(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctrErrors := make(map[string]error)
|
||||
|
||||
// Pause to all containers
|
||||
for _, ctr := range allCtrs {
|
||||
ctr.lock.Lock()
|
||||
|
||||
if err := ctr.syncContainer(); err != nil {
|
||||
ctr.lock.Unlock()
|
||||
ctrErrors[ctr.ID()] = err
|
||||
continue
|
||||
}
|
||||
|
||||
// Ignore containers that are not paused
|
||||
if ctr.state.State != ContainerStatePaused {
|
||||
ctr.lock.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
if err := ctr.unpause(); err != nil {
|
||||
ctr.lock.Unlock()
|
||||
ctrErrors[ctr.ID()] = err
|
||||
continue
|
||||
}
|
||||
|
||||
ctr.lock.Unlock()
|
||||
}
|
||||
|
||||
if len(ctrErrors) > 0 {
|
||||
return ctrErrors, errors.Wrapf(ErrCtrExists, "error unpausing some containers")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Restart restarts all containers within a pod that are not paused or in an error state.
|
||||
// It combines the effects of Stop() and Start() on a container
|
||||
// Each container will use its own stop timeout.
|
||||
@ -403,6 +521,7 @@ func (p *Pod) Restart(ctx context.Context) (map[string]error, error) {
|
||||
if !p.valid {
|
||||
return nil, ErrPodRemoved
|
||||
}
|
||||
|
||||
allCtrs, err := p.runtime.state.PodContainers(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
116
test/e2e/pod_pause_test.go
Normal file
116
test/e2e/pod_pause_test.go
Normal file
@ -0,0 +1,116 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman pod pause", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
podmanTest PodmanTest
|
||||
)
|
||||
|
||||
pausedState := "Paused"
|
||||
|
||||
BeforeEach(func() {
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanCreate(tempdir)
|
||||
podmanTest.RestoreAllArtifacts()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.CleanupPod()
|
||||
|
||||
})
|
||||
|
||||
It("podman pod pause bogus pod", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "pause", "foobar"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman unpause bogus pod", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "unpause", "foobar"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman pod pause a created pod by id", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
podid := session.OutputToString()
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "pause", podid})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman pod pause a running pod by id", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
podid := session.OutputToString()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("", podid)
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "pause", podid})
|
||||
result.WaitWithDefaultTimeout()
|
||||
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState))
|
||||
|
||||
result = podmanTest.Podman([]string{"pod", "unpause", podid})
|
||||
result.WaitWithDefaultTimeout()
|
||||
|
||||
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||
})
|
||||
|
||||
It("podman unpause a running pod by id", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
podid := session.OutputToString()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("", podid)
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "unpause", podid})
|
||||
result.WaitWithDefaultTimeout()
|
||||
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||
})
|
||||
|
||||
It("podman pod pause a running pod by name", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--name", "test1"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("", "test1")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
result := podmanTest.Podman([]string{"pod", "pause", "test1"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
|
||||
Expect(podmanTest.GetContainerStatus()).To(Equal(pausedState))
|
||||
|
||||
result = podmanTest.Podman([]string{"pod", "unpause", "test1"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user