Files
podman/pkg/bindings/images/pull.go
baude 8d4e19634c Podman image bindings for 3.0
Begin the migration of the image bindings for podman 3.0.  this includes
the use of options for each binding.  build was intentionally not
converted as I believe it needs more discussion before migration.
specifically, the build options themselves.

also noteworthly is that the remove image and remove images bindings
were merged into one.  the remove images (or batch remove) has one
downside in that the errors return no longer adhere to http return
codes.  this should be discussed and reimplemented in subsequent code.

Signed-off-by: baude <bbaude@redhat.com>
2020-12-15 16:04:59 -06:00

100 lines
2.4 KiB
Go

package images
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strconv"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/hashicorp/go-multierror"
)
// Pull is the binding for libpod's v2 endpoints for pulling images. Note that
// `rawImage` must be a reference to a registry (i.e., of docker transport or be
// normalized to one). Other transports are rejected as they do not make sense
// in a remote context. Progress reported on stderr
func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, error) {
if options == nil {
options = new(PullOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
params, err := options.ToParams()
if err != nil {
return nil, err
}
params.Set("reference", rawImage)
if options.SkipTLSVerify != nil {
params.Del("SkipTLSVerify")
// Note: we have to verify if skipped is false.
params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify()))
}
// TODO: have a global system context we can pass around (1st argument)
header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.GetAuthfile(), options.GetUsername(), options.GetPassword())
if err != nil {
return nil, err
}
response, err := conn.DoRequest(nil, http.MethodPost, "/images/pull", params, header)
if err != nil {
return nil, err
}
defer response.Body.Close()
if !response.IsSuccess() {
return nil, response.Process(err)
}
// Historically pull writes status to stderr
stderr := io.Writer(os.Stderr)
if options.GetQuiet() {
stderr = ioutil.Discard
}
dec := json.NewDecoder(response.Body)
var images []string
var mErr error
for {
var report entities.ImagePullReport
if err := dec.Decode(&report); err != nil {
if errors.Is(err, io.EOF) {
break
}
report.Error = err.Error() + "\n"
}
select {
case <-response.Request.Context().Done():
return images, mErr
default:
// non-blocking select
}
switch {
case report.Stream != "":
fmt.Fprint(stderr, report.Stream)
case report.Error != "":
mErr = multierror.Append(mErr, errors.New(report.Error))
case len(report.Images) > 0:
images = report.Images
case report.ID != "":
default:
return images, errors.New("failed to parse pull results stream, unexpected input")
}
}
return images, mErr
}