@@ -2,6 +2,7 @@ package server
2
2
3
3
import (
4
4
"encoding/json"
5
+ "errors"
5
6
"fmt"
6
7
"path"
7
8
@@ -18,6 +19,9 @@ import (
18
19
imageapiv1 "github.com/openshift/origin/pkg/image/apis/image/v1"
19
20
)
20
21
22
+ // ErrNoManifestMetadata is an error informing about invalid manifest that lacks metadata.
23
+ var ErrNoManifestMetadata = errors .New ("no manifest metadata found" )
24
+
21
25
func unmarshalManifestSchema1 (content []byte , signatures [][]byte ) (distribution.Manifest , error ) {
22
26
// prefer signatures from the manifest
23
27
if _ , err := libtrust .ParsePrettySignature (content , "signatures" ); err == nil {
@@ -46,69 +50,97 @@ func unmarshalManifestSchema1(content []byte, signatures [][]byte) (distribution
46
50
}
47
51
48
52
type manifestSchema1Handler struct {
49
- repo * repository
50
- manifest * schema1.SignedManifest
53
+ repo * repository
54
+ manifest * schema1.SignedManifest
55
+ cachedLayers []imageapiv1.ImageLayer
51
56
}
52
57
53
58
var _ ManifestHandler = & manifestSchema1Handler {}
54
59
55
- func (h * manifestSchema1Handler ) FillImageMetadata (ctx context.Context , image * imageapiv1.Image ) error {
56
- signatures , err := h .manifest .Signatures ()
57
- if err != nil {
58
- return err
60
+ func (h * manifestSchema1Handler ) Layers (ctx context.Context ) ([]imageapiv1.ImageLayer , error ) {
61
+ if h .cachedLayers == nil {
62
+ var sizeContainer = imageapi.DockerV1CompatibilityImageSize {}
63
+
64
+ layers := make ([]imageapiv1.ImageLayer , len (h .manifest .FSLayers ))
65
+ for hi , li := 0 , len (h .manifest .FSLayers )- 1 ; hi < len (h .manifest .FSLayers ) && li >= 0 ; hi , li = hi + 1 , li - 1 {
66
+ layer := & layers [li ]
67
+ sizeContainer .Size = 0
68
+ if hi < len (h .manifest .History ) {
69
+ if err := json .Unmarshal ([]byte (h .manifest .History [hi ].V1Compatibility ), & sizeContainer ); err != nil {
70
+ sizeContainer .Size = 0
71
+ }
72
+ }
73
+ if err := h .updateLayerMetadata (ctx , layer , & h .manifest .FSLayers [hi ], sizeContainer .Size ); err != nil {
74
+ return nil , err
75
+ }
76
+ }
77
+
78
+ h .cachedLayers = layers
59
79
}
60
80
61
- for _ , signDigest := range signatures {
62
- image .DockerImageSignatures = append (image .DockerImageSignatures , signDigest )
81
+ layers := make ([]imageapiv1.ImageLayer , len (h .cachedLayers ))
82
+ for i , l := range h .cachedLayers {
83
+ layers [i ] = l
63
84
}
64
85
65
- refs := h .manifest .References ()
86
+ return layers , nil
87
+ }
66
88
67
- if err := imageMetadataFromManifest (image ); err != nil {
68
- return fmt .Errorf ("unable to fill image %s metadata: %v" , image .Name , err )
89
+ func (h * manifestSchema1Handler ) Metadata (ctx context.Context ) (* imageapi.DockerImage , error ) {
90
+ if len (h .manifest .History ) == 0 {
91
+ // should never have an empty history, but just in case...
92
+ return nil , ErrNoManifestMetadata
69
93
}
70
94
71
- blobSet := sets .NewString ()
72
- meta , ok := image .DockerImageMetadata .Object .(* imageapi.DockerImage )
73
- if ! ok {
74
- return fmt .Errorf ("image %q does not have metadata" , image .Name )
95
+ v1Metadata := imageapi.DockerV1CompatibilityImage {}
96
+ if err := json .Unmarshal ([]byte (h .manifest .History [0 ].V1Compatibility ), & v1Metadata ); err != nil {
97
+ return nil , err
75
98
}
76
- meta .Size = int64 (0 )
77
99
78
- blobs := h .repo .Blobs (ctx )
79
- for i := range image .DockerImageLayers {
80
- layer := & image .DockerImageLayers [i ]
81
- // DockerImageLayers represents h.manifest.Manifest.FSLayers in reversed order
82
- desc , err := blobs .Stat (ctx , refs [len (image .DockerImageLayers )- i - 1 ].Digest )
83
- if err != nil {
84
- context .GetLogger (ctx ).Errorf ("failed to stat blob %s of image %s" , layer .Name , image .DockerImageReference )
85
- return err
86
- }
87
- // The MediaType appeared in manifest schema v2. We need to fill it
88
- // manually in the old images if it is not already filled.
89
- if len (layer .MediaType ) == 0 {
90
- if len (desc .MediaType ) > 0 {
91
- layer .MediaType = desc .MediaType
92
- } else {
93
- layer .MediaType = schema1 .MediaTypeManifestLayer
94
- }
95
- }
96
- layer .LayerSize = desc .Size
97
- // count empty layer just once (empty layer may actually have non-zero size)
98
- if ! blobSet .Has (layer .Name ) {
99
- meta .Size += desc .Size
100
- blobSet .Insert (layer .Name )
100
+ var (
101
+ dockerImageSize int64
102
+ layerSet = sets .NewString ()
103
+ )
104
+
105
+ layers , err := h .Layers (ctx )
106
+ if err != nil {
107
+ return nil , err
108
+ }
109
+ for _ , layer := range layers {
110
+ if ! layerSet .Has (layer .Name ) {
111
+ dockerImageSize += layer .LayerSize
112
+ layerSet .Insert (layer .Name )
101
113
}
102
114
}
103
- image .DockerImageMetadata .Object = meta
104
115
105
- return nil
116
+ meta := & imageapi.DockerImage {}
117
+ meta .ID = v1Metadata .ID
118
+ meta .Parent = v1Metadata .Parent
119
+ meta .Comment = v1Metadata .Comment
120
+ meta .Created = v1Metadata .Created
121
+ meta .Container = v1Metadata .Container
122
+ meta .ContainerConfig = v1Metadata .ContainerConfig
123
+ meta .DockerVersion = v1Metadata .DockerVersion
124
+ meta .Author = v1Metadata .Author
125
+ meta .Config = v1Metadata .Config
126
+ meta .Architecture = v1Metadata .Architecture
127
+ meta .Size = dockerImageSize
128
+
129
+ return meta , nil
130
+ }
131
+
132
+ func (h * manifestSchema1Handler ) Signatures (ctx context.Context ) ([][]byte , error ) {
133
+ return h .manifest .Signatures ()
106
134
}
107
135
108
136
func (h * manifestSchema1Handler ) Manifest () distribution.Manifest {
109
137
return h .manifest
110
138
}
111
139
140
+ func (h * manifestSchema1Handler ) Config (ctx context.Context ) ([]byte , error ) {
141
+ return nil , nil
142
+ }
143
+
112
144
func (h * manifestSchema1Handler ) Payload () (mediaType string , payload []byte , canonical []byte , err error ) {
113
145
mt , payload , err := h .manifest .Payload ()
114
146
return mt , payload , h .manifest .Canonical , err
@@ -187,3 +219,25 @@ func (h *manifestSchema1Handler) Verify(ctx context.Context, skipDependencyVerif
187
219
func (h * manifestSchema1Handler ) Digest () (digest.Digest , error ) {
188
220
return digest .FromBytes (h .manifest .Canonical ), nil
189
221
}
222
+
223
+ func (h * manifestSchema1Handler ) updateLayerMetadata (
224
+ ctx context.Context ,
225
+ layerMetadata * imageapiv1.ImageLayer ,
226
+ manifestLayer * schema1.FSLayer ,
227
+ size int64 ,
228
+ ) error {
229
+ layerMetadata .Name = manifestLayer .BlobSum .String ()
230
+ layerMetadata .MediaType = schema1 .MediaTypeManifestLayer
231
+ if size > 0 {
232
+ layerMetadata .LayerSize = size
233
+ return nil
234
+ }
235
+
236
+ desc , err := h .repo .Blobs (ctx ).Stat (ctx , digest .Digest (layerMetadata .Name ))
237
+ if err != nil {
238
+ context .GetLogger (ctx ).Errorf ("failed to stat blob %s" , layerMetadata .Name )
239
+ return err
240
+ }
241
+ layerMetadata .LayerSize = desc .Size
242
+ return nil
243
+ }
0 commit comments