@@ -11,23 +11,20 @@ import (
11
11
"github.com/golang/glog"
12
12
godigest "github.com/opencontainers/go-digest"
13
13
14
+ imagev1 "github.com/openshift/api/image/v1"
14
15
imageapi "github.com/openshift/origin/pkg/image/apis/image"
15
16
"github.com/openshift/origin/pkg/image/apis/image/docker10"
16
17
)
17
18
18
- func fillImageLayers (image * imageapi.Image , manifest docker10.DockerImageManifest ) error {
19
- if len (image .DockerImageLayers ) != 0 {
20
- // DockerImageLayers is already filled by the registry.
21
- return nil
22
- }
23
-
19
+ func getImageLayers (manifest docker10.DockerImageManifest ) ([]imageapi.ImageLayer , error ) {
20
+ var imageLayers []imageapi.ImageLayer
24
21
switch manifest .SchemaVersion {
25
22
case 1 :
26
23
if len (manifest .History ) != len (manifest .FSLayers ) {
27
- return fmt .Errorf ("the image %s (%s) has mismatched history and fslayer cardinality (%d != %d)" , image . Name , image . DockerImageReference , len (manifest .History ), len (manifest .FSLayers ))
24
+ return nil , fmt .Errorf ("mismatched history and fslayer cardinality (%d != %d)" , len (manifest .History ), len (manifest .FSLayers ))
28
25
}
29
26
30
- image . DockerImageLayers = make ([]imageapi.ImageLayer , len (manifest .FSLayers ))
27
+ imageLayers = make ([]imageapi.ImageLayer , len (manifest .FSLayers ))
31
28
for i , obj := range manifest .History {
32
29
layer := manifest .FSLayers [i ]
33
30
@@ -42,29 +39,80 @@ func fillImageLayers(image *imageapi.Image, manifest docker10.DockerImageManifes
42
39
// in order from the oldest to the youngest.
43
40
revidx := (len (manifest .History ) - 1 ) - i // n-1, n-2, ..., 1, 0
44
41
45
- image . DockerImageLayers [revidx ].Name = layer .DockerBlobSum
46
- image . DockerImageLayers [revidx ].LayerSize = size .Size
47
- image . DockerImageLayers [revidx ].MediaType = schema1 .MediaTypeManifestLayer
42
+ imageLayers [revidx ].Name = layer .DockerBlobSum
43
+ imageLayers [revidx ].LayerSize = size .Size
44
+ imageLayers [revidx ].MediaType = schema1 .MediaTypeManifestLayer
48
45
}
49
46
case 2 :
50
47
// The layer list is ordered starting from the base image (opposite order of schema1).
51
48
// So, we do not need to change the order of layers.
52
- image . DockerImageLayers = make ([]imageapi.ImageLayer , len (manifest .Layers ))
49
+ imageLayers = make ([]imageapi.ImageLayer , len (manifest .Layers ))
53
50
for i , layer := range manifest .Layers {
54
- image . DockerImageLayers [i ].Name = layer .Digest
55
- image . DockerImageLayers [i ].LayerSize = layer .Size
56
- image . DockerImageLayers [i ].MediaType = layer .MediaType
51
+ imageLayers [i ].Name = layer .Digest
52
+ imageLayers [i ].LayerSize = layer .Size
53
+ imageLayers [i ].MediaType = layer .MediaType
57
54
}
58
55
default :
59
- return fmt .Errorf ("unrecognized Docker image manifest schema %d for %q (%s) " , manifest .SchemaVersion , image . Name , image . DockerImageReference )
56
+ return nil , fmt .Errorf ("unrecognized Docker image manifest schema %d" , manifest .SchemaVersion )
60
57
}
61
58
62
- if image .Annotations == nil {
63
- image .Annotations = map [string ]string {}
59
+ return imageLayers , nil
60
+ }
61
+
62
+ // reorderImageLayers mutates the given image. It reorders the layers in ascending order.
63
+ // Ascending order matches the order of layers in schema 2. Schema 1 has reversed (descending) order of layers.
64
+ func reorderImageLayers (imageLayers []imageapi.ImageLayer , layersOrder , imageManifestMediaType string ) bool {
65
+ if imageLayers == nil || len (imageLayers ) == 0 {
66
+ return false
64
67
}
65
- image .Annotations [imageapi .DockerImageLayersOrderAnnotation ] = imageapi .DockerImageLayersOrderAscending
66
68
67
- return nil
69
+ if layersOrder == "" {
70
+ switch imageManifestMediaType {
71
+ case schema1 .MediaTypeManifest , schema1 .MediaTypeSignedManifest :
72
+ layersOrder = imageapi .DockerImageLayersOrderAscending
73
+ case schema2 .MediaTypeManifest :
74
+ layersOrder = imageapi .DockerImageLayersOrderDescending
75
+ default :
76
+ return false
77
+ }
78
+ }
79
+
80
+ if layersOrder == imageapi .DockerImageLayersOrderDescending {
81
+ // reverse order of the layers (lowest = 0, highest = i)
82
+ for i , j := 0 , len (imageLayers )- 1 ; i < j ; i , j = i + 1 , j - 1 {
83
+ imageLayers [i ], imageLayers [j ] = imageLayers [j ], imageLayers [i ]
84
+ }
85
+ }
86
+
87
+ return true
88
+ }
89
+
90
+ func convertImageLayers (imageLayers []imagev1.ImageLayer ) []imageapi.ImageLayer {
91
+ if imageLayers == nil {
92
+ return nil
93
+ }
94
+
95
+ result := make ([]imageapi.ImageLayer , len (imageLayers ))
96
+ for i := range imageLayers {
97
+ result [i ].MediaType = imageLayers [i ].MediaType
98
+ result [i ].Name = imageLayers [i ].Name
99
+ result [i ].LayerSize = imageLayers [i ].LayerSize
100
+ }
101
+ return result
102
+ }
103
+
104
+ func GetImageMetadata (image * imagev1.Image ) (imageapi.DockerImage , error ) {
105
+ if len (image .DockerImageManifest ) == 0 {
106
+ return imageapi.DockerImage {}, nil
107
+ }
108
+
109
+ imageLayers := convertImageLayers (image .DockerImageLayers )
110
+ reorderImageLayers (imageLayers , image .Annotations [imageapi .DockerImageLayersOrderAnnotation ], image .DockerImageManifestMediaType )
111
+
112
+ _ , imageMetadata , _ , _ , err := getImageMetadata (image .Name , image .DockerImageReference ,
113
+ image .DockerImageManifest , image .DockerImageConfig , imageLayers )
114
+ return imageMetadata , err
115
+
68
116
}
69
117
70
118
// ImageWithMetadata mutates the given image. It parses raw DockerImageManifest data stored in the image and
@@ -74,110 +122,109 @@ func ImageWithMetadata(image *imageapi.Image) error {
74
122
return nil
75
123
}
76
124
77
- ReorderImageLayers (image )
125
+ if ok := reorderImageLayers (image .DockerImageLayers ,
126
+ image .Annotations [imageapi .DockerImageLayersOrderAnnotation ], image .DockerImageManifestMediaType ); ok {
127
+ if image .Annotations == nil {
128
+ image .Annotations = map [string ]string {}
129
+ }
130
+ image .Annotations [imageapi .DockerImageLayersOrderAnnotation ] = imageapi .DockerImageLayersOrderAscending
131
+ }
78
132
79
133
if len (image .DockerImageLayers ) > 0 && image .DockerImageMetadata .Size > 0 && len (image .DockerImageManifestMediaType ) > 0 {
80
134
glog .V (5 ).Infof ("Image metadata already filled for %s" , image .Name )
81
135
return nil
82
136
}
137
+ imageManifestMediaType , imageMetadata , imageLayers , orderAscending , err := getImageMetadata (image .Name , image .DockerImageReference ,
138
+ image .DockerImageManifest , image .DockerImageConfig , image .DockerImageLayers )
139
+ if err != nil {
140
+ return err
141
+ }
142
+ image .DockerImageManifestMediaType = imageManifestMediaType
143
+ image .DockerImageMetadata = imageMetadata
144
+ image .DockerImageLayers = imageLayers
145
+ if orderAscending {
146
+ if image .Annotations == nil {
147
+ image .Annotations = map [string ]string {}
148
+ }
149
+ image .Annotations [imageapi .DockerImageLayersOrderAnnotation ] = imageapi .DockerImageLayersOrderAscending
150
+ }
83
151
152
+ return nil
153
+ }
154
+
155
+ func getImageMetadata (imageName , imageReference , imageManifest , imageConfig string ,
156
+ imageLayers []imageapi.ImageLayer ) (string , imageapi.DockerImage , []imageapi.ImageLayer , bool , error ) {
84
157
manifest := docker10.DockerImageManifest {}
85
- if err := json .Unmarshal ([]byte (image . DockerImageManifest ), & manifest ); err != nil {
86
- return err
158
+ if err := json .Unmarshal ([]byte (imageManifest ), & manifest ); err != nil {
159
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , err
87
160
}
88
161
89
- err := fillImageLayers (image , manifest )
90
- if err != nil {
91
- return err
162
+ var err error
163
+ var orderAscending bool
164
+ if len (imageLayers ) == 0 {
165
+ imageLayers , err = getImageLayers (manifest )
166
+ if err != nil {
167
+ return "" , imageapi.DockerImage {}, []imageapi.ImageLayer {}, false , fmt .Errorf ("the image %s (%s) failed reading layers: %v" , imageName , imageReference , err )
168
+ }
169
+ orderAscending = true
92
170
}
93
171
172
+ var imageManifestMediaType string
173
+ var imageMetadata imageapi.DockerImage
94
174
switch manifest .SchemaVersion {
95
175
case 1 :
96
- image . DockerImageManifestMediaType = schema1 .MediaTypeManifest
176
+ imageManifestMediaType = schema1 .MediaTypeManifest
97
177
98
178
if len (manifest .History ) == 0 {
99
179
// It should never have an empty history, but just in case.
100
- return fmt .Errorf ("the image %s (%s) has a schema 1 manifest, but it doesn't have history" , image . Name , image . DockerImageReference )
180
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , fmt .Errorf ("the image %s (%s) has a schema 1 manifest, but it doesn't have history" , imageName , imageReference )
101
181
}
102
182
103
183
v1Metadata := docker10.DockerV1CompatibilityImage {}
104
184
if err := json .Unmarshal ([]byte (manifest .History [0 ].DockerV1Compatibility ), & v1Metadata ); err != nil {
105
- return err
185
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , err
106
186
}
107
187
108
- if err := imageapi .Convert_compatibility_to_api_DockerImage (& v1Metadata , & image . DockerImageMetadata ); err != nil {
109
- return err
188
+ if err := imageapi .Convert_compatibility_to_api_DockerImage (& v1Metadata , & imageMetadata ); err != nil {
189
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , err
110
190
}
111
191
case 2 :
112
- image . DockerImageManifestMediaType = schema2 .MediaTypeManifest
192
+ imageManifestMediaType = schema2 .MediaTypeManifest
113
193
114
- if len (image . DockerImageConfig ) == 0 {
115
- return fmt .Errorf ("dockerImageConfig must not be empty for manifest schema 2" )
194
+ if len (imageConfig ) == 0 {
195
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , fmt .Errorf ("dockerImageConfig must not be empty for manifest schema 2" )
116
196
}
117
197
118
198
config := docker10.DockerImageConfig {}
119
- if err := json .Unmarshal ([]byte (image . DockerImageConfig ), & config ); err != nil {
120
- return fmt .Errorf ("failed to parse dockerImageConfig: %v" , err )
199
+ if err := json .Unmarshal ([]byte (imageConfig ), & config ); err != nil {
200
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , fmt .Errorf ("failed to parse dockerImageConfig: %v" , err )
121
201
}
122
202
123
- if err := imageapi .Convert_imageconfig_to_api_DockerImage (& config , & image . DockerImageMetadata ); err != nil {
124
- return err
203
+ if err := imageapi .Convert_imageconfig_to_api_DockerImage (& config , & imageMetadata ); err != nil {
204
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , err
125
205
}
126
- image . DockerImageMetadata .ID = manifest .Config .Digest
206
+ imageMetadata .ID = manifest .Config .Digest
127
207
128
208
default :
129
- return fmt .Errorf ("unrecognized Docker image manifest schema %d for %q (%s)" , manifest .SchemaVersion , image . Name , image . DockerImageReference )
209
+ return "" , imageapi. DockerImage {}, []imageapi. ImageLayer {}, false , fmt .Errorf ("unrecognized Docker image manifest schema %d for %q (%s)" , manifest .SchemaVersion , imageName , imageReference )
130
210
}
131
211
132
212
layerSet := sets .NewString ()
133
213
if manifest .SchemaVersion == 2 {
134
214
layerSet .Insert (manifest .Config .Digest )
135
- image . DockerImageMetadata . Size = int64 (len (image . DockerImageConfig ))
215
+ imageMetadata . Size = int64 (len (imageConfig ))
136
216
} else {
137
- image . DockerImageMetadata .Size = 0
217
+ imageMetadata .Size = 0
138
218
}
139
- for _ , layer := range image . DockerImageLayers {
219
+ for _ , layer := range imageLayers {
140
220
if layerSet .Has (layer .Name ) {
141
221
continue
142
222
}
143
223
layerSet .Insert (layer .Name )
144
- image .DockerImageMetadata .Size += layer .LayerSize
145
- }
146
-
147
- return nil
148
- }
149
-
150
- // ReorderImageLayers mutates the given image. It reorders the layers in ascending order.
151
- // Ascending order matches the order of layers in schema 2. Schema 1 has reversed (descending) order of layers.
152
- func ReorderImageLayers (image * imageapi.Image ) {
153
- if len (image .DockerImageLayers ) == 0 {
154
- return
155
- }
156
-
157
- layersOrder , ok := image .Annotations [imageapi .DockerImageLayersOrderAnnotation ]
158
- if ! ok {
159
- switch image .DockerImageManifestMediaType {
160
- case schema1 .MediaTypeManifest , schema1 .MediaTypeSignedManifest :
161
- layersOrder = imageapi .DockerImageLayersOrderAscending
162
- case schema2 .MediaTypeManifest :
163
- layersOrder = imageapi .DockerImageLayersOrderDescending
164
- default :
165
- return
166
- }
167
- }
168
-
169
- if layersOrder == imageapi .DockerImageLayersOrderDescending {
170
- // reverse order of the layers (lowest = 0, highest = i)
171
- for i , j := 0 , len (image .DockerImageLayers )- 1 ; i < j ; i , j = i + 1 , j - 1 {
172
- image .DockerImageLayers [i ], image .DockerImageLayers [j ] = image .DockerImageLayers [j ], image .DockerImageLayers [i ]
173
- }
174
- }
175
-
176
- if image .Annotations == nil {
177
- image .Annotations = map [string ]string {}
224
+ imageMetadata .Size += layer .LayerSize
178
225
}
179
226
180
- image . Annotations [ imageapi . DockerImageLayersOrderAnnotation ] = imageapi . DockerImageLayersOrderAscending
227
+ return imageManifestMediaType , imageMetadata , imageLayers , orderAscending , nil
181
228
}
182
229
183
230
// ManifestMatchesImage returns true if the provided manifest matches the name of the image.
0 commit comments