summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel J Walsh <dwalsh@redhat.com>2020-07-09 14:53:46 -0400
committerDaniel J Walsh <dwalsh@redhat.com>2020-08-20 13:35:11 -0400
commit4e31c8136dffd2272e49715b83fba092621ffd2a (patch)
tree52070eed2d7619f1a33c40ff826c681fb6dc6e7f
parent386de7a1fbfef0c266e04f6471f9382a5d39a02f (diff)
downloadpodman-4e31c8136dffd2272e49715b83fba092621ffd2a.tar.gz
podman-4e31c8136dffd2272e49715b83fba092621ffd2a.tar.bz2
podman-4e31c8136dffd2272e49715b83fba092621ffd2a.zip
Cleanup handling of podman mount/unmount
We should default to the user name unmount rather then the internal name of umount. Also User namespace was not being handled correctly. We want to inform the user that if they do a mount when in rootless mode that they have to be first in the podman unshare state. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
-rw-r--r--cmd/podman/containers/mount.go17
-rw-r--r--cmd/podman/containers/unmount.go41
-rw-r--r--cmd/podman/main.go18
-rw-r--r--cmd/podman/registry/config.go3
-rw-r--r--docs/source/markdown/links/podman-container-umount.12
-rw-r--r--docs/source/markdown/links/podman-container-unmount.12
-rw-r--r--docs/source/markdown/links/podman-umount.11
-rw-r--r--docs/source/markdown/links/podman-unmount.11
-rw-r--r--docs/source/markdown/podman-container.1.md2
-rw-r--r--docs/source/markdown/podman-mount.1.md9
-rw-r--r--docs/source/markdown/podman-unmount.1.md (renamed from docs/source/markdown/podman-umount.1.md)22
-rw-r--r--docs/source/markdown/podman.1.md2
-rw-r--r--pkg/rootless/rootless_linux.c7
-rw-r--r--test/e2e/mount_rootless_test.go62
-rw-r--r--test/e2e/mount_test.go5
15 files changed, 145 insertions, 49 deletions
diff --git a/cmd/podman/containers/mount.go b/cmd/podman/containers/mount.go
index 37ee92177..e2603a55c 100644
--- a/cmd/podman/containers/mount.go
+++ b/cmd/podman/containers/mount.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/libpod/v2/cmd/podman/utils"
"github.com/containers/libpod/v2/cmd/podman/validate"
"github.com/containers/libpod/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@@ -31,7 +32,8 @@ var (
return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
},
Annotations: map[string]string{
- registry.ParentNSRequired: "",
+ registry.UnshareNSRequired: "",
+ registry.ParentNSRequired: "",
},
}
@@ -51,7 +53,7 @@ var (
func mountFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&mountOpts.All, "all", "a", false, "Mount all containers")
- flags.StringVar(&mountOpts.Format, "format", "", "Change the output format to Go template")
+ flags.StringVar(&mountOpts.Format, "format", "", "Print the mounted containers in specified format (json)")
flags.BoolVar(&mountOpts.NoTruncate, "notruncate", false, "Do not truncate output")
}
@@ -90,14 +92,21 @@ func mount(_ *cobra.Command, args []string) error {
}
return errs.PrintErrors()
}
- if mountOpts.Format == "json" {
+
+ switch mountOpts.Format {
+ case "json":
return printJSON(reports)
+ case "":
+ // do nothing
+ default:
+ return errors.Errorf("unknown --format argument: %s", mountOpts.Format)
}
+
mrs := make([]mountReporter, 0, len(reports))
for _, r := range reports {
mrs = append(mrs, mountReporter{r})
}
- row := "{{.ID}} {{.Path}}"
+ row := "{{.ID}} {{.Path}}\n"
format := "{{range . }}" + row + "{{end}}"
tmpl, err := template.New("mounts").Parse(format)
if err != nil {
diff --git a/cmd/podman/containers/unmount.go b/cmd/podman/containers/unmount.go
index c40c2be7e..6556a6510 100644
--- a/cmd/podman/containers/unmount.go
+++ b/cmd/podman/containers/unmount.go
@@ -18,31 +18,32 @@ var (
An unmount can be forced with the --force flag.
`
- umountCommand = &cobra.Command{
- Use: "umount [flags] CONTAINER [CONTAINER...]",
- Aliases: []string{"unmount"},
+ unmountCommand = &cobra.Command{
+ Use: "unmount [flags] CONTAINER [CONTAINER...]",
+ Aliases: []string{"umount"},
Short: "Unmounts working container's root filesystem",
Long: description,
RunE: unmount,
Args: func(cmd *cobra.Command, args []string) error {
return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
- Example: `podman umount ctrID
- podman umount ctrID1 ctrID2 ctrID3
- podman umount --all`,
+ Example: `podman unmount ctrID
+ podman unmount ctrID1 ctrID2 ctrID3
+ podman unmount --all`,
}
containerUnmountCommand = &cobra.Command{
- Use: umountCommand.Use,
- Short: umountCommand.Short,
- Long: umountCommand.Long,
- RunE: umountCommand.RunE,
+ Use: unmountCommand.Use,
+ Short: unmountCommand.Short,
+ Aliases: unmountCommand.Aliases,
+ Long: unmountCommand.Long,
+ RunE: unmountCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
},
- Example: `podman container umount ctrID
- podman container umount ctrID1 ctrID2 ctrID3
- podman container umount --all`,
+ Example: `podman container unmount ctrID
+ podman container unmount ctrID1 ctrID2 ctrID3
+ podman container unmount --all`,
}
)
@@ -50,25 +51,25 @@ var (
unmountOpts entities.ContainerUnmountOptions
)
-func umountFlags(flags *pflag.FlagSet) {
- flags.BoolVarP(&unmountOpts.All, "all", "a", false, "Umount all of the currently mounted containers")
- flags.BoolVarP(&unmountOpts.Force, "force", "f", false, "Force the complete umount all of the currently mounted containers")
+func unmountFlags(flags *pflag.FlagSet) {
+ flags.BoolVarP(&unmountOpts.All, "all", "a", false, "Unmount all of the currently mounted containers")
+ flags.BoolVarP(&unmountOpts.Force, "force", "f", false, "Force the complete unmount of the specified mounted containers")
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
- Command: umountCommand,
+ Command: unmountCommand,
})
- umountFlags(umountCommand.Flags())
- validate.AddLatestFlag(umountCommand, &unmountOpts.Latest)
+ unmountFlags(unmountCommand.Flags())
+ validate.AddLatestFlag(unmountCommand, &unmountOpts.Latest)
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Command: containerUnmountCommand,
Parent: containerCmd,
})
- umountFlags(containerUnmountCommand.Flags())
+ unmountFlags(containerUnmountCommand.Flags())
validate.AddLatestFlag(containerUnmountCommand, &unmountOpts.Latest)
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 5f740a006..4bdb020af 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -39,13 +39,21 @@ func main() {
for _, m := range c.Mode {
if cfg.EngineMode == m {
// Command cannot be run rootless
- _, found := c.Command.Annotations[registry.ParentNSRequired]
- if rootless.IsRootless() && found {
- c.Command.RunE = func(cmd *cobra.Command, args []string) error {
- return fmt.Errorf("cannot run command %q in rootless mode", cmd.CommandPath())
+ _, found := c.Command.Annotations[registry.UnshareNSRequired]
+ if found {
+ if rootless.IsRootless() && found && os.Getuid() != 0 {
+ c.Command.RunE = func(cmd *cobra.Command, args []string) error {
+ return fmt.Errorf("cannot run command %q in rootless mode, must execute `podman unshare` first", cmd.CommandPath())
+ }
+ }
+ } else {
+ _, found = c.Command.Annotations[registry.ParentNSRequired]
+ if rootless.IsRootless() && found {
+ c.Command.RunE = func(cmd *cobra.Command, args []string) error {
+ return fmt.Errorf("cannot run command %q in rootless mode", cmd.CommandPath())
+ }
}
}
-
parent := rootCmd
if c.Parent != nil {
parent = c.Parent
diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go
index 24e728bad..ea33e3a4e 100644
--- a/cmd/podman/registry/config.go
+++ b/cmd/podman/registry/config.go
@@ -15,7 +15,8 @@ import (
)
const (
- ParentNSRequired = "ParentNSRequired"
+ ParentNSRequired = "ParentNSRequired"
+ UnshareNSRequired = "UnshareNSRequired"
)
var (
diff --git a/docs/source/markdown/links/podman-container-umount.1 b/docs/source/markdown/links/podman-container-umount.1
index 789dabbb0..aa4add453 100644
--- a/docs/source/markdown/links/podman-container-umount.1
+++ b/docs/source/markdown/links/podman-container-umount.1
@@ -1 +1 @@
-.so man1/podman-umount.1
+.so man1/podman-unmount.1
diff --git a/docs/source/markdown/links/podman-container-unmount.1 b/docs/source/markdown/links/podman-container-unmount.1
index 789dabbb0..aa4add453 100644
--- a/docs/source/markdown/links/podman-container-unmount.1
+++ b/docs/source/markdown/links/podman-container-unmount.1
@@ -1 +1 @@
-.so man1/podman-umount.1
+.so man1/podman-unmount.1
diff --git a/docs/source/markdown/links/podman-umount.1 b/docs/source/markdown/links/podman-umount.1
new file mode 100644
index 000000000..aa4add453
--- /dev/null
+++ b/docs/source/markdown/links/podman-umount.1
@@ -0,0 +1 @@
+.so man1/podman-unmount.1
diff --git a/docs/source/markdown/links/podman-unmount.1 b/docs/source/markdown/links/podman-unmount.1
deleted file mode 100644
index 789dabbb0..000000000
--- a/docs/source/markdown/links/podman-unmount.1
+++ /dev/null
@@ -1 +0,0 @@
-.so man1/podman-umount.1
diff --git a/docs/source/markdown/podman-container.1.md b/docs/source/markdown/podman-container.1.md
index 4ea7c7acc..0a6ceea33 100644
--- a/docs/source/markdown/podman-container.1.md
+++ b/docs/source/markdown/podman-container.1.md
@@ -41,7 +41,7 @@ The container command allows you to manage containers
| stats | [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. |
| stop | [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. |
| top | [podman-top(1)](podman-top.1.md) | Display the running processes of a container. |
-| umount | [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem.(Alias unmount) |
+| unmount | [podman-unmount(1)](podman-unmount.1.md) | Unmount a working container's root filesystem.(Alias unmount) |
| unpause | [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. |
| wait | [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. |
diff --git a/docs/source/markdown/podman-mount.1.md b/docs/source/markdown/podman-mount.1.md
index c7bfedb48..077d3bd04 100644
--- a/docs/source/markdown/podman-mount.1.md
+++ b/docs/source/markdown/podman-mount.1.md
@@ -12,9 +12,12 @@ podman\-mount - Mount a working container's root filesystem
Mounts the specified containers' root file system in a location which can be
accessed from the host, and returns its location.
-If you execute the command without any arguments, the tool will list all of the
+If you execute the command without any arguments, Podman will list all of the
currently mounted containers.
+Rootless mode only supports mounting VFS driver, unless you enter the user namespace
+via the `podman unshare` command. All other storage drivers will fail to mount.
+
## RETURN VALUE
The location of the mounted file system. On error an empty string and errno is
returned.
@@ -27,7 +30,7 @@ Mount all containers.
**--format**=*format*
-Print the mounted containers in specified format (json)
+Print the mounted containers in specified format (json).
**--latest**, **-l**
@@ -70,4 +73,4 @@ a7060253093b /var/lib/containers/storage/overlay/0ff7d7ca68bed1ace424f9df154d2dd
```
## SEE ALSO
-podman(1), podman-umount(1), mount(8)
+podman(1), podman-umount(1), mount(8), podman-unshare(1)
diff --git a/docs/source/markdown/podman-umount.1.md b/docs/source/markdown/podman-unmount.1.md
index 100c47b32..47c55cc0b 100644
--- a/docs/source/markdown/podman-umount.1.md
+++ b/docs/source/markdown/podman-unmount.1.md
@@ -1,23 +1,23 @@
-% podman-umount(1)
+% podman-unmount(1)
## NAME
-podman\-umount - Unmount a working container's root filesystem
+podman\-unmount - Unmount a working container's root filesystem
## SYNOPSIS
-**podman umount** *container* [...]
+**podman unmount** [*options*] *container* [...]
-**podman container umount** *container* [...]
+**podman umount** [*options*] *container* [...]
-**podman container unmount** *container* [...]
+**podman container unmount** [*options*] *container* [...]
-**podman unmount** *container* [...]
+**podman container umount** [*options*] *container* [...]
## DESCRIPTION
Unmounts the specified containers' root file system, if no other processes
are using it.
Container storage increments a mount counter each time a container is mounted.
-When a container is unmounted, the mount counter is decremented and the
+When a container is unmounted, the mount counter is decremented, and the
container's root filesystem is physically unmounted only when the mount
counter reaches zero indicating no other processes are using the mount.
An unmount can be forced with the --force flag.
@@ -45,11 +45,11 @@ The latest option is not supported on the remote client.
## EXAMPLE
-podman umount containerID
+podman container unmount containerID
-podman umount containerID1 containerID2 containerID3
+podman unmount containerID1 containerID2 containerID3
-podman umount --all
+podman unmount --all
## SEE ALSO
-podman(1), podman-mount(1)
+podman(1), podman-container-mount(1), podman-image-mount(1)
diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index 01a054ff4..d5c844b8a 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -203,7 +203,7 @@ the exit codes follow the `chroot` standard, see below:
| [podman-system(1)](podman-system.1.md) | Manage podman. |
| [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. |
| [podman-top(1)](podman-top.1.md) | Display the running processes of a container. |
-| [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. |
+| [podman-unmount(1)](podman-unmount.1.md) | Unmount a working container's root filesystem. |
| [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. |
| [podman-unshare(1)](podman-unshare.1.md) | Run a command inside of a modified user namespace. |
| [podman-untag(1)](podman-untag.1.md) | Removes one or more names from a locally-stored image. |
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 2c6f7ae38..d2f217dd3 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -210,6 +210,13 @@ can_use_shortcut ()
ret = false;
break;
}
+
+ if (argv[argc+1] != NULL && strcmp (argv[argc], "container") == 0 &&
+ strcmp (argv[argc+1], "mount") == 0)
+ {
+ ret = false;
+ break;
+ }
}
free (argv[0]);
diff --git a/test/e2e/mount_rootless_test.go b/test/e2e/mount_rootless_test.go
new file mode 100644
index 000000000..986c11c16
--- /dev/null
+++ b/test/e2e/mount_rootless_test.go
@@ -0,0 +1,62 @@
+// +build !remote
+
+package integration
+
+import (
+ "os"
+
+ . "github.com/containers/libpod/v2/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman mount", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ )
+
+ BeforeEach(func() {
+ if os.Geteuid() == 0 {
+ Skip("This function is not enabled for rootfull podman")
+ }
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanTestCreate(tempdir)
+ podmanTest.Setup()
+ podmanTest.SeedImages()
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ processTestResult(f)
+
+ })
+
+ It("podman mount", func() {
+ setup := podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid := setup.OutputToString()
+
+ mount := podmanTest.Podman([]string{"mount", cid})
+ mount.WaitWithDefaultTimeout()
+ Expect(mount.ExitCode()).ToNot(Equal(0))
+ Expect(mount.ErrorToString()).To(ContainSubstring("podman unshare"))
+ })
+
+ It("podman unshare podman mount", func() {
+ setup := podmanTest.Podman([]string{"create", ALPINE, "ls"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ cid := setup.OutputToString()
+
+ session := podmanTest.Podman([]string{"unshare", PODMAN_BINARY, "mount", cid})
+ session.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+ })
+})
diff --git a/test/e2e/mount_test.go b/test/e2e/mount_test.go
index 657daedef..d98999162 100644
--- a/test/e2e/mount_test.go
+++ b/test/e2e/mount_test.go
@@ -80,6 +80,11 @@ var _ = Describe("Podman mount", func() {
Expect(j.ExitCode()).To(Equal(0))
Expect(j.IsJSONOutputValid()).To(BeTrue())
+ j = podmanTest.Podman([]string{"mount", "--format='{{.foobar}}'"})
+ j.WaitWithDefaultTimeout()
+ Expect(j.ExitCode()).ToNot(Equal(0))
+ Expect(j.ErrorToString()).To(ContainSubstring("unknown --format"))
+
umount := podmanTest.Podman([]string{"umount", cid})
umount.WaitWithDefaultTimeout()
Expect(umount.ExitCode()).To(Equal(0))