summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel J Walsh <dwalsh@redhat.com>2020-10-29 13:28:01 -0400
committerDaniel J Walsh <dwalsh@redhat.com>2020-11-04 13:52:08 -0500
commit6ca705bf1af6fd516b14ab043dc922e55eeaf832 (patch)
tree02cee3832aa7aea4a40913bb9bcba28a0054174e
parentab273a9cbd08e25e3794c606a863644eb3a06e30 (diff)
downloadpodman-6ca705bf1af6fd516b14ab043dc922e55eeaf832.tar.gz
podman-6ca705bf1af6fd516b14ab043dc922e55eeaf832.tar.bz2
podman-6ca705bf1af6fd516b14ab043dc922e55eeaf832.zip
Add support for mounting external containers
Continue progress on use of external containers. This PR adds the ability to mount, umount and list the storage containers whether they are in libpod or not. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
-rw-r--r--docs/source/markdown/podman-mount.1.md6
-rw-r--r--docs/source/markdown/podman-unmount.1.md4
-rw-r--r--libpod/runtime_ctr.go50
-rw-r--r--pkg/domain/infra/abi/containers.go73
-rw-r--r--test/system/060-mount.bats31
5 files changed, 157 insertions, 7 deletions
diff --git a/docs/source/markdown/podman-mount.1.md b/docs/source/markdown/podman-mount.1.md
index 33c5aece8..a6ed3f10d 100644
--- a/docs/source/markdown/podman-mount.1.md
+++ b/docs/source/markdown/podman-mount.1.md
@@ -13,7 +13,9 @@ 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, Podman will list all of the
-currently mounted containers.
+currently mounted containers, including external containers. External containers are
+containers in container/storage by tools other then Podman. For example Buildah and
+CRI-O.
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.
@@ -26,7 +28,7 @@ returned.
**--all**, **-a**
-Mount all containers.
+Mount all podman containers. (External containers will not be mounted)
**--format**=*format*
diff --git a/docs/source/markdown/podman-unmount.1.md b/docs/source/markdown/podman-unmount.1.md
index 47c55cc0b..08d1286ab 100644
--- a/docs/source/markdown/podman-unmount.1.md
+++ b/docs/source/markdown/podman-unmount.1.md
@@ -22,6 +22,10 @@ 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.
+Note: Podman can be used to unmount Podman containers as well as external containers.
+External containers are containers created in container/storage by other tools like
+Buildah and CRI-O.
+
## OPTIONS
**--all**, **-a**
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index de73a9ff3..c84268889 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -918,6 +918,56 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
return prunedContainers, pruneErrors, nil
}
+// MountStorageContainer mounts the storage container's root filesystem
+func (r *Runtime) MountStorageContainer(id string) (string, error) {
+ if _, err := r.GetContainer(id); err == nil {
+ return "", errors.Wrapf(define.ErrCtrExists, "ctr %s is a libpod container", id)
+ }
+ container, err := r.store.Container(id)
+ if err != nil {
+ return "", err
+ }
+ mountPoint, err := r.store.Mount(container.ID, "")
+ if err != nil {
+ return "", errors.Wrapf(err, "error mounting storage for container %s", id)
+ }
+ return mountPoint, nil
+}
+
+// UnmountStorageContainer unmounts the storage container's root filesystem
+func (r *Runtime) UnmountStorageContainer(id string, force bool) (bool, error) {
+ if _, err := r.GetContainer(id); err == nil {
+ return false, errors.Wrapf(define.ErrCtrExists, "ctr %s is a libpod container", id)
+ }
+ container, err := r.store.Container(id)
+ if err != nil {
+ return false, err
+ }
+ return r.store.Unmount(container.ID, force)
+}
+
+// MountedStorageContainer returns whether a storage container is mounted
+// along with the mount path
+func (r *Runtime) IsStorageContainerMounted(id string) (bool, string, error) {
+ var path string
+ if _, err := r.GetContainer(id); err == nil {
+ return false, "", errors.Wrapf(define.ErrCtrExists, "ctr %s is a libpod container", id)
+ }
+
+ mountCnt, err := r.storageService.MountedContainerImage(id)
+ if err != nil {
+ return false, "", err
+ }
+ mounted := mountCnt > 0
+ if mounted {
+ path, err = r.storageService.GetMountpoint(id)
+ if err != nil {
+ return false, "", err
+ }
+ }
+ return mounted, path, nil
+}
+
// StorageContainers returns a list of containers from containers/storage that
// are not currently known to Podman.
func (r *Runtime) StorageContainers() ([]storage.Container, error) {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 98b886845..855f9ece8 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1058,11 +1058,23 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
os.Exit(ret)
}
}
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
+ reports := []*entities.ContainerMountReport{}
+ // Attempt to mount named containers directly from storage,
+ // this will fail and code will fall through to removing the container from libpod.`
+ names := []string{}
+ for _, ctr := range nameOrIDs {
+ report := entities.ContainerMountReport{Id: ctr}
+ if report.Path, report.Err = ic.Libpod.MountStorageContainer(ctr); report.Err != nil {
+ names = append(names, ctr)
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil {
return nil, err
}
- reports := make([]*entities.ContainerMountReport, 0, len(ctrs))
for _, ctr := range ctrs {
report := entities.ContainerMountReport{Id: ctr.ID()}
report.Path, report.Err = ctr.Mount()
@@ -1072,6 +1084,30 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
return reports, nil
}
+ storageCtrs, err := ic.Libpod.StorageContainers()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, sctr := range storageCtrs {
+ mounted, path, err := ic.Libpod.IsStorageContainerMounted(sctr.ID)
+ if err != nil {
+ return nil, err
+ }
+
+ var name string
+ if len(sctr.Names) > 0 {
+ name = sctr.Names[0]
+ }
+ if mounted {
+ reports = append(reports, &entities.ContainerMountReport{
+ Id: sctr.ID,
+ Name: name,
+ Path: path,
+ })
+ }
+ }
+
// No containers were passed, so we send back what is mounted
ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
if err != nil {
@@ -1091,15 +1127,44 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
})
}
}
+
return reports, nil
}
func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
+ reports := []*entities.ContainerUnmountReport{}
+ names := []string{}
+ if options.All {
+ storageCtrs, err := ic.Libpod.StorageContainers()
+ if err != nil {
+ return nil, err
+ }
+ for _, sctr := range storageCtrs {
+ mounted, _, _ := ic.Libpod.IsStorageContainerMounted(sctr.ID)
+ if mounted {
+ report := entities.ContainerUnmountReport{Id: sctr.ID}
+ if _, report.Err = ic.Libpod.UnmountStorageContainer(sctr.ID, options.Force); report.Err != nil {
+ if errors.Cause(report.Err) != define.ErrCtrExists {
+ reports = append(reports, &report)
+ }
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+ }
+ }
+ for _, ctr := range nameOrIDs {
+ report := entities.ContainerUnmountReport{Id: ctr}
+ if _, report.Err = ic.Libpod.UnmountStorageContainer(ctr, options.Force); report.Err != nil {
+ names = append(names, ctr)
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil {
return nil, err
}
- reports := []*entities.ContainerUnmountReport{}
for _, ctr := range ctrs {
state, err := ctr.State()
if err != nil {
diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats
index 73d210084..f04f34bf6 100644
--- a/test/system/060-mount.bats
+++ b/test/system/060-mount.bats
@@ -2,7 +2,6 @@
load helpers
-
@test "podman mount - basic test" {
# Only works with root (FIXME: does it work with rootless + vfs?)
skip_if_rootless "mount does not work rootless"
@@ -151,4 +150,34 @@ load helpers
run_podman rm -f $cid
}
+@test "podman mount external container - basic test" {
+ # Only works with root (FIXME: does it work with rootless + vfs?)
+ skip_if_rootless "mount does not work rootless"
+ skip_if_remote "mounting remote is meaningless"
+
+ # Create a container that podman does not know about
+ external_cid=$(buildah from $IMAGE)
+
+ run_podman mount $external_cid
+ mount_path=$output
+
+ # Test image will always have this file, and will always have the tag
+ test -d $mount_path
+ is $(< "$mount_path/home/podman/testimage-id") "$PODMAN_TEST_IMAGE_TAG" \
+ "Contents of well-known file in image"
+
+ # Make sure that 'podman mount' (no args) returns the expected path
+ run_podman mount --notruncate
+
+ reported_mountpoint=$(echo "$output" | awk '{print $2}')
+ is $reported_mountpoint $mount_path "mountpoint reported by 'podman mount'"
+
+ # umount, and make sure files are gone
+ run_podman umount $external_cid
+ if [ -d "$mount_path" ]; then
+ die "'podman umount' did not umount"
+ fi
+ buildah rm $external_cid
+}
+
# vim: filetype=sh