summaryrefslogtreecommitdiff
path: root/pkg/api/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/handlers')
-rw-r--r--pkg/api/handlers/compat/images.go76
-rw-r--r--pkg/api/handlers/compat/images_push.go112
2 files changed, 89 insertions, 99 deletions
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 3f4320efa..7b336c470 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -1,7 +1,6 @@
package compat
import (
- "context"
"encoding/json"
"fmt"
"io/ioutil"
@@ -13,12 +12,12 @@ 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"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
- "github.com/containers/podman/v3/pkg/channel"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/storage"
@@ -210,6 +209,11 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
})
}
+type pullResult struct {
+ images []*libimage.Image
+ err error
+}
+
func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
// 200 no error
// 404 repo does not exist or no read access
@@ -231,6 +235,14 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
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)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrap(err, "failed to resolve image name"))
+ return
+ }
+
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String()))
@@ -247,26 +259,14 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
}
pullOptions.Writer = os.Stderr // allows for debugging on the server
- stderr := channel.NewWriter(make(chan []byte))
- defer stderr.Close()
-
progress := make(chan types.ProgressProperties)
+
pullOptions.Progress = progress
- var img string
- runCtx, cancel := context.WithCancel(context.Background())
+ pullResChan := make(chan pullResult)
go func() {
- defer cancel()
- pulledImages, err := runtime.LibimageRuntime().Pull(runCtx, fromImage, config.PullPolicyAlways, pullOptions)
- if err != nil {
- stderr.Write([]byte(err.Error() + "\n"))
- } else {
- if len(pulledImages) == 0 {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.New("internal error: no images pulled"))
- return
- }
- img = pulledImages[0].ID()
- }
+ pulledImages, err := runtime.LibimageRuntime().Pull(r.Context(), fromImage, config.PullPolicyAlways, pullOptions)
+ pullResChan <- pullResult{images: pulledImages, err: err}
}()
flush := func() {
@@ -281,7 +281,6 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
enc := json.NewEncoder(w)
enc.SetEscapeHTML(true)
- var failed bool
loop: // break out of for/select infinite loop
for {
@@ -312,32 +311,31 @@ loop: // break out of for/select infinite loop
}
report.Id = e.Artifact.Digest.Encoded()[0:12]
if err := enc.Encode(report); err != nil {
- stderr.Write([]byte(err.Error()))
- }
- flush()
- case e := <-stderr.Chan():
- failed = true
- report.Error = string(e)
- if err := enc.Encode(report); err != nil {
logrus.Warnf("Failed to json encode error %q", err.Error())
}
flush()
- case <-runCtx.Done():
- if !failed {
- if utils.IsLibpodRequest(r) {
- report.Status = "Pull complete"
+ case pullRes := <-pullResChan:
+ err := pullRes.err
+ pulledImages := pullRes.images
+ if err != nil {
+ report.Error = err.Error()
+ } else {
+ if len(pulledImages) > 0 {
+ img := pulledImages[0].ID()
+ if utils.IsLibpodRequest(r) {
+ report.Status = "Pull complete"
+ } else {
+ report.Status = "Download complete"
+ }
+ report.Id = img[0:12]
} else {
- report.Status = "Download complete"
- }
- report.Id = img[0:12]
- if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to json encode error %q", err.Error())
+ report.Error = "internal error: no images pulled"
}
- flush()
}
- break loop // break out of for/select infinite loop
- case <-r.Context().Done():
- // Client has closed connection
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+ flush()
break loop // break out of for/select infinite loop
}
}
diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go
index db02af445..62f8cdc77 100644
--- a/pkg/api/handlers/compat/images_push.go
+++ b/pkg/api/handlers/compat/images_push.go
@@ -1,7 +1,6 @@
package compat
import (
- "context"
"encoding/json"
"fmt"
"io/ioutil"
@@ -12,7 +11,6 @@ import (
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
- "github.com/containers/podman/v3/pkg/channel"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/storage"
@@ -101,46 +99,33 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
destination = imageName
}
- errorWriter := channel.NewWriter(make(chan []byte))
- defer errorWriter.Close()
-
- statusWriter := channel.NewWriter(make(chan []byte))
- defer statusWriter.Close()
-
- runCtx, cancel := context.WithCancel(context.Background())
- var failed bool
-
- go func() {
- defer cancel()
-
- statusWriter.Write([]byte(fmt.Sprintf("The push refers to repository [%s]", imageName)))
-
- err := imageEngine.Push(runCtx, imageName, destination, options)
- if err != nil {
- if errors.Cause(err) != storage.ErrImageUnknown {
- errorWriter.Write([]byte("An image does not exist locally with the tag: " + imageName))
- } else {
- errorWriter.Write([]byte(err.Error()))
- }
- }
- }()
-
- flush := func() {
- if flusher, ok := w.(http.Flusher); ok {
- flusher.Flush()
- }
+ flush := func() {}
+ if flusher, ok := w.(http.Flusher); ok {
+ flush = flusher.Flush
}
w.WriteHeader(http.StatusOK)
w.Header().Add("Content-Type", "application/json")
flush()
+ var report jsonmessage.JSONMessage
enc := json.NewEncoder(w)
enc.SetEscapeHTML(true)
+ report.Status = fmt.Sprintf("The push refers to repository [%s]", imageName)
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+ flush()
+
+ pushErrChan := make(chan error)
+ go func() {
+ pushErrChan <- imageEngine.Push(r.Context(), imageName, destination, options)
+ }()
+
loop: // break out of for/select infinite loop
for {
- var report jsonmessage.JSONMessage
+ report = jsonmessage.JSONMessage{}
select {
case e := <-options.Progress:
@@ -160,43 +145,50 @@ loop: // break out of for/select infinite loop
}
report.ID = e.Artifact.Digest.Encoded()[0:12]
if err := enc.Encode(report); err != nil {
- errorWriter.Write([]byte(err.Error()))
+ logrus.Warnf("Failed to json encode error %q", err.Error())
}
flush()
- case e := <-statusWriter.Chan():
- report.Status = string(e)
- if err := enc.Encode(report); err != nil {
- errorWriter.Write([]byte(err.Error()))
+ case err := <-pushErrChan:
+ if err != nil {
+ var msg string
+ if errors.Cause(err) != storage.ErrImageUnknown {
+ msg = "An image does not exist locally with the tag: " + imageName
+ } else {
+ msg = err.Error()
+ }
+ report.Error = &jsonmessage.JSONError{
+ Message: msg,
+ }
+ report.ErrorMessage = msg
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+ flush()
+ break loop
}
- flush()
- case e := <-errorWriter.Chan():
- failed = true
- report.Error = &jsonmessage.JSONError{
- Message: string(e),
+
+ digestBytes, err := ioutil.ReadAll(digestFile)
+ if err != nil {
+ report.Error = &jsonmessage.JSONError{
+ Message: err.Error(),
+ }
+ report.ErrorMessage = err.Error()
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+ flush()
+ break loop
}
- report.ErrorMessage = string(e)
+ tag := query.Tag
+ if tag == "" {
+ tag = "latest"
+ }
+ report.Status = fmt.Sprintf("%s: digest: %s", tag, string(digestBytes))
if err := enc.Encode(report); err != nil {
logrus.Warnf("Failed to json encode error %q", err.Error())
}
+
flush()
- case <-runCtx.Done():
- if !failed {
- digestBytes, err := ioutil.ReadAll(digestFile)
- if err == nil {
- tag := query.Tag
- if tag == "" {
- tag = "latest"
- }
- report.Status = fmt.Sprintf("%s: digest: %s", tag, string(digestBytes))
- if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to json encode error %q", err.Error())
- }
- flush()
- }
- }
- break loop // break out of for/select infinite loop
- case <-r.Context().Done():
- // Client has closed connection
break loop // break out of for/select infinite loop
}
}