summaryrefslogtreecommitdiff
path: root/pkg/domain/infra/abi/archive.go
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2021-03-02 09:20:53 +0100
committerValentin Rothberg <rothberg@redhat.com>2021-03-04 15:43:12 +0100
commita090301bbb10424ce4f99e40c97959f0e8664718 (patch)
tree3b2596e3d152204d35162b1ca89f524c5803ad8c /pkg/domain/infra/abi/archive.go
parent833670079c5b1f95fbb7c9bb8ba9095f1c66c7b4 (diff)
downloadpodman-a090301bbb10424ce4f99e40c97959f0e8664718.tar.gz
podman-a090301bbb10424ce4f99e40c97959f0e8664718.tar.bz2
podman-a090301bbb10424ce4f99e40c97959f0e8664718.zip
podman cp: support copying on tmpfs mounts
Traditionally, the path resolution for containers has been resolved on the *host*; relative to the container's mount point or relative to specified bind mounts or volumes. While this works nicely for non-running containers, it poses a problem for running ones. In that case, certain kinds of mounts (e.g., tmpfs) will not resolve correctly. A tmpfs is held in memory and hence cannot be resolved relatively to the container's mount point. A copy operation will succeed but the data will not show up inside the container. To support these kinds of mounts, we need to join the *running* container's mount namespace (and PID namespace) when copying. Note that this change implies moving the copy and stat logic into `libpod` since we need to keep the container locked to avoid race conditions. The immediate benefit is that all logic is now inside `libpod`; the code isn't scattered anymore. Further note that Docker does not support copying to tmpfs mounts. Tests have been extended to cover *both* path resolutions for running and created containers. New tests have been added to exercise the tmpfs-mount case. For the record: Some tests could be improved by using `start -a` instead of a start-exec sequence. Unfortunately, `start -a` is flaky in the CI which forced me to use the more expensive start-exec option. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'pkg/domain/infra/abi/archive.go')
-rw-r--r--pkg/domain/infra/abi/archive.go163
1 files changed, 2 insertions, 161 deletions
diff --git a/pkg/domain/infra/abi/archive.go b/pkg/domain/infra/abi/archive.go
index 528771ee7..2ea63aa5e 100644
--- a/pkg/domain/infra/abi/archive.go
+++ b/pkg/domain/infra/abi/archive.go
@@ -3,72 +3,16 @@ package abi
import (
"context"
"io"
- "path/filepath"
- "strings"
- buildahCopiah "github.com/containers/buildah/copier"
- "github.com/containers/buildah/pkg/chrootuser"
- "github.com/containers/buildah/util"
- "github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/containers/storage"
- "github.com/containers/storage/pkg/archive"
- "github.com/containers/storage/pkg/idtools"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
-// NOTE: Only the parent directory of the container path must exist. The path
-// itself may be created while copying.
func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrID string, containerPath string, reader io.Reader) (entities.ContainerCopyFunc, error) {
container, err := ic.Libpod.LookupContainer(nameOrID)
if err != nil {
return nil, err
}
-
- containerMountPoint, err := container.Mount()
- if err != nil {
- return nil, err
- }
-
- unmount := func() {
- if err := container.Unmount(false); err != nil {
- logrus.Errorf("Error unmounting container: %v", err)
- }
- }
-
- _, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerMountPoint, containerPath)
- if err != nil {
- unmount()
- return nil, err
- }
-
- decompressed, err := archive.DecompressStream(reader)
- if err != nil {
- unmount()
- return nil, err
- }
-
- idMappings, idPair, err := getIDMappingsAndPair(container, resolvedRoot)
- if err != nil {
- unmount()
- return nil, err
- }
-
- logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", containerPath, resolvedContainerPath, container.Name(), container.ID())
-
- return func() error {
- defer unmount()
- defer decompressed.Close()
- putOptions := buildahCopiah.PutOptions{
- UIDMap: idMappings.UIDMap,
- GIDMap: idMappings.GIDMap,
- ChownDirs: idPair,
- ChownFiles: idPair,
- }
- return buildahCopiah.Put(resolvedRoot, resolvedContainerPath, putOptions, decompressed)
- }, nil
+ return container.CopyFromArchive(ctx, containerPath, reader)
}
func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, containerPath string, writer io.Writer) (entities.ContainerCopyFunc, error) {
@@ -76,108 +20,5 @@ func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID
if err != nil {
return nil, err
}
-
- containerMountPoint, err := container.Mount()
- if err != nil {
- return nil, err
- }
-
- unmount := func() {
- if err := container.Unmount(false); err != nil {
- logrus.Errorf("Error unmounting container: %v", err)
- }
- }
-
- // Make sure that "/" copies the *contents* of the mount point and not
- // the directory.
- if containerPath == "/" {
- containerPath = "/."
- }
-
- statInfo, resolvedRoot, resolvedContainerPath, err := ic.containerStat(container, containerMountPoint, containerPath)
- if err != nil {
- unmount()
- return nil, err
- }
-
- idMappings, idPair, err := getIDMappingsAndPair(container, resolvedRoot)
- if err != nil {
- unmount()
- return nil, err
- }
-
- logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", containerPath, resolvedContainerPath, container.Name(), container.ID())
-
- return func() error {
- defer container.Unmount(false)
- getOptions := buildahCopiah.GetOptions{
- // Unless the specified points to ".", we want to copy the base directory.
- KeepDirectoryNames: statInfo.IsDir && filepath.Base(containerPath) != ".",
- UIDMap: idMappings.UIDMap,
- GIDMap: idMappings.GIDMap,
- ChownDirs: idPair,
- ChownFiles: idPair,
- }
- return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedContainerPath}, writer)
- }, nil
-}
-
-// getIDMappingsAndPair returns the ID mappings for the container and the host
-// ID pair.
-func getIDMappingsAndPair(container *libpod.Container, containerMount string) (*storage.IDMappingOptions, *idtools.IDPair, error) {
- user, err := getContainerUser(container, containerMount)
- if err != nil {
- return nil, nil, err
- }
-
- idMappingOpts, err := container.IDMappings()
- if err != nil {
- return nil, nil, err
- }
-
- hostUID, hostGID, err := util.GetHostIDs(idtoolsToRuntimeSpec(idMappingOpts.UIDMap), idtoolsToRuntimeSpec(idMappingOpts.GIDMap), user.UID, user.GID)
- if err != nil {
- return nil, nil, err
- }
-
- idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
- return &idMappingOpts, &idPair, nil
-}
-
-// getContainerUser returns the specs.User of the container.
-func getContainerUser(container *libpod.Container, mountPoint string) (specs.User, error) {
- userspec := container.Config().User
-
- uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
- u := specs.User{
- UID: uid,
- GID: gid,
- Username: userspec,
- }
-
- if !strings.Contains(userspec, ":") {
- groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
- if err2 != nil {
- if errors.Cause(err2) != chrootuser.ErrNoSuchUser && err == nil {
- err = err2
- }
- } else {
- u.AdditionalGids = groups
- }
- }
-
- return u, err
-}
-
-// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec.
-func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
- for _, idmap := range idMaps {
- tempIDMap := specs.LinuxIDMapping{
- ContainerID: uint32(idmap.ContainerID),
- HostID: uint32(idmap.HostID),
- Size: uint32(idmap.Size),
- }
- convertedIDMap = append(convertedIDMap, tempIDMap)
- }
- return convertedIDMap
+ return container.CopyToArchive(ctx, containerPath, writer)
}