summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/mount.go2
-rw-r--r--cmd/podman/restart.go115
-rw-r--r--commands.md1
-rw-r--r--completions/bash/podman12
-rw-r--r--docs/podman-restart.1.md46
-rw-r--r--docs/podman.1.md1
-rw-r--r--libpod/container_api.go27
-rw-r--r--test/e2e/restart_test.go81
-rw-r--r--test/e2e/rm_test.go19
-rw-r--r--transfer.md62
11 files changed, 314 insertions, 53 deletions
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 4034be267..2a0ca30ee 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -56,6 +56,7 @@ func main() {
portCommand,
pullCommand,
pushCommand,
+ restartCommand,
rmCommand,
rmiCommand,
runCommand,
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index 6c6b89ee9..2d274cfaf 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -79,7 +79,7 @@ func mountCmd(c *cli.Context) error {
if err != nil {
return errors.Wrapf(err, "error looking up container %q", args[0])
}
- mountPoint, err := ctr.Mount(ctr.MountLabel())
+ mountPoint, err := ctr.Mount()
if err != nil {
return errors.Wrapf(err, "error mounting container %q", ctr.ID())
}
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
new file mode 100644
index 000000000..84aa5f830
--- /dev/null
+++ b/cmd/podman/restart.go
@@ -0,0 +1,115 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/pkg/errors"
+ "github.com/projectatomic/libpod/libpod"
+ "github.com/urfave/cli"
+)
+
+var (
+ restartFlags = []cli.Flag{
+ cli.UintFlag{
+ Name: "timeout, time, t",
+ Usage: "Seconds to wait for stop before killing the container",
+ Value: libpod.CtrRemoveTimeout,
+ },
+ LatestFlag,
+ }
+ restartDescription = `Restarts one or more running containers. The container ID or name can be used. A timeout before forcibly stopping can be set, but defaults to 10 seconds`
+
+ restartCommand = cli.Command{
+ Name: "restart",
+ Usage: "Restart one or more containers",
+ Description: restartDescription,
+ Flags: restartFlags,
+ Action: restartCmd,
+ ArgsUsage: "CONTAINER [CONTAINER ...]",
+ UseShortOptionHandling: true,
+ }
+)
+
+func restartCmd(c *cli.Context) error {
+ args := c.Args()
+ if len(args) < 1 && !c.Bool("latest") {
+ return errors.Wrapf(libpod.ErrInvalidArg, "you must provide at least one container name or ID")
+ }
+
+ if err := validateFlags(c, restartFlags); err != nil {
+ return err
+ }
+
+ runtime, err := getRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "error creating libpod runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ var lastError error
+
+ timeout := c.Uint("timeout")
+ useTimeout := c.IsSet("timeout")
+
+ // Handle --latest
+ if c.Bool("latest") {
+ lastCtr, err := runtime.GetLatestContainer()
+ if err != nil {
+ lastError = errors.Wrapf(err, "unable to get latest container")
+ } else {
+ ctrTimeout := lastCtr.StopTimeout()
+ if useTimeout {
+ ctrTimeout = timeout
+ }
+
+ lastError = restartCtr(ctrTimeout, lastCtr)
+ }
+ }
+
+ for _, id := range args {
+ ctr, err := runtime.LookupContainer(id)
+ if err != nil {
+ if lastError != nil {
+ fmt.Fprintln(os.Stderr, lastError)
+ }
+ lastError = errors.Wrapf(err, "unable to find container %s", id)
+ continue
+ }
+
+ ctrTimeout := ctr.StopTimeout()
+ if useTimeout {
+ ctrTimeout = timeout
+ }
+
+ if err := restartCtr(ctrTimeout, ctr); err != nil {
+ if lastError != nil {
+ fmt.Fprintln(os.Stderr, lastError)
+ }
+ lastError = errors.Wrapf(err, "error restarting container %s", ctr.ID())
+ }
+ }
+
+ return lastError
+}
+
+// Restart a single container
+func restartCtr(timeout uint, ctr *libpod.Container) error {
+ state, err := ctr.State()
+ if err != nil {
+ return err
+ }
+ if state == libpod.ContainerStateRunning {
+ if err := ctr.StopWithTimeout(timeout); err != nil {
+ return err
+ }
+ }
+
+ if err := ctr.Start(); err != nil {
+ return err
+ }
+
+ fmt.Printf("%s\n", ctr.ID())
+
+ return nil
+}
diff --git a/commands.md b/commands.md
index c2301420a..987f4abfe 100644
--- a/commands.md
+++ b/commands.md
@@ -29,6 +29,7 @@
| [podman-ps(1)](/docs/podman-ps.1.md) | Prints out information about containers |[![...](/docs/play.png)](https://asciinema.org/a/bbT41kac6CwZ5giESmZLIaTLR)|
| [podman-pull(1)](/docs/podman-pull.1.md) | Pull an image from a registry |[![...](/docs/play.png)](https://asciinema.org/a/lr4zfoynHJOUNu1KaXa1dwG2X)|
| [podman-push(1)](/docs/podman-push.1.md) | Push an image to a specified destination |[![...](/docs/play.png)](https://asciinema.org/a/133276)|
+| [podman-restart](/docs/podman-restart.1.md) | Restarts one or more containers ||
| [podman-rm(1)](/docs/podman-rm.1.md) | Removes one or more containers |[![...](/docs/play.png)](https://asciinema.org/a/7EMk22WrfGtKWmgHJX9Nze1Qp)|
| [podman-rmi(1)](/docs/podman-rmi.1.md) | Removes one or more images |[![...](/docs/play.png)](https://asciinema.org/a/133799)|
| [podman-run(1)](/docs/podman-run.1.md) | Run a command in a container ||
diff --git a/completions/bash/podman b/completions/bash/podman
index ae7db9f6d..4313fe94f 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1001,7 +1001,6 @@ _podman_mount() {
"
local options_with_args="
- --label
--format
"
@@ -1314,6 +1313,16 @@ _podman_run() {
_podman_container_run
}
+_podman_restart() {
+ local options_with_args="
+ --timeout -t
+ "
+ local boolean_options="
+ --latest
+ -l"
+ _complete_ "$options_with_args" "$boolean_options"
+}
+
_podman_rm() {
local boolean_options="
--all
@@ -1609,6 +1618,7 @@ _podman_podman() {
ps
pull
push
+ restart
rm
rmi
run
diff --git a/docs/podman-restart.1.md b/docs/podman-restart.1.md
new file mode 100644
index 000000000..7b9e6173a
--- /dev/null
+++ b/docs/podman-restart.1.md
@@ -0,0 +1,46 @@
+% podman(1) podman-restart - Restart a container
+% Matt Heon
+# podman-restart "1" "March 2017" "podman"
+
+## NAME
+podman restart - Restart a container
+
+## SYNOPSIS
+**podman attach [OPTIONS] CONTAINER [CONTAINER...]**
+
+## DESCRIPTION
+The restart command allows containers to be restarted using their ID or name.
+Containers will be stopped if they are running and then restarted. Stopped
+containers will not be stopped and will only be started.
+
+## OPTIONS
+**--timeout**
+Timeout to wait before forcibly stopping the container
+
+**--latest, -l**
+Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
+to run containers such as CRI-O, the last started container could be from either of those methods.
+
+## EXAMPLES ##
+
+```
+podman restart -l
+ec588fc80b05e19d3006bf2e8aa325f0a2e2ff1f609b7afb39176ca8e3e13467
+```
+
+```
+podman restart ff6cf1
+ff6cf1e5e77e6dba1efc7f3fcdb20e8b89ad8947bc0518be1fcb2c78681f226f
+```
+
+```
+podman restart --timeout 4 test1 test2
+c3bb026838c30e5097f079fa365c9a4769d52e1017588278fa00d5c68ebc1502
+17e13a63081a995136f907024bcfe50ff532917988a152da229db9d894c5a9ec
+```
+
+## SEE ALSO
+podman(1), podman-run(1), podman-start(1), podman-create(1)
+
+## HISTORY
+March 2018, Originally compiled by Matt Heon <mheon@redhat.com>
diff --git a/docs/podman.1.md b/docs/podman.1.md
index 60ad16f37..e7639192b 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -78,6 +78,7 @@ has the capability to debug pods/images created by crio.
| [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
| [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. |
| [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. |
+| [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
| [podman-run(1)](podman-run.1.md) | Run a command in a container. |
diff --git a/libpod/container_api.go b/libpod/container_api.go
index cfffa2232..ef94aa4c9 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -368,7 +368,7 @@ func (c *Container) Attach(noStdin bool, keys string) error {
// Mount mounts a container's filesystem on the host
// The path where the container has been mounted is returned
-func (c *Container) Mount(label string) (string, error) {
+func (c *Container) Mount() (string, error) {
if !c.locked {
c.lock.Lock()
defer c.lock.Unlock()
@@ -378,27 +378,11 @@ func (c *Container) Mount(label string) (string, error) {
}
}
- // return mountpoint if container already mounted
- if c.state.Mounted {
- return c.state.Mountpoint, nil
- }
-
- mountLabel := label
- if label == "" {
- mountLabel = c.config.MountLabel
- }
- mountPoint, err := c.runtime.store.Mount(c.ID(), mountLabel)
- if err != nil {
+ if err := c.mountStorage(); err != nil {
return "", err
}
- c.state.Mountpoint = mountPoint
- c.state.Mounted = true
- if err := c.save(); err != nil {
- return "", err
- }
-
- return mountPoint, nil
+ return c.state.Mountpoint, nil
}
// Unmount unmounts a container's filesystem on the host
@@ -416,6 +400,11 @@ func (c *Container) Unmount() error {
return errors.Wrapf(ErrCtrStateInvalid, "cannot remove storage for container %s as it is running or paused", c.ID())
}
+ // Check if we have active exec sessions
+ if len(c.state.ExecSessions) != 0 {
+ return errors.Wrapf(ErrCtrStateInvalid, "container %s has active exec sessions, refusing to clean up", c.ID())
+ }
+
return c.cleanupStorage()
}
diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go
new file mode 100644
index 000000000..ea03d022f
--- /dev/null
+++ b/test/e2e/restart_test.go
@@ -0,0 +1,81 @@
+package integration
+
+import (
+ "os"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman 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.Cleanup()
+ })
+
+ It("Podman restart bogus container", func() {
+ session := podmanTest.Podman([]string{"start", "123"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ })
+
+ It("Podman restart stopped container by name", func() {
+ _, exitCode, _ := podmanTest.RunLsContainer("test1")
+ Expect(exitCode).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"restart", "test1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
+ It("Podman restart stopped container by ID", func() {
+ session := podmanTest.Podman([]string{"create", "-d", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ cid := session.OutputToString()
+
+ startSession := podmanTest.Podman([]string{"start", cid})
+ startSession.WaitWithDefaultTimeout()
+ Expect(startSession.ExitCode()).To(Equal(0))
+
+ session2 := podmanTest.Podman([]string{"restart", cid})
+ session2.WaitWithDefaultTimeout()
+ Expect(session2.ExitCode()).To(Equal(0))
+ })
+
+ It("Podman restart running container", func() {
+ _ = podmanTest.RunTopContainer("test1")
+ ok := WaitForContainer(&podmanTest)
+ Expect(ok).To(BeTrue())
+
+ session := podmanTest.Podman([]string{"restart", "--latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
+ It("Podman restart multiple containers", func() {
+ _, exitCode, _ := podmanTest.RunLsContainer("test1")
+ Expect(exitCode).To(Equal(0))
+
+ _, exitCode, _ = podmanTest.RunLsContainer("test2")
+ Expect(exitCode).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"restart", "test1", "test2"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+})
diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go
index 910656ef0..1404312d9 100644
--- a/test/e2e/rm_test.go
+++ b/test/e2e/rm_test.go
@@ -59,7 +59,7 @@ var _ = Describe("Podman rm", func() {
Expect(result.ExitCode()).To(Equal(0))
})
- It("podman rm created container", func() {
+ It("podman rm running container with -f", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -105,4 +105,21 @@ var _ = Describe("Podman rm", func() {
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
})
+
+ It("podman rm the latest container", func() {
+ session := podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ _, ec, cid := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+
+ result := podmanTest.Podman([]string{"rm", "-l"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ output := result.OutputToString()
+ Expect(output).To(ContainSubstring(cid))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+
+ })
})
diff --git a/transfer.md b/transfer.md
index 53d6c472c..2748004ec 100644
--- a/transfer.md
+++ b/transfer.md
@@ -38,36 +38,37 @@ There are other equivalents for these tools
| Existing Step | PODMAN (and friends) |
| :--- | :--- |
-| `docker attach` | [`podman exec`](./docs/podman-attach.1.md)|
-| `docker build` | [`podman build`](./docs/podman-build.1.md) |
-| `docker commit` | [`podman commit`](./docs/podman-commit.1.md)|
-| `docker cp` | [`podman mount`](./docs/podman-cp.1.md) **** |
-| `docker create` | [`podman create`](./docs/podman-create.1.md) |
-| `docker diff` | [`podman diff`](./docs/podman-diff.1.md) |
-| `docker export` | [`podman export`](./docs/podman-export.1.md) |
-| `docker history`| [`podman history`](./docs/podman-history.1.md)|
-| `docker images` | [`podman images`](./docs/podman-images.1.md) |
-| `docker import` | [`podman import`](./docs/podman-import.1.md) |
-| `docker kill` | [`podman kill`](./docs/podman-kill.1.md) |
-| `docker load` | [`podman load`](./docs/podman-load.1.md) |
-| `docker login` | [`podman login`](./docs/podman-login.1.md) |
-| `docker logout` | [`podman logout`](./docs/podman-logout.1.md) |
-| `docker pause` | [`podman pause`](./docs/podman-pause.1.md) |
-| `docker ps` | [`podman ps`](./docs/podman-ps.1.md) |
-| `docker pull` | [`podman pull`](./docs/podman-pull.1.md) |
-| `docker push` | [`podman push`](./docs/podman-push.1.md) |
-| `docker rm` | [`podman rm`](./docs/podman-rm.1.md) |
-| `docker rmi` | [`podman rmi`](./docs/podman-rmi.1.md) |
-| `docker run` | [`podman run`](./docs/podman-run.1.md) |
-| `docker save` | [`podman save`](./docs/podman-save.1.md) |
-| `docker search` | [`podman search`](./docs/podman-search.1.md) |
-| `docker start` | [`podman start`](./docs/podman-start.1.md) |
-| `docker stop` | [`podman stop`](./docs/podman-stop.1.md) |
-| `docker tag` | [`podman tag`](./docs/podman-tag.1.md) |
-| `docker top` | [`podman top`](./docs/podman-top.1.md) |
-| `docker unpause`| [`podman unpause`](./docs/podman-unpause.1.md)|
-| `docker version`| [`podman version`](./docs/podman-version.1.md)|
-| `docker wait` | [`podman wait`](./docs/podman-wait.1.md) |
+| `docker attach` | [`podman exec`](./docs/podman-attach.1.md) |
+| `docker build` | [`podman build`](./docs/podman-build.1.md) |
+| `docker commit` | [`podman commit`](./docs/podman-commit.1.md) |
+| `docker cp` | [`podman mount`](./docs/podman-cp.1.md) **** |
+| `docker create` | [`podman create`](./docs/podman-create.1.md) |
+| `docker diff` | [`podman diff`](./docs/podman-diff.1.md) |
+| `docker export` | [`podman export`](./docs/podman-export.1.md) |
+| `docker history` | [`podman history`](./docs/podman-history.1.md) |
+| `docker images` | [`podman images`](./docs/podman-images.1.md) |
+| `docker import` | [`podman import`](./docs/podman-import.1.md) |
+| `docker kill` | [`podman kill`](./docs/podman-kill.1.md) |
+| `docker load` | [`podman load`](./docs/podman-load.1.md) |
+| `docker login` | [`podman login`](./docs/podman-login.1.md) |
+| `docker logout` | [`podman logout`](./docs/podman-logout.1.md) |
+| `docker pause` | [`podman pause`](./docs/podman-pause.1.md) |
+| `docker ps` | [`podman ps`](./docs/podman-ps.1.md) |
+| `docker pull` | [`podman pull`](./docs/podman-pull.1.md) |
+| `docker push` | [`podman push`](./docs/podman-push.1.md) |
+| `docker restart` | [`podman restart`](./docs/podman-restart.1.md)] |
+| `docker rm` | [`podman rm`](./docs/podman-rm.1.md) |
+| `docker rmi` | [`podman rmi`](./docs/podman-rmi.1.md) |
+| `docker run` | [`podman run`](./docs/podman-run.1.md) |
+| `docker save` | [`podman save`](./docs/podman-save.1.md) |
+| `docker search` | [`podman search`](./docs/podman-search.1.md) |
+| `docker start` | [`podman start`](./docs/podman-start.1.md) |
+| `docker stop` | [`podman stop`](./docs/podman-stop.1.md) |
+| `docker tag` | [`podman tag`](./docs/podman-tag.1.md) |
+| `docker top` | [`podman top`](./docs/podman-top.1.md) |
+| `docker unpause` | [`podman unpause`](./docs/podman-unpause.1.md) |
+| `docker version` | [`podman version`](./docs/podman-version.1.md) |
+| `docker wait` | [`podman wait`](./docs/podman-wait.1.md) |
**** Use mount to take advantage of the entire linux tool chain rather then just cp. Read [`here`](./docs/podman-cp.1.md) for more information.
@@ -85,7 +86,6 @@ Those Docker commands currently do not have equivalents in `podman`:
| `docker plugin` |podman does not support plugins. We recommend you use alternative OCI Runtimes or OCI Runtime Hooks to alter behavior of podman.|
| `docker port` ||
| `docker rename` | podman does not support rename, you need to use `podman rm` and `podman create` to rename a container.|
-| `docker restart` | podman does not support restart. We recommend that you put your podman containers into a systemd unit file and use it for restarting applications.|
| `docker secret` ||
| `docker service` ||
| `docker stack` ||