summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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