Skip to content

Commit 4588760

Browse files
committed
Replace hardcoded resolver cache mutation with CSV cache.Source.
Signed-off-by: Ben Luddy <[email protected]>
1 parent 6f59a3b commit 4588760

File tree

10 files changed

+883
-802
lines changed

10 files changed

+883
-802
lines changed

Diff for: pkg/controller/operators/catalog/operator.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
189189
}
190190
op.sources = grpc.NewSourceStore(logger, 10*time.Second, 10*time.Minute, op.syncSourceState)
191191
op.reconciler = reconciler.NewRegistryReconcilerFactory(lister, opClient, configmapRegistryImage, op.now, ssaClient)
192-
res := resolver.NewOperatorStepResolver(lister, crClient, opClient.KubernetesInterface(), operatorNamespace, op.sources, logger)
192+
res := resolver.NewOperatorStepResolver(lister, crClient, operatorNamespace, op.sources, logger)
193193
op.resolver = resolver.NewInstrumentedResolver(res, metrics.RegisterDependencyResolutionSuccess, metrics.RegisterDependencyResolutionFailure)
194194

195195
// Wire OLM CR sharedIndexInformers

Diff for: pkg/controller/registry/resolver/cache/cache.go

+9-21
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ func New(sp SourceProvider, options ...Option) *Cache {
127127
}
128128

129129
type NamespacedOperatorCache struct {
130-
existing *SourceKey
131130
snapshots map[SourceKey]*snapshotHeader
132131
}
133132

@@ -264,31 +263,14 @@ func (c *NamespacedOperatorCache) FindPreferred(preferred *SourceKey, preferredN
264263
if preferred != nil && preferred.Empty() {
265264
preferred = nil
266265
}
267-
sorted := newSortableSnapshots(c.existing, preferred, preferredNamespace, c.snapshots)
266+
sorted := newSortableSnapshots(preferred, preferredNamespace, c.snapshots)
268267
sort.Sort(sorted)
269268
for _, snapshot := range sorted.snapshots {
270269
result = append(result, snapshot.Find(p...)...)
271270
}
272271
return result
273272
}
274273

275-
func (c *NamespacedOperatorCache) WithExistingOperators(snapshot *Snapshot, namespace string) MultiCatalogOperatorFinder {
276-
key := NewVirtualSourceKey(namespace)
277-
o := &NamespacedOperatorCache{
278-
existing: &key,
279-
snapshots: map[SourceKey]*snapshotHeader{
280-
key: {
281-
key: key,
282-
snapshot: snapshot,
283-
},
284-
},
285-
}
286-
for k, v := range c.snapshots {
287-
o.snapshots[k] = v
288-
}
289-
return o
290-
}
291-
292274
func (c *NamespacedOperatorCache) Find(p ...Predicate) []*Entry {
293275
return c.FindPreferred(nil, "", p...)
294276
}
@@ -331,7 +313,14 @@ type sortableSnapshots struct {
331313
existing *SourceKey
332314
}
333315

