Added pod restart
With tests, man page and completions. Signed-off-by: haircommander <pehunt@redhat.com> Closes: #1152 Approved by: rhatdan
This commit is contained in:
parent
7789284cbe
commit
8ce0e0b246
|
|
@ -19,6 +19,7 @@ var (
|
|||
Subcommands: []cli.Command{
|
||||
podCreateCommand,
|
||||
podPsCommand,
|
||||
podRestartCommand,
|
||||
podRmCommand,
|
||||
podStartCommand,
|
||||
podStopCommand,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
|
||||
"github.com/projectatomic/libpod/libpod"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
podRestartFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "restart all pods",
|
||||
},
|
||||
LatestFlag,
|
||||
}
|
||||
podRestartDescription = `Restarts one or more pods. The pod ID or name can be used.`
|
||||
|
||||
podRestartCommand = cli.Command{
|
||||
Name: "restart",
|
||||
Usage: "Restart one or more pods",
|
||||
Description: podRestartDescription,
|
||||
Flags: podRestartFlags,
|
||||
Action: podRestartCmd,
|
||||
ArgsUsage: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]",
|
||||
UseShortOptionHandling: true,
|
||||
}
|
||||
)
|
||||
|
||||
func podRestartCmd(c *cli.Context) error {
|
||||
if err := checkMutuallyExclusiveFlags(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := libpodruntime.GetRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
args := c.Args()
|
||||
var pods []*libpod.Pod
|
||||
var lastError error
|
||||
|
||||
if c.Bool("all") {
|
||||
pods, err = runtime.Pods()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to get running pods")
|
||||
}
|
||||
}
|
||||
|
||||
if c.Bool("latest") {
|
||||
pod, err := runtime.GetLatestPod()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to get latest pod")
|
||||
}
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
|
||||
for _, i := range args {
|
||||
pod, err := runtime.LookupPod(i)
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
logrus.Errorf("%q", lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to find pod %s", i)
|
||||
continue
|
||||
}
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
|
||||
ctx := getContext()
|
||||
for _, pod := range pods {
|
||||
ctr_errs, err := pod.Restart(ctx)
|
||||
if ctr_errs != nil {
|
||||
for ctr, err := range ctr_errs {
|
||||
if lastError != nil {
|
||||
logrus.Errorf("%q", lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to restart 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 restart pod %q", pod.ID())
|
||||
continue
|
||||
}
|
||||
fmt.Println(pod.ID())
|
||||
}
|
||||
return lastError
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
| [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods ||
|
||||
| [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod ||
|
||||
| [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system ||
|
||||
| [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 ||
|
||||
|
|
|
|||
|
|
@ -2121,6 +2121,27 @@ _podman_pod_ps() {
|
|||
__podman_pod_ps
|
||||
}
|
||||
|
||||
_podman_pod_restart() {
|
||||
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_rm() {
|
||||
local options_with_args="
|
||||
"
|
||||
|
|
@ -2195,6 +2216,7 @@ _podman_pod() {
|
|||
subcommands="
|
||||
create
|
||||
ps
|
||||
restart
|
||||
rm
|
||||
start
|
||||
stop
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
% podman-pod-restart "1"
|
||||
|
||||
## NAME
|
||||
podman\-pod\-restart - Restart one or more pods
|
||||
|
||||
## SYNOPSIS
|
||||
**podman pod restart** [*options*] *pod* ...
|
||||
|
||||
## DESCRIPTION
|
||||
Restart containers in one or more pods. Containers will be stopped if running and then restarted.
|
||||
Stopped containers will only be started. You may use pod IDs or names as input.
|
||||
The pod ID will be printed upon successful restart.
|
||||
When restarting multiple pods, an error from restarting one pod will not effect restarting other pods.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--all, -a**
|
||||
|
||||
Restarts all pods
|
||||
|
||||
**--latest, -l**
|
||||
|
||||
Instead of providing the pod name or ID, restart the last created pod.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
podman pod restart mywebserverpod
|
||||
cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907
|
||||
|
||||
podman pod restart 490eb 3557fb
|
||||
490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5
|
||||
3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
|
||||
|
||||
3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
|
||||
|
||||
podman pod restart --latest
|
||||
3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
|
||||
|
||||
podman pod restart --all
|
||||
19456b4cd557eaf9629825113a552681a6013f8c8cad258e36ab825ef536e818
|
||||
3557fbea6ad61569de0506fe037479bd9896603c31d3069a6677f23833916fab
|
||||
490eb241aaf704d4dd2629904410fe4aa31965d9310a735f8755267f4ded1de5
|
||||
70c358daecf71ef9be8f62404f926080ca0133277ef7ce4f6aa2d5af6bb2d3e9
|
||||
cc8f0bea67b1a1a11aec1ecd38102a1be4b145577f21fc843c7c83b77fc28907
|
||||
|
||||
## SEE ALSO
|
||||
podman-pod(1), podman-pod-start(1), podman-restart(1)
|
||||
|
||||
## HISTORY
|
||||
July 2018, Originally compiled by Peter Hunt <pehunt@redhat.com>
|
||||
118
libpod/pod.go
118
libpod/pod.go
|
|
@ -435,124 +435,6 @@ func (p *Pod) Restart(ctx context.Context) (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
|
||||
}
|
||||
|
||||
// Kill sends a signal to all running containers within a pod
|
||||
// Signals will only be sent to running containers. Containers that are not
|
||||
// running will be ignored. All signals are sent independently, and sending will
|
||||
|
|
|
|||
|
|
@ -0,0 +1,175 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman pod restart", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
podmanTest PodmanTest
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanCreate(tempdir)
|
||||
podmanTest.RestoreAllArtifacts()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.CleanupPod()
|
||||
})
|
||||
|
||||
It("podman pod restart bogus pod", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "restart", "123"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(125))
|
||||
})
|
||||
|
||||
It("podman pod restart single empty pod", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
cid := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "restart", cid})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(125))
|
||||
})
|
||||
|
||||
It("podman pod restart single pod by name", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test1", "foobar99")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1"})
|
||||
startTime.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "restart", "foobar99"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1"})
|
||||
restartTime.WaitWithDefaultTimeout()
|
||||
Expect(restartTime.OutputToString()).To(Not(Equal(startTime.OutputToString())))
|
||||
})
|
||||
|
||||
It("podman pod restart multiple pods", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test1", "foobar99")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
|
||||
session2.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test3", "foobar100")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test4", "foobar100")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2", "test3", "test4"})
|
||||
startTime.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "restart", "foobar99", "foobar100"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2", "test3", "test4"})
|
||||
restartTime.WaitWithDefaultTimeout()
|
||||
Expect(restartTime.OutputToStringArray()[0]).To(Not(Equal(startTime.OutputToStringArray()[0])))
|
||||
Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1])))
|
||||
Expect(restartTime.OutputToStringArray()[2]).To(Not(Equal(startTime.OutputToStringArray()[2])))
|
||||
Expect(restartTime.OutputToStringArray()[3]).To(Not(Equal(startTime.OutputToStringArray()[3])))
|
||||
})
|
||||
|
||||
It("podman pod restart all pods", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test1", "foobar99")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
|
||||
session2.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
|
||||
startTime.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "restart", "-a"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
|
||||
restartTime.WaitWithDefaultTimeout()
|
||||
Expect(restartTime.OutputToStringArray()[0]).To(Not(Equal(startTime.OutputToStringArray()[0])))
|
||||
Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1])))
|
||||
})
|
||||
|
||||
It("podman pod restart latest pod", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test1", "foobar99")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session2 := podmanTest.Podman([]string{"pod", "create", "--name", "foobar100"})
|
||||
session2.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
startTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
|
||||
startTime.WaitWithDefaultTimeout()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "restart", "-l"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
restartTime := podmanTest.Podman([]string{"inspect", "--format='{{.State.StartedAt}}'", "test1", "test2"})
|
||||
restartTime.WaitWithDefaultTimeout()
|
||||
Expect(restartTime.OutputToStringArray()[0]).To(Equal(startTime.OutputToStringArray()[0]))
|
||||
Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1])))
|
||||
})
|
||||
|
||||
It("podman pod restart multiple pods with bogus", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--name", "foobar99"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
cid1 := session.OutputToString()
|
||||
|
||||
session = podmanTest.RunTopContainerInPod("", "foobar99")
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "restart", cid1, "doesnotexist"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(125))
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue