From fcce1da1bbeae708961f3002540fbd04b46e5f40 Mon Sep 17 00:00:00 2001 From: Milivoje Legenovic Date: Thu, 25 Feb 2021 00:42:06 +0100 Subject: Correct compat images/create?fromImage response Signed-off-by: Milivoje Legenovic --- pkg/api/handlers/compat/images.go | 123 ++++++++++++++++++++++++++------- pkg/api/handlers/libpod/images_pull.go | 3 +- pkg/autoupdate/autoupdate.go | 1 + pkg/checkpoint/checkpoint_restore.go | 2 +- pkg/domain/infra/abi/images.go | 4 +- pkg/domain/infra/abi/play.go | 2 +- 6 files changed, 105 insertions(+), 30 deletions(-) (limited to 'pkg') diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index 1a4dd939e..e5caa9ea5 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -1,6 +1,7 @@ package compat import ( + "context" "encoding/json" "fmt" "io" @@ -11,11 +12,13 @@ import ( "github.com/containers/buildah" "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/types" "github.com/containers/podman/v3/libpod" image2 "github.com/containers/podman/v3/libpod/image" "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/util" "github.com/gorilla/schema" @@ -236,33 +239,103 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) { if sys := runtime.SystemContext(); sys != nil { registryOpts.DockerCertPath = sys.DockerCertPath } - img, err := runtime.ImageRuntime().New(r.Context(), - fromImage, - "", // signature policy - authfile, - nil, // writer - ®istryOpts, - image2.SigningOptions{}, - nil, // label - util.PullImageAlways, - ) - if err != nil { - utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) - return + + stderr := channel.NewWriter(make(chan []byte)) + defer stderr.Close() + + progress := make(chan types.ProgressProperties) + + var img string + runCtx, cancel := context.WithCancel(context.Background()) + go func() { + defer cancel() + + newImage, err := runtime.ImageRuntime().New( + runCtx, + fromImage, + "", // signature policy + authfile, + nil, // writer + ®istryOpts, + image2.SigningOptions{}, + nil, // label + util.PullImageAlways, + progress) + if err != nil { + stderr.Write([]byte(err.Error() + "\n")) + } else { + img = newImage.ID() + } + }() + + flush := func() { + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } } - // Success - utils.WriteResponse(w, http.StatusOK, struct { - Status string `json:"status"` - Error string `json:"error,omitempty"` - Progress string `json:"progress"` - ProgressDetail map[string]string `json:"progressDetail"` - Id string `json:"id"` // nolint - }{ - Status: fmt.Sprintf("pulling image (%s) from %s (Download complete)", img.Tag, strings.Join(img.Names(), ", ")), - ProgressDetail: map[string]string{}, - Id: img.ID(), - }) + w.WriteHeader(http.StatusOK) + w.Header().Add("Content-Type", "application/json") + flush() + + enc := json.NewEncoder(w) + enc.SetEscapeHTML(true) + var failed bool + +loop: // break out of for/select infinite loop + for { + var report struct { + Stream string `json:"stream,omitempty"` + Status string `json:"status,omitempty"` + Progress struct { + Current uint64 `json:"current,omitempty"` + Total int64 `json:"total,omitempty"` + } `json:"progressDetail,omitempty"` + Error string `json:"error,omitempty"` + Id string `json:"id,omitempty"` // nolint + } + + select { + case e := <-progress: + switch e.Event { + case types.ProgressEventNewArtifact: + report.Status = "Pulling fs layer" + case types.ProgressEventRead: + report.Status = "Downloading" + report.Progress.Current = e.Offset + report.Progress.Total = e.Artifact.Size + case types.ProgressEventSkipped: + report.Status = "Already exists" + case types.ProgressEventDone: + report.Status = "Download complete" + } + 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 { + report.Status = "Pull complete" + report.Id = img[0:12] + 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 + } + } } func GetImage(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index c8b777be4..e2e4b53b4 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -136,7 +136,8 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { &dockerRegistryOptions, image.SigningOptions{}, nil, - util.PullImageAlways) + util.PullImageAlways, + nil) if err != nil { stderr.Write([]byte(err.Error() + "\n")) } else { diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index 0cf51e5a6..53095c295 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -304,6 +304,7 @@ func updateImage(runtime *libpod.Runtime, name string, options Options) (*image. image.SigningOptions{}, nil, util.PullImageAlways, + nil, ) if err != nil { return nil, err diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go index a608762b5..6285680c0 100644 --- a/pkg/checkpoint/checkpoint_restore.go +++ b/pkg/checkpoint/checkpoint_restore.go @@ -121,7 +121,7 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt return nil, err } - _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.Engine.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing) + _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.Engine.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing, nil) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 46d967789..562653403 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -247,7 +247,7 @@ func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options } if !options.AllTags { - newImage, err := runtime.New(ctx, rawImage, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, label, options.PullPolicy) + newImage, err := runtime.New(ctx, rawImage, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, label, options.PullPolicy, nil) if err != nil { return nil, err } @@ -280,7 +280,7 @@ func pull(ctx context.Context, runtime *image.Runtime, rawImage string, options foundIDs := []string{} for _, tag := range tags { name := rawImage + ":" + tag - newImage, err := runtime.New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) + newImage, err := runtime.New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways, nil) if err != nil { logrus.Errorf("error pulling image %q", name) continue diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index c5e20a607..b7ca69281 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -221,7 +221,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } // This ensures the image is the image store - newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy) + newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy, nil) if err != nil { return nil, err } -- cgit v1.2.3-54-g00ecf