@@ -15,14 +15,13 @@ import (
15
15
"github.com/operator-framework/api/pkg/operators/v1alpha1"
16
16
v1alpha1listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
17
17
"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"
19
18
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/solver"
20
19
"github.com/operator-framework/operator-registry/pkg/api"
21
20
opregistry "github.com/operator-framework/operator-registry/pkg/registry"
22
21
)
23
22
24
23
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 )
26
25
}
27
26
28
27
type SatResolver struct {
@@ -52,7 +51,7 @@ func (w *debugWriter) Write(b []byte) (int, error) {
52
51
return n , nil
53
52
}
54
53
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 ) {
56
55
var errs []error
57
56
58
57
installables := make (map [solver.Identifier ]solver.Installable )
@@ -61,14 +60,15 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
61
60
// TODO: better abstraction
62
61
startingCSVs := make (map [string ]struct {})
63
62
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" )
68
68
}
69
- namespacedCache := r .cache .Namespaced (namespaces ... ).WithExistingOperators (existingSnapshot , namespaces [0 ])
70
69
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 )
72
72
if err != nil {
73
73
return nil , err
74
74
}
@@ -80,15 +80,16 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
80
80
for _ , sub := range subs {
81
81
// find the currently installed operator (if it exists)
82
82
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 )
91
89
}
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 ]
92
93
}
93
94
94
95
if current == nil && sub .Spec .StartingCSV != "" {
@@ -461,116 +462,6 @@ func (r *SatResolver) getBundleInstallables(preferredNamespace string, bundleSta
461
462
return ids , installables , nil
462
463
}
463
464
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
-
574
465
func (r * SatResolver ) addInvariants (namespacedCache cache.MultiCatalogOperatorFinder , installables map [solver.Identifier ]solver.Installable ) {
575
466
// no two operators may provide the same GVK or Package in a namespace
576
467
gvkConflictToInstallable := make (map [opregistry.GVKProperty ][]solver.Identifier )
@@ -924,51 +815,6 @@ func predicateForRequiredLabelProperty(value string) (cache.Predicate, error) {
924
815
return cache .LabelPredicate (label .Label ), nil
925
816
}
926
817
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
-
972
818
func providedAPIsToProperties (apis cache.APISet ) (out []* api.Property , err error ) {
973
819
out = make ([]* api.Property , 0 )
974
820
for a := range apis {
0 commit comments