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:
haircommander 2018-07-23 16:02:46 -04:00 committed by Atomic Bot
parent 7789284cbe
commit 8ce0e0b246
7 changed files with 347 additions and 118 deletions

View File

@ -19,6 +19,7 @@ var (
Subcommands: []cli.Command{
podCreateCommand,
podPsCommand,
podRestartCommand,
podRmCommand,
podStartCommand,
podStopCommand,

98
cmd/podman/pod_restart.go Normal file
View File

@ -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
}

View File

@ -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 ||

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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))
})
})