github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/storage/signaturestore.go (about)

     1  package storage
     2  
     3  import (
     4  	"path"
     5  	"sync"
     6  
     7  	"github.com/docker/distribution/context"
     8  	"github.com/docker/distribution/digest"
     9  )
    10  
    11  type signatureStore struct {
    12  	repository *repository
    13  	blobStore  *blobStore
    14  	ctx        context.Context
    15  }
    16  
    17  func (s *signatureStore) Get(dgst digest.Digest) ([][]byte, error) {
    18  	signaturesPath, err := pathFor(manifestSignaturesPathSpec{
    19  		name:     s.repository.Name(),
    20  		revision: dgst,
    21  	})
    22  
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	// Need to append signature digest algorithm to path to get all items.
    28  	// Perhaps, this should be in the pathMapper but it feels awkward. This
    29  	// can be eliminated by implementing listAll on drivers.
    30  	signaturesPath = path.Join(signaturesPath, "sha256")
    31  
    32  	signaturePaths, err := s.blobStore.driver.List(s.ctx, signaturesPath)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	var wg sync.WaitGroup
    38  	type result struct {
    39  		index     int
    40  		signature []byte
    41  		err       error
    42  	}
    43  	ch := make(chan result)
    44  
    45  	bs := s.linkedBlobStore(s.ctx, dgst)
    46  	for i, sigPath := range signaturePaths {
    47  		sigdgst, err := digest.ParseDigest("sha256:" + path.Base(sigPath))
    48  		if err != nil {
    49  			context.GetLogger(s.ctx).Errorf("could not get digest from path: %q, skipping", sigPath)
    50  			continue
    51  		}
    52  
    53  		wg.Add(1)
    54  		go func(idx int, sigdgst digest.Digest) {
    55  			defer wg.Done()
    56  			context.GetLogger(s.ctx).
    57  				Debugf("fetching signature %q", sigdgst)
    58  
    59  			r := result{index: idx}
    60  
    61  			if p, err := bs.Get(s.ctx, sigdgst); err != nil {
    62  				context.GetLogger(s.ctx).
    63  					Errorf("error fetching signature %q: %v", sigdgst, err)
    64  				r.err = err
    65  			} else {
    66  				r.signature = p
    67  			}
    68  
    69  			ch <- r
    70  		}(i, sigdgst)
    71  	}
    72  	done := make(chan struct{})
    73  	go func() {
    74  		wg.Wait()
    75  		close(done)
    76  	}()
    77  
    78  	// aggregrate the results
    79  	signatures := make([][]byte, len(signaturePaths))
    80  loop:
    81  	for {
    82  		select {
    83  		case result := <-ch:
    84  			signatures[result.index] = result.signature
    85  			if result.err != nil && err == nil {
    86  				// only set the first one.
    87  				err = result.err
    88  			}
    89  		case <-done:
    90  			break loop
    91  		}
    92  	}
    93  
    94  	return signatures, err
    95  }
    96  
    97  func (s *signatureStore) Put(dgst digest.Digest, signatures ...[]byte) error {
    98  	bs := s.linkedBlobStore(s.ctx, dgst)
    99  	for _, signature := range signatures {
   100  		if _, err := bs.Put(s.ctx, "application/json", signature); err != nil {
   101  			return err
   102  		}
   103  	}
   104  	return nil
   105  }
   106  
   107  // linkedBlobStore returns the namedBlobStore of the signatures for the
   108  // manifest with the given digest. Effectively, each signature link path
   109  // layout is a unique linked blob store.
   110  func (s *signatureStore) linkedBlobStore(ctx context.Context, revision digest.Digest) *linkedBlobStore {
   111  	linkpath := func(name string, dgst digest.Digest) (string, error) {
   112  		return pathFor(manifestSignatureLinkPathSpec{
   113  			name:      name,
   114  			revision:  revision,
   115  			signature: dgst,
   116  		})
   117  
   118  	}
   119  
   120  	return &linkedBlobStore{
   121  		ctx:        ctx,
   122  		repository: s.repository,
   123  		blobStore:  s.blobStore,
   124  		blobAccessController: &linkedBlobStatter{
   125  			blobStore:   s.blobStore,
   126  			repository:  s.repository,
   127  			linkPathFns: []linkPathFunc{linkpath},
   128  		},
   129  		linkPathFns: []linkPathFunc{linkpath},
   130  	}
   131  }