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 }