@@ -128,23 +128,23 @@ func unpackImage(ctx context.Context, reg image.Registry, ref image.Reference) (
128
128
129
129
func populate (ctx context.Context , loader registry.Load , graphLoader registry.GraphLoader , querier registry.Query , reg image.Registry , refs []image.Reference , mode registry.Mode , overwrite bool ) error {
130
130
unpackedImageMap := make (map [image.Reference ]string , 0 )
131
+ overwrittenBundles := map [string ][]string {}
132
+ var imagesToAdd []* registry.Bundle
131
133
for _ , ref := range refs {
132
134
to , from , cleanup , err := unpackImage (ctx , reg , ref )
133
135
if err != nil {
134
136
return err
135
137
}
136
138
unpackedImageMap [to ] = from
137
139
defer cleanup ()
138
- }
139
140
140
- overwriteImageMap := make (map [string ]map [image.Reference ]string , 0 )
141
- if overwrite {
142
- // find all bundles that are attempting to overwrite
143
- for to , from := range unpackedImageMap {
144
- img , err := registry .NewImageInput (to , from )
145
- if err != nil {
146
- return err
147
- }
141
+ img , err := registry .NewImageInput (to , from )
142
+ if err != nil {
143
+ return err
144
+ }
145
+ imagesToAdd = append (imagesToAdd , img .Bundle )
146
+
147
+ if overwrite {
148
148
overwritten , err := querier .GetBundlePathIfExists (ctx , img .Bundle .Name )
149
149
if err != nil {
150
150
if err == registry .ErrBundleImageNotInDatabase {
@@ -155,57 +155,24 @@ func populate(ctx context.Context, loader registry.Load, graphLoader registry.Gr
155
155
if overwritten == "" {
156
156
return fmt .Errorf ("index add --overwrite-latest is only supported when using bundle images" )
157
157
}
158
- // get all bundle paths for that package - we will re-add these to regenerate the graph
159
- bundles , err := querier .GetBundlesForPackage (ctx , img .Bundle .Package )
160
- if err != nil {
161
- return err
162
- }
163
- type unpackedImage struct {
164
- to image.Reference
165
- from string
166
- cleanup func ()
167
- err error
168
- }
169
- unpacked := make (chan unpackedImage )
170
- for bundle := range bundles {
171
- // parallelize image pulls
172
- go func (bundle registry.BundleKey , img * registry.ImageInput ) {
173
- if bundle .CsvName != img .Bundle .Name {
174
- to , from , cleanup , err := unpackImage (ctx , reg , image .SimpleReference (bundle .BundlePath ))
175
- unpacked <- unpackedImage {to : to , from : from , cleanup : cleanup , err : err }
176
- } else {
177
- unpacked <- unpackedImage {to : to , from : from , cleanup : func () { return }, err : nil }
178
- }
179
- }(bundle , img )
180
- }
181
- if _ , ok := overwriteImageMap [img .Bundle .Package ]; ! ok {
182
- overwriteImageMap [img .Bundle .Package ] = make (map [image.Reference ]string , 0 )
183
- }
184
- for i := 0 ; i < len (bundles ); i ++ {
185
- unpack := <- unpacked
186
- if unpack .err != nil {
187
- return unpack .err
188
- }
189
- overwriteImageMap [img .Bundle .Package ][unpack .to ] = unpack .from
190
- if _ , ok := unpackedImageMap [unpack .to ]; ok {
191
- delete (unpackedImageMap , unpack .to )
192
- }
193
- defer unpack .cleanup ()
194
- }
158
+ overwrittenBundles [img .Bundle .Package ] = append (overwrittenBundles [img .Bundle .Package ], img .Bundle .Name )
195
159
}
196
160
}
197
161
198
- populator := registry .NewDirectoryPopulator (loader , graphLoader , querier , unpackedImageMap , overwriteImageMap , overwrite )
199
- if err := populator .Populate (mode ); err != nil {
162
+ expectedBundles , err := expectedGraphBundles (imagesToAdd , graphLoader , overwrite )
163
+ if err != nil {
164
+
200
165
return err
166
+
201
167
}
168
+ populator := registry .NewDirectoryPopulator (loader , graphLoader , querier , unpackedImageMap , overwrittenBundles )
169
+
170
+ if err := populator .Populate (mode ); err != nil {
171
+
172
+ return err
202
173
203
- for _ , imgMap := range overwriteImageMap {
204
- for to , from := range imgMap {
205
- unpackedImageMap [to ] = from
206
- }
207
174
}
208
- return checkForBundles (ctx , querier .(* sqlite.SQLQuerier ), graphLoader , unpackedImageMap )
175
+ return checkForBundles (ctx , querier .(* sqlite.SQLQuerier ), graphLoader , expectedBundles )
209
176
}
210
177
211
178
type DeleteFromRegistryRequest struct {
@@ -291,7 +258,7 @@ func (r RegistryUpdater) PruneFromRegistry(request PruneFromRegistryRequest) err
291
258
}
292
259
defer db .Close ()
293
260
294
- dbLoader , err := sqlite .NewSQLLiteLoader (db )
261
+ dbLoader , err := sqlite .NewDeprecationAwareLoader (db )
295
262
if err != nil {
296
263
return err
297
264
}
@@ -344,7 +311,7 @@ func (r RegistryUpdater) DeprecateFromRegistry(request DeprecateFromRegistryRequ
344
311
}
345
312
defer db .Close ()
346
313
347
- dbLoader , err := sqlite .NewSQLLiteLoader (db )
314
+ dbLoader , err := sqlite .NewDeprecationAwareLoader (db )
348
315
if err != nil {
349
316
return err
350
317
}
@@ -430,55 +397,10 @@ func checkForBundlePaths(querier registry.GRPCQuery, bundlePaths []string) ([]st
430
397
return found , missing , nil
431
398
}
432
399
433
- // packagesFromUnpackedRefs creates packages from a set of unpacked ref dirs without their upgrade edges.
434
- func packagesFromUnpackedRefs (bundles map [image.Reference ]string ) (map [string ]registry.Package , error ) {
435
- graph := map [string ]registry.Package {}
436
- for to , from := range bundles {
437
- b , err := registry .NewImageInput (to , from )
438
- if err != nil {
439
- return nil , fmt .Errorf ("failed to parse unpacked bundle image %s: %v" , to , err )
440
- }
441
- v , err := b .Bundle .Version ()
442
- if err != nil {
443
- return nil , fmt .Errorf ("failed to parse version for %s (%s): %v" , b .Bundle .Name , b .Bundle .BundleImage , err )
444
- }
445
- key := registry.BundleKey {
446
- CsvName : b .Bundle .Name ,
447
- Version : v ,
448
- BundlePath : b .Bundle .BundleImage ,
449
- }
450
- if _ , ok := graph [b .Bundle .Package ]; ! ok {
451
- graph [b .Bundle .Package ] = registry.Package {
452
- Name : b .Bundle .Package ,
453
- Channels : map [string ]registry.Channel {},
454
- }
455
- }
456
- for _ , c := range b .Bundle .Channels {
457
- if _ , ok := graph [b .Bundle .Package ].Channels [c ]; ! ok {
458
- graph [b .Bundle .Package ].Channels [c ] = registry.Channel {
459
- Nodes : map [registry.BundleKey ]map [registry.BundleKey ]struct {}{},
460
- }
461
- }
462
- graph [b .Bundle .Package ].Channels [c ].Nodes [key ] = nil
463
- }
464
- }
465
-
466
- return graph , nil
467
- }
468
-
469
400
// replaces mode selects highest version as channel head and
470
401
// prunes any bundles in the upgrade chain after the channel head.
471
402
// check for the presence of all bundles after a replaces-mode add.
472
- func checkForBundles (ctx context.Context , q * sqlite.SQLQuerier , g registry.GraphLoader , bundles map [image.Reference ]string ) error {
473
- if len (bundles ) == 0 {
474
- return nil
475
- }
476
-
477
- required , err := packagesFromUnpackedRefs (bundles )
478
- if err != nil {
479
- return err
480
- }
481
-
403
+ func checkForBundles (ctx context.Context , q * sqlite.SQLQuerier , g registry.GraphLoader , required map [string ]* registry.Package ) error {
482
404
var errs []error
483
405
for _ , pkg := range required {
484
406
graph , err := g .Generate (pkg .Name )
@@ -523,3 +445,75 @@ func isDeprecated(ctx context.Context, q *sqlite.SQLQuerier, bundle registry.Bun
523
445
}
524
446
return false , nil
525
447
}
448
+
449
+ // expectedGraphBundles returns a set of package-channel-bundle tuples that MUST be present following an add.
450
+ /* opm index add drops bundles that replace a channel head, and since channel head selection heuristics
451
+ * choose the bundle with the greatest semver as the channel head, any bundle that replaces such a bundle
452
+ * will be dropped from the graph following an add.
453
+ * eg: 1.0.1 <- 1.0.1-new
454
+ *
455
+ * 1.0.1-new replaces 1.0.1 but will not be chosen as the channel head because of its non-empty pre-release version.
456
+ * expectedGraphBundles gives a set of bundles (old bundles from the graphLoader and the newly added set of bundles from
457
+ * imagesToAdd) that must be present following an add to ensure no bundle is dropped.
458
+ *
459
+ * Overwritten bundles will only be verified on the channels of the newly added version.
460
+ * Any inherited channels due to addition of a new bundle on its tail bundles may not be verified
461
+ * eg: 1.0.1 (alpha) <-[1.0.2 (alpha, stable)]
462
+ * When 1.0.2 in alpha and stable channels is added replacing 1.0.1, 1.0.1's presence will only be marked as expected on
463
+ * the alpha channel, not on the inherited stable channel.
464
+ */
465
+ func expectedGraphBundles (imagesToAdd []* registry.Bundle , graphLoader registry.GraphLoader , overwrite bool ) (map [string ]* registry.Package , error ) {
466
+ expectedBundles := map [string ]* registry.Package {}
467
+ for _ , bundle := range imagesToAdd {
468
+ version , err := bundle .Version ()
469
+ if err != nil {
470
+ return nil , err
471
+ }
472
+ newBundleKey := registry.BundleKey {
473
+ BundlePath : bundle .BundleImage ,
474
+ Version : version ,
475
+ CsvName : bundle .Name ,
476
+ }
477
+ var pkg * registry.Package
478
+ var ok bool
479
+ if pkg , ok = expectedBundles [bundle .Package ]; ! ok {
480
+ var err error
481
+ if pkg , err = graphLoader .Generate (bundle .Package ); err != nil {
482
+ if err != registry .ErrPackageNotInDatabase {
483
+ return nil , err
484
+ }
485
+ pkg = & registry.Package {
486
+ Name : bundle .Package ,
487
+ Channels : map [string ]registry.Channel {},
488
+ }
489
+ }
490
+ }
491
+ for c , channelEntries := range pkg .Channels {
492
+ for oldBundle := range channelEntries .Nodes {
493
+ if oldBundle .CsvName == bundle .Name {
494
+ if overwrite {
495
+ delete (pkg .Channels [c ].Nodes , oldBundle )
496
+ if len (pkg .Channels [c ].Nodes ) == 0 {
497
+ delete (pkg .Channels , c )
498
+ }
499
+ } else {
500
+ return nil , registry.BundleImageAlreadyAddedErr {ErrorString : fmt .Sprintf ("Bundle %s already exists" , bundle .BundleImage )}
501
+ }
502
+ }
503
+ }
504
+ }
505
+ for _ , c := range bundle .Channels {
506
+ if _ , ok := pkg .Channels [c ]; ! ok {
507
+ pkg .Channels [c ] = registry.Channel {
508
+ Nodes : map [registry.BundleKey ]map [registry.BundleKey ]struct {}{},
509
+ }
510
+ }
511
+ // This can miss out on some channels, when a new bundle has channels that the one it replaces does not.
512
+ // eg: When bundle A in channel A replaces bundle B in channel B is added, bundle B is also added to channel A
513
+ // but it is only expected to be in channel B, presence in channel A will be ignored
514
+ pkg .Channels [c ].Nodes [newBundleKey ] = nil
515
+ }
516
+ expectedBundles [bundle .Package ] = pkg
517
+ }
518
+ return expectedBundles , nil
519
+ }
0 commit comments