@@ -101,7 +101,7 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
101101 }
102102
103103 // find operators, in channel order, that can skip from the current version or list the current in "replaces"
104- subInstallables , err := r .getSubscriptionInstallables (pkg , current , catalog , predicates , channelFilter , namespacedCache , visited )
104+ subInstallables , err := r .getSubscriptionInstallables (pkg , sub . Namespace , current , catalog , predicates , channelFilter , namespacedCache , visited )
105105 if err != nil {
106106 errs = append (errs , err )
107107 continue
@@ -122,7 +122,7 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
122122 if len (errs ) > 0 {
123123 return nil , utilerrors .NewAggregate (errs )
124124 }
125- s , err := solver .New (solver .WithInput (input ), solver .WithTracer (solver.LoggingTracer {& debugWriter {r .log }}))
125+ s , err := solver .New (solver .WithInput (input ), solver .WithTracer (solver.LoggingTracer {Writer : & debugWriter {r .log }}))
126126 if err != nil {
127127 return nil , err
128128 }
@@ -135,6 +135,14 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
135135 operatorInstallables := make ([]BundleInstallable , 0 )
136136 for _ , installable := range solvedInstallables {
137137 if bundleInstallable , ok := installable .(* BundleInstallable ); ok {
138+ _ , _ , catalog , err := bundleInstallable .BundleSourceInfo ()
139+ if err != nil {
140+ return nil , fmt .Errorf ("error determining origin of operator: %w" , err )
141+ }
142+ if catalog .Virtual () {
143+ // Result is expected to contain only new things.
144+ continue
145+ }
138146 operatorInstallables = append (operatorInstallables , * bundleInstallable )
139147 }
140148 }
@@ -171,7 +179,7 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
171179 return operators , nil
172180}
173181
174- func (r * SatResolver ) getSubscriptionInstallables (pkg string , current * Operator , catalog registry.CatalogKey , cachePredicates []OperatorPredicate , channelPredicates []OperatorPredicate , namespacedCache MultiCatalogOperatorFinder , visited map [OperatorSurface ]* BundleInstallable ) (map [solver.Identifier ]solver.Installable , error ) {
182+ func (r * SatResolver ) getSubscriptionInstallables (pkg , namespace string , current * Operator , catalog registry.CatalogKey , cachePredicates []OperatorPredicate , channelPredicates []OperatorPredicate , namespacedCache MultiCatalogOperatorFinder , visited map [OperatorSurface ]* BundleInstallable ) (map [solver.Identifier ]solver.Installable , error ) {
175183 installables := make (map [solver.Identifier ]solver.Installable , 0 )
176184 candidates := make ([]* BundleInstallable , 0 )
177185
@@ -180,12 +188,6 @@ func (r *SatResolver) getSubscriptionInstallables(pkg string, current *Operator,
180188
181189 bundles := namespacedCache .Catalog (catalog ).Find (cachePredicates ... )
182190
183- // there are no options for this package, return early
184- if len (bundles ) == 0 {
185- // should this condition fail resolution altogether?
186- return installables , nil
187- }
188-
189191 // bundles in the default channel appear first, then lexicographically order by channel name
190192 sort .SliceStable (bundles , func (i , j int ) bool {
191193 var idef bool
@@ -243,9 +245,19 @@ func (r *SatResolver) getSubscriptionInstallables(pkg string, current *Operator,
243245 // track which operator this is replacing, so that it can be realized when creating the resources on cluster
244246 if current != nil {
245247 c .Replaces = current .Identifier ()
248+ // Until properties are projected onto CSVs,
249+ // an installed operator can't be confidently
250+ // folded into the existing package uniqueness
251+ // constraints, so for the replacement case, a
252+ // one-to-one conflict is created between the
253+ // replacer and the replacee.
254+ c .AddConflict (bundleId (current .Identifier (), current .Channel (), registry .NewVirtualCatalogKey (namespace )))
246255 }
247256 depIds = append (depIds , c .Identifier ())
248257 }
258+ if current != nil {
259+ depIds = append (depIds , bundleId (current .Identifier (), current .Channel (), registry .NewVirtualCatalogKey (namespace )))
260+ }
249261
250262 // all candidates added as options for this constraint
251263 subInstallable .AddDependency (depIds )
@@ -363,8 +375,12 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1
363375 }
364376 standaloneOperators := make ([]* Operator , 0 )
365377 for _ , csv := range csvs {
366- if _ , ok := csvsWithSubscriptions [csv ]; ok {
367- continue
378+ var constraints []solver.Constraint
379+ if _ , ok := csvsWithSubscriptions [csv ]; ! ok {
380+ // CSVs already associated with a Subscription
381+ // may be replaced, but freestanding CSVs must
382+ // appear in any solution.
383+ constraints = append (constraints , solver .Mandatory ())
368384 }
369385
370386 op , err := NewOperatorFromV1Alpha1CSV (csv )
@@ -377,7 +393,7 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1
377393 standaloneOperators = append (standaloneOperators , op )
378394
379395 // all standalone operators are mandatory
380- i := NewBundleInstallable (op .Identifier (), "" , existingOperatorCatalog , solver . Mandatory () )
396+ i := NewBundleInstallable (op .Identifier (), "" , existingOperatorCatalog , constraints ... )
381397 installables = append (installables , & i )
382398 }
383399
0 commit comments