aboutsummaryrefslogtreecommitdiff
path: root/cmd/podman/images/mount.go
blob: fac06e32478502dc00c480cbd90408f2bb5d0266 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
}