Example #1
0
// ParseReference parses a reference into either a digest or tag reference
func ParseReference(ref string) Reference {
	if strings.Contains(ref, ":") {
		dgst, err := digest.ParseDigest(ref)
		if err == nil {
			return digestReference{digest: dgst}
		}
	}
	return tagReference{tag: ref}
}
Example #2
0
// readlink returns the linked digest at path.
func (bs *blobStore) readlink(ctx context.Context, path string) (digest.Digest, error) {
	content, err := bs.driver.GetContent(ctx, path)
	if err != nil {
		return "", err
	}

	linked, err := digest.ParseDigest(string(content))
	if err != nil {
		return "", err
	}

	return linked, nil
}
Example #3
0
func getDigest(ctx context.Context) (dgst digest.Digest, err error) {
	dgstStr := ctxu.GetStringValue(ctx, "vars.digest")

	if dgstStr == "" {
		ctxu.GetLogger(ctx).Errorf("digest not available")
		return "", errDigestNotAvailable
	}

	d, err := digest.ParseDigest(dgstStr)
	if err != nil {
		ctxu.GetLogger(ctx).Errorf("error parsing digest=%q: %v", dgstStr, err)
		return "", err
	}

	return d, nil
}
Example #4
0
// imageManifestDispatcher takes the request context and builds the
// appropriate handler for handling image manifest requests.
func imageManifestDispatcher(ctx *Context, r *http.Request) http.Handler {
	imageManifestHandler := &imageManifestHandler{
		Context: ctx,
	}
	reference := getReference(ctx)
	dgst, err := digest.ParseDigest(reference)
	if err != nil {
		// We just have a tag
		imageManifestHandler.Tag = reference
	} else {
		imageManifestHandler.Digest = dgst
	}

	return handlers.MethodHandler{
		"GET":    http.HandlerFunc(imageManifestHandler.GetImageManifest),
		"PUT":    http.HandlerFunc(imageManifestHandler.PutImageManifest),
		"DELETE": http.HandlerFunc(imageManifestHandler.DeleteImageManifest),
	}
}
Example #5
0
func (s *signatureStore) Get(dgst digest.Digest) ([][]byte, error) {
	signaturesPath, err := s.blobStore.pm.path(manifestSignaturesPathSpec{
		name:     s.repository.Name(),
		revision: dgst,
	})

	if err != nil {
		return nil, err
	}

	// Need to append signature digest algorithm to path to get all items.
	// Perhaps, this should be in the pathMapper but it feels awkward. This
	// can be eliminated by implementing listAll on drivers.
	signaturesPath = path.Join(signaturesPath, "sha256")

	signaturePaths, err := s.blobStore.driver.List(s.ctx, signaturesPath)
	if err != nil {
		return nil, err
	}

	var wg sync.WaitGroup
	type result struct {
		index     int
		signature []byte
		err       error
	}
	ch := make(chan result)

	bs := s.linkedBlobStore(s.ctx, dgst)
	for i, sigPath := range signaturePaths {
		sigdgst, err := digest.ParseDigest("sha256:" + path.Base(sigPath))
		if err != nil {
			context.GetLogger(s.ctx).Errorf("could not get digest from path: %q, skipping", sigPath)
			continue
		}

		wg.Add(1)
		go func(idx int, sigdgst digest.Digest) {
			defer wg.Done()
			context.GetLogger(s.ctx).
				Debugf("fetching signature %q", sigdgst)

			r := result{index: idx}

			if p, err := bs.Get(s.ctx, sigdgst); err != nil {
				context.GetLogger(s.ctx).
					Errorf("error fetching signature %q: %v", sigdgst, err)
				r.err = err
			} else {
				r.signature = p
			}

			ch <- r
		}(i, sigdgst)
	}
	done := make(chan struct{})
	go func() {
		wg.Wait()
		close(done)
	}()

	// aggregrate the results
	signatures := make([][]byte, len(signaturePaths))
loop:
	for {
		select {
		case result := <-ch:
			signatures[result.index] = result.signature
			if result.err != nil && err == nil {
				// only set the first one.
				err = result.err
			}
		case <-done:
			break loop
		}
	}

	return signatures, err
}
Example #6
0
// PutBlobUploadComplete takes the final request of a blob upload. The
// request may include all the blob data or no blob data. Any data
// provided is received and verified. If successful, the blob is linked
// into the blob store and 201 Created is returned with the canonical
// url of the blob.
func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *http.Request) {
	if buh.Upload == nil {
		buh.Errors = append(buh.Errors, v2.ErrorCodeBlobUploadUnknown)
		return
	}

	dgstStr := r.FormValue("digest") // TODO(stevvooe): Support multiple digest parameters!

	if dgstStr == "" {
		// no digest? return error, but allow retry.
		buh.Errors = append(buh.Errors, v2.ErrorCodeDigestInvalid.WithDetail("digest missing"))
		return
	}

	dgst, err := digest.ParseDigest(dgstStr)
	if err != nil {
		// no digest? return error, but allow retry.
		buh.Errors = append(buh.Errors, v2.ErrorCodeDigestInvalid.WithDetail("digest parsing failed"))
		return
	}

	// Read in the data, if any.
	if _, err := io.Copy(buh.Upload, r.Body); err != nil {
		ctxu.GetLogger(buh).Errorf("unknown error copying into upload: %v", err)
		buh.Errors = append(buh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
		return
	}

	desc, err := buh.Upload.Commit(buh, distribution.Descriptor{
		Digest: dgst,

		// TODO(stevvooe): This isn't wildly important yet, but we should
		// really set the length and mediatype. For now, we can let the
		// backend take care of this.
	})

	if err != nil {
		switch err := err.(type) {
		case distribution.ErrBlobInvalidDigest:
			buh.Errors = append(buh.Errors, v2.ErrorCodeDigestInvalid.WithDetail(err))
		default:
			switch err {
			case distribution.ErrBlobInvalidLength, distribution.ErrBlobDigestUnsupported:
				buh.Errors = append(buh.Errors, v2.ErrorCodeBlobUploadInvalid.WithDetail(err))
			default:
				ctxu.GetLogger(buh).Errorf("unknown error completing upload: %#v", err)
				buh.Errors = append(buh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
			}

		}

		// Clean up the backend blob data if there was an error.
		if err := buh.Upload.Cancel(buh); err != nil {
			// If the cleanup fails, all we can do is observe and report.
			ctxu.GetLogger(buh).Errorf("error canceling upload after error: %v", err)
		}

		return
	}

	// Build our canonical blob url
	blobURL, err := buh.urlBuilder.BuildBlobURL(buh.Repository.Name(), desc.Digest)
	if err != nil {
		buh.Errors = append(buh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
		return
	}

	w.Header().Set("Location", blobURL)
	w.Header().Set("Content-Length", "0")
	w.Header().Set("Docker-Content-Digest", desc.Digest.String())
	w.WriteHeader(http.StatusCreated)
}