summaryrefslogtreecommitdiff
path: root/pkg/api
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api')
-rw-r--r--pkg/api/handlers/compat/containers_create.go7
-rw-r--r--pkg/api/handlers/compat/images.go77
-rw-r--r--pkg/api/handlers/compat/images_build.go50
-rw-r--r--pkg/api/handlers/compat/images_history.go10
-rw-r--r--pkg/api/handlers/compat/images_push.go12
-rw-r--r--pkg/api/handlers/compat/images_remove.go8
-rw-r--r--pkg/api/handlers/compat/images_tag.go17
-rw-r--r--pkg/api/handlers/utils/images.go48
8 files changed, 182 insertions, 47 deletions
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index d5abb6e44..8837e08ca 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -52,6 +52,13 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
return
}
+ imageName, err := utils.NormalizeToDockerHub(r, body.Config.Image)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ body.Config.Image = imageName
+
newImage, resolvedName, err := runtime.LibimageRuntime().LookupImage(body.Config.Image, nil)
if err != nil {
if errors.Cause(err) == storage.ErrImageUnknown {
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 0b7ba8bee..af8b6b63d 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -12,7 +12,6 @@ import (
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/manifest"
- "github.com/containers/image/v5/pkg/shortnames"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/api/handlers"
@@ -56,6 +55,12 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
defer os.Remove(tmpfile.Name())
name := utils.GetName(r)
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+
imageEngine := abi.ImageEngine{Libpod: runtime}
saveOptions := entities.ImageSaveOptions{
@@ -63,7 +68,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
Output: tmpfile.Name(),
}
- if err := imageEngine.Save(r.Context(), name, nil, saveOptions); err != nil {
+ if err := imageEngine.Save(r.Context(), possiblyNormalizedName, nil, saveOptions); err != nil {
if errors.Cause(err) == storage.ErrImageUnknown {
utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
return
@@ -87,9 +92,6 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
}
func CommitContainer(w http.ResponseWriter, r *http.Request) {
- var (
- destImage string
- )
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
@@ -98,12 +100,12 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
Changes string `schema:"changes"`
Comment string `schema:"comment"`
Container string `schema:"container"`
+ Pause bool `schema:"pause"`
+ Repo string `schema:"repo"`
+ Tag string `schema:"tag"`
// fromSrc string # fromSrc is currently unused
- Pause bool `schema:"pause"`
- Repo string `schema:"repo"`
- Tag string `schema:"tag"`
}{
- // This is where you can override the golang default value for one of fields
+ Tag: "latest",
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
@@ -116,7 +118,6 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
return
}
sc := runtime.SystemContext()
- tag := "latest"
options := libpod.ContainerCommitOptions{
Pause: true,
}
@@ -133,9 +134,6 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
return
}
- if len(query.Tag) > 0 {
- tag = query.Tag
- }
options.Message = query.Comment
options.Author = query.Author
options.Pause = query.Pause
@@ -146,9 +144,15 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
return
}
- // I know mitr hates this ... but doing for now
+ var destImage string
if len(query.Repo) > 1 {
- destImage = fmt.Sprintf("%s:%s", query.Repo, tag)
+ destImage = fmt.Sprintf("%s:%s", query.Repo, query.Tag)
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, destImage)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ destImage = possiblyNormalizedName
}
commitImage, err := ctr.Commit(r.Context(), destImage, options)
@@ -156,7 +160,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure"))
return
}
- utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: commitImage.ID()}) // nolint
+ utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: commitImage.ID()}) // nolint
}
func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
@@ -195,12 +199,22 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
}
}
+ reference := query.Repo
+ if query.Repo != "" {
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, reference)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ reference = possiblyNormalizedName
+ }
+
platformSpecs := strings.Split(query.Platform, "/")
opts := entities.ImageImportOptions{
Source: source,
Changes: query.Changes,
Message: query.Message,
- Reference: query.Repo,
+ Reference: reference,
OS: platformSpecs[0],
}
if len(platformSpecs) > 1 {
@@ -250,13 +264,9 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
return
}
- fromImage := mergeNameAndTagOrDigest(query.FromImage, query.Tag)
-
- // without this early check this function would return 200 but reported error via body stream soon after
- // it's better to let caller know early via HTTP status code that request cannot be processed
- _, err := shortnames.Resolve(runtime.SystemContext(), fromImage)
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, mergeNameAndTagOrDigest(query.FromImage, query.Tag))
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrap(err, "failed to resolve image name"))
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
return
}
@@ -291,7 +301,7 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
pullResChan := make(chan pullResult)
go func() {
- pulledImages, err := runtime.LibimageRuntime().Pull(r.Context(), fromImage, config.PullPolicyAlways, pullOptions)
+ pulledImages, err := runtime.LibimageRuntime().Pull(r.Context(), possiblyNormalizedName, config.PullPolicyAlways, pullOptions)
pullResChan <- pullResult{images: pulledImages, err: err}
}()
@@ -371,7 +381,13 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
// 404 no such
// 500 internal
name := utils.GetName(r)
- newImage, err := utils.GetImage(r, name)
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+
+ newImage, err := utils.GetImage(r, possiblyNormalizedName)
if err != nil {
// Here we need to fiddle with the error message because docker-py is looking for "No
// such image" to determine on how to raise the correct exception.
@@ -483,7 +499,16 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
return
}
- images := query.Names
+ images := make([]string, len(query.Names))
+ for i, img := range query.Names {
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, img)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ images[i] = possiblyNormalizedName
+ }
+
tmpfile, err := ioutil.TempFile("", "api.tar")
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index ac5934c13..bc53e9312 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -118,7 +118,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
SecurityOpt string `schema:"securityopt"`
ShmSize int `schema:"shmsize"`
Squash bool `schema:"squash"`
- Tag []string `schema:"t"`
+ Tags []string `schema:"t"`
Target string `schema:"target"`
Timestamp int64 `schema:"timestamp"`
Ulimits string `schema:"ulimits"`
@@ -144,6 +144,9 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}
}
+ // convert tag formats
+ tags := query.Tags
+
// convert addcaps formats
var addCaps = []string{}
if _, found := r.URL.Query()["addcaps"]; found {
@@ -240,8 +243,13 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}
var output string
- if len(query.Tag) > 0 {
- output = query.Tag[0]
+ if len(tags) > 0 {
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, tags[0])
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ output = possiblyNormalizedName
}
format := buildah.Dockerv2ImageManifest
registry := query.Registry
@@ -257,9 +265,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}
}
}
- var additionalTags []string
- if len(query.Tag) > 1 {
- additionalTags = query.Tag[1:]
+ var additionalTags []string // nolint
+ for i := 1; i < len(tags); i++ {
+ possiblyNormalizedTag, err := utils.NormalizeToDockerHub(r, tags[i])
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ additionalTags = append(additionalTags, possiblyNormalizedTag)
}
var buildArgs = map[string]string{}
@@ -404,6 +417,22 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}
defer auth.RemoveAuthfile(authfile)
+ fromImage := query.From
+ if fromImage != "" {
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, fromImage)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ fromImage = possiblyNormalizedName
+ }
+
+ systemContext := &types.SystemContext{
+ AuthFilePath: authfile,
+ DockerAuthConfig: creds,
+ }
+ utils.PossiblyEnforceDockerHub(r, systemContext)
+
// Channels all mux'ed in select{} below to follow API build protocol
stdout := channel.NewWriter(make(chan []byte))
defer stdout.Close()
@@ -458,7 +487,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Err: auxout,
Excludes: excludes,
ForceRmIntermediateCtrs: query.ForceRm,
- From: query.From,
+ From: fromImage,
IgnoreUnrecognizedInstructions: query.Ignore,
Isolation: isolation,
Jobs: &jobs,
@@ -481,10 +510,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
RusageLogFile: query.RusageLogFile,
Squash: query.Squash,
Target: query.Target,
- SystemContext: &types.SystemContext{
- AuthFilePath: authfile,
- DockerAuthConfig: creds,
- },
+ SystemContext: systemContext,
}
for _, platformSpec := range query.Platform {
@@ -590,7 +616,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
logrus.Warnf("Failed to json encode error %v", err)
}
flush()
- for _, tag := range query.Tag {
+ for _, tag := range tags {
m.Stream = fmt.Sprintf("Successfully tagged %s\n", tag)
if err := enc.Encode(m); err != nil {
logrus.Warnf("Failed to json encode error %v", err)
diff --git a/pkg/api/handlers/compat/images_history.go b/pkg/api/handlers/compat/images_history.go
index 0c6b9fa88..fb3c2ebd2 100644
--- a/pkg/api/handlers/compat/images_history.go
+++ b/pkg/api/handlers/compat/images_history.go
@@ -14,9 +14,15 @@ func HistoryImage(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
name := utils.GetName(r)
- newImage, _, err := runtime.LibimageRuntime().LookupImage(name, nil)
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name))
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+
+ newImage, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, nil)
+ if err != nil {
+ utils.ImageNotFound(w, possiblyNormalizedName, errors.Wrapf(err, "failed to find image %s", possiblyNormalizedName))
return
}
history, err := newImage.History(r.Context())
diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go
index 8b6d3d56a..5ecb429ae 100644
--- a/pkg/api/handlers/compat/images_push.go
+++ b/pkg/api/handlers/compat/images_push.go
@@ -61,12 +61,24 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
if query.Tag != "" {
imageName += ":" + query.Tag
}
+
if _, err := utils.ParseStorageReference(imageName); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "image source %q is not a containers-storage-transport reference", imageName))
return
}
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, imageName)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+ imageName = possiblyNormalizedName
+ if _, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, nil); err != nil {
+ utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName))
+ return
+ }
+
authconf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String()))
diff --git a/pkg/api/handlers/compat/images_remove.go b/pkg/api/handlers/compat/images_remove.go
index 2dc247c1f..5c06d8de0 100644
--- a/pkg/api/handlers/compat/images_remove.go
+++ b/pkg/api/handlers/compat/images_remove.go
@@ -34,12 +34,18 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
}
}
name := utils.GetName(r)
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+
imageEngine := abi.ImageEngine{Libpod: runtime}
options := entities.ImageRemoveOptions{
Force: query.Force,
}
- report, rmerrors := imageEngine.Remove(r.Context(), []string{name}, options)
+ report, rmerrors := imageEngine.Remove(r.Context(), []string{possiblyNormalizedName}, options)
if len(rmerrors) > 0 && rmerrors[0] != nil {
err := rmerrors[0]
if errors.Cause(err) == storage.ErrImageUnknown {
diff --git a/pkg/api/handlers/compat/images_tag.go b/pkg/api/handlers/compat/images_tag.go
index 5d413a821..3fe13e2f5 100644
--- a/pkg/api/handlers/compat/images_tag.go
+++ b/pkg/api/handlers/compat/images_tag.go
@@ -14,12 +14,16 @@ import (
func TagImage(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
- // /v1.xx/images/(name)/tag
name := utils.GetName(r)
+ possiblyNormalizedName, err := utils.NormalizeToDockerHub(r, name)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
// Allow tagging manifest list instead of resolving instances from manifest
lookupOptions := &libimage.LookupImageOptions{ManifestList: true}
- newImage, _, err := runtime.LibimageRuntime().LookupImage(name, lookupOptions)
+ newImage, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, lookupOptions)
if err != nil {
utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name))
return
@@ -35,7 +39,14 @@ func TagImage(w http.ResponseWriter, r *http.Request) {
}
repo := r.Form.Get("repo")
tagName := fmt.Sprintf("%s:%s", repo, tag)
- if err := newImage.Tag(tagName); err != nil {
+
+ possiblyNormalizedTag, err := utils.NormalizeToDockerHub(r, tagName)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error normalizing image"))
+ return
+ }
+
+ if err := newImage.Tag(possiblyNormalizedTag); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index d5eb71aa1..d874165e3 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -3,19 +3,61 @@ package utils
import (
"fmt"
"net/http"
+ "strings"
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/filters"
"github.com/containers/image/v5/docker"
- "github.com/containers/image/v5/storage"
+ storageTransport "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
api "github.com/containers/podman/v3/pkg/api/types"
+ "github.com/containers/podman/v3/pkg/util"
+ "github.com/containers/storage"
+ "github.com/docker/distribution/reference"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
+// NormalizeToDockerHub normalizes the specified nameOrID to Docker Hub if the
+// request is for the compat API and if containers.conf set the specific mode.
+// If nameOrID is a (short) ID for a local image, the full ID will be returned.
+func NormalizeToDockerHub(r *http.Request, nameOrID string) (string, error) {
+ if IsLibpodRequest(r) || !util.DefaultContainerConfig().Engine.CompatAPIEnforceDockerHub {
+ return nameOrID, nil
+ }
+
+ // Try to lookup the input to figure out if it was an ID or not.
+ runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
+ img, _, err := runtime.LibimageRuntime().LookupImage(nameOrID, nil)
+ if err != nil {
+ if errors.Cause(err) != storage.ErrImageUnknown {
+ return "", fmt.Errorf("normalizing name for compat API: %v", err)
+ }
+ } else if strings.HasPrefix(img.ID(), nameOrID) {
+ return img.ID(), nil
+ }
+
+ // No ID, so we can normalize.
+ named, err := reference.ParseNormalizedNamed(nameOrID)
+ if err != nil {
+ return "", fmt.Errorf("normalizing name for compat API: %v", err)
+ }
+
+ return named.String(), nil
+}
+
+// PossiblyEnforceDockerHub sets fields in the system context to enforce
+// resolving short names to Docker Hub if the request is for the compat API and
+// if containers.conf set the specific mode.
+func PossiblyEnforceDockerHub(r *http.Request, sys *types.SystemContext) {
+ if IsLibpodRequest(r) || !util.DefaultContainerConfig().Engine.CompatAPIEnforceDockerHub {
+ return
+ }
+ sys.PodmanOnlyShortNamesIgnoreRegistriesConfAndForceDockerHub = true
+}
+
// IsRegistryReference checks if the specified name points to the "docker://"
// transport. If it points to no supported transport, we'll assume a
// non-transport reference pointing to an image (e.g., "fedora:latest").
@@ -35,13 +77,13 @@ func IsRegistryReference(name string) error {
// `types.ImageReference` and enforces it to refer to a
// containers-storage-transport reference.
func ParseStorageReference(name string) (types.ImageReference, error) {
- storagePrefix := fmt.Sprintf("%s:", storage.Transport.Name())
+ storagePrefix := storageTransport.Transport.Name()
imageRef, err := alltransports.ParseImageName(name)
if err == nil && imageRef.Transport().Name() != docker.Transport.Name() {
return nil, errors.Errorf("reference %q must be a storage reference", name)
} else if err != nil {
origErr := err
- imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", storagePrefix, name))
+ imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s:%s", storagePrefix, name))
if err != nil {
return nil, errors.Wrapf(origErr, "reference %q must be a storage reference", name)
}