Cleanup /libpod/images/load handler

* Remove orphaned code
* Add meaningful error from LoadImageFromSingleImageArchive() when
  heuristic fails to determine payload format
* Correct swagger to output correct types and headers

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce
2021-03-18 12:17:11 -07:00
parent 5325957d53
commit 417f362811
5 changed files with 43 additions and 29 deletions

View File

@ -313,16 +313,24 @@ func (r *Runtime) LoadImageFromSingleImageArchive(ctx context.Context, writer io
func() (types.ImageReference, error) { func() (types.ImageReference, error) {
return layout.NewReference(inputFile, "") return layout.NewReference(inputFile, "")
}, },
func() (types.ImageReference, error) {
// This item needs to be last to break out of loop and report meaningful error message
return nil,
errors.New("payload does not match any of the supported image formats (oci-archive, oci-dir, docker-archive, docker-dir)")
},
} { } {
src, err := referenceFn() src, err := referenceFn()
if err == nil && src != nil { if err != nil {
saveErr = err
continue
}
newImages, err := r.ImageRuntime().LoadFromArchiveReference(ctx, src, signaturePolicy, writer) newImages, err := r.ImageRuntime().LoadFromArchiveReference(ctx, src, signaturePolicy, writer)
if err == nil { if err == nil {
return getImageNames(newImages), nil return getImageNames(newImages), nil
} }
saveErr = err saveErr = err
} }
}
return "", errors.Wrapf(saveErr, "error pulling image") return "", errors.Wrapf(saveErr, "error pulling image")
} }

View File

@ -319,18 +319,6 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
func ImagesLoad(w http.ResponseWriter, r *http.Request) { func ImagesLoad(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime) runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Reference string `schema:"reference"`
}{
// Add defaults here once needed.
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
tmpfile, err := ioutil.TempFile("", "libpod-images-load.tar") tmpfile, err := ioutil.TempFile("", "libpod-images-load.tar")
if err != nil { if err != nil {
@ -338,14 +326,15 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) {
return return
} }
defer os.Remove(tmpfile.Name()) defer os.Remove(tmpfile.Name())
defer tmpfile.Close()
if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF { _, err = io.Copy(tmpfile, r.Body)
tmpfile.Close()
if err != nil && err != io.EOF {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file")) utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
return return
} }
tmpfile.Close()
loadedImage, err := runtime.LoadImage(context.Background(), tmpfile.Name(), os.Stderr, "") loadedImage, err := runtime.LoadImage(context.Background(), tmpfile.Name(), os.Stderr, "")
if err != nil { if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to load image")) utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to load image"))

View File

@ -810,11 +810,14 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// summary: Load image // summary: Load image
// description: Load an image (oci-archive or docker-archive) stream. // description: Load an image (oci-archive or docker-archive) stream.
// parameters: // parameters:
// - in: formData // - in: body
// name: upload // name: upload
// description: tarball of container image
// type: file
// required: true // required: true
// description: tarball of container image
// schema:
// type: string
// consumes:
// - application/x-tar
// produces: // produces:
// - application/json // - application/json
// responses: // responses:

View File

@ -1,4 +1,5 @@
import collections import collections
import io
import os import os
import subprocess import subprocess
import sys import sys
@ -6,6 +7,7 @@ import time
import unittest import unittest
from docker import DockerClient, errors from docker import DockerClient, errors
from docker.errors import APIError
from test.python.docker import Podman from test.python.docker import Podman
from test.python.docker.compat import common, constant from test.python.docker.compat import common, constant
@ -79,9 +81,7 @@ class TestImages(unittest.TestCase):
self.assertEqual(len(self.client.images.list()), 2) self.assertEqual(len(self.client.images.list()), 2)
# List images with filter # List images with filter
self.assertEqual( self.assertEqual(len(self.client.images.list(filters={"reference": "alpine"})), 1)
len(self.client.images.list(filters={"reference": "alpine"})), 1
)
def test_search_image(self): def test_search_image(self):
"""Search for image""" """Search for image"""
@ -149,15 +149,22 @@ class TestImages(unittest.TestCase):
self.assertEqual(len(self.client.images.list()), 2) self.assertEqual(len(self.client.images.list()), 2)
def test_load_corrupt_image(self):
"""Import|Load Image failure"""
tarball = io.BytesIO("This is a corrupt tarball".encode("utf-8"))
with self.assertRaises(APIError):
self.client.images.load(tarball)
def test_build_image(self): def test_build_image(self):
labels = {"apple": "red", "grape": "green"} labels = {"apple": "red", "grape": "green"}
_ = self.client.images.build(path="test/python/docker/build_labels", labels=labels, tag="labels") _ = self.client.images.build(
path="test/python/docker/build_labels", labels=labels, tag="labels"
)
image = self.client.images.get("labels") image = self.client.images.get("labels")
self.assertEqual(image.labels["apple"], labels["apple"]) self.assertEqual(image.labels["apple"], labels["apple"])
self.assertEqual(image.labels["grape"], labels["grape"]) self.assertEqual(image.labels["grape"], labels["grape"])
if __name__ == "__main__": if __name__ == "__main__":
# Setup temporary space # Setup temporary space
unittest.main() unittest.main()

View File

@ -32,7 +32,7 @@ verify_iid_and_name() {
echo "I am an invalid file and should cause a podman-load error" > $invalid echo "I am an invalid file and should cause a podman-load error" > $invalid
run_podman 125 load -i $invalid run_podman 125 load -i $invalid
# podman and podman-remote emit different messages; this is a common string # podman and podman-remote emit different messages; this is a common string
is "$output" ".*error pulling image: unable to pull .*" \ is "$output" ".*payload does not match any of the supported image formats .*" \
"load -i INVALID fails with expected diagnostic" "load -i INVALID fails with expected diagnostic"
} }
@ -137,6 +137,13 @@ verify_iid_and_name() {
"Diagnostic from 'podman load' without redirection or -i" "Diagnostic from 'podman load' without redirection or -i"
} }
@test "podman load - redirect corrupt payload" {
run_podman 125 load <<< "Danger, Will Robinson!! This is a corrupt tarball!"
is "$output" \
".*payload does not match any of the supported image formats .*" \
"Diagnostic from 'podman load' unknown/corrupt payload"
}
@test "podman load - multi-image archive" { @test "podman load - multi-image archive" {
img1="quay.io/libpod/testimage:00000000" img1="quay.io/libpod/testimage:00000000"
img2="quay.io/libpod/testimage:20200902" img2="quay.io/libpod/testimage:20200902"