summaryrefslogtreecommitdiff
path: root/pkg/api
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2020-02-04 12:48:13 +0100
committerValentin Rothberg <rothberg@redhat.com>2020-02-10 12:36:45 +0100
commit76e2a0c5d3365205cb104280d41015d6ab25cd9a (patch)
treecaaa958c7b9c09f283e7e4498fdd8c473403f32e /pkg/api
parentee811431d29962c3a801903ca3ca342a2000f65e (diff)
downloadpodman-76e2a0c5d3365205cb104280d41015d6ab25cd9a.tar.gz
podman-76e2a0c5d3365205cb104280d41015d6ab25cd9a.tar.bz2
podman-76e2a0c5d3365205cb104280d41015d6ab25cd9a.zip
v2 api: /libpod/images/pull
Implement the /libpod/images/pull endpoint and correct the swagger docs. The reference parameter is mandatory and must either be a c/image/docker/reference or a reference to the "docker://" transport as the pull endpoint is meant to only support pulling images from a registry. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'pkg/api')
-rw-r--r--pkg/api/handlers/libpod/images.go125
-rw-r--r--pkg/api/handlers/types.go29
-rw-r--r--pkg/api/server/register_images.go25
3 files changed, 157 insertions, 22 deletions
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 6c926c45b..fffcad8ed 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -1,15 +1,22 @@
package libpod
import (
+ "context"
"fmt"
"io/ioutil"
"net/http"
"os"
"strconv"
+ "github.com/containers/image/v5/docker"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/image/v5/types"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -186,6 +193,120 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) {
}
func ImagesPull(w http.ResponseWriter, r *http.Request) {
- //TODO ...
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.New("/libpod/images/pull is not yet implemented"))
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Reference string `schema:"reference"`
+ Credentials string `schema:"credentials"`
+ OverrideOS string `schema:"overrideOS"`
+ OverrideArch string `schema:"overrideArch"`
+ TLSVerify bool `schema:"tlsVerify"`
+ AllTags bool `schema:"allTags"`
+ }{
+ TLSVerify: true,
+ }
+
+ 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
+ }
+
+ if len(query.Reference) == 0 {
+ utils.InternalServerError(w, errors.New("reference parameter cannot be empty"))
+ return
+ }
+ // Enforce the docker transport. This is just a precaution as some callers
+ // might accustomed to using the "transport:reference" notation. Using
+ // another than the "docker://" transport does not really make sense for a
+ // remote case. For loading tarballs, the load and import endpoints should
+ // be used.
+ imageRef, err := alltransports.ParseImageName(query.Reference)
+ if err == nil && imageRef.Transport().Name() != docker.Transport.Name() {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Errorf("reference %q must be a docker reference", query.Reference))
+ return
+ } else if err != nil {
+ origErr := err
+ imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s:%s", docker.Transport.Name(), query.Reference))
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(origErr, "reference %q must be a docker reference", query.Reference))
+ return
+ }
+ }
+
+ // all-tags doesn't work with a tagged reference, so let's check early
+ namedRef, err := reference.Parse(query.Reference)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "error parsing reference %q", query.Reference))
+ return
+ }
+ if _, isTagged := namedRef.(reference.Tagged); isTagged && query.AllTags {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Errorf("reference %q must not have a tag for all-tags", query.Reference))
+ return
+ }
+
+ var registryCreds *types.DockerAuthConfig
+ if len(query.Credentials) != 0 {
+ creds, err := util.ParseRegistryCreds(query.Credentials)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "error parsing credentials %q", query.Credentials))
+ return
+ }
+ registryCreds = creds
+ }
+
+ // Setup the registry options
+ dockerRegistryOptions := image.DockerRegistryOptions{
+ DockerRegistryCreds: registryCreds,
+ OSChoice: query.OverrideOS,
+ ArchitectureChoice: query.OverrideArch,
+ }
+ if query.TLSVerify {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ // Prepare the images we want to pull
+ imagesToPull := []string{}
+ res := []handlers.LibpodImagesPullReport{}
+ imageName := namedRef.String()
+
+ if !query.AllTags {
+ imagesToPull = append(imagesToPull, imageName)
+ } else {
+ systemContext := image.GetSystemContext("", "", false)
+ tags, err := docker.GetRepositoryTags(context.Background(), systemContext, imageRef)
+ if err != nil {
+ utils.InternalServerError(w, errors.Wrap(err, "error getting repository tags"))
+ return
+ }
+ for _, tag := range tags {
+ imagesToPull = append(imagesToPull, fmt.Sprintf("%s:%s", imageName, tag))
+ }
+ }
+
+ // Finally pull the images
+ for _, img := range imagesToPull {
+ newImage, err := runtime.ImageRuntime().New(
+ context.Background(),
+ img,
+ "",
+ "",
+ os.Stderr,
+ &dockerRegistryOptions,
+ image.SigningOptions{},
+ nil,
+ util.PullImageAlways)
+ if err != nil {
+ utils.InternalServerError(w, errors.Wrapf(err, "error pulling image %q", query.Reference))
+ return
+ }
+ res = append(res, handlers.LibpodImagesPullReport{ID: newImage.ID()})
+ }
+
+ utils.WriteResponse(w, http.StatusOK, res)
}
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 6169adb18..c19397e60 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -33,6 +33,20 @@ type ContainerConfig struct {
dockerContainer.Config
}
+type LibpodImagesLoadReport struct {
+ ID string `json:"id"`
+ RepoTags []string `json:"repoTags"`
+}
+
+type LibpodImagesImportReport struct {
+ ID string `json:"id"`
+ RepoTags []string `json:"repoTags"`
+}
+
+type LibpodImagesPullReport struct {
+ ID string `json:"id"`
+}
+
type ImageSummary struct {
docker.ImageSummary
CreatedTime time.Time `json:"CreatedTime,omitempty"`
@@ -49,21 +63,6 @@ type LibpodContainersPruneReport struct {
PruneError string `json:"error"`
}
-type LibpodImagesLoadReport struct {
- ID string `json:"id"`
- RepoTags []string `json:"repoTags"`
-}
-
-type LibpodImagesImportReport struct {
- ID string `json:"id"`
- RepoTags []string `json:"repoTags"`
-}
-
-type LibpodImagesPullReport struct {
- ID string `json:"id"`
- RepoTags []string `json:"repoTags"`
-}
-
type Info struct {
docker.Info
BuildahVersion string
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 4a46b6ee6..98858dac2 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -691,34 +691,49 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/import"), APIHandler(s.Context, libpod.ImagesImport)).Methods(http.MethodPost)
- // swagger:operation GET /libpod/images/pull libpod libpodImagesPull
+ // swagger:operation POST /libpod/images/pull libpod libpodImagesPull
// ---
// tags:
// - images
- // summary: Import image
- // description: Import a previosly exported image as a tarball.
+ // summary: Pull images
+ // description: Pull one or more images from a container registry.
// parameters:
// - in: query
// name: reference
- // description: Mandatory reference to the image (e.g., quay.io/image/name:tag)/
+ // description: Mandatory reference to the image (e.g., quay.io/image/name:tag)
// type: string
// - in: query
// name: credentials
// description: username:password for the registry.
// type: string
// - in: query
+ // name: os
+ // description: Pull image for the specified operating system.
+ // type: string
+ // - in: query
+ // name: arch
+ // description: Pull image for the specified architecture.
+ // type: string
+ // - in: query
// name: tls-verify
// description: Require TLS verification.
// type: boolean
// default: true
+ // - in: query
+ // name: all-tags
+ // description: Pull all tagged images in the repository.
+ // type: bool
// produces:
// - application/json
// responses:
// 200:
// $ref: "#/responses/DocsLibpodImagesPullResponse"
+ // $ref: "#/response/LibpodImagesPullResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
// 500:
// $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/pull"), APIHandler(s.Context, libpod.ImagesPull)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/images/pull"), APIHandler(s.Context, libpod.ImagesPull)).Methods(http.MethodPut)
// swagger:operation POST /libpod/images/prune libpod libpodPruneImages
// ---
// tags: