@@ -14,14 +14,13 @@ import (
14
14
"github.com/operator-framework/api/pkg/constraints"
15
15
"github.com/operator-framework/api/pkg/operators/v1alpha1"
16
16
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache"
17
- "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/projection"
18
17
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/solver"
19
18
"github.com/operator-framework/operator-registry/pkg/api"
20
19
opregistry "github.com/operator-framework/operator-registry/pkg/registry"
21
20
)
22
21
23
22
type OperatorResolver interface {
24
- SolveOperators (csvs []* v1alpha1.ClusterServiceVersion , subs [] * v1alpha1. Subscription , add map [cache.OperatorSourceInfo ]struct {}) (cache.OperatorSet , error )
23
+ SolveOperators (csvs []* v1alpha1.ClusterServiceVersion , add map [cache.OperatorSourceInfo ]struct {}) (cache.OperatorSet , error )
25
24
}
26
25
27
26
type SatResolver struct {
@@ -51,7 +50,7 @@ func (w *debugWriter) Write(b []byte) (int, error) {
51
50
return n , nil
52
51
}
53
52
54
- func (r * SatResolver ) SolveOperators (namespaces []string , csvs [] * v1alpha1. ClusterServiceVersion , subs []* v1alpha1.Subscription ) (cache.OperatorSet , error ) {
53
+ func (r * SatResolver ) SolveOperators (namespaces []string , subs []* v1alpha1.Subscription ) (cache.OperatorSet , error ) {
55
54
var errs []error
56
55
57
56
variables := make (map [solver.Identifier ]solver.Variable )
@@ -60,14 +59,15 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
60
59
// TODO: better abstraction
61
60
startingCSVs := make (map [string ]struct {})
62
61
63
- // build a virtual catalog of all currently installed CSVs
64
- existingSnapshot , err := r .newSnapshotForNamespace (namespaces [0 ], subs , csvs )
65
- if err != nil {
66
- return nil , err
62
+ namespacedCache := r .cache .Namespaced (namespaces ... )
63
+
64
+ if len (namespaces ) < 1 {
65
+ // the first namespace is treated as the preferred namespace today
66
+ return nil , fmt .Errorf ("at least one namespace must be provided to resolution" )
67
67
}
68
- namespacedCache := r .cache .Namespaced (namespaces ... ).WithExistingOperators (existingSnapshot , namespaces [0 ])
69
68
70
- _ , existingVariables , err := r .getBundleVariables (namespaces [0 ], cache .Filter (existingSnapshot .Entries , cache .True ()), namespacedCache , visited )
69
+ preferredNamespace := namespaces [0 ]
70
+ _ , existingVariables , err := r .getBundleVariables (preferredNamespace , namespacedCache .Catalog (cache .NewVirtualSourceKey (preferredNamespace )).Find (cache .True ()), namespacedCache , visited )
71
71
if err != nil {
72
72
return nil , err
73
73
}
@@ -79,15 +79,16 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
79
79
for _ , sub := range subs {
80
80
// find the currently installed operator (if it exists)
81
81
var current * cache.Entry
82
- for _ , csv := range csvs {
83
- if csv .Name == sub .Status .InstalledCSV {
84
- op , err := newOperatorFromV1Alpha1CSV (csv )
85
- if err != nil {
86
- return nil , err
87
- }
88
- current = op
89
- break
82
+
83
+ matches := namespacedCache .Catalog (cache .NewVirtualSourceKey (sub .Namespace )).Find (cache .CSVNamePredicate (sub .Status .InstalledCSV ))
84
+ if len (matches ) > 1 {
85
+ var names []string
86
+ for _ , each := range matches {
87
+ names = append (names , each .Name )
90
88
}
89
+ return nil , fmt .Errorf ("multiple name matches for status.installedCSV of subscription %s/%s: %s" , sub .Namespace , sub .Name , strings .Join (names , ", " ))
90
+ } else if len (matches ) == 1 {
91
+ current = matches [0 ]
91
92
}
92
93
93
94
if current == nil && sub .Spec .StartingCSV != "" {
@@ -460,116 +461,6 @@ func (r *SatResolver) getBundleVariables(preferredNamespace string, bundleStack
460
461
return ids , variables , nil
461
462
}
462
463
463
- func (r * SatResolver ) inferProperties (csv * v1alpha1.ClusterServiceVersion , subs []* v1alpha1.Subscription ) ([]* api.Property , error ) {
464
- var properties []* api.Property
465
-
466
- packages := make (map [string ]struct {})
467
- for _ , sub := range subs {
468
- if sub .Status .InstalledCSV != csv .Name {
469
- continue
470
- }
471
- // Without sanity checking the Subscription spec's
472
- // package against catalog contents, updates to the
473
- // Subscription spec could result in a bad package
474
- // inference.
475
- 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 ))) {
476
- if pkg := entry .Package (); pkg != "" {
477
- packages [pkg ] = struct {}{}
478
- }
479
- }
480
- }
481
- if l := len (packages ); l != 1 {
482
- r .log .Warnf ("could not unambiguously infer package name for %q (found %d distinct package names)" , csv .Name , l )
483
- return properties , nil
484
- }
485
- var pkg string
486
- for pkg = range packages {
487
- // Assign the single key to pkg.
488
- }
489
- var version string // Emit empty string rather than "0.0.0" if .spec.version is zero-valued.
490
- if ! csv .Spec .Version .Version .Equals (semver.Version {}) {
491
- version = csv .Spec .Version .String ()
492
- }
493
- pp , err := json .Marshal (opregistry.PackageProperty {
494
- PackageName : pkg ,
495
- Version : version ,
496
- })
497
- if err != nil {
498
- return nil , fmt .Errorf ("failed to marshal inferred package property: %w" , err )
499
- }
500
- properties = append (properties , & api.Property {
501
- Type : opregistry .PackageType ,
502
- Value : string (pp ),
503
- })
504
-
505
- return properties , nil
506
- }
507
-
508
- func (r * SatResolver ) newSnapshotForNamespace (namespace string , subs []* v1alpha1.Subscription , csvs []* v1alpha1.ClusterServiceVersion ) (* cache.Snapshot , error ) {
509
- existingOperatorCatalog := cache .NewVirtualSourceKey (namespace )
510
- // build a catalog snapshot of CSVs without subscriptions
511
- csvSubscriptions := make (map [* v1alpha1.ClusterServiceVersion ]* v1alpha1.Subscription )
512
- for _ , sub := range subs {
513
- for _ , csv := range csvs {
514
- if csv .Name == sub .Status .InstalledCSV {
515
- csvSubscriptions [csv ] = sub
516
- break
517
- }
518
- }
519
- }
520
- var csvsMissingProperties []* v1alpha1.ClusterServiceVersion
521
- standaloneOperators := make ([]* cache.Entry , 0 )
522
- for _ , csv := range csvs {
523
- op , err := newOperatorFromV1Alpha1CSV (csv )
524
- if err != nil {
525
- return nil , err
526
- }
527
-
528
- if anno , ok := csv .GetAnnotations ()[projection .PropertiesAnnotationKey ]; ! ok {
529
- csvsMissingProperties = append (csvsMissingProperties , csv )
530
- if inferred , err := r .inferProperties (csv , subs ); err != nil {
531
- r .log .Warnf ("unable to infer properties for csv %q: %w" , csv .Name , err )
532
- } else {
533
- op .Properties = append (op .Properties , inferred ... )
534
- }
535
- } else if props , err := projection .PropertyListFromPropertiesAnnotation (anno ); err != nil {
536
- return nil , fmt .Errorf ("failed to retrieve properties of csv %q: %w" , csv .GetName (), err )
537
- } else {
538
- op .Properties = props
539
- }
540
-
541
- op .SourceInfo = & cache.OperatorSourceInfo {
542
- Catalog : existingOperatorCatalog ,
543
- Subscription : csvSubscriptions [csv ],
544
- }
545
- // Try to determine source package name from properties and add to SourceInfo.
546
- for _ , p := range op .Properties {
547
- if p .Type != opregistry .PackageType {
548
- continue
549
- }
550
- var pp opregistry.PackageProperty
551
- err := json .Unmarshal ([]byte (p .Value ), & pp )
552
- if err != nil {
553
- r .log .Warnf ("failed to unmarshal package property of csv %q: %w" , csv .Name , err )
554
- continue
555
- }
556
- op .SourceInfo .Package = pp .PackageName
557
- }
558
-
559
- standaloneOperators = append (standaloneOperators , op )
560
- }
561
-
562
- if len (csvsMissingProperties ) > 0 {
563
- names := make ([]string , len (csvsMissingProperties ))
564
- for i , csv := range csvsMissingProperties {
565
- names [i ] = csv .GetName ()
566
- }
567
- r .log .Infof ("considered csvs without properties annotation during resolution: %v" , names )
568
- }
569
-
570
- return & cache.Snapshot {Entries : standaloneOperators }, nil
571
- }
572
-
573
464
func (r * SatResolver ) addInvariants (namespacedCache cache.MultiCatalogOperatorFinder , variables map [solver.Identifier ]solver.Variable ) {
574
465
// no two operators may provide the same GVK or Package in a namespace
575
466
gvkConflictToVariable := make (map [opregistry.GVKProperty ][]solver.Identifier )
@@ -923,51 +814,6 @@ func predicateForRequiredLabelProperty(value string) (cache.Predicate, error) {
923
814
return cache .LabelPredicate (label .Label ), nil
924
815
}
925
816
926
- func newOperatorFromV1Alpha1CSV (csv * v1alpha1.ClusterServiceVersion ) (* cache.Entry , error ) {
927
- providedAPIs := cache .EmptyAPISet ()
928
- for _ , crdDef := range csv .Spec .CustomResourceDefinitions .Owned {
929
- parts := strings .SplitN (crdDef .Name , "." , 2 )
930
- if len (parts ) < 2 {
931
- return nil , fmt .Errorf ("error parsing crd name: %s" , crdDef .Name )
932
- }
933
- providedAPIs [opregistry.APIKey {Plural : parts [0 ], Group : parts [1 ], Version : crdDef .Version , Kind : crdDef .Kind }] = struct {}{}
934
- }
935
- for _ , api := range csv .Spec .APIServiceDefinitions .Owned {
936
- providedAPIs [opregistry.APIKey {Group : api .Group , Version : api .Version , Kind : api .Kind , Plural : api .Name }] = struct {}{}
937
- }
938
-
939
- requiredAPIs := cache .EmptyAPISet ()
940
- for _ , crdDef := range csv .Spec .CustomResourceDefinitions .Required {
941
- parts := strings .SplitN (crdDef .Name , "." , 2 )
942
- if len (parts ) < 2 {
943
- return nil , fmt .Errorf ("error parsing crd name: %s" , crdDef .Name )
944
- }
945
- requiredAPIs [opregistry.APIKey {Plural : parts [0 ], Group : parts [1 ], Version : crdDef .Version , Kind : crdDef .Kind }] = struct {}{}
946
- }
947
- for _ , api := range csv .Spec .APIServiceDefinitions .Required {
948
- requiredAPIs [opregistry.APIKey {Group : api .Group , Version : api .Version , Kind : api .Kind , Plural : api .Name }] = struct {}{}
949
- }
950
-
951
- properties , err := providedAPIsToProperties (providedAPIs )
952
- if err != nil {
953
- return nil , err
954
- }
955
- dependencies , err := requiredAPIsToProperties (requiredAPIs )
956
- if err != nil {
957
- return nil , err
958
- }
959
- properties = append (properties , dependencies ... )
960
-
961
- return & cache.Entry {
962
- Name : csv .GetName (),
963
- Version : & csv .Spec .Version .Version ,
964
- ProvidedAPIs : providedAPIs ,
965
- RequiredAPIs : requiredAPIs ,
966
- SourceInfo : & cache .ExistingOperator ,
967
- Properties : properties ,
968
- }, nil
969
- }
970
-
971
817
func providedAPIsToProperties (apis cache.APISet ) (out []* api.Property , err error ) {
972
818
out = make ([]* api.Property , 0 )
973
819
for a := range apis {
0 commit comments