summaryrefslogtreecommitdiff
path: root/pkg/api/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/handlers')
-rw-r--r--pkg/api/handlers/compat/containers_archive.go319
-rw-r--r--pkg/api/handlers/compat/networks.go9
-rw-r--r--pkg/api/handlers/compat/volumes.go4
-rw-r--r--pkg/api/handlers/types.go57
4 files changed, 86 insertions, 303 deletions
diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go
index 1dd563393..223eb2cd5 100644
--- a/pkg/api/handlers/compat/containers_archive.go
+++ b/pkg/api/handlers/compat/containers_archive.go
@@ -5,24 +5,16 @@ 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"
- "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"
-
"net/http"
"os"
"time"
+ "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/podman/v2/pkg/copy"
"github.com/gorilla/schema"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
func Archive(w http.ResponseWriter, r *http.Request) {
@@ -32,14 +24,14 @@ func Archive(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPut:
handlePut(w, r, decoder, runtime)
- case http.MethodGet, http.MethodHead:
- handleHeadOrGet(w, r, decoder, runtime)
+ case http.MethodHead, http.MethodGet:
+ handleHeadAndGet(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)))
+ utils.Error(w, fmt.Sprintf("unsupported method: %v", r.Method), http.StatusNotImplemented, errors.New(fmt.Sprintf("unsupported method: %v", r.Method)))
}
}
-func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) {
+func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) {
query := struct {
Path string `schema:"path"`
}{}
@@ -66,170 +58,62 @@ func handleHeadOrGet(w http.ResponseWriter, r *http.Request, decoder *schema.Dec
return
}
- mountPoint, err := ctr.Mount()
+ source, err := copy.CopyItemForContainer(ctr, query.Path, true, true)
+ defer source.CleanUp()
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to mount the container"))
+ utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
return
}
- defer func() {
- if err := ctr.Unmount(false); err != nil {
- logrus.Warnf("failed to unmount container %s: %q", containerName, err)
- }
- }()
-
- opts := copier.StatOptions{}
-
- mountPoint, path, err := fixUpMountPointAndPath(runtime, ctr, mountPoint, query.Path)
+ // NOTE: Docker always sets the header.
+ info, err := source.Stat()
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
+ utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
return
}
-
- stats, err := copier.Stat(mountPoint, "", opts, []string{filepath.Join(mountPoint, path)})
+ statHeader, err := fileInfoToDockerStats(info)
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)
+ 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 {
+ // Our work is done when the user is interested in the header only.
+ if r.Method == http.MethodHead {
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(false); 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)
+ // Alright, the users wants data from the container.
+ destination, err := copy.CopyItemForWriter(w)
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))
+ if err := copy.Copy(&source, &destination, false); err != nil {
+ utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
}
-func statsToHeader(stats *copier.StatForItem) (string, error) {
- statsDTO := struct {
+func fileInfoToDockerStats(info *copy.FileInfo) (string, error) {
+ dockerStats := 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,
+ Name: info.Name,
+ Size: info.Size,
+ Mode: info.Mode,
+ ModTime: info.ModTime,
+ LinkTarget: info.LinkTarget,
}
- jsonBytes, err := json.Marshal(&statsDTO)
+ jsonBytes, err := json.Marshal(&dockerStats)
if err != nil {
return "", errors.Wrap(err, "failed to serialize file stats")
}
@@ -250,130 +134,45 @@ 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{
- 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 := pathWithBindMountSource(mount, ctrPath)
- 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 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"`
+ }{}
-func pathWithVolumeMount(runtime *libpod.Runtime, volDestName, volName, path string) (string, string, error) {
- destVolume, err := runtime.GetVolume(volName)
+ err := decoder.Decode(&query, r.URL.Query())
if err != nil {
- return "", "", errors.Wrapf(err, "error getting volume destination %s", volName)
- }
-
- if !filepath.IsAbs(path) {
- path = filepath.Join(string(os.PathSeparator), path)
+ utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query"))
+ return
}
- 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))
- }
+ ctrName := utils.GetName(r)
- if path == "" {
- return false, specs.Mount{}
+ 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
}
- 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
- }
+ destination, err := copy.CopyItemForContainer(ctr, query.Path, true, false)
+ defer destination.CleanUp()
+ if err != nil {
+ utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ return
}
- 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))]
+ source, err := copy.CopyItemForReader(r.Body)
+ defer source.CleanUp()
+ if err != nil {
+ utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ return
}
- return pathStr == target
-}
-
-func pathWithBindMountSource(m specs.Mount, path string) (string, string) {
- if !filepath.IsAbs(path) {
- path = filepath.Join(string(os.PathSeparator), path)
+ w.WriteHeader(http.StatusOK)
+ if err := copy.Copy(&source, &destination, false); err != nil {
+ utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ return
}
-
- return m.Source, strings.TrimPrefix(path, m.Destination)
}
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index b4f3aa2f1..fe13971b0 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -271,11 +271,16 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
return
}
+ net, err := getNetworkResourceByNameOrID(name, runtime, nil)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
body := struct {
Id string
Warning []string
}{
- Id: name,
+ Id: net.ID,
}
utils.WriteResponse(w, http.StatusCreated, body)
}
@@ -320,7 +325,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
return
}
- utils.WriteResponse(w, http.StatusNoContent, "")
+ utils.WriteResponse(w, http.StatusNoContent, nil)
}
// Connect adds a container to a network
diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go
index a3c9fbd2f..71b848932 100644
--- a/pkg/api/handlers/compat/volumes.go
+++ b/pkg/api/handlers/compat/volumes.go
@@ -223,7 +223,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
}
} else {
// Success
- utils.WriteResponse(w, http.StatusNoContent, "")
+ utils.WriteResponse(w, http.StatusNoContent, nil)
}
} else {
if !query.Force {
@@ -232,7 +232,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) {
// Volume does not exist and `force` is truthy - this emulates what
// Docker would do when told to `force` removal of a nonextant
// volume
- utils.WriteResponse(w, http.StatusNoContent, "")
+ utils.WriteResponse(w, http.StatusNoContent, nil)
}
}
}
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 25e7640b6..c9adde09d 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -178,55 +178,34 @@ type ExecStartConfig struct {
}
func ImageToImageSummary(l *libpodImage.Image) (*entities.ImageSummary, error) {
- containers, err := l.Containers()
- if err != nil {
- return nil, errors.Wrapf(err, "failed to obtain Containers for image %s", l.ID())
- }
- containerCount := len(containers)
-
- // FIXME: GetParent() panics
- // parent, err := l.GetParent(context.TODO())
- // if err != nil {
- // return nil, errors.Wrapf(err, "failed to obtain ParentID for image %s", l.ID())
- // }
-
- labels, err := l.Labels(context.TODO())
+ imageData, err := l.Inspect(context.TODO())
if err != nil {
- return nil, errors.Wrapf(err, "failed to obtain Labels for image %s", l.ID())
+ return nil, errors.Wrapf(err, "failed to obtain summary for image %s", l.ID())
}
- size, err := l.Size(context.TODO())
- if err != nil {
- return nil, errors.Wrapf(err, "failed to obtain Size for image %s", l.ID())
- }
-
- repoTags, err := l.RepoTags()
+ containers, err := l.Containers()
if err != nil {
- return nil, errors.Wrapf(err, "failed to obtain RepoTags for image %s", l.ID())
- }
-
- digests := make([]string, len(l.Digests()))
- for i, d := range l.Digests() {
- digests[i] = string(d)
+ return nil, errors.Wrapf(err, "failed to obtain Containers for image %s", l.ID())
}
+ containerCount := len(containers)
is := entities.ImageSummary{
ID: l.ID(),
- ParentId: l.Parent,
- RepoTags: repoTags,
- RepoDigests: digests,
+ ParentId: imageData.Parent,
+ RepoTags: imageData.RepoTags,
+ RepoDigests: imageData.RepoDigests,
Created: l.Created().Unix(),
- Size: int64(*size),
+ Size: imageData.Size,
SharedSize: 0,
- VirtualSize: l.VirtualSize,
- Labels: labels,
+ VirtualSize: imageData.VirtualSize,
+ Labels: imageData.Labels,
Containers: containerCount,
ReadOnly: l.IsReadOnly(),
Dangling: l.Dangling(),
Names: l.Names(),
- Digest: string(l.Digest()),
+ Digest: string(imageData.Digest),
ConfigDigest: string(l.ConfigDigest),
- History: l.NamesHistory(),
+ History: imageData.NamesHistory,
}
return &is, nil
}
@@ -283,8 +262,8 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
}
}
dockerImageInspect := docker.ImageInspect{
- Architecture: l.Architecture,
- Author: l.Author,
+ Architecture: info.Architecture,
+ Author: info.Author,
Comment: info.Comment,
Config: &config,
Created: l.Created().Format(time.RFC3339Nano),
@@ -292,9 +271,9 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
GraphDriver: docker.GraphDriverData{},
ID: fmt.Sprintf("sha256:%s", l.ID()),
Metadata: docker.ImageMetadata{},
- Os: l.Os,
- OsVersion: l.Version,
- Parent: l.Parent,
+ Os: info.Os,
+ OsVersion: info.Version,
+ Parent: info.Parent,
RepoDigests: info.RepoDigests,
RepoTags: info.RepoTags,
RootFS: rootfs,