9
9
"io/ioutil"
10
10
"net/http"
11
11
"os"
12
- "regexp"
13
- "runtime"
14
12
"strconv"
15
13
"time"
16
14
@@ -20,8 +18,6 @@ import (
20
18
21
19
"github.com/docker/distribution"
22
20
distributioncontext "github.com/docker/distribution/context"
23
- "github.com/docker/distribution/manifest/manifestlist"
24
- "github.com/docker/distribution/manifest/schema1"
25
21
"github.com/docker/distribution/manifest/schema2"
26
22
"github.com/docker/distribution/reference"
27
23
"github.com/docker/distribution/registry/client"
@@ -38,6 +34,8 @@ import (
38
34
"github.com/openshift/origin/pkg/image/dockerlayer/add"
39
35
"github.com/openshift/origin/pkg/image/registryclient"
40
36
"github.com/openshift/origin/pkg/image/registryclient/dockercredentials"
37
+ imagemanifest "github.com/openshift/origin/pkg/oc/cli/image/manifest"
38
+ "github.com/openshift/origin/pkg/oc/cli/image/workqueue"
41
39
)
42
40
43
41
var (
@@ -86,10 +84,7 @@ type AppendImageOptions struct {
86
84
DropHistory bool
87
85
CreatedAt string
88
86
89
- OSFilter * regexp.Regexp
90
- DefaultOSFilter bool
91
-
92
- FilterByOS string
87
+ FilterOptions imagemanifest.FilterOptions
93
88
94
89
MaxPerRegistry int
95
90
@@ -100,12 +95,6 @@ type AppendImageOptions struct {
100
95
genericclioptions.IOStreams
101
96
}
102
97
103
- // schema2ManifestOnly specifically requests a manifest list first
104
- var schema2ManifestOnly = distribution .WithManifestMediaTypes ([]string {
105
- manifestlist .MediaTypeManifestList ,
106
- schema2 .MediaTypeManifest ,
107
- })
108
-
109
98
func NewAppendImageOptions (streams genericclioptions.IOStreams ) * AppendImageOptions {
110
99
return & AppendImageOptions {
111
100
IOStreams : streams ,
@@ -129,9 +118,10 @@ func NewCmdAppendImage(name string, streams genericclioptions.IOStreams) *cobra.
129
118
}
130
119
131
120
flag := cmd .Flags ()
121
+ o .FilterOptions .Bind (flag )
122
+
132
123
flag .BoolVar (& o .DryRun , "dry-run" , o .DryRun , "Print the actions that would be taken and exit without writing to the destination." )
133
124
flag .BoolVar (& o .Insecure , "insecure" , o .Insecure , "Allow push and pull operations to registries to be made over HTTP" )
134
- flag .StringVar (& o .FilterByOS , "filter-by-os" , o .FilterByOS , "A regular expression to control which images are mirrored. Images will be passed as '<platform>/<architecture>[/<variant>]'." )
135
125
136
126
flag .StringVar (& o .From , "from" , o .From , "The image to use as a base. If empty, a new scratch image is created." )
137
127
flag .StringVar (& o .To , "to" , o .To , "The Docker repository tag to upload the appended image to." )
@@ -148,17 +138,8 @@ func NewCmdAppendImage(name string, streams genericclioptions.IOStreams) *cobra.
148
138
}
149
139
150
140
func (o * AppendImageOptions ) Complete (cmd * cobra.Command , args []string ) error {
151
- pattern := o .FilterByOS
152
- if len (pattern ) == 0 && ! cmd .Flags ().Changed ("filter-by-os" ) {
153
- o .DefaultOSFilter = true
154
- pattern = regexp .QuoteMeta (fmt .Sprintf ("%s/%s" , runtime .GOOS , runtime .GOARCH ))
155
- }
156
- if len (pattern ) > 0 {
157
- re , err := regexp .Compile (pattern )
158
- if err != nil {
159
- return fmt .Errorf ("--filter-by-os was not a valid regular expression: %v" , err )
160
- }
161
- o .OSFilter = re
141
+ if err := o .FilterOptions .Complete (cmd .Flags ()); err != nil {
142
+ return err
162
143
}
163
144
164
145
for _ , arg := range args {
@@ -175,20 +156,6 @@ func (o *AppendImageOptions) Complete(cmd *cobra.Command, args []string) error {
175
156
return nil
176
157
}
177
158
178
- // includeDescriptor returns true if the provided manifest should be included.
179
- func (o * AppendImageOptions ) includeDescriptor (d * manifestlist.ManifestDescriptor , hasMultiple bool ) bool {
180
- if o .OSFilter == nil {
181
- return true
182
- }
183
- if o .DefaultOSFilter && ! hasMultiple {
184
- return true
185
- }
186
- if len (d .Platform .Variant ) > 0 {
187
- return o .OSFilter .MatchString (fmt .Sprintf ("%s/%s/%s" , d .Platform .OS , d .Platform .Architecture , d .Platform .Variant ))
188
- }
189
- return o .OSFilter .MatchString (fmt .Sprintf ("%s/%s" , d .Platform .OS , d .Platform .Architecture ))
190
- }
191
-
192
159
func (o * AppendImageOptions ) Run () error {
193
160
var createdAt * time.Time
194
161
if len (o .CreatedAt ) > 0 {
@@ -256,97 +223,16 @@ func (o *AppendImageOptions) Run() error {
256
223
return err
257
224
}
258
225
fromRepo = repo
259
- var srcDigest digest.Digest
260
- if len (from .Tag ) > 0 {
261
- desc , err := repo .Tags (ctx ).Get (ctx , from .Tag )
262
- if err != nil {
263
- return err
264
- }
265
- srcDigest = desc .Digest
266
- } else {
267
- srcDigest = digest .Digest (from .ID )
268
- }
269
- manifests , err := repo .Manifests (ctx )
270
- if err != nil {
271
- return err
272
- }
273
- srcManifest , err := manifests .Get (ctx , srcDigest , schema2ManifestOnly )
274
- if err != nil {
275
- return err
276
- }
277
226
278
- originalSrcDigest := srcDigest
279
- srcManifests , srcManifest , srcDigest , err := processManifestList (ctx , srcDigest , srcManifest , manifests , * from , o .includeDescriptor )
227
+ srcManifest , _ , location , err := imagemanifest .FirstManifest (ctx , * from , repo , o .FilterOptions .Include )
280
228
if err != nil {
281
- return err
229
+ return fmt . Errorf ( "unable to read image %s: %v" , from , err )
282
230
}
283
- if len (srcManifests ) == 0 {
284
- return fmt .Errorf ("filtered all images from %s" , from )
285
- }
286
-
287
- var location string
288
- if srcDigest == originalSrcDigest {
289
- location = fmt .Sprintf ("manifest %s" , srcDigest )
290
- } else {
291
- location = fmt .Sprintf ("manifest %s in manifest list %s" , srcDigest , originalSrcDigest )
231
+ base , layers , err = imagemanifest .ManifestToImageConfig (ctx , srcManifest , repo .Blobs (ctx ), location )
232
+ if err != nil {
233
+ return fmt .Errorf ("unable to parse image %s: %v" , from , err )
292
234
}
293
235
294
- switch t := srcManifest .(type ) {
295
- case * schema2.DeserializedManifest :
296
- if t .Config .MediaType != schema2 .MediaTypeImageConfig {
297
- return fmt .Errorf ("unable to append layers to images with config %s from %s" , t .Config .MediaType , location )
298
- }
299
- configJSON , err := repo .Blobs (ctx ).Get (ctx , t .Config .Digest )
300
- if err != nil {
301
- return fmt .Errorf ("unable to find manifest for image %s: %v" , * from , err )
302
- }
303
- glog .V (4 ).Infof ("Raw image config json:\n %s" , string (configJSON ))
304
- config := & docker10.DockerImageConfig {}
305
- if err := json .Unmarshal (configJSON , & config ); err != nil {
306
- return fmt .Errorf ("the source image manifest could not be parsed: %v" , err )
307
- }
308
-
309
- base = config
310
- layers = t .Layers
311
- base .Size = 0
312
- for _ , layer := range t .Layers {
313
- base .Size += layer .Size
314
- }
315
-
316
- case * schema1.SignedManifest :
317
- if glog .V (4 ) {
318
- _ , configJSON , _ := srcManifest .Payload ()
319
- glog .Infof ("Raw image config json:\n %s" , string (configJSON ))
320
- }
321
- if len (t .History ) == 0 {
322
- return fmt .Errorf ("input image is in an unknown format: no v1Compatibility history" )
323
- }
324
- config := & docker10.DockerV1CompatibilityImage {}
325
- if err := json .Unmarshal ([]byte (t .History [0 ].V1Compatibility ), & config ); err != nil {
326
- return err
327
- }
328
-
329
- base = & docker10.DockerImageConfig {}
330
- if err := docker10 .Convert_DockerV1CompatibilityImage_to_DockerImageConfig (config , base ); err != nil {
331
- return err
332
- }
333
-
334
- // schema1 layers are in reverse order
335
- layers = make ([]distribution.Descriptor , 0 , len (t .FSLayers ))
336
- for i := len (t .FSLayers ) - 1 ; i >= 0 ; i -- {
337
- layer := distribution.Descriptor {
338
- MediaType : schema2 .MediaTypeLayer ,
339
- Digest : t .FSLayers [i ].BlobSum ,
340
- // size must be reconstructed from the blobs
341
- }
342
- // we must reconstruct the tar sum from the blobs
343
- add .AddLayerToConfig (base , layer , "" )
344
- layers = append (layers , layer )
345
- }
346
-
347
- default :
348
- return fmt .Errorf ("unable to append layers to images of type %T from %s" , srcManifest , location )
349
- }
350
236
} else {
351
237
base = add .NewEmptyConfig ()
352
238
layers = []distribution.Descriptor {add .AddScratchLayerToConfig (base )}
@@ -445,8 +331,8 @@ func (o *AppendImageOptions) Run() error {
445
331
// upload base layers in parallel
446
332
stopCh := make (chan struct {})
447
333
defer close (stopCh )
448
- q := newWorkQueue (o .MaxPerRegistry , stopCh )
449
- err = q .Try (func (w Try ) {
334
+ q := workqueue . New (o .MaxPerRegistry , stopCh )
335
+ err = q .Try (func (w workqueue. Try ) {
450
336
for i := range layers [:numLayers ] {
451
337
layer := & layers [i ]
452
338
index := i
@@ -551,7 +437,7 @@ func (o *AppendImageOptions) Run() error {
551
437
if err != nil {
552
438
return fmt .Errorf ("unable to upload the new image manifest: %v" , err )
553
439
}
554
- toDigest , err := putManifestInCompatibleSchema (ctx , manifest , to .Tag , toManifests , fromRepo .Blobs (ctx ), toRepo .Named ())
440
+ toDigest , err := imagemanifest . PutManifestInCompatibleSchema (ctx , manifest , to .Tag , toManifests , fromRepo .Blobs (ctx ), toRepo .Named ())
555
441
if err != nil {
556
442
return fmt .Errorf ("unable to convert the image to a compatible schema version: %v" , err )
557
443
}
0 commit comments