mirror of
https://github.com/containers/podman
synced 2024-10-19 16:54:07 +00:00
Merge pull request #7085 from rhatdan/cmount
Cleanup handling of podman mount/unmount
This commit is contained in:
commit
91c92d10fc
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -40,13 +40,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
|
||||
|
|
|
@ -15,7 +15,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ParentNSRequired = "ParentNSRequired"
|
||||
ParentNSRequired = "ParentNSRequired"
|
||||
UnshareNSRequired = "UnshareNSRequired"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -1 +1 @@
|
|||
.so man1/podman-umount.1
|
||||
.so man1/podman-unmount.1
|
||||
|
|
|
@ -1 +1 @@
|
|||
.so man1/podman-umount.1
|
||||
.so man1/podman-unmount.1
|
||||
|
|
1
docs/source/markdown/links/podman-umount.1
Normal file
1
docs/source/markdown/links/podman-umount.1
Normal file
|
@ -0,0 +1 @@
|
|||
.so man1/podman-unmount.1
|
|
@ -1 +0,0 @@
|
|||
.so man1/podman-umount.1
|
|
@ -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. |
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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** [*options*] *container* [...]
|
||||
**podman unmount** [*options*] *container* [...]
|
||||
|
||||
**podman container umount** [*options*] *container* [...]
|
||||
**podman umount** [*options*] *container* [...]
|
||||
|
||||
**podman container unmount** [*options*] *container* [...]
|
||||
|
||||
**podman unmount** [*options*] *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)
|
|
@ -207,7 +207,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. |
|
||||
|
|
|
@ -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]);
|
||||
|
|
62
test/e2e/mount_rootless_test.go
Normal file
62
test/e2e/mount_rootless_test.go
Normal file
|
@ -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))
|
||||
})
|
||||
})
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue