Skip to content

Commit 5ef6205

Browse files
committed
Make a subscription without at least one candidate fail resolution.
In order to allow subscriptions to be satisfied by an already-installed CSV, those operators that are already associated with a subscription are now a part of the resolution constraint system.
1 parent 18dd8b3 commit 5ef6205

File tree

5 files changed

+173
-114
lines changed

5 files changed

+173
-114
lines changed

pkg/controller/registry/resolver/installabletypes.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ func (i *BundleInstallable) MakeProhibited() {
2828
i.constraints = append(i.constraints, solver.Prohibited())
2929
}
3030

31+
func (i *BundleInstallable) AddConflict(id solver.Identifier) {
32+
i.constraints = append(i.constraints, solver.Conflict(id))
33+
}
34+
3135
func (i *BundleInstallable) AddDependency(dependencies []solver.Identifier) {
3236
i.constraints = append(i.constraints, solver.Dependency(dependencies...))
3337
}
@@ -47,9 +51,13 @@ func (i *BundleInstallable) BundleSourceInfo() (string, string, registry.Catalog
4751
return csvName, channel, catalog, nil
4852
}
4953

54+
func bundleId(bundle, channel string, catalog registry.CatalogKey) solver.Identifier {
55+
return solver.Identifier(fmt.Sprintf("%s/%s/%s", catalog.String(), channel, bundle))
56+
}
57+
5058
func NewBundleInstallable(bundle, channel string, catalog registry.CatalogKey, constraints ...solver.Constraint) BundleInstallable {
5159
return BundleInstallable{
52-
identifier: solver.Identifier(fmt.Sprintf("%s/%s/%s", catalog.String(), channel, bundle)),
60+
identifier: bundleId(bundle, channel, catalog),
5361
constraints: constraints,
5462
}
5563
}
@@ -75,7 +83,5 @@ func (r SubscriptionInstallable) Constraints() []solver.Constraint {
7583
}
7684

7785
func (r *SubscriptionInstallable) AddDependency(dependencies []solver.Identifier) {
78-
if len(dependencies) > 0 {
79-
r.constraints = append(r.constraints, solver.Dependency(dependencies...))
80-
}
86+
r.constraints = append(r.constraints, solver.Dependency(dependencies...))
8187
}

pkg/controller/registry/resolver/resolver.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)