github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/bindings/images/pull.go (about) 1 package images 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net/http" 10 "os" 11 "strconv" 12 13 "github.com/containers/image/v5/types" 14 "github.com/hanks177/podman/v4/pkg/auth" 15 "github.com/hanks177/podman/v4/pkg/bindings" 16 "github.com/hanks177/podman/v4/pkg/domain/entities" 17 "github.com/hanks177/podman/v4/pkg/errorhandling" 18 "github.com/pkg/errors" 19 ) 20 21 // Pull is the binding for libpod's v2 endpoints for pulling images. Note that 22 // `rawImage` must be a reference to a registry (i.e., of docker transport or be 23 // normalized to one). Other transports are rejected as they do not make sense 24 // in a remote context. Progress reported on stderr 25 func Pull(ctx context.Context, rawImage string, options *PullOptions) ([]string, error) { 26 if options == nil { 27 options = new(PullOptions) 28 } 29 conn, err := bindings.GetClient(ctx) 30 if err != nil { 31 return nil, err 32 } 33 params, err := options.ToParams() 34 if err != nil { 35 return nil, err 36 } 37 params.Set("reference", rawImage) 38 39 if options.SkipTLSVerify != nil { 40 params.Del("SkipTLSVerify") 41 // Note: we have to verify if skipped is false. 42 params.Set("tlsVerify", strconv.FormatBool(!options.GetSkipTLSVerify())) 43 } 44 45 header, err := auth.MakeXRegistryAuthHeader(&types.SystemContext{AuthFilePath: options.GetAuthfile()}, options.GetUsername(), options.GetPassword()) 46 if err != nil { 47 return nil, err 48 } 49 50 response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/images/pull", params, header) 51 if err != nil { 52 return nil, err 53 } 54 defer response.Body.Close() 55 56 if !response.IsSuccess() { 57 return nil, response.Process(err) 58 } 59 60 // Historically pull writes status to stderr 61 stderr := io.Writer(os.Stderr) 62 if options.GetQuiet() { 63 stderr = ioutil.Discard 64 } 65 66 dec := json.NewDecoder(response.Body) 67 var images []string 68 var pullErrors []error 69 for { 70 var report entities.ImagePullReport 71 if err := dec.Decode(&report); err != nil { 72 if errors.Is(err, io.EOF) { 73 break 74 } 75 report.Error = err.Error() + "\n" 76 } 77 78 select { 79 case <-response.Request.Context().Done(): 80 break 81 default: 82 // non-blocking select 83 } 84 85 switch { 86 case report.Stream != "": 87 fmt.Fprint(stderr, report.Stream) 88 case report.Error != "": 89 pullErrors = append(pullErrors, errors.New(report.Error)) 90 case len(report.Images) > 0: 91 images = report.Images 92 case report.ID != "": 93 default: 94 return images, errors.Errorf("failed to parse pull results stream, unexpected input: %v", report) 95 } 96 } 97 return images, errorhandling.JoinErrors(pullErrors) 98 }