func (r *Session) GetRemoteImageLayer(imgID, registry string, token []string, imgSize int64) (io.ReadCloser, error) { var ( retries = 5 client *http.Client res *http.Response imageURL = fmt.Sprintf("%simages/%s/layer", registry, imgID) ) req, err := r.reqFactory.NewRequest("GET", imageURL, nil) if err != nil { return nil, fmt.Errorf("Error while getting from the server: %s\n", err) } setTokenAuth(req, token) for i := 1; i <= retries; i++ { res, client, err = r.doRequest(req) if err != nil { res.Body.Close() if i == retries { return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)", res.StatusCode, imgID) } time.Sleep(time.Duration(i) * 5 * time.Second) continue } break } if res.StatusCode != 200 { res.Body.Close() return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)", res.StatusCode, imgID) } // Check if encrypted. if res.Header.Get("X-Docker-Encrypt") == "True" { key, err := utils.GetDefaultKey() if err != nil { return nil, fmt.Errorf("Server error: Status %d while getting default key(%s): %v", res.StatusCode, imgID, err) } res.Body, err = utils.AesReadCloserWrapper(key, res.Body) if err != nil { return nil, fmt.Errorf("Server error: Status %d while creating AES read closer(%s): %v", res.StatusCode, imgID, err) } } if res.Header.Get("Accept-Ranges") == "bytes" && imgSize > 0 { log.Debugf("server supports resume") return httputils.ResumableRequestReaderWithInitialResponse(client, req, 5, imgSize, res), nil } log.Debugf("server doesn't support resume") return res.Body, nil }
func (r *Session) PushImageLayerRegistry(imgID string, layer io.Reader, registry string, token []string, jsonRaw []byte) (checksum string, checksumPayload string, err error) { log.Debugf("[registry] Calling PUT %s", registry+"images/"+imgID+"/layer") tarsumLayer := &tarsum.TarSum{Reader: layer} h := sha256.New() h.Write(jsonRaw) h.Write([]byte{'\n'}) // FIXME: by doing this way, we will produce wrong checksum. key, err := utils.GetDefaultKey() if err != nil { return "", "", fmt.Errorf("Failed to get default key: %v", err) } checksumLayer, err := utils.AesReadCloserWrapper(key, io.TeeReader(tarsumLayer, h)) if err != nil { return "", "", fmt.Errorf("Failed to create AES read closer: %v", err) } req, err := r.reqFactory.NewRequest("PUT", registry+"images/"+imgID+"/layer", checksumLayer) if err != nil { return "", "", err } req.Header.Add("Content-Type", "application/octet-stream") req.Header.Add("X-Docker-Signature", utils.GetSignature(key)) req.ContentLength = -1 req.TransferEncoding = []string{"chunked"} setTokenAuth(req, token) res, _, err := r.doRequest(req) if err != nil { return "", "", fmt.Errorf("Failed to upload layer: %s", err) } if rc, ok := layer.(io.Closer); ok { if err := rc.Close(); err != nil { return "", "", err } } defer res.Body.Close() if res.StatusCode != 200 { errBody, err := ioutil.ReadAll(res.Body) if err != nil { return "", "", utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res) } return "", "", utils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %s", res.StatusCode, errBody), res) } checksumPayload = "sha256:" + hex.EncodeToString(h.Sum(nil)) return tarsumLayer.Sum(jsonRaw), checksumPayload, nil }
// Retrieve an image from the Registry. func (r *Session) GetRemoteImageJSON(imgID, registry string, token []string) ([]byte, int, error) { // Get the JSON req, err := r.reqFactory.NewRequest("GET", registry+"images/"+imgID+"/json", nil) if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) } // FIXME: check if it is encrypted. key, err := utils.GetDefaultKey() if err != nil { return nil, -1, fmt.Errorf("Failed to get default key: %v", err) } req.Header.Add("X-Docker-Signature", utils.GetSignature(key)) setTokenAuth(req, token) res, _, err := r.doRequest(req) if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) } defer res.Body.Close() if res.StatusCode != 200 { return nil, -1, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res) } // TODO: check if server supports encrypt. // if the size header is not present, then set it to '-1' imageSize := -1 if hdr := res.Header.Get("X-Docker-Size"); hdr != "" { imageSize, err = strconv.Atoi(hdr) if err != nil { return nil, -1, err } } jsonString, err := ioutil.ReadAll(res.Body) if err != nil { return nil, -1, fmt.Errorf("Failed to parse downloaded json: %s (%s)", err, jsonString) } return jsonString, imageSize, nil }