forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
manifeststore.go
195 lines (165 loc) · 5.65 KB
/
manifeststore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package storage
import (
"fmt"
"io"
"github.com/docker/distribution"
"github.com/docker/distribution/context"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/reference"
"github.com/docker/libtrust"
)
type manifestStore struct {
repository *repository
revisionStore *revisionStore
tagStore *tagStore
ctx context.Context
skipDependencyVerification bool
enumerateAllDigests bool
}
var _ distribution.ManifestService = &manifestStore{}
func (ms *manifestStore) Exists(dgst digest.Digest) (bool, error) {
context.GetLogger(ms.ctx).Debug("(*manifestStore).Exists")
_, err := ms.revisionStore.blobStore.Stat(ms.ctx, dgst)
if err != nil {
if err == distribution.ErrBlobUnknown {
return false, nil
}
return false, err
}
return true, nil
}
func (ms *manifestStore) Get(dgst digest.Digest) (*schema1.SignedManifest, error) {
context.GetLogger(ms.ctx).Debug("(*manifestStore).Get")
return ms.revisionStore.get(ms.ctx, dgst)
}
// SkipLayerVerification allows a manifest to be Put before it's
// layers are on the filesystem
func SkipLayerVerification(ms distribution.ManifestService) error {
if ms, ok := ms.(*manifestStore); ok {
ms.skipDependencyVerification = true
return nil
}
return fmt.Errorf("skip layer verification only valid for manifestStore")
}
// EnumerateAllDigests causes Enumerate method to include all the digests found
// without checking whether they exist and belong to manifest revisions or not.
func EnumerateAllDigests(ms distribution.ManifestService) error {
if ms, ok := ms.(*manifestStore); ok {
ms.enumerateAllDigests = true
return nil
}
return fmt.Errorf("enumerate all digests only valid for manifeststore")
}
func (ms *manifestStore) Put(manifest *schema1.SignedManifest) error {
context.GetLogger(ms.ctx).Debug("(*manifestStore).Put")
if err := ms.verifyManifest(ms.ctx, manifest); err != nil {
return err
}
// Store the revision of the manifest
revision, err := ms.revisionStore.put(ms.ctx, manifest)
if err != nil {
return err
}
// Now, tag the manifest
return ms.tagStore.tag(manifest.Tag, revision.Digest)
}
// Delete removes the revision of the specified manfiest.
func (ms *manifestStore) Delete(dgst digest.Digest) error {
context.GetLogger(ms.ctx).Debug("(*manifestStore).Delete")
return ms.revisionStore.delete(ms.ctx, dgst)
}
func (ms *manifestStore) Tags() ([]string, error) {
context.GetLogger(ms.ctx).Debug("(*manifestStore).Tags")
return ms.tagStore.tags()
}
func (ms *manifestStore) ExistsByTag(tag string) (bool, error) {
context.GetLogger(ms.ctx).Debug("(*manifestStore).ExistsByTag")
return ms.tagStore.exists(tag)
}
func (ms *manifestStore) GetByTag(tag string, options ...distribution.ManifestServiceOption) (*schema1.SignedManifest, error) {
for _, option := range options {
err := option(ms)
if err != nil {
return nil, err
}
}
context.GetLogger(ms.ctx).Debug("(*manifestStore).GetByTag")
dgst, err := ms.tagStore.resolve(tag)
if err != nil {
return nil, err
}
return ms.revisionStore.get(ms.ctx, dgst)
}
// Enumerate retuns an array of digests of all manifest revisions in repository.
// Returned digests may not be resolvable to actual data.
func (ms *manifestStore) Enumerate() ([]digest.Digest, error) {
context.GetLogger(ms.ctx).Debug("(*manifestStore).Enumerate")
dgsts, err := ms.revisionStore.enumerate()
if err != nil && err != io.EOF {
return nil, err
}
if ms.enumerateAllDigests {
return dgsts, nil
}
res := make([]digest.Digest, 0, len(dgsts))
for _, dgst := range dgsts {
if _, err := ms.Get(dgst); err == nil {
res = append(res, dgst)
}
}
return res, nil
}
// verifyManifest ensures that the manifest content is valid from the
// perspective of the registry. It ensures that the signature is valid for the
// enclosed payload. As a policy, the registry only tries to store valid
// content, leaving trust policies of that content up to consumers.
func (ms *manifestStore) verifyManifest(ctx context.Context, mnfst *schema1.SignedManifest) error {
var errs distribution.ErrManifestVerification
if len(mnfst.Name) > reference.NameTotalLengthMax {
errs = append(errs,
distribution.ErrManifestNameInvalid{
Name: mnfst.Name,
Reason: fmt.Errorf("manifest name must not be more than %v characters", reference.NameTotalLengthMax),
})
}
if !reference.NameRegexp.MatchString(mnfst.Name) {
errs = append(errs,
distribution.ErrManifestNameInvalid{
Name: mnfst.Name,
Reason: fmt.Errorf("invalid manifest name format"),
})
}
if len(mnfst.History) != len(mnfst.FSLayers) {
errs = append(errs, fmt.Errorf("mismatched history and fslayer cardinality %d != %d",
len(mnfst.History), len(mnfst.FSLayers)))
}
if _, err := schema1.Verify(mnfst); err != nil {
switch err {
case libtrust.ErrMissingSignatureKey, libtrust.ErrInvalidJSONContent, libtrust.ErrMissingSignatureKey:
errs = append(errs, distribution.ErrManifestUnverified{})
default:
if err.Error() == "invalid signature" { // TODO(stevvooe): This should be exported by libtrust
errs = append(errs, distribution.ErrManifestUnverified{})
} else {
errs = append(errs, err)
}
}
}
if !ms.skipDependencyVerification {
for _, fsLayer := range mnfst.FSLayers {
_, err := ms.repository.Blobs(ctx).Stat(ctx, fsLayer.BlobSum)
if err != nil {
if err != distribution.ErrBlobUnknown {
errs = append(errs, err)
}
// On error here, we always append unknown blob errors.
errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: fsLayer.BlobSum})
}
}
}
if len(errs) != 0 {
return errs
}
return nil
}