@@ -53,56 +53,75 @@ type manifestSchema1Handler struct {
53
53
var _ ManifestHandler = & manifestSchema1Handler {}
54
54
55
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
56
+ // If we already have metadata don't mutate existing metadata.
57
+ meta , ok := image .DockerImageMetadata .Object .(* imageapi.DockerImage )
58
+ hasMetadata := ok && meta .Size > 0
59
+ if len (image .DockerImageLayers ) > 0 && hasMetadata && len (image .DockerImageManifestMediaType ) > 0 {
60
+ return nil
59
61
}
60
62
61
- for _ , signDigest := range signatures {
62
- image .DockerImageSignatures = append (image .DockerImageSignatures , signDigest )
63
+ manifestData := image .DockerImageManifest
64
+ manifest := imageapi.DockerImageManifest {}
65
+ if err := json .Unmarshal ([]byte (manifestData ), & manifest ); err != nil {
66
+ return err
63
67
}
64
68
65
- refs := h . manifest . References ()
69
+ image . DockerImageManifestMediaType = schema1 . MediaTypeManifest
66
70
67
- if err := imageMetadataFromManifest (image ); err != nil {
68
- return fmt .Errorf ("unable to fill image %s metadata: %v" , image .Name , err )
71
+ if len (manifest .History ) == 0 {
72
+ // should never have an empty history, but just in case...
73
+ return nil
69
74
}
70
75
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 )
76
+ v1Metadata := imageapi.DockerV1CompatibilityImage {}
77
+ if err := json .Unmarshal ([]byte (manifest .History [0 ].DockerV1Compatibility ), & v1Metadata ); err != nil {
78
+ return err
75
79
}
76
- meta .Size = int64 (0 )
77
80
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
81
+ var (
82
+ dockerImageSize int64
83
+ err error
84
+ layerSet = sets .NewString ()
85
+ sizeContainer = imageapi.DockerV1CompatibilityImageSize {}
86
+ )
87
+
88
+ image .DockerImageLayers = make ([]imageapiv1.ImageLayer , len (manifest .FSLayers ))
89
+ for hi , li := 0 , len (manifest .FSLayers )- 1 ; hi < len (manifest .FSLayers ) && li >= 0 ; hi , li = hi + 1 , li - 1 {
90
+ layer := & image .DockerImageLayers [li ]
91
+ if hi == 0 { // the first item in history is v1Metadata
92
+ err = h .updateLayerMetadata (ctx , layer , & manifest .FSLayers [hi ], v1Metadata .Size )
93
+ } else {
94
+ sizeContainer .Size = 0
95
+ if hi < len (manifest .History ) {
96
+ if err := json .Unmarshal ([]byte (manifest .History [hi ].DockerV1Compatibility ), & sizeContainer ); err != nil {
97
+ sizeContainer .Size = 0
98
+ }
94
99
}
100
+ err = h .updateLayerMetadata (ctx , layer , & manifest .FSLayers [hi ], sizeContainer .Size )
95
101
}
96
- layer .LayerSize = desc .Size
102
+ if err != nil {
103
+ return fmt .Errorf ("failed to update layer metadata of image %s: %v" , image .DockerImageReference , err )
104
+ }
105
+
97
106
// 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 )
107
+ if ! layerSet .Has (layer .Name ) {
108
+ dockerImageSize += layer . LayerSize
109
+ layerSet .Insert (layer .Name )
101
110
}
102
111
}
103
- image .DockerImageMetadata .Object = meta
104
112
105
- return nil
113
+ signatures , err := h .manifest .Signatures ()
114
+ if err != nil {
115
+ return err
116
+ }
117
+
118
+ for _ , signDigest := range signatures {
119
+ image .DockerImageSignatures = append (image .DockerImageSignatures , signDigest )
120
+ }
121
+
122
+ image .DockerImageMetadata .Object = v1ToDockerImageMetadata (& v1Metadata , "" , dockerImageSize )
123
+
124
+ return encodeRawDockerImageMetadata (image , true )
106
125
}
107
126
108
127
func (h * manifestSchema1Handler ) Manifest () distribution.Manifest {
@@ -187,3 +206,20 @@ func (h *manifestSchema1Handler) Verify(ctx context.Context, skipDependencyVerif
187
206
func (h * manifestSchema1Handler ) Digest () (digest.Digest , error ) {
188
207
return digest .FromBytes (h .manifest .Canonical ), nil
189
208
}
209
+
210
+ func (h * manifestSchema1Handler ) updateLayerMetadata (ctx context.Context , layer * imageapiv1.ImageLayer , manifestLayer * imageapi.DockerFSLayer , size int64 ) error {
211
+ layer .Name = manifestLayer .DockerBlobSum
212
+ layer .MediaType = schema1 .MediaTypeManifestLayer
213
+ if size > 0 {
214
+ layer .LayerSize = size
215
+ return nil
216
+ }
217
+
218
+ desc , err := h .repo .Blobs (ctx ).Stat (ctx , digest .Digest (layer .Name ))
219
+ if err != nil {
220
+ context .GetLogger (ctx ).Errorf ("failed to stat blob %s" , layer .Name )
221
+ return err
222
+ }
223
+ layer .LayerSize = desc .Size
224
+ return nil
225
+ }
0 commit comments