Skip to content

Commit 0666fff

Browse files
authored
Clarify solver package responsibility. (#2647)
As part of preparing the resolution component (and subcomponents) for use as a library, this clarifies the responsibility of the solver package as a general-purpose boolean constraint satisfiability solver. Renaming the Variable type -- formerly Installable -- avoids unnecessarily tying it to the resolver package's operator installability use case. The solver package finds solutions to constraint satisfaction problems in general. Signed-off-by: Ben Luddy <[email protected]>
1 parent 6f59a3b commit 0666fff

14 files changed

+337
-334
lines changed

pkg/controller/operators/catalog/operator_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1189,8 +1189,8 @@ func TestSyncResolvingNamespace(t *testing.T) {
11891189
},
11901190
resolveErr: solver.NotSatisfiable{
11911191
{
1192-
Installable: resolver.NewSubscriptionInstallable("a", nil),
1193-
Constraint: resolver.PrettyConstraint(solver.Mandatory(), "something"),
1192+
Variable: resolver.NewSubscriptionVariable("a", nil),
1193+
Constraint: resolver.PrettyConstraint(solver.Mandatory(), "something"),
11941194
},
11951195
},
11961196
},

pkg/controller/registry/resolver/resolver.go

+68-68
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func (w *debugWriter) Write(b []byte) (int, error) {
5555
func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.ClusterServiceVersion, subs []*v1alpha1.Subscription) (cache.OperatorSet, error) {
5656
var errs []error
5757

58-
installables := make(map[solver.Identifier]solver.Installable)
59-
visited := make(map[*cache.Entry]*BundleInstallable)
58+
variables := make(map[solver.Identifier]solver.Variable)
59+
visited := make(map[*cache.Entry]*BundleVariable)
6060

6161
// TODO: better abstraction
6262
startingCSVs := make(map[string]struct{})
@@ -68,12 +68,12 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
6868
}
6969
namespacedCache := r.cache.Namespaced(namespaces...).WithExistingOperators(existingSnapshot, namespaces[0])
7070

71-
_, existingInstallables, err := r.getBundleInstallables(namespaces[0], cache.Filter(existingSnapshot.Entries, cache.True()), namespacedCache, visited)
71+
_, existingVariables, err := r.getBundleVariables(namespaces[0], cache.Filter(existingSnapshot.Entries, cache.True()), namespacedCache, visited)
7272
if err != nil {
7373
return nil, err
7474
}
75-
for _, i := range existingInstallables {
76-
installables[i.Identifier()] = i
75+
for _, i := range existingVariables {
76+
variables[i.Identifier()] = i
7777
}
7878

7979
// build constraints for each Subscription
@@ -96,25 +96,25 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
9696
}
9797

9898
// find operators, in channel order, that can skip from the current version or list the current in "replaces"
99-
subInstallables, err := r.getSubscriptionInstallables(sub, current, namespacedCache, visited)
99+
subVariables, err := r.getSubscriptionVariables(sub, current, namespacedCache, visited)
100100
if err != nil {
101101
errs = append(errs, err)
102102
continue
103103
}
104104

105-
for _, i := range subInstallables {
106-
installables[i.Identifier()] = i
105+
for _, i := range subVariables {
106+
variables[i.Identifier()] = i
107107
}
108108
}
109109

110-
r.addInvariants(namespacedCache, installables)
110+
r.addInvariants(namespacedCache, variables)
111111

112112
if err := namespacedCache.Error(); err != nil {
113113
return nil, err
114114
}
115115

