Skip to content

Commit

Permalink
Merge pull request containers#6851 from rhatdan/mount
Browse files Browse the repository at this point in the history
Add podman image mount
  • Loading branch information
openshift-merge-robot authored Jul 29, 2020
2 parents 539bb4c + 6979d14 commit 7f0c094
Show file tree
Hide file tree
Showing 16 changed files with 789 additions and 22 deletions.
139 changes: 139 additions & 0 deletions cmd/podman/images/mount.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package images

import (
"fmt"
"os"
"text/tabwriter"
"text/template"

"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

var (
mountDescription = `podman image mount
Lists all mounted images mount points if no images is specified
podman image mount IMAGE-NAME-OR-ID
Mounts the specified image and prints the mountpoint
`

mountCommand = &cobra.Command{
Use: "mount [flags] [IMAGE...]",
Short: "Mount an images's root filesystem",
Long: mountDescription,
RunE: mount,
Example: `podman image mount imgID
podman image mount imgID1 imgID2 imgID3
podman image mount
podman image mount --all`,
Annotations: map[string]string{
registry.UnshareNSRequired: "",
registry.ParentNSRequired: "",
},
}
)

var (
mountOpts entities.ImageMountOptions
)

func mountFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&mountOpts.All, "all", "a", false, "Mount all images")
flags.StringVar(&mountOpts.Format, "format", "", "Print the mounted images in specified format (json)")
}

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Command: mountCommand,
Parent: imageCmd,
})
mountFlags(mountCommand.Flags())
}

func mount(_ *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
if len(args) > 0 && mountOpts.All {
return errors.New("when using the --all switch, you may not pass any image names or IDs")
}
reports, err := registry.ImageEngine().Mount(registry.GetContext(), args, mountOpts)
if err != nil {
return err
}
if len(args) > 0 || mountOpts.All {
for _, r := range reports {
if r.Err == nil {
fmt.Println(r.Path)
continue
}
errs = append(errs, r.Err)
}
return errs.PrintErrors()
}

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}}\n"
format := "{{range . }}" + row + "{{end}}"
tmpl, err := template.New("mounts").Parse(format)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
defer w.Flush()
return tmpl.Execute(w, mrs)
}

func printJSON(reports []*entities.ImageMountReport) error {
type jreport struct {
ID string `json:"id"`
Names []string
Repositories []string
Mountpoint string `json:"mountpoint"`
}
jreports := make([]jreport, 0, len(reports))

for _, r := range reports {
jreports = append(jreports, jreport{
ID: r.Id,
Names: []string{r.Name},
Repositories: r.Repositories,
Mountpoint: r.Path,
})
}
b, err := json.MarshalIndent(jreports, "", " ")
if err != nil {
return err
}
fmt.Println(string(b))
return nil
}

type mountReporter struct {
*entities.ImageMountReport
}

func (m mountReporter) ID() string {
if len(m.Repositories) > 0 {
return m.Repositories[0]
}
return m.Id
}
71 changes: 71 additions & 0 deletions cmd/podman/images/unmount.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package images

import (
"fmt"

"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

var (
description = `Image storage increments a mount counter each time an image is mounted.
When an image is unmounted, the mount counter is decremented. The image'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.
`
unmountCommand = &cobra.Command{
Use: "unmount [flags] IMAGE [IMAGE...]",
Aliases: []string{"umount"},
Short: "Unmount an image's root filesystem",
Long: description,
RunE: unmount,
Example: `podman unmount imgID
podman unmount imgID1 imgID2 imgID3
podman unmount --all`,
}
)

var (
unmountOpts entities.ImageUnmountOptions
)

func unmountFlags(flags *pflag.FlagSet) {
flags.BoolVarP(&unmountOpts.All, "all", "a", false, "Unmount all of the currently mounted images")
flags.BoolVarP(&unmountOpts.Force, "force", "f", false, "Force the complete unmount of the specified mounted images")
}

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode},
Parent: imageCmd,
Command: unmountCommand,
})
unmountFlags(unmountCommand.Flags())
}