334-
func newSortableSnapshots(existing, preferred *SourceKey, preferredNamespace string, snapshots map[SourceKey]*snapshotHeader) sortableSnapshots {
316+
func newSortableSnapshots(preferred *SourceKey, preferredNamespace string, snapshots map[SourceKey]*snapshotHeader) sortableSnapshots {
317+
var existing *SourceKey
318+
for key := range snapshots {
319+
if key.Virtual() && key.Namespace == preferredNamespace {
320+
existing = &key
321+
break
322+
}
323+
}
335324
sorted := sortableSnapshots{
336325
existing: existing,
337326
preferred: preferred,
@@ -416,7 +405,6 @@ type OperatorFinder interface {
416405
type MultiCatalogOperatorFinder interface {
417406
Catalog(SourceKey) OperatorFinder
418407
FindPreferred(preferred *SourceKey, preferredNamespace string, predicates ...Predicate) []*Entry
419-
WithExistingOperators(snapshot *Snapshot, namespace string) MultiCatalogOperatorFinder
420408
Error() error
421409
OperatorFinder
422410
}

Diff for: pkg/controller/registry/resolver/cache/operators.go

-3
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,6 @@ func (i *OperatorSourceInfo) String() string {
199199
return fmt.Sprintf("%s/%s in %s/%s", i.Package, i.Channel, i.Catalog.Name, i.Catalog.Namespace)
200200
}
201201

202-
var NoCatalog = SourceKey{Name: "", Namespace: ""}
203-
var ExistingOperator = OperatorSourceInfo{Package: "", Channel: "", StartingCSV: "", Catalog: NoCatalog, DefaultChannel: false}
204-
205202
type Entry struct {
206203
Name string
207204
Replaces string

Diff for: pkg/controller/registry/resolver/resolver.go

+18-172
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@ import (
1515
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1616
v1alpha1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
1717
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache"
18-
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/projection"
1918
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/solver"
2019
"github.com/operator-framework/operator-registry/pkg/api"
2120
opregistry "github.com/operator-framework/operator-registry/pkg/registry"
2221
)
2322

2423
type OperatorResolver interface {
25-
SolveOperators(csvs []*v1alpha1.ClusterServiceVersion, subs []*v1alpha1.Subscription, add map[cache.OperatorSourceInfo]struct{}) (cache.OperatorSet, error)
24+
SolveOperators(csvs []*v1alpha1.ClusterServiceVersion, add map[cache.OperatorSourceInfo]struct{}) (cache.OperatorSet, error)
2625
}
2726

2827
type SatResolver struct {
@@ -52,7 +51,7 @@ func (w *debugWriter) Write(b []byte) (int, error) {
5251
return n, nil
5352
}
5453

55-
func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.ClusterServiceVersion, subs []*v1alpha1.Subscription) (cache.OperatorSet, error) {
54+
func (r *SatResolver) SolveOperators(namespaces []string, subs []*v1alpha1.Subscription) (cache.OperatorSet, error) {
5655
var errs []error
5756

5857
installables := make(map[solver.Identifier]solver.Installable)
@@ -61,14 +60,15 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
6160
// TODO: better abstraction
6261
startingCSVs := make(map[string]struct{})
6362

64-
// build a virtual catalog of all currently installed CSVs
65-
existingSnapshot, err := r.newSnapshotForNamespace(namespaces[0], subs, csvs)
66-
if err != nil {
67-
return nil, err
63+
namespacedCache := r.cache.Namespaced(namespaces...)
64+
65+
if len(namespaces) < 1 {
66+
// the first namespace is treated as the preferred namespace today
67+
return nil, fmt.Errorf("at least one namespace must be provided to resolution")
6868
}
69-
namespacedCache := r.cache.Namespaced(namespaces...).WithExistingOperators(existingSnapshot, namespaces[0])
7069

71-
_, existingInstallables, err := r.getBundleInstallables(namespaces[0], cache.Filter(existingSnapshot.Entries, cache.True()), namespacedCache, visited)
70+
preferredNamespace := namespaces[0]
71+
_, existingInstallables, err := r.getBundleInstallables(preferredNamespace, namespacedCache.Catalog(cache.NewVirtualSourceKey(preferredNamespace)).Find(cache.True()), namespacedCache, visited)
7272
if err != nil {
7373
return nil, err
7474
}
@@ -80,15 +80,16 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
8080
for _, sub := range subs {
8181
// find the currently installed operator (if it exists)
8282
var current *cache.Entry
83-
for _, csv := range csvs {
84-
if csv.Name == sub.Status.InstalledCSV {
85-
op, err := newOperatorFromV1Alpha1CSV(csv)
86-
if err != nil {
87-
return nil, err
88-
}
89-
current = op
90-
break
83+
84+
matches := namespacedCache.Catalog(cache.NewVirtualSourceKey(sub.Namespace)).Find(cache.CSVNamePredicate(sub.Status.InstalledCSV))
85+
if len(matches) > 1 {
86+
var names []string
87+
for _, each := range matches {
88+
names = append(names, each.Name)
9189
}
90+
return nil, fmt.Errorf("multiple name matches for status.installedCSV of subscription %s/%s: %s", sub.Namespace, sub.Name, strings.Join(names, ", "))
91+
} else if len(matches) == 1 {
92+
current = matches[0]
9293
}
9394

9495
if current == nil && sub.Spec.StartingCSV != "" {
@@ -461,116 +462,6 @@ func (r *SatResolver) getBundleInstallables(preferredNamespace string, bundleSta
461462
return ids, installables, nil
462463
}
463464

464-
func (r *SatResolver) inferProperties(csv *v1alpha1.ClusterServiceVersion, subs []*v1alpha1.Subscription) ([]*api.Property, error) {
465-
var properties []*api.Property
466-
467-
packages := make(map[string]struct{})
468-
for _, sub := range subs {
469-
if sub.Status.InstalledCSV != csv.Name {
470-
continue
471-
}
472-
// Without sanity checking the Subscription spec's
473-
// package against catalog contents, updates to the
474-
// Subscription spec could result in a bad package
475-
// inference.
476-
for _, entry := range r.cache.Namespaced(sub.Spec.CatalogSourceNamespace).Catalog(cache.SourceKey{Namespace: sub.Spec.CatalogSourceNamespace, Name: sub.Spec.CatalogSource}).Find(cache.And(cache.CSVNamePredicate(csv.Name), cache.PkgPredicate(sub.Spec.Package))) {
477-
if pkg := entry.Package(); pkg != "" {
478-
packages[pkg] = struct{}{}
479-
}
480-
}
481-
}
482-
if l := len(packages); l != 1 {
483-
r.log.Warnf("could not unambiguously infer package name for %q (found %d distinct package names)", csv.Name, l)
484-
return properties, nil
485-
}
486-
var pkg string
487-
for pkg = range packages {
488-
// Assign the single key to pkg.
489-
}
490-
var version string // Emit empty string rather than "0.0.0" if .spec.version is zero-valued.
491-
if !csv.Spec.Version.Version.Equals(semver.Version{}) {
492-
version = csv.Spec.Version.String()
493-
}
494-
pp, err := json.Marshal(opregistry.PackageProperty{
495-
PackageName: pkg,
496-
Version: version,
497-
})
498-
if err != nil {
499-
return nil, fmt.Errorf("failed to marshal inferred package property: %w", err)
500-
}
501-
properties = append(properties, &api.Property{
502-
Type: opregistry.PackageType,
503-
Value: string(pp),
504-
})
505-
506-
return properties, nil
507-
}
508-
509-
func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1.Subscription, csvs []*v1alpha1.ClusterServiceVersion) (*cache.Snapshot, error) {
510-
existingOperatorCatalog := cache.NewVirtualSourceKey(namespace)
511-
// build a catalog snapshot of CSVs without subscriptions
512-
csvSubscriptions := make(map[*v1alpha1.ClusterServiceVersion]*v1alpha1.Subscription)
513-
for _, sub := range subs {
514-
for _, csv := range csvs {
515-
if csv.Name == sub.Status.InstalledCSV {
516-
csvSubscriptions[csv] = sub
517-
break
518-
}
519-
}
520-
}
521-
var csvsMissingProperties []*v1alpha1.ClusterServiceVersion
522-
standaloneOperators := make([]*cache.Entry, 0)
523-
for _, csv := range csvs {
524-
op, err := newOperatorFromV1Alpha1CSV(csv)
525-
if err != nil {
526-
return nil, err
527-
}
528-
529-
if anno, ok := csv.GetAnnotations()[projection.PropertiesAnnotationKey]; !ok {
530-
csvsMissingProperties = append(csvsMissingProperties, csv)
531-
if inferred, err := r.inferProperties(csv, subs); err != nil {
532-
r.log.Warnf("unable to infer properties for csv %q: %w", csv.Name, err)
533-
} else {
534-
op.Properties = append(op.Properties, inferred...)
535-
}
536-
} else if props, err := projection.PropertyListFromPropertiesAnnotation(anno); err != nil {
537-
return nil, fmt.Errorf("failed to retrieve properties of csv %q: %w", csv.GetName(), err)
538-
} else {
539-
op.Properties = props
540-
}
541-
542-
op.SourceInfo = &cache.OperatorSourceInfo{
543-
Catalog: existingOperatorCatalog,
544-
Subscription: csvSubscriptions[csv],
545-
}
546-
// Try to determine source package name from properties and add to SourceInfo.
547-
for _, p := range op.Properties {
548-
if p.Type != opregistry.PackageType {
549-
continue
550-
}
551-
var pp opregistry.PackageProperty
552-
err := json.Unmarshal([]byte(p.Value), &pp)
553-
if err != nil {
554-
r.log.Warnf("failed to unmarshal package property of csv %q: %w", csv.Name, err)
555-
continue
556-
}
557-
op.SourceInfo.Package = pp.PackageName
558-
}
559-
560-
standaloneOperators = append(standaloneOperators, op)
561-
}
562-
563-
if len(csvsMissingProperties) > 0 {
564-
names := make([]string, len(csvsMissingProperties))
565-
for i, csv := range csvsMissingProperties {
566-
names[i] = csv.GetName()
567-
}
568-
r.log.Infof("considered csvs without properties annotation during resolution: %v", names)
569-
}
570-
571-
return &cache.Snapshot{Entries: standaloneOperators}, nil
572-
}
573-
574465
func (r *SatResolver) addInvariants(namespacedCache cache.MultiCatalogOperatorFinder, installables map[solver.Identifier]solver.Installable) {
575466
// no two operators may provide the same GVK or Package in a namespace
576467
gvkConflictToInstallable := make(map[opregistry.GVKProperty][]solver.Identifier)
@@ -924,51 +815,6 @@ func predicateForRequiredLabelProperty(value string) (cache.Predicate, error) {
924815
return cache.LabelPredicate(label.Label), nil
925816
}
926817

927-
func newOperatorFromV1Alpha1CSV(csv *v1alpha1.ClusterServiceVersion) (*cache.Entry, error) {
928-
providedAPIs := cache.EmptyAPISet()
929-
for _, crdDef := range csv.Spec.CustomResourceDefinitions.Owned {
930-
parts := strings.SplitN(crdDef.Name, ".", 2)
931-
if len(parts) < 2 {
932-
return nil, fmt.Errorf("error parsing crd name: %s", crdDef.Name)
933-
}
934-
providedAPIs[opregistry.APIKey{Plural: parts[0], Group: parts[1], Version: crdDef.Version, Kind: crdDef.Kind}] = struct{}{}
935-
}
936-
for _, api := range csv.Spec.APIServiceDefinitions.Owned {
937-
providedAPIs[opregistry.APIKey{Group: api.Group, Version: api.Version, Kind: api.Kind, Plural: api.Name}] = struct{}{}
938-
}
939-
940-
requiredAPIs := cache.EmptyAPISet()
941-
for _, crdDef := range csv.Spec.CustomResourceDefinitions.Required {
942-
parts := strings.SplitN(crdDef.Name, ".", 2)
943-
if len(parts) < 2 {
944-
return nil, fmt.Errorf("error parsing crd name: %s", crdDef.Name)
945-
}
946-
requiredAPIs[opregistry.APIKey{Plural: parts[0], Group: parts[1], Version: crdDef.Version, Kind: crdDef.Kind}] = struct{}{}
947-
}
948-
for _, api := range csv.Spec.APIServiceDefinitions.Required {
949-
requiredAPIs[opregistry.APIKey{Group: api.Group, Version: api.Version, Kind: api.Kind, Plural: api.Name}] = struct{}{}
950-
}
951-
952-
properties, err := providedAPIsToProperties(providedAPIs)
953-
if err != nil {
954-
return nil, err
955-
}
956-
dependencies, err := requiredAPIsToProperties(requiredAPIs)
957-
if err != nil {
958-
return nil, err
959-
}
960-
properties = append(properties, dependencies...)
961-
962-
return &cache.Entry{
963-
Name: csv.GetName(),
964-
Version: &csv.Spec.Version.Version,
965-
ProvidedAPIs: providedAPIs,
966-
RequiredAPIs: requiredAPIs,
967-
SourceInfo: &cache.ExistingOperator,
968-
Properties: properties,
969-
}, nil
970-
}
971-
972818
func providedAPIsToProperties(apis cache.APISet) (out []*api.Property, err error) {
973819
out = make([]*api.Property, 0)
974820
for a := range apis {

0 commit comments

Comments
 (0)