Skip to content

Commit 4b67acc

Browse files
Merge pull request #1990 from benluddy/subscription-constraint-strings
Bug 1921954: Clarify subscription constraint strings in resolution failures.
2 parents df2741d + 360cf6f commit 4b67acc

File tree

6 files changed

+74
-19
lines changed

6 files changed

+74
-19
lines changed

pkg/controller/registry/resolver/installabletypes.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ func NewBundleInstallable(bundle, channel string, catalog registry.CatalogKey, c
6464

6565
func NewSubscriptionInstallable(pkg string) SubscriptionInstallable {
6666
return SubscriptionInstallable{
67-
identifier: solver.Identifier(pkg),
68-
constraints: []solver.Constraint{solver.Mandatory()},
67+
identifier: solver.Identifier(pkg),
68+
constraints: []solver.Constraint{
69+
ConstraintSubscriptionExists,
70+
},
6971
}
7072
}
7173

@@ -83,5 +85,35 @@ func (r SubscriptionInstallable) Constraints() []solver.Constraint {
8385
}
8486

8587
func (r *SubscriptionInstallable) AddDependency(dependencies []solver.Identifier) {
86-
r.constraints = append(r.constraints, solver.Dependency(dependencies...))
88+
if len(dependencies) == 0 {
89+
r.constraints = append(r.constraints, ConstraintSubscriptionWithoutCandidates)
90+
return
91+
}
92+
93+
s := make([]string, len(dependencies))
94+
for i, each := range dependencies {
95+
s[i] = string(each)
96+
}
97+
r.constraints = append(r.constraints, PrettyConstraint(solver.Dependency(dependencies...), fmt.Sprintf("subscription to %%s requires at least one of %s", strings.Join(s, ", "))))
98+
}
99+
100+
func PrettyConstraint(c solver.Constraint, format string) solver.Constraint {
101+
return prettyConstraint{
102+
Constraint: c,
103+
format: format,
104+
}
87105
}
106+
107+
type prettyConstraint struct {
108+
solver.Constraint
109+
format string
110+
}
111+
112+
func (pc prettyConstraint) String(subject solver.Identifier) string {
113+
return fmt.Sprintf(pc.format, subject)
114+
}
115+
116+
var (
117+
ConstraintSubscriptionExists = PrettyConstraint(solver.Mandatory(), "a subscription to package %s exists in the namespace")
118+
ConstraintSubscriptionWithoutCandidates = PrettyConstraint(solver.Dependency(), "no operators found matching the subscription criteria for %s")
119+
)

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Constraint interface {
1414
String(subject Identifier) string
1515
apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit
1616
order() []Identifier
17+
anchor() bool
1718
}
1819

1920
// zeroConstraint is returned by ConstraintOf in error cases.
@@ -33,6 +34,10 @@ func (zeroConstraint) order() []Identifier {
3334
return nil
3435
}
3536

37+
func (zeroConstraint) anchor() bool {
38+
return false
39+
}
40+
3641
// AppliedConstraint values compose a single Constraint with the
3742
// Installable it applies to.
3843
type AppliedConstraint struct {
@@ -60,6 +65,10 @@ func (constraint mandatory) order() []Identifier {
6065
return nil
6166
}
6267

68+
func (constraint mandatory) anchor() bool {
69+
return true
70+
}
71+
6372
// Mandatory returns a Constraint that will permit only solutions that
6473
// contain a particular Installable.
6574
func Mandatory() Constraint {
@@ -80,6 +89,10 @@ func (constraint prohibited) order() []Identifier {
8089
return nil
8190
}
8291

92+
func (constraint prohibited) anchor() bool {
93+
return false
94+
}
95+
8396
// Prohibited returns a Constraint that will reject any solution that
8497
// contains a particular Installable. Callers may also decide to omit
8598
// an Installable from input to Solve rather than apply such a
@@ -113,6 +126,10 @@ func (constraint dependency) order() []Identifier {
113126
return constraint
114127
}
115128

129+
func (constraint dependency) anchor() bool {
130+
return false
131+
}
132+
116133
// Dependency returns a Constraint that will only permit solutions
117134
// containing a given Installable on the condition that at least one
118135
// of the Installables identified by the given Identifiers also
@@ -136,6 +153,10 @@ func (constraint conflict) order() []Identifier {
136153
return nil
137154
}
138155

156+
func (constraint conflict) anchor() bool {
157+
return false
158+
}
159+
139160
// Conflict returns a Constraint that will permit solutions containing
140161
// either the constrained Installable, the Installable identified by
141162
// the given Identifier, or neither, but not both.
@@ -168,6 +189,10 @@ func (constraint leq) order() []Identifier {
168189
return nil
169190
}
170191

192+
func (constraint leq) anchor() bool {
193+
return false
194+
}
195+
171196
// AtMost returns a Constraint that forbids solutions that contain
172197
// more than n of the Installables identified by the given
173198
// Identifiers.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,14 @@ func (d *litMapping) CardinalityConstrainer(g inter.Adder, ms []z.Lit) *logic.Ca
158158
return cs
159159
}
160160

161-
// MandatoryIdentifiers returns a slice containing the Identifiers of
162-
// every Installable with at least one "Mandatory" constraint, in the
161+
// AnchorIdentifiers returns a slice containing the Identifiers of
162+
// every Installable with at least one "anchor" constraint, in the
163163
// order they appear in the input.
164-
func (d *litMapping) MandatoryIdentifiers() []Identifier {
164+
func (d *litMapping) AnchorIdentifiers() []Identifier {
165165
var ids []Identifier
166166
for _, installable := range d.inorder {
167167
for _, constraint := range installable.Constraints() {
168-
if _, ok := constraint.(mandatory); ok {
168+
if constraint.anchor() {
169169
ids = append(ids, installable.Identifier())
170170
break
171171
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func TestSearch(t *testing.T) {
8888
}
8989

9090
var anchors []z.Lit
91-
for _, id := range h.lits.MandatoryIdentifiers() {
91+
for _, id := range h.lits.AnchorIdentifiers() {
9292
anchors = append(anchors, h.lits.LitOf(id))
9393
}
9494

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func (s *solver) Solve(ctx context.Context) (result []Installable, err error) {
6565

6666
// collect literals of all mandatory installables to assume as a baseline
6767
var assumptions []z.Lit
68-
for _, anchor := range s.litMap.MandatoryIdentifiers() {
68+
for _, anchor := range s.litMap.AnchorIdentifiers() {
6969
assumptions = append(assumptions, s.litMap.LitOf(anchor))
7070
}
7171

pkg/controller/registry/resolver/step_resolver_test.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func SharedResolverSpecs() []resolverTest {
105105
solver.Dependency(),
106106
},
107107
},
108-
Constraint: solver.Mandatory(),
108+
Constraint: ConstraintSubscriptionExists,
109109
},
110110
{
111111
Installable: &SubscriptionInstallable{
@@ -115,7 +115,7 @@ func SharedResolverSpecs() []resolverTest {
115115
solver.Dependency(),
116116
},
117117
},
118-
Constraint: solver.Dependency(),
118+
Constraint: ConstraintSubscriptionWithoutCandidates,
119119
},
120120
},
121121
},
@@ -270,12 +270,11 @@ func SharedResolverSpecs() []resolverTest {
270270
Installable: &SubscriptionInstallable{
271271
identifier: "a",
272272
constraints: []solver.Constraint{
273-
solver.Mandatory(),
274-
solver.Dependency("catsrc/catsrc-namespace/alpha/a.v1"),
275-
solver.AtMost(1, "catsrc/catsrc-namespace/alpha/a.v1"),
273+
ConstraintSubscriptionExists,
274+
PrettyConstraint(solver.Dependency("catsrc/catsrc-namespace/alpha/a.v1"), "subscription to %s requires at least one of catsrc/catsrc-namespace/alpha/a.v1"),
276275
},
277276
},
278-
Constraint: solver.Dependency("catsrc/catsrc-namespace/alpha/a.v1"),
277+
Constraint: PrettyConstraint(solver.Dependency("catsrc/catsrc-namespace/alpha/a.v1"), "subscription to %s requires at least one of catsrc/catsrc-namespace/alpha/a.v1"),
279278
},
280279
{
281280
Installable: &BundleInstallable{
@@ -288,12 +287,11 @@ func SharedResolverSpecs() []resolverTest {
288287
Installable: &SubscriptionInstallable{
289288
identifier: "a",
290289
constraints: []solver.Constraint{
291-
solver.Mandatory(),
292-
solver.Dependency("catsrc/catsrc-namespace/alpha/a.v1"),
293-
solver.AtMost(1, "catsrc/catsrc-namespace/alpha/a.v1"),
290+
ConstraintSubscriptionExists,
291+
PrettyConstraint(solver.Dependency("catsrc/catsrc-namespace/alpha/a.v1"), "subscription to %s requires at least one of catsrc/catsrc-namespace/alpha/a.v1"),
294292
},
295293
},
296-
Constraint: solver.Mandatory(),
294+
Constraint: ConstraintSubscriptionExists,
297295
},
298296
}),
299297
},

0 commit comments

Comments
 (0)