func unmount(cmd *cobra.Command, args []string) error {
var errs utils.OutputErrors
if len(args) < 1 && !unmountOpts.All {
return errors.New("image name or ID must be specified")
}
if len(args) > 0 && unmountOpts.All {
return errors.New("when using the --all switch, you may not pass any image names or IDs")
}
reports, err := registry.ImageEngine().Unmount(registry.GetContext(), args, unmountOpts)
if err != nil {
return err
}
for _, r := range reports {
if r.Err == nil {
fmt.Println(r.Id)
} else {
errs = append(errs, r.Err)
}
}
return errs.PrintErrors()
}
53 changes: 53 additions & 0 deletions completions/bash/podman
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,56 @@ _podman_info() {
esac
}

_podman_image_umount() {
_podman_image_unmount
}

_podman_image_unmount() {
local boolean_options="
--all
-a
--help
-h
--force
-f
"
local options_with_args="
"

local all_options="$options_with_args $boolean_options"
case "$cur" in
-*)
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
;;
*)
__podman_complete_images --force-tag --id
;;
esac
}

_podman_image_mount() {
local boolean_options="
--all
-a
--help
-h
"

local options_with_args="
--format
"

local all_options="$options_with_args $boolean_options"
case "$cur" in
-*)
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
;;
*)
__podman_complete_images --force-tag --id
;;
esac
}

_podman_image_build() {
_podman_build
}
Expand Down Expand Up @@ -1590,6 +1640,7 @@ _podman_image() {
inspect
load
ls
mount
prune
pull
push
Expand All @@ -1598,6 +1649,8 @@ _podman_image() {
sign
tag
trust
umount
unmount
untag
"
local aliases="
Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/links/podman-image-umount.1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.so man1/podman-image-unmount.1
76 changes: 76 additions & 0 deletions docs/source/markdown/podman-image-mount.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
% podman-image-mount(1)

## NAME
podman\-image\-mount - Mount an image's root filesystem

## SYNOPSIS
**podman image mount** [*options*] [*image* ...]

## DESCRIPTION
Mounts the specified images' 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, Podman will list all of the
currently mounted images.

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.

## OPTIONS

**--all**, **-a**

Mount all images.

**--format**=*format*

Print the mounted images in specified format (json).

## EXAMPLE

```
podman image mount fedora ubi8-init
/var/lib/containers/storage/overlay/f3ac502d97b5681989dff84dfedc8354239bcecbdc2692f9a639f4e080a02364/merged
/var/lib/containers/storage/overlay/0ff7d7ca68bed1ace424f9df154d2dd7b5a125c19d887f17653cbcd5b6e30ba1/merged
```

```
podman mount
registry.fedoraproject.org/fedora:latest /var/lib/containers/storage/overlay/f3ac502d97b5681989dff84dfedc8354239bcecbdc2692f9a639f4e080a02364/merged
registry.access.redhat.com/ubi8-init:latest /var/lib/containers/storage/overlay/0ff7d7ca68bed1ace424f9df154d2dd7b5a125c19d887f17653cbcd5b6e30ba1/merged
```

```
podman image mount --format json
[
{
"id": "00ff39a8bf19f810a7e641f7eb3ddc47635913a19c4996debd91fafb6b379069",
"Names": [
"sha256:58de585a231aca14a511347bc85b912a6f000159b49bc2b0582032911e5d3a6c"
],
"Repositories": [
"registry.fedoraproject.org/fedora:latest"
],
"mountpoint": "/var/lib/containers/storage/overlay/0ccfac04663bbe8813b5f24502ee0b7371ce5bf3c5adeb12e4258d191c2cf7bc/merged"
},
{
"id": "bcc2dc9a261774ad25a15e07bb515f9b77424266abf2a1252ec7bcfed1dd0ac2",
"Names": [
"sha256:d5f260b2e51b3ee9d05de1c31d261efc9af28e7d2d47cedf054c496d71424d63"
],
"Repositories": [
"registry.access.redhat.com/ubi8-init:latest"
],
"mountpoint": "/var/lib/containers/storage/overlay/d66b58e3391ea8ce4c81316c72e22b332618f2a28b461a32ed673e8998cdaeb8/merged"
}
]
```

## SEE ALSO
podman(1), podman-image-umount(1), mount(8), podman-unshare(1)
Loading

0 comments on commit 7f0c094

Please sign in to comment.