Skip to content

Commit 04d2956

Browse files
committed
Check only for new bundles on add (#798)
* clarify pruned bundle message Signed-off-by: Ankita Thomas <[email protected]> * check only newly added bundles for pruning Signed-off-by: Ankita Thomas <[email protected]> * update tests, remove deprecation check on added bundles Signed-off-by: Ankita Thomas <[email protected]> Upstream-repository: operator-registry Upstream-commit: 2ef669fa19baaeb7dce3252d5d3e29ecaf59f753
1 parent 3085d76 commit 04d2956

File tree

3 files changed

+231
-477
lines changed

3 files changed

+231
-477
lines changed

staging/operator-registry/pkg/lib/registry/registry.go

Lines changed: 19 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -159,20 +159,14 @@ func populate(ctx context.Context, loader registry.Load, graphLoader registry.Gr
159159
}
160160
}
161161

162-
expectedBundles, err := expectedGraphBundles(imagesToAdd, graphLoader, overwrite)
163-
if err != nil {
164-
165-
return err
166-
167-
}
168162
populator := registry.NewDirectoryPopulator(loader, graphLoader, querier, unpackedImageMap, overwrittenBundles)
169163

170164
if err := populator.Populate(mode); err != nil {
171165

172166
return err
173167

174168
}
175-
return checkForBundles(ctx, querier.(*sqlite.SQLQuerier), graphLoader, expectedBundles)
169+
return checkForBundles(ctx, querier.(*sqlite.SQLQuerier), graphLoader, imagesToAdd)
176170
}
177171

178172
type DeleteFromRegistryRequest struct {
@@ -399,121 +393,38 @@ func checkForBundlePaths(querier registry.GRPCQuery, bundlePaths []string) ([]st
399393

400394
// replaces mode selects highest version as channel head and
401395
// prunes any bundles in the upgrade chain after the channel head.
402-
// check for the presence of all bundles after a replaces-mode add.
403-
func checkForBundles(ctx context.Context, q *sqlite.SQLQuerier, g registry.GraphLoader, required map[string]*registry.Package) error {
396+
// check for the presence of newly added bundles after a replaces-mode add.
397+
func checkForBundles(ctx context.Context, q *sqlite.SQLQuerier, g registry.GraphLoader, required []*registry.Bundle) error {
404398
var errs []error
405-
for _, pkg := range required {
406-
graph, err := g.Generate(pkg.Name)
399+
for _, bundle := range required {
400+
graph, err := g.Generate(bundle.Package)
407401
if err != nil {
408-
errs = append(errs, fmt.Errorf("unable to verify added bundles for package %s: %v", pkg.Name, err))
402+
errs = append(errs, fmt.Errorf("unable to verify added bundles for package %s: %v", bundle.Package, err))
409403
continue
410404
}
411405

412-
for channel, missing := range pkg.Channels {
413-
// trace replaces chain for reachable bundles
406+
for _, channel := range bundle.Channels {
407+
var foundImage bool
414408
for next := []registry.BundleKey{graph.Channels[channel].Head}; len(next) > 0; next = next[1:] {
415-
delete(missing.Nodes, next[0])
409+
if next[0].BundlePath == bundle.BundleImage {
410+
foundImage = true
411+
break
412+
}
416413
for edge := range graph.Channels[channel].Nodes[next[0]] {
417414
next = append(next, edge)
418415
}
419416
}
420417

421-
for bundle := range missing.Nodes {
422-
// check if bundle is deprecated. Bundles readded after deprecation should not be present in index and can be ignored.
423-
deprecated, err := isDeprecated(ctx, q, bundle)
424-
if err != nil {
425-
errs = append(errs, fmt.Errorf("could not validate pruned bundle %s (%s) as deprecated: %v", bundle.CsvName, bundle.BundlePath, err))
426-
}
427-
if !deprecated {
428-
errs = append(errs, fmt.Errorf("added bundle %s pruned from package %s, channel %s: this may be due to incorrect channel head (%s)", bundle.BundlePath, pkg.Name, channel, graph.Channels[channel].Head.CsvName))
429-
}
418+
if foundImage {
419+
continue
430420
}
431-
}
432-
}
433-
return utilerrors.NewAggregate(errs)
434-
}
435-
436-
func isDeprecated(ctx context.Context, q *sqlite.SQLQuerier, bundle registry.BundleKey) (bool, error) {
437-
props, err := q.GetPropertiesForBundle(ctx, bundle.CsvName, bundle.Version, bundle.BundlePath)
438-
if err != nil {
439-
return false, err
440-
}
441-
for _, prop := range props {
442-
if prop.Type == registry.DeprecatedType {
443-
return true, nil
444-
}
445-
}
446-
return false, nil
447-
}
448421

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-
}
422+
var headSkips []string
423+
for b := range graph.Channels[channel].Nodes[graph.Channels[channel].Head] {
424+
headSkips = append(headSkips, b.CsvName)
489425
}
426+
errs = append(errs, fmt.Errorf("add prunes bundle %s (%s) from package %s, channel %s: this may be due to incorrect channel head (%s, skips/replaces %v)", bundle.Name, bundle.BundleImage, bundle.Package, channel, graph.Channels[channel].Head.CsvName, headSkips))
490427
}
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
517428
}
518-
return expectedBundles, nil
429+
return utilerrors.NewAggregate(errs)
519430
}

0 commit comments

Comments
 (0)