From 4e2d18db903e19c6cb56d75da0f69e42abe64c47 Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Wed, 4 Nov 2020 20:18:02 +0100 Subject: Implement containers/{id or name}/archive Signed-off-by: Matej Vasek --- pkg/api/handlers/compat/containers_archive.go | 341 +++++++++++++++++++++++++- 1 file changed, 337 insertions(+), 4 deletions(-) (limited to 'pkg/api/handlers/compat') diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 293a17e0f..f42a821cd 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -1,12 +1,345 @@ package compat import ( - "errors" - "net/http" - + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "github.com/containers/buildah/copier" + "github.com/containers/buildah/pkg/chrootuser" + "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers/utils" + "github.com/containers/storage/pkg/idtools" + "github.com/opencontainers/runtime-spec/specs-go" + "path/filepath" + "strings" + + "github.com/gorilla/schema" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "net/http" + "os" + "time" ) func Archive(w http.ResponseWriter, r *http.Request) { - utils.Error(w, "not implemented", http.StatusNotImplemented, errors.New("not implemented")) + decoder := r.Context().Value("decoder").(*schema.Decoder) + runtime := r.Context().Value("runtime").(*libpod.Runtime) + + switch r.Method { + case http.MethodPut: + handlePut(w, r, decoder, runtime) + case http.MethodGet, http.MethodHead: + handleHeadOrGet(w, r, decoder, runtime) + default: + utils.Error(w, fmt.Sprintf("not implemented, method: %v", r.Method), http.StatusNotImplemented, errors.New(fmt.Sprintf("not implemented, method: %v", r.Method))) + } +} + +func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) { + query := struct { + Path string `schema:"path"` + }{} + + err := decoder.Decode(&query, r.URL.Query()) + if err != nil { + utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query")) + return + } + if query.Path == "" { + utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.New("missing `path` parameter")) + return + } + + containerName := utils.GetName(r) + + ctr, err := runtime.LookupContainer(containerName) + if errors.Cause(err) == define.ErrNoSuchCtr { + utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrap(err, "the container doesn't exists")) + return + } else if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + mountPoint, err := ctr.Mount() + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to mount the container")) + return + } + defer func() { + if err := ctr.Unmount(true); err != nil { + logrus.Warnf("failed to unmount container %s: %q", containerName, err) + } + }() + + opts := copier.StatOptions{} + + mountPoint, path, err := fixUpMountPointAndPath(runtime, ctr, mountPoint, query.Path) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + + stats, err := copier.Stat(mountPoint, "", opts, []string{filepath.Join(mountPoint, path)}) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to get stats about file")) + return + } + if len(stats) <= 0 || len(stats[0].Globbed) <= 0 { + errs := make([]string, 0, len(stats)) + for _, stat := range stats { + if stat.Error != "" { + errs = append(errs, stat.Error) + } + } + utils.Error(w, "Not found.", http.StatusNotFound, fmt.Errorf("file doesn't exist (errs: %q)", strings.Join(errs, ";"))) + return + } + + statHeader, err := statsToHeader(stats[0].Results[stats[0].Globbed[0]]) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) + return + } + + w.Header().Add("X-Docker-Container-Path-Stat", statHeader) + + if r.Method == http.MethodGet { + idMappingOpts, err := ctr.IDMappings() + if err != nil { + utils.Error(w, "Not found.", http.StatusInternalServerError, + errors.Wrapf(err, "error getting IDMappingOptions")) + return + } + destOwner := idtools.IDPair{UID: os.Getuid(), GID: os.Getgid()} + + opts := copier.GetOptions{ + UIDMap: idMappingOpts.UIDMap, + GIDMap: idMappingOpts.GIDMap, + ChownDirs: &destOwner, + ChownFiles: &destOwner, + KeepDirectoryNames: true, + } + + w.WriteHeader(http.StatusOK) + err = copier.Get(mountPoint, "", opts, []string{filepath.Join(mountPoint, path)}, w) + if err != nil { + logrus.Error(errors.Wrapf(err, "failed to copy from the %s container path %s", containerName, query.Path)) + return + } + } else { + w.WriteHeader(http.StatusOK) + } + +} + +func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) { + query := struct { + Path string `schema:"path"` + // TODO handle params below + NoOverwriteDirNonDir bool `schema:"noOverwriteDirNonDir"` + CopyUIDGID bool `schema:"copyUIDGID"` + }{} + + err := decoder.Decode(&query, r.URL.Query()) + if err != nil { + utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query")) + return + } + + ctrName := utils.GetName(r) + + ctr, err := runtime.LookupContainer(ctrName) + if err != nil { + utils.Error(w, "Not found", http.StatusNotFound, errors.Wrapf(err, "the %s container doesn't exists", ctrName)) + return + } + mountPoint, err := ctr.Mount() + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, errors.Wrapf(err, "failed to mount the %s container", ctrName)) + return + } + defer func() { + if err := ctr.Unmount(true); err != nil { + logrus.Warnf("failed to unmount container %s", ctrName) + } + }() + + user, err := getUser(mountPoint, ctr.User()) + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) + return + } + idMappingOpts, err := ctr.IDMappings() + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, errors.Wrapf(err, "error getting IDMappingOptions")) + return + } + destOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)} + + opts := copier.PutOptions{ + UIDMap: idMappingOpts.UIDMap, + GIDMap: idMappingOpts.GIDMap, + ChownDirs: &destOwner, + ChownFiles: &destOwner, + } + + mountPoint, path, err := fixUpMountPointAndPath(runtime, ctr, mountPoint, query.Path) + if err != nil { + utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) + return + } + + w.WriteHeader(http.StatusOK) + err = copier.Put(mountPoint, filepath.Join(mountPoint, path), opts, r.Body) + if err != nil { + logrus.Error(errors.Wrapf(err, "failed to copy to the %s container path %s", ctrName, query.Path)) + return + } +} + +func statsToHeader(stats *copier.StatForItem) (string, error) { + statsDTO := struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mode os.FileMode `json:"mode"` + ModTime time.Time `json:"mtime"` + LinkTarget string `json:"linkTarget"` + }{ + Name: filepath.Base(stats.Name), + Size: stats.Size, + Mode: stats.Mode, + ModTime: stats.ModTime, + LinkTarget: stats.ImmediateTarget, + } + + jsonBytes, err := json.Marshal(&statsDTO) + if err != nil { + return "", errors.Wrap(err, "failed to serialize file stats") + } + + buff := bytes.NewBuffer(make([]byte, 0, 128)) + base64encoder := base64.NewEncoder(base64.StdEncoding, buff) + _, err = base64encoder.Write(jsonBytes) + if err != nil { + return "", err + } + err = base64encoder.Close() + if err != nil { + return "", err + } + + return buff.String(), nil +} + +func getUser(mountPoint string, userspec string) (specs.User, error) { + 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 +} + +func fixUpMountPointAndPath(runtime *libpod.Runtime, ctr *libpod.Container, mountPoint, ctrPath string) (string, string, error) { + if !filepath.IsAbs(ctrPath) { + endsWithSep := strings.HasSuffix(ctrPath, string(filepath.Separator)) + ctrPath = filepath.Join(ctr.WorkingDir(), ctrPath) + if endsWithSep { + ctrPath = ctrPath + string(filepath.Separator) + } + } + if isVol, volDestName, volName := isVolumeDestName(ctrPath, ctr); isVol { //nolint(gocritic) + newMountPoint, path, err := pathWithVolumeMount(runtime, volDestName, volName, ctrPath) + if err != nil { + return "", "", errors.Wrapf(err, "error getting source path from volume %s", volDestName) + } + mountPoint = newMountPoint + ctrPath = path + } else if isBindMount, mount := isBindMountDestName(ctrPath, ctr); isBindMount { //nolint(gocritic) + newMountPoint, path, err := pathWithBindMountSource(mount, ctrPath) + if err != nil { + return "", "", errors.Wrapf(err, "error getting source path from bind mount %s", mount.Destination) + } + mountPoint = newMountPoint + ctrPath = path + } + return mountPoint, ctrPath, nil +} + +func isVolumeDestName(path string, ctr *libpod.Container) (bool, string, string) { + separator := string(os.PathSeparator) + if filepath.IsAbs(path) { + path = strings.TrimPrefix(path, separator) + } + if path == "" { + return false, "", "" + } + for _, vol := range ctr.Config().NamedVolumes { + volNamePath := strings.TrimPrefix(vol.Dest, separator) + if matchVolumePath(path, volNamePath) { + return true, vol.Dest, vol.Name + } + } + return false, "", "" +} + +func pathWithVolumeMount(runtime *libpod.Runtime, volDestName, volName, path string) (string, string, error) { + destVolume, err := runtime.GetVolume(volName) + if err != nil { + return "", "", errors.Wrapf(err, "error getting volume destination %s", volName) + } + if !filepath.IsAbs(path) { + path = filepath.Join(string(os.PathSeparator), path) + } + return destVolume.MountPoint(), strings.TrimPrefix(path, volDestName), err +} + +func isBindMountDestName(path string, ctr *libpod.Container) (bool, specs.Mount) { + separator := string(os.PathSeparator) + if filepath.IsAbs(path) { + path = strings.TrimPrefix(path, string(os.PathSeparator)) + } + if path == "" { + return false, specs.Mount{} + } + for _, m := range ctr.Config().Spec.Mounts { + if m.Type != "bind" { + continue + } + mDest := strings.TrimPrefix(m.Destination, separator) + if matchVolumePath(path, mDest) { + return true, m + } + } + return false, specs.Mount{} +} + +func matchVolumePath(path, target string) bool { + pathStr := filepath.Clean(path) + target = filepath.Clean(target) + for len(pathStr) > len(target) && strings.Contains(pathStr, string(os.PathSeparator)) { + pathStr = pathStr[:strings.LastIndex(pathStr, string(os.PathSeparator))] + } + return pathStr == target +} + +func pathWithBindMountSource(m specs.Mount, path string) (string, string, error) { + if !filepath.IsAbs(path) { + path = filepath.Join(string(os.PathSeparator), path) + } + return m.Source, strings.TrimPrefix(path, m.Destination), nil } -- cgit v1.2.3-54-g00ecf From 430729a391824774dcf11d93e7211c5785eb17c0 Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Wed, 4 Nov 2020 22:03:53 +0100 Subject: fix lint Signed-off-by: Matej Vasek --- pkg/api/handlers/compat/containers_archive.go | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'pkg/api/handlers/compat') diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index f42a821cd..870e681de 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -5,6 +5,9 @@ import ( "encoding/base64" "encoding/json" "fmt" + "path/filepath" + "strings" + "github.com/containers/buildah/copier" "github.com/containers/buildah/pkg/chrootuser" "github.com/containers/podman/v2/libpod" @@ -12,15 +15,14 @@ import ( "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/storage/pkg/idtools" "github.com/opencontainers/runtime-spec/specs-go" - "path/filepath" - "strings" - "github.com/gorilla/schema" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" "net/http" "os" "time" + + "github.com/gorilla/schema" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) func Archive(w http.ResponseWriter, r *http.Request) { @@ -131,7 +133,6 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec } else { w.WriteHeader(http.StatusOK) } - } func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) { @@ -249,7 +250,6 @@ func getUser(mountPoint string, userspec string) (specs.User, error) { } else { u.AdditionalGids = groups } - } return u, err } @@ -270,10 +270,7 @@ func fixUpMountPointAndPath(runtime *libpod.Runtime, ctr *libpod.Container, moun mountPoint = newMountPoint ctrPath = path } else if isBindMount, mount := isBindMountDestName(ctrPath, ctr); isBindMount { //nolint(gocritic) - newMountPoint, path, err := pathWithBindMountSource(mount, ctrPath) - if err != nil { - return "", "", errors.Wrapf(err, "error getting source path from bind mount %s", mount.Destination) - } + newMountPoint, path := pathWithBindMountSource(mount, ctrPath) mountPoint = newMountPoint ctrPath = path } @@ -337,9 +334,9 @@ func matchVolumePath(path, target string) bool { return pathStr == target } -func pathWithBindMountSource(m specs.Mount, path string) (string, string, error) { +func pathWithBindMountSource(m specs.Mount, path string) (string, string) { if !filepath.IsAbs(path) { path = filepath.Join(string(os.PathSeparator), path) } - return m.Source, strings.TrimPrefix(path, m.Destination), nil + return m.Source, strings.TrimPrefix(path, m.Destination) } -- cgit v1.2.3-54-g00ecf From 7da4083549eb73d2b45b04db08a38db478ab2c11 Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Wed, 4 Nov 2020 22:24:04 +0100 Subject: style: wsl Signed-off-by: Matej Vasek --- pkg/api/handlers/compat/containers_archive.go | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'pkg/api/handlers/compat') diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 870e681de..1d57cb59a 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -49,6 +49,7 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query")) return } + if query.Path == "" { utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.New("missing `path` parameter")) return @@ -64,11 +65,13 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) return } + mountPoint, err := ctr.Mount() if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to mount the container")) return } + defer func() { if err := ctr.Unmount(true); err != nil { logrus.Warnf("failed to unmount container %s: %q", containerName, err) @@ -88,14 +91,18 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to get stats about file")) return } + if len(stats) <= 0 || len(stats[0].Globbed) <= 0 { errs := make([]string, 0, len(stats)) + for _, stat := range stats { if stat.Error != "" { errs = append(errs, stat.Error) } } + utils.Error(w, "Not found.", http.StatusNotFound, fmt.Errorf("file doesn't exist (errs: %q)", strings.Join(errs, ";"))) + return } @@ -114,6 +121,7 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec errors.Wrapf(err, "error getting IDMappingOptions")) return } + destOwner := idtools.IDPair{UID: os.Getuid(), GID: os.Getgid()} opts := copier.GetOptions{ @@ -125,6 +133,7 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec } w.WriteHeader(http.StatusOK) + err = copier.Get(mountPoint, "", opts, []string{filepath.Join(mountPoint, path)}, w) if err != nil { logrus.Error(errors.Wrapf(err, "failed to copy from the %s container path %s", containerName, query.Path)) @@ -156,11 +165,13 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, utils.Error(w, "Not found", http.StatusNotFound, errors.Wrapf(err, "the %s container doesn't exists", ctrName)) return } + mountPoint, err := ctr.Mount() if err != nil { utils.Error(w, "Something went wrong", http.StatusInternalServerError, errors.Wrapf(err, "failed to mount the %s container", ctrName)) return } + defer func() { if err := ctr.Unmount(true); err != nil { logrus.Warnf("failed to unmount container %s", ctrName) @@ -172,11 +183,13 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) return } + idMappingOpts, err := ctr.IDMappings() if err != nil { utils.Error(w, "Something went wrong", http.StatusInternalServerError, errors.Wrapf(err, "error getting IDMappingOptions")) return } + destOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)} opts := copier.PutOptions{ @@ -193,6 +206,7 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, } w.WriteHeader(http.StatusOK) + err = copier.Put(mountPoint, filepath.Join(mountPoint, path), opts, r.Body) if err != nil { logrus.Error(errors.Wrapf(err, "failed to copy to the %s container path %s", ctrName, query.Path)) @@ -222,10 +236,12 @@ func statsToHeader(stats *copier.StatForItem) (string, error) { buff := bytes.NewBuffer(make([]byte, 0, 128)) base64encoder := base64.NewEncoder(base64.StdEncoding, buff) + _, err = base64encoder.Write(jsonBytes) if err != nil { return "", err } + err = base64encoder.Close() if err != nil { return "", err @@ -241,6 +257,7 @@ func getUser(mountPoint string, userspec string) (specs.User, error) { GID: gid, Username: userspec, } + if !strings.Contains(userspec, ":") { groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID)) if err2 != nil { @@ -251,6 +268,7 @@ func getUser(mountPoint string, userspec string) (specs.User, error) { u.AdditionalGids = groups } } + return u, err } @@ -258,6 +276,7 @@ func fixUpMountPointAndPath(runtime *libpod.Runtime, ctr *libpod.Container, moun if !filepath.IsAbs(ctrPath) { endsWithSep := strings.HasSuffix(ctrPath, string(filepath.Separator)) ctrPath = filepath.Join(ctr.WorkingDir(), ctrPath) + if endsWithSep { ctrPath = ctrPath + string(filepath.Separator) } @@ -267,6 +286,7 @@ func fixUpMountPointAndPath(runtime *libpod.Runtime, ctr *libpod.Container, moun if err != nil { return "", "", errors.Wrapf(err, "error getting source path from volume %s", volDestName) } + mountPoint = newMountPoint ctrPath = path } else if isBindMount, mount := isBindMountDestName(ctrPath, ctr); isBindMount { //nolint(gocritic) @@ -274,23 +294,28 @@ func fixUpMountPointAndPath(runtime *libpod.Runtime, ctr *libpod.Container, moun mountPoint = newMountPoint ctrPath = path } + return mountPoint, ctrPath, nil } func isVolumeDestName(path string, ctr *libpod.Container) (bool, string, string) { separator := string(os.PathSeparator) + if filepath.IsAbs(path) { path = strings.TrimPrefix(path, separator) } + if path == "" { return false, "", "" } + for _, vol := range ctr.Config().NamedVolumes { volNamePath := strings.TrimPrefix(vol.Dest, separator) if matchVolumePath(path, volNamePath) { return true, vol.Dest, vol.Name } } + return false, "", "" } @@ -299,38 +324,47 @@ func pathWithVolumeMount(runtime *libpod.Runtime, volDestName, volName, path str if err != nil { return "", "", errors.Wrapf(err, "error getting volume destination %s", volName) } + if !filepath.IsAbs(path) { path = filepath.Join(string(os.PathSeparator), path) } + return destVolume.MountPoint(), strings.TrimPrefix(path, volDestName), err } func isBindMountDestName(path string, ctr *libpod.Container) (bool, specs.Mount) { separator := string(os.PathSeparator) + if filepath.IsAbs(path) { path = strings.TrimPrefix(path, string(os.PathSeparator)) } + if path == "" { return false, specs.Mount{} } + for _, m := range ctr.Config().Spec.Mounts { if m.Type != "bind" { continue } + mDest := strings.TrimPrefix(m.Destination, separator) if matchVolumePath(path, mDest) { return true, m } } + return false, specs.Mount{} } func matchVolumePath(path, target string) bool { pathStr := filepath.Clean(path) target = filepath.Clean(target) + for len(pathStr) > len(target) && strings.Contains(pathStr, string(os.PathSeparator)) { pathStr = pathStr[:strings.LastIndex(pathStr, string(os.PathSeparator))] } + return pathStr == target } @@ -338,5 +372,6 @@ func pathWithBindMountSource(m specs.Mount, path string) (string, string) { if !filepath.IsAbs(path) { path = filepath.Join(string(os.PathSeparator), path) } + return m.Source, strings.TrimPrefix(path, m.Destination) } -- cgit v1.2.3-54-g00ecf From 6ad2f1d2482ff156257c74a2b4bcd75d5b12d95d Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Thu, 19 Nov 2020 00:40:11 +0100 Subject: fix: unmount container without force Signed-off-by: Matej Vasek --- pkg/api/handlers/compat/containers_archive.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pkg/api/handlers/compat') diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 1d57cb59a..337b1787c 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -73,7 +73,7 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec } defer func() { - if err := ctr.Unmount(true); err != nil { + if err := ctr.Unmount(false); err != nil { logrus.Warnf("failed to unmount container %s: %q", containerName, err) } }() -- cgit v1.2.3-54-g00ecf From be7e9f63f241c826e3a5772da355a3d66d254c6c Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Thu, 19 Nov 2020 00:52:27 +0100 Subject: add comment Signed-off-by: Matej Vasek --- pkg/api/handlers/compat/containers_archive.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'pkg/api/handlers/compat') diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 337b1787c..10f755a59 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -250,6 +250,8 @@ func statsToHeader(stats *copier.StatForItem) (string, error) { return buff.String(), nil } +// the utility functions below are copied from abi/cp.go + func getUser(mountPoint string, userspec string) (specs.User, error) { uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec) u := specs.User{ -- cgit v1.2.3-54-g00ecf From 4d0346c028589737591615a308f69736a9fa0534 Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Thu, 19 Nov 2020 19:27:00 +0100 Subject: not forcing unmount Signed-off-by: Matej Vasek --- pkg/api/handlers/compat/containers_archive.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pkg/api/handlers/compat') diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go index 10f755a59..1dd563393 100644 --- a/pkg/api/handlers/compat/containers_archive.go +++ b/pkg/api/handlers/compat/containers_archive.go @@ -173,7 +173,7 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, } defer func() { - if err := ctr.Unmount(true); err != nil { + if err := ctr.Unmount(false); err != nil { logrus.Warnf("failed to unmount container %s", ctrName) } }() -- cgit v1.2.3-54-g00ecf