1 package storage
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7
8 "github.com/docker/distribution"
9 dcontext "github.com/docker/distribution/context"
10 "github.com/docker/distribution/manifest"
11 "github.com/docker/distribution/manifest/manifestlist"
12 "github.com/docker/distribution/manifest/ocischema"
13 "github.com/docker/distribution/manifest/schema1"
14 "github.com/docker/distribution/manifest/schema2"
15 "github.com/opencontainers/go-digest"
16 v1 "github.com/opencontainers/image-spec/specs-go/v1"
17 )
18
19
20 type ManifestHandler interface {
21
22 Unmarshal(ctx context.Context, dgst digest.Digest, content []byte) (distribution.Manifest, error)
23
24
25 Put(ctx context.Context, manifest distribution.Manifest, skipDependencyVerification bool) (digest.Digest, error)
26 }
27
28
29
30 func SkipLayerVerification() distribution.ManifestServiceOption {
31 return skipLayerOption{}
32 }
33
34 type skipLayerOption struct{}
35
36 func (o skipLayerOption) Apply(m distribution.ManifestService) error {
37 if ms, ok := m.(*manifestStore); ok {
38 ms.skipDependencyVerification = true
39 return nil
40 }
41 return fmt.Errorf("skip layer verification only valid for manifestStore")
42 }
43
44 type manifestStore struct {
45 repository *repository
46 blobStore *linkedBlobStore
47 ctx context.Context
48
49 skipDependencyVerification bool
50
51 schema1Handler ManifestHandler
52 schema2Handler ManifestHandler
53 ocischemaHandler ManifestHandler
54 manifestListHandler ManifestHandler
55 }
56
57 var _ distribution.ManifestService = &manifestStore{}
58
59 func (ms *manifestStore) Exists(ctx context.Context, dgst digest.Digest) (bool, error) {
60 dcontext.GetLogger(ms.ctx).Debug("(*manifestStore).Exists")
61
62 _, err := ms.blobStore.Stat(ms.ctx, dgst)
63 if err != nil {
64 if err == distribution.ErrBlobUnknown {
65 return false, nil
66 }
67
68 return false, err
69 }
70
71 return true, nil
72 }
73
74 func (ms *manifestStore) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
75 dcontext.GetLogger(ms.ctx).Debug("(*manifestStore).Get")
76
77
78
79
80 content, err := ms.blobStore.Get(ctx, dgst)
81 if err != nil {
82 if err == distribution.ErrBlobUnknown {
83 return nil, distribution.ErrManifestUnknownRevision{
84 Name: ms.repository.Named().Name(),
85 Revision: dgst,
86 }
87 }
88
89 return nil, err
90 }
91
92 var versioned manifest.Versioned
93 if err = json.Unmarshal(content, &versioned); err != nil {
94 return nil, err
95 }
96
97 switch versioned.SchemaVersion {
98 case 1:
99 return ms.schema1Handler.Unmarshal(ctx, dgst, content)
100 case 2:
101
102 switch versioned.MediaType {
103 case schema2.MediaTypeManifest:
104 return ms.schema2Handler.Unmarshal(ctx, dgst, content)
105 case v1.MediaTypeImageManifest:
106 return ms.ocischemaHandler.Unmarshal(ctx, dgst, content)
107 case manifestlist.MediaTypeManifestList, v1.MediaTypeImageIndex:
108 return ms.manifestListHandler.Unmarshal(ctx, dgst, content)
109 case "":
110
111
112
113 res, err := ms.manifestListHandler.Unmarshal(ctx, dgst, content)
114 resIndex := res.(*manifestlist.DeserializedManifestList)
115 if err == nil && resIndex.Manifests != nil {
116 return resIndex, nil
117 }
118
119
120 return ms.ocischemaHandler.Unmarshal(ctx, dgst, content)
121 default:
122 return nil, distribution.ErrManifestVerification{fmt.Errorf("unrecognized manifest content type %s", versioned.MediaType)}
123 }
124 }
125
126 return nil, fmt.Errorf("unrecognized manifest schema version %d", versioned.SchemaVersion)
127 }
128
129 func (ms *manifestStore) Put(ctx context.Context, manifest distribution.Manifest, options ...distribution.ManifestServiceOption) (digest.Digest, error) {
130 dcontext.GetLogger(ms.ctx).Debug("(*manifestStore).Put")
131
132 switch manifest.(type) {
133 case *schema1.SignedManifest:
134 return ms.schema1Handler.Put(ctx, manifest, ms.skipDependencyVerification)
135 case *schema2.DeserializedManifest:
136 return ms.schema2Handler.Put(ctx, manifest, ms.skipDependencyVerification)
137 case *ocischema.DeserializedManifest:
138 return ms.ocischemaHandler.Put(ctx, manifest, ms.skipDependencyVerification)
139 case *manifestlist.DeserializedManifestList:
140 return ms.manifestListHandler.Put(ctx, manifest, ms.skipDependencyVerification)
141 }
142
143 return "", fmt.Errorf("unrecognized manifest type %T", manifest)
144 }
145
146
147 func (ms *manifestStore) Delete(ctx context.Context, dgst digest.Digest) error {
148 dcontext.GetLogger(ms.ctx).Debug("(*manifestStore).Delete")
149 return ms.blobStore.Delete(ctx, dgst)
150 }
151
152 func (ms *manifestStore) Enumerate(ctx context.Context, ingester func(digest.Digest) error) error {
153 err := ms.blobStore.Enumerate(ctx, func(dgst digest.Digest) error {
154 err := ingester(dgst)
155 if err != nil {
156 return err
157 }
158 return nil
159 })
160 return err
161 }
162
View as plain text