Merge pull request #694 from rhatdan/mount
Add kpod-mount and kpod-umount to mount and umount container images
This commit is contained in:
commit
8e394e0589
9 changed files with 328 additions and 5 deletions
|
@ -26,10 +26,12 @@ func main() {
|
|||
imagesCommand,
|
||||
infoCommand,
|
||||
inspectCommand,
|
||||
mountCommand,
|
||||
pullCommand,
|
||||
pushCommand,
|
||||
rmiCommand,
|
||||
tagCommand,
|
||||
umountCommand,
|
||||
versionCommand,
|
||||
saveCommand,
|
||||
loadCommand,
|
||||
|
|
117
cmd/kpod/mount.go
Normal file
117
cmd/kpod/mount.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
js "encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
mountDescription = `
|
||||
kpod mount
|
||||
Lists all mounted containers mount points
|
||||
|
||||
kpod mount CONTAINER-NAME-OR-ID
|
||||
Mounts the specified container and outputs the mountpoint
|
||||
`
|
||||
|
||||
mountFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "notruncate",
|
||||
Usage: "do not truncate output",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "label",
|
||||
Usage: "SELinux label for the mount point",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Print mounted containers in specified format",
|
||||
},
|
||||
}
|
||||
mountCommand = cli.Command{
|
||||
Name: "mount",
|
||||
Usage: "Mount a working container's root filesystem",
|
||||
Description: mountDescription,
|
||||
Action: mountCmd,
|
||||
ArgsUsage: "[CONTAINER-NAME-OR-ID]",
|
||||
Flags: mountFlags,
|
||||
}
|
||||
)
|
||||
|
||||
// MountOutputParams stores info about each layer
|
||||
type jsonMountPoint struct {
|
||||
ID string `json:"id"`
|
||||
Names []string `json:"names"`
|
||||
MountPoint string `json:"mountpoint"`
|
||||
}
|
||||
|
||||
func mountCmd(c *cli.Context) error {
|
||||
formats := map[string]bool{
|
||||
"": true,
|
||||
"json": true,
|
||||
}
|
||||
|
||||
args := c.Args()
|
||||
json := c.String("format") == "json"
|
||||
if !formats[c.String("format")] {
|
||||
return errors.Errorf("%q is not a supported format", c.String("format"))
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments specified")
|
||||
}
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
store, err := getStore(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting store")
|
||||
}
|
||||
if len(args) == 1 {
|
||||
if json {
|
||||
return errors.Wrapf(err, "json option can not be used with a container id")
|
||||
}
|
||||
mountPoint, err := store.Mount(args[0], c.String("label"))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error finding container %q", args[0])
|
||||
}
|
||||
fmt.Printf("%s\n", mountPoint)
|
||||
} else {
|
||||
jsonMountPoints := []jsonMountPoint{}
|
||||
containers, err2 := store.Containers()
|
||||
if err2 != nil {
|
||||
return errors.Wrapf(err2, "error reading list of all containers")
|
||||
}
|
||||
for _, container := range containers {
|
||||
layer, err := store.Layer(container.LayerID)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error finding layer %q for container %q", container.LayerID, container.ID)
|
||||
}
|
||||
if layer.MountPoint == "" {
|
||||
continue
|
||||
}
|
||||
if json {
|
||||
jsonMountPoints = append(jsonMountPoints, jsonMountPoint{ID: container.ID, Names: container.Names, MountPoint: layer.MountPoint})
|
||||
continue
|
||||
}
|
||||
|
||||
if c.Bool("notruncate") {
|
||||
fmt.Printf("%-64s %s\n", container.ID, layer.MountPoint)
|
||||
} else {
|
||||
fmt.Printf("%-12.12s %s\n", container.ID, layer.MountPoint)
|
||||
}
|
||||
}
|
||||
if json {
|
||||
data, err := js.MarshalIndent(jsonMountPoints, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s\n", data)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
41
cmd/kpod/umount.go
Normal file
41
cmd/kpod/umount.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
umountCommand = cli.Command{
|
||||
Name: "umount",
|
||||
Aliases: []string{"unmount"},
|
||||
Usage: "Unmount a working container's root filesystem",
|
||||
Description: "Unmounts a working container's root filesystem",
|
||||
Action: umountCmd,
|
||||
ArgsUsage: "CONTAINER-NAME-OR-ID",
|
||||
}
|
||||
)
|
||||
|
||||
func umountCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("container ID must be specified")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments specified")
|
||||
}
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
store, err := getStore(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = store.Unmount(args[0])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error unmounting container %q", args[0])
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -71,6 +71,48 @@ _kpod_pull() {
|
|||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_unmount() {
|
||||
_kpod_umount $@
|
||||
}
|
||||
|
||||
_kpod_umount() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
"
|
||||
local options_with_args="
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_mount() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
--notruncate
|
||||
"
|
||||
|
||||
local options_with_args="
|
||||
--label
|
||||
--format
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_push() {
|
||||
local boolean_options="
|
||||
--disable-compression
|
||||
|
@ -175,15 +217,18 @@ _kpod_kpod() {
|
|||
--help -h
|
||||
"
|
||||
commands="
|
||||
history
|
||||
images
|
||||
launch
|
||||
load
|
||||
mount
|
||||
pull
|
||||
push
|
||||
rmi
|
||||
tag
|
||||
umount
|
||||
unmount
|
||||
version
|
||||
pull
|
||||
history
|
||||
load
|
||||
"
|
||||
|
||||
case "$prev" in
|
||||
|
|
50
docs/kpod-mount.1.md
Normal file
50
docs/kpod-mount.1.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
% kpod(1) kpod-mount - Mount a working container's root filesystem.
|
||||
% Dan Walsh
|
||||
# kpod-mount "1" "July 2017" "kpod"
|
||||
|
||||
## NAME
|
||||
kpod mount - Mount a working container's root filesystem.
|
||||
|
||||
## SYNOPSIS
|
||||
**kpod** **mount**
|
||||
|
||||
**kpod** **mount** **containerID**
|
||||
|
||||
## DESCRIPTION
|
||||
Mounts the specified container's 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
|
||||
currently mounted containers.
|
||||
|
||||
## RETURN VALUE
|
||||
The location of the mounted file system. On error an empty string and errno is
|
||||
returned.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--format**
|
||||
Print the mounted containers in specified format (json)
|
||||
|
||||
**--notruncate**
|
||||
|
||||
Do not truncate IDs in output.
|
||||
|
||||
**--label**
|
||||
|
||||
SELinux label for the mount point
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
kpod mount c831414b10a3
|
||||
|
||||
/var/lib/containers/storage/overlay2/f3ac502d97b5681989dff84dfedc8354239bcecbdc2692f9a639f4e080a02364/merged
|
||||
|
||||
kpod mount
|
||||
|
||||
c831414b10a3 /var/lib/containers/storage/overlay2/f3ac502d97b5681989dff84dfedc8354239bcecbdc2692f9a639f4e080a02364/merged
|
||||
|
||||
a7060253093b /var/lib/containers/storage/overlay2/0ff7d7ca68bed1ace424f9df154d2dd7b5a125c19d887f17653cbcd5b6e30ba1/merged
|
||||
|
||||
## SEE ALSO
|
||||
kpod(1), kpod-umount(1), mount(8)
|
|
@ -10,7 +10,7 @@ kpod push - Push an image from local storage to elsewhere
|
|||
|
||||
## DESCRIPTION
|
||||
Pushes an image from local storage to a specified destination, decompressing
|
||||
and recompessing layers as needed.
|
||||
and recompressing layers as needed.
|
||||
|
||||
## imageID
|
||||
Image stored in local container/storage
|
||||
|
|
19
docs/kpod-umount.1.md
Normal file
19
docs/kpod-umount.1.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
% kpod(1) kpod-umount - Unmount a working container's root filesystem.
|
||||
% Dan Walsh
|
||||
# kpod-umount "1" "July 2017" "kpod"
|
||||
|
||||
## NAME
|
||||
kpod umount - Unmount a working container's root file system.
|
||||
|
||||
## SYNOPSIS
|
||||
**kpod** **umount** **containerID**
|
||||
|
||||
## DESCRIPTION
|
||||
Unmounts the specified container's root file system.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
kpod umount containerID
|
||||
|
||||
## SEE ALSO
|
||||
kpod(1), kpod-mount(1)
|
|
@ -18,7 +18,7 @@ function teardown() {
|
|||
}
|
||||
|
||||
@test "kpod pull from docker with tag" {
|
||||
run ${KPOD_BINARY} $KPOD_OPTIONS pull debian:6.0.10
|
||||
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull debian:6.0.10
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
run ${KPOD_BINARY} $KPOD_OPTIONS rmi debian:6.0.10
|
||||
|
|
49
test/kpod_mount.bats
Normal file
49
test/kpod_mount.bats
Normal file
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
function teardown() {
|
||||
cleanup_test
|
||||
}
|
||||
|
||||
load helpers
|
||||
|
||||
IMAGE="redis:alpine"
|
||||
ROOT="$TESTDIR/crio"
|
||||
RUNROOT="$TESTDIR/crio-run"
|
||||
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT ${STORAGE_OPTS}"
|
||||
|
||||
@test "mount" {
|
||||
start_crio
|
||||
run crioctl pod run --config "$TESTDATA"/sandbox_config.json
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
pod_id="$output"
|
||||
run crioctl image pull "$IMAGE"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
run crioctl ctr create --config "$TESTDATA"/container_config.json --pod "$pod_id"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
ctr_id="$output"
|
||||
run ${KPOD_BINARY} ${KPOD_OPTIONS} mount $ctr_id
|
||||
echo "$output"
|
||||
echo ${KPOD_BINARY} ${KPOD_OPTIONS} mount $ctr_id
|
||||
[ "$status" -eq 0 ]
|
||||
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} mount --notruncate | grep $ctr_id"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
run ${KPOD_BINARY} ${KPOD_OPTIONS} unmount $ctr_id
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
run ${KPOD_BINARY} ${KPOD_OPTIONS} mount $ctr_id
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
root="$output"
|
||||
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} mount --format=json | python -m json.tool | grep $ctr_id"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
touch $root/foobar
|
||||
${KPOD_BINARY} ${KPOD_OPTIONS} unmount $ctr_id
|
||||
cleanup_ctrs
|
||||
cleanup_pods
|
||||
stop_crio
|
||||
}
|
Loading…
Reference in a new issue