116-
input := make([]solver.Installable, 0)
117-
for _, i := range installables {
116+
input := make([]solver.Variable, 0)
117+
for _, i := range variables {
118118
input = append(input, i)
119119
}
120120

@@ -125,30 +125,30 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
125125
if err != nil {
126126
return nil, err
127127
}
128-
solvedInstallables, err := s.Solve(context.TODO())
128+
solvedVariables, err := s.Solve(context.TODO())
129129
if err != nil {
130130
return nil, err
131131
}
132132

133-
// get the set of bundle installables from the result solved installables
134-
operatorInstallables := make([]BundleInstallable, 0)
135-
for _, installable := range solvedInstallables {
136-
if bundleInstallable, ok := installable.(*BundleInstallable); ok {
137-
_, _, catalog, err := bundleInstallable.BundleSourceInfo()
133+
// get the set of bundle variables from the result solved variables
134+
operatorVariables := make([]BundleVariable, 0)
135+
for _, variable := range solvedVariables {
136+
if bundleVariable, ok := variable.(*BundleVariable); ok {
137+
_, _, catalog, err := bundleVariable.BundleSourceInfo()
138138
if err != nil {
139139
return nil, fmt.Errorf("error determining origin of operator: %w", err)
140140
}
141141
if catalog.Virtual() {
142142
// Result is expected to contain only new things.
143143
continue
144144
}
145-
operatorInstallables = append(operatorInstallables, *bundleInstallable)
145+
operatorVariables = append(operatorVariables, *bundleVariable)
146146
}
147147
}
148148

149149
operators := make(map[string]*cache.Entry)
150-
for _, installableOperator := range operatorInstallables {
151-
csvName, channel, catalog, err := installableOperator.BundleSourceInfo()
150+
for _, variableOperator := range operatorVariables {
151+
csvName, channel, catalog, err := variableOperator.BundleSourceInfo()
152152
if err != nil {
153153
errs = append(errs, err)
154154
continue
@@ -181,11 +181,11 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
181181
BundlePath: op.BundlePath,
182182
Bundle: op.Bundle,
183183
}
184-
if len(installableOperator.Replaces) > 0 {
185-
op.Replaces = installableOperator.Replaces
184+
if len(variableOperator.Replaces) > 0 {
185+
op.Replaces = variableOperator.Replaces
186186
}
187187

188-
// lookup if this installable came from a starting CSV
188+
// lookup if this variable came from a starting CSV
189189
if _, ok := startingCSVs[csvName]; ok {
190190
op.SourceInfo.StartingCSV = csvName
191191
}
@@ -200,10 +200,10 @@ func (r *SatResolver) SolveOperators(namespaces []string, csvs []*v1alpha1.Clust
200200
return operators, nil
201201
}
202202

203-
// newBundleInstallableFromEntry converts an entry into a bundle installable with
203+
// newBundleVariableFromEntry converts an entry into a bundle variable with
204204
// system constraints applied, if they are defined for the entry
205-
func (r *SatResolver) newBundleInstallableFromEntry(entry *cache.Entry) (*BundleInstallable, error) {
206-
bundleInstalleble, err := NewBundleInstallableFromOperator(entry)
205+
func (r *SatResolver) newBundleVariableFromEntry(entry *cache.Entry) (*BundleVariable, error) {
206+
bundleInstalleble, err := NewBundleVariableFromOperator(entry)
207207
if err != nil {
208208
return nil, err
209209
}
@@ -219,9 +219,9 @@ func (r *SatResolver) newBundleInstallableFromEntry(entry *cache.Entry) (*Bundle
219219
return &bundleInstalleble, nil
220220
}
221221

222-
func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, current *cache.Entry, namespacedCache cache.MultiCatalogOperatorFinder, visited map[*cache.Entry]*BundleInstallable) (map[solver.Identifier]solver.Installable, error) {
222+
func (r *SatResolver) getSubscriptionVariables(sub *v1alpha1.Subscription, current *cache.Entry, namespacedCache cache.MultiCatalogOperatorFinder, visited map[*cache.Entry]*BundleVariable) (map[solver.Identifier]solver.Variable, error) {
223223
var cachePredicates, channelPredicates []cache.Predicate
224-
installables := make(map[solver.Identifier]solver.Installable)
224+
variables := make(map[solver.Identifier]solver.Variable)
225225

226226
catalog := cache.SourceKey{
227227
Name: sub.Spec.CatalogSource,
@@ -249,21 +249,21 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu
249249
))
250250
entries = namespacedCache.Catalog(catalog).Find(cachePredicates...)
251251

252-
var si solver.Installable
252+
var si solver.Variable
253253
switch {
254254
case nall == 0:
255-
si = NewInvalidSubscriptionInstallable(sub.GetName(), fmt.Sprintf("no operators found from catalog %s in namespace %s referenced by subscription %s", sub.Spec.CatalogSource, sub.Spec.CatalogSourceNamespace, sub.GetName()))
255+
si = NewInvalidSubscriptionVariable(sub.GetName(), fmt.Sprintf("no operators found from catalog %s in namespace %s referenced by subscription %s", sub.Spec.CatalogSource, sub.Spec.CatalogSourceNamespace, sub.GetName()))
256256
case npkg == 0:
257-
si = NewInvalidSubscriptionInstallable(sub.GetName(), fmt.Sprintf("no operators found in package %s in the catalog referenced by subscription %s", sub.Spec.Package, sub.GetName()))
257+
si = NewInvalidSubscriptionVariable(sub.GetName(), fmt.Sprintf("no operators found in package %s in the catalog referenced by subscription %s", sub.Spec.Package, sub.GetName()))
258258
case nch == 0:
259-
si = NewInvalidSubscriptionInstallable(sub.GetName(), fmt.Sprintf("no operators found in channel %s of package %s in the catalog referenced by subscription %s", sub.Spec.Channel, sub.Spec.Package, sub.GetName()))
259+
si = NewInvalidSubscriptionVariable(sub.GetName(), fmt.Sprintf("no operators found in channel %s of package %s in the catalog referenced by subscription %s", sub.Spec.Channel, sub.Spec.Package, sub.GetName()))
260260
case ncsv == 0:
261-
si = NewInvalidSubscriptionInstallable(sub.GetName(), fmt.Sprintf("no operators found with name %s in channel %s of package %s in the catalog referenced by subscription %s", sub.Spec.StartingCSV, sub.Spec.Channel, sub.Spec.Package, sub.GetName()))
261+
si = NewInvalidSubscriptionVariable(sub.GetName(), fmt.Sprintf("no operators found with name %s in channel %s of package %s in the catalog referenced by subscription %s", sub.Spec.StartingCSV, sub.Spec.Channel, sub.Spec.Package, sub.GetName()))
262262
}
263263

264264
if si != nil {
265-
installables[si.Identifier()] = si
266-
return installables, nil
265+
variables[si.Identifier()] = si
266+
return variables, nil
267267
}
268268
}
269269

@@ -305,23 +305,23 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu
305305
}
306306
}
307307

308-
candidates := make([]*BundleInstallable, 0)
308+
candidates := make([]*BundleVariable, 0)
309309
for _, o := range cache.Filter(sortedBundles, channelPredicates...) {
310310
predicates := append(cachePredicates, cache.CSVNamePredicate(o.Name))
311311
stack := namespacedCache.Catalog(catalog).Find(predicates...)
312-
id, installable, err := r.getBundleInstallables(sub.Namespace, stack, namespacedCache, visited)
312+
id, variable, err := r.getBundleVariables(sub.Namespace, stack, namespacedCache, visited)
313313
if err != nil {
314314
return nil, err
315315
}
316316
if len(id) < 1 {
317317
return nil, fmt.Errorf("could not find any potential bundles for subscription: %s", sub.Spec.Package)
318318
}
319319

320-
for _, i := range installable {
320+
for _, i := range variable {
321321
if _, ok := id[i.Identifier()]; ok {
322322
candidates = append(candidates, i)
323323
}
324-
installables[i.Identifier()] = i
324+
variables[i.Identifier()] = i
325325
}
326326
}
327327

@@ -347,17 +347,17 @@ func (r *SatResolver) getSubscriptionInstallables(sub *v1alpha1.Subscription, cu
347347
}
348348

349349
// all candidates added as options for this constraint
350-
subInstallable := NewSubscriptionInstallable(sub.GetName(), depIds)
351-
installables[subInstallable.Identifier()] = subInstallable
350+
subVariable := NewSubscriptionVariable(sub.GetName(), depIds)
351+
variables[subVariable.Identifier()] = subVariable
352352

353-
return installables, nil
353+
return variables, nil
354354
}
355355

356-
func (r *SatResolver) getBundleInstallables(preferredNamespace string, bundleStack []*cache.Entry, namespacedCache cache.MultiCatalogOperatorFinder, visited map[*cache.Entry]*BundleInstallable) (map[solver.Identifier]struct{}, map[solver.Identifier]*BundleInstallable, error) {
356+
func (r *SatResolver) getBundleVariables(preferredNamespace string, bundleStack []*cache.Entry, namespacedCache cache.MultiCatalogOperatorFinder, visited map[*cache.Entry]*BundleVariable) (map[solver.Identifier]struct{}, map[solver.Identifier]*BundleVariable, error) {
357357
errs := make([]error, 0)
358-
installables := make(map[solver.Identifier]*BundleInstallable) // all installables, including dependencies
358+
variables := make(map[solver.Identifier]*BundleVariable) // all variables, including dependencies
359359

360-
// track the first layer of installable ids
360+
// track the first layer of variable ids
361361
var initial = make(map[*cache.Entry]struct{})
362362
for _, o := range bundleStack {
363363
initial[o] = struct{}{}
@@ -372,17 +372,17 @@ func (r *SatResolver) getBundleInstallables(preferredNamespace string, bundleSta
372372
bundleStack = bundleStack[:len(bundleStack)-1]
373373

374374
if b, ok := visited[bundle]; ok {
375-
installables[b.identifier] = b
375+
variables[b.identifier] = b
376376
continue
377377
}
378378

379-
bundleInstallable, err := r.newBundleInstallableFromEntry(bundle)
379+
bundleVariable, err := r.newBundleVariableFromEntry(bundle)
380380
if err != nil {
381381
errs = append(errs, err)
382382
continue
383383
}
384384

385-
visited[bundle] = bundleInstallable
385+
visited[bundle] = bundleVariable
386386

387387
dependencyPredicates, err := r.pc.convertDependencyProperties(bundle.Properties)
388388
if err != nil {
@@ -431,34 +431,34 @@ func (r *SatResolver) getBundleInstallables(preferredNamespace string, bundleSta
431431
// (after sorting) to remove all bundles that
432432
// don't satisfy the dependency.
433433
for _, b := range cache.Filter(sortedBundles, d) {
434-
i, err := r.newBundleInstallableFromEntry(b)
434+
i, err := r.newBundleVariableFromEntry(b)
435435
if err != nil {
436436
errs = append(errs, err)
437437
continue
438438
}
439-
installables[i.Identifier()] = i
439+
variables[i.Identifier()] = i
440440
bundleDependencies = append(bundleDependencies, i.Identifier())
441441
bundleStack = append(bundleStack, b)
442442
}
443-
bundleInstallable.AddConstraint(PrettyConstraint(
443+
bundleVariable.AddConstraint(PrettyConstraint(
444444
solver.Dependency(bundleDependencies...),
445445
fmt.Sprintf("bundle %s requires an operator %s", bundle.Name, d.String()),
446446
))
447447
}
448448

449-
installables[bundleInstallable.Identifier()] = bundleInstallable
449+
variables[bundleVariable.Identifier()] = bundleVariable
450450
}
451451

452452
if len(errs) > 0 {
453453
return nil, nil, utilerrors.NewAggregate(errs)
454454
}
455455

456-
ids := make(map[solver.Identifier]struct{}) // immediate installables found via predicates
456+
ids := make(map[solver.Identifier]struct{}) // immediate variables found via predicates
457457
for o := range initial {
458458
ids[visited[o].Identifier()] = struct{}{}
459459
}
460460

461-
return ids, installables, nil
461+
return ids, variables, nil
462462
}
463463

464464
func (r *SatResolver) inferProperties(csv *v1alpha1.ClusterServiceVersion, subs []*v1alpha1.Subscription) ([]*api.Property, error) {
@@ -571,16 +571,16 @@ func (r *SatResolver) newSnapshotForNamespace(namespace string, subs []*v1alpha1
571571
return &cache.Snapshot{Entries: standaloneOperators}, nil
572572
}
573573

574-
func (r *SatResolver) addInvariants(namespacedCache cache.MultiCatalogOperatorFinder, installables map[solver.Identifier]solver.Installable) {
574+
func (r *SatResolver) addInvariants(namespacedCache cache.MultiCatalogOperatorFinder, variables map[solver.Identifier]solver.Variable) {
575575
// no two operators may provide the same GVK or Package in a namespace
576-
gvkConflictToInstallable := make(map[opregistry.GVKProperty][]solver.Identifier)
577-
packageConflictToInstallable := make(map[string][]solver.Identifier)
578-
for _, installable := range installables {
579-
bundleInstallable, ok := installable.(*BundleInstallable)
576+
gvkConflictToVariable := make(map[opregistry.GVKProperty][]solver.Identifier)
577+
packageConflictToVariable := make(map[string][]solver.Identifier)
578+
for _, variable := range variables {
579+
bundleVariable, ok := variable.(*BundleVariable)
580580
if !ok {
581581
continue
582582
}
583-
csvName, channel, catalog, err := bundleInstallable.BundleSourceInfo()
583+
csvName, channel, catalog, err := bundleVariable.BundleSourceInfo()
584584
if err != nil {
585585
continue
586586
}
@@ -600,7 +600,7 @@ func (r *SatResolver) addInvariants(namespacedCache cache.MultiCatalogOperatorFi
600600
if err != nil {
601601
continue
602602
}
603-
gvkConflictToInstallable[prop] = append(gvkConflictToInstallable[prop], installable.Identifier())
603+
gvkConflictToVariable[prop] = append(gvkConflictToVariable[prop], variable.Identifier())
604604
}
605605

606606
// cannot have the same package
@@ -613,18 +613,18 @@ func (r *SatResolver) addInvariants(namespacedCache cache.MultiCatalogOperatorFi
613613
if err != nil {
614614
continue
615615
}
616-
packageConflictToInstallable[prop.PackageName] = append(packageConflictToInstallable[prop.PackageName], installable.Identifier())
616+
packageConflictToVariable[prop.PackageName] = append(packageConflictToVariable[prop.PackageName], variable.Identifier())
617617
}
618618
}
619619

620-
for gvk, is := range gvkConflictToInstallable {
621-
s := NewSingleAPIProviderInstallable(gvk.Group, gvk.Version, gvk.Kind, is)
622-
installables[s.Identifier()] = s
620+
for gvk, is := range gvkConflictToVariable {
621+
s := NewSingleAPIProviderVariable(gvk.Group, gvk.Version, gvk.Kind, is)
622+
variables[s.Identifier()] = s
623623
}
624624

625-
for pkg, is := range packageConflictToInstallable {
626-
s := NewSinglePackageInstanceInstallable(pkg, is)
627-
installables[s.Identifier()] = s
625+
for pkg, is := range packageConflictToVariable {
626+
s := NewSinglePackageInstanceVariable(pkg, is)
627+
variables[s.Identifier()] = s
628628
}
629629
}
630630

pkg/controller/registry/resolver/solver/bench_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"testing"
88
)
99

10-
var BenchmarkInput = func() []Installable {
10+
var BenchmarkInput = func() []Variable {
1111
const (
1212
length = 256
1313
seed = 9
@@ -22,7 +22,7 @@ var BenchmarkInput = func() []Installable {
2222
return Identifier(strconv.Itoa(i))
2323
}
2424

25-
installable := func(i int) TestInstallable {
25+
variable := func(i int) TestVariable {
2626
var c []Constraint
2727
if rand.Float64() < pMandatory {
2828
c = append(c, Mandatory())
@@ -49,16 +49,16 @@ var BenchmarkInput = func() []Installable {
4949
c = append(c, Conflict(id(y)))
5050
}
5151
}
52-
return TestInstallable{
52+
return TestVariable{
5353
identifier: id(i),
5454
constraints: c,
5555
}
5656
}
5757

5858
rand.Seed(seed)
59-
result := make([]Installable, length)
59+
result := make([]Variable, length)
6060
for i := range result {
61-
result[i] = installable(i)
61+
result[i] = variable(i)
6262
}
6363
return result
6464
}()

0 commit comments

Comments
 (0)