Example #1
0
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
}
Example #2
0
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
}
Example #3
0
// 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
}