Skip to content

feat(resolver): Indicate dependency class in resolution constraint text #2258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 0 additions & 182 deletions pkg/controller/registry/resolver/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"sync"
"time"

"github.com/blang/semver/v4"
"github.com/sirupsen/logrus"

"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1"
Expand Down Expand Up @@ -387,16 +386,6 @@ func (s SortableSnapshots) Swap(i, j int) {
s.snapshots[i], s.snapshots[j] = s.snapshots[j], s.snapshots[i]
}

type OperatorPredicateFunc func(*Operator) bool

func (opf OperatorPredicateFunc) Test(o *Operator) bool {
return opf(o)
}

type OperatorPredicate interface {
Test(*Operator) bool
}

func (s *CatalogSnapshot) Find(p ...OperatorPredicate) []*Operator {
s.m.RLock()
defer s.m.RUnlock()
Expand All @@ -420,155 +409,6 @@ func (f EmptyOperatorFinder) Find(...OperatorPredicate) []*Operator {
return nil
}

func WithCSVName(name string) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
return o.name == name
})
}

func WithChannel(channel string) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
// all operators match the empty channel
if channel == "" {
return true
}
if o.bundle == nil {
return false
}
return o.bundle.ChannelName == channel
})
}

func WithPackage(pkg string) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
for _, p := range o.Properties() {
if p.Type != opregistry.PackageType {
continue
}
var prop opregistry.PackageProperty
err := json.Unmarshal([]byte(p.Value), &prop)
if err != nil {
continue
}
if prop.PackageName == pkg {
return true
}
}
return o.Package() == pkg
})
}

func WithVersionInRange(r semver.Range) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
for _, p := range o.Properties() {
if p.Type != opregistry.PackageType {
continue
}
var prop opregistry.PackageProperty
err := json.Unmarshal([]byte(p.Value), &prop)
if err != nil {
continue
}
ver, err := semver.Parse(prop.Version)
if err != nil {
continue
}
if r(ver) {
return true
}
}
return o.version != nil && r(*o.version)
})
}

func WithLabel(label string) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
for _, p := range o.Properties() {
if p.Type != opregistry.LabelType {
continue
}
var prop opregistry.LabelProperty
err := json.Unmarshal([]byte(p.Value), &prop)
if err != nil {
continue
}
if prop.Label == label {
return true
}
}
return false
})
}

func WithCatalog(key registry.CatalogKey) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
return key.Equal(o.SourceInfo().Catalog)
})
}

func ProvidingAPI(api opregistry.APIKey) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
for _, p := range o.Properties() {
if p.Type != opregistry.GVKType {
continue
}
var prop opregistry.GVKProperty
err := json.Unmarshal([]byte(p.Value), &prop)
if err != nil {
continue
}
if prop.Kind == api.Kind && prop.Version == api.Version && prop.Group == api.Group {
return true
}
}
return false
})
}

func SkipRangeIncludes(version semver.Version) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
// TODO: lift range parsing to OperatorSurface
semverRange, err := semver.ParseRange(o.bundle.SkipRange)
return err == nil && semverRange(version)
})
}

func Replaces(name string) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
if o.Replaces() == name {
return true
}
for _, s := range o.bundle.Skips {
if s == name {
return true
}
}
return false
})
}

func And(p ...OperatorPredicate) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
for _, l := range p {
if l.Test(o) == false {
return false
}
}
return true
})
}

func Or(p ...OperatorPredicate) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
for _, l := range p {
if l.Test(o) == true {
return true
}
}
return false
})
}

func AtLeast(n int, operators []*Operator) ([]*Operator, error) {
if len(operators) < n {
return nil, fmt.Errorf("expected at least %d operator(s), got %d", n, len(operators))
Expand Down Expand Up @@ -596,25 +436,3 @@ func Filter(operators []*Operator, p ...OperatorPredicate) []*Operator {
func Matches(o *Operator, p ...OperatorPredicate) bool {
return And(p...).Test(o)
}

func True() OperatorPredicate {
return OperatorPredicateFunc(func(*Operator) bool {
return true
})
}

func False() OperatorPredicate {
return OperatorPredicateFunc(func(*Operator) bool {
return false
})
}

func CountingPredicate(p OperatorPredicate, n *int) OperatorPredicate {
return OperatorPredicateFunc(func(o *Operator) bool {
if p.Test(o) {
*n++
return true
}
return false
})
}
62 changes: 8 additions & 54 deletions pkg/controller/registry/resolver/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func TestOperatorCacheConcurrency(t *testing.T) {
nc := c.Namespaced(namespaces...)
for _, index := range indices {
name := fmt.Sprintf("%s/%s", keys[index].Namespace, keys[index].Name)
operators := nc.Find(WithCSVName(name))
operators := nc.Find(CSVNamePredicate(name))
if len(operators) != 1 {
return fmt.Errorf("expected 1 operator, got %d", len(operators))
}
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestOperatorCacheExpiration(t *testing.T) {
c := NewOperatorCache(rcp, logrus.New(), catsrcLister)
c.ttl = 0 // instantly stale

require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(WithCSVName("csvname")), 1)
require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(CSVNamePredicate("csvname")), 1)
}

func TestOperatorCacheReuse(t *testing.T) {
Expand All @@ -182,7 +182,7 @@ func TestOperatorCacheReuse(t *testing.T) {

c := NewOperatorCache(rcp, logrus.New(), catsrcLister)

require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(WithCSVName("csvname")), 1)
require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(CSVNamePredicate("csvname")), 1)
}

func TestCatalogSnapshotExpired(t *testing.T) {
Expand Down Expand Up @@ -232,7 +232,7 @@ func TestCatalogSnapshotFind(t *testing.T) {
for _, tt := range []tc{
{
Name: "nothing satisfies predicate",
Predicate: OperatorPredicateFunc(func(*Operator) bool {
Predicate: OperatorPredicateTestFunc(func(*Operator) bool {
return false
}),
Operators: []*Operator{
Expand All @@ -244,15 +244,15 @@ func TestCatalogSnapshotFind(t *testing.T) {
},
{
Name: "no operators in snapshot",
Predicate: OperatorPredicateFunc(func(*Operator) bool {
Predicate: OperatorPredicateTestFunc(func(*Operator) bool {
return true
}),
Operators: nil,
Expected: nil,
},
{
Name: "everything satisfies predicate",
Predicate: OperatorPredicateFunc(func(*Operator) bool {
Predicate: OperatorPredicateTestFunc(func(*Operator) bool {
return true
}),
Operators: []*Operator{
Expand All @@ -268,7 +268,7 @@ func TestCatalogSnapshotFind(t *testing.T) {
},
{
Name: "some satisfy predicate",
Predicate: OperatorPredicateFunc(func(o *Operator) bool {
Predicate: OperatorPredicateTestFunc(func(o *Operator) bool {
return o.name != "a"
}),
Operators: []*Operator{
Expand Down Expand Up @@ -333,55 +333,9 @@ func TestStripPluralRequiredAndProvidedAPIKeys(t *testing.T) {
c := NewOperatorCache(rcp, logrus.New(), catsrcLister)

nc := c.Namespaced("testnamespace")
result, err := AtLeast(1, nc.Find(ProvidingAPI(opregistry.APIKey{Group: "g", Version: "v1", Kind: "K"})))
result, err := AtLeast(1, nc.Find(ProvidingAPIPredicate(opregistry.APIKey{Group: "g", Version: "v1", Kind: "K"})))
assert.NoError(t, err)
assert.Equal(t, 1, len(result))
assert.Equal(t, "K.v1.g", result[0].providedAPIs.String())
assert.Equal(t, "K2.v2.g2", result[0].requiredAPIs.String())
}

func TestCountingPredicate(t *testing.T) {
for _, tc := range []struct {
Name string
TestResults []bool
Expected int
}{
{
Name: "no increment on failure",
TestResults: []bool{false},
Expected: 0,
},
{
Name: "increment on success",
TestResults: []bool{true},
Expected: 1,
},
{
Name: "multiple increments",
TestResults: []bool{true, true},
Expected: 2,
},
{
Name: "no increment without test",
TestResults: nil,
Expected: 0,
},
} {
t.Run(tc.Name, func(t *testing.T) {
var (
n int
result bool
)

p := CountingPredicate(OperatorPredicateFunc(func(*Operator) bool {
return result
}), &n)

for _, result = range tc.TestResults {
p.Test(nil)
}

assert.Equal(t, tc.Expected, n)
})
}
}
4 changes: 2 additions & 2 deletions pkg/controller/registry/resolver/installabletypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ func (i *BundleInstallable) AddConflict(id solver.Identifier) {
i.constraints = append(i.constraints, solver.Conflict(id))
}

func (i *BundleInstallable) AddDependency(dependencies []solver.Identifier) {
i.constraints = append(i.constraints, solver.Dependency(dependencies...))
func (i *BundleInstallable) AddConstraint(c solver.Constraint) {
i.constraints = append(i.constraints, c)
}

func (i *BundleInstallable) BundleSourceInfo() (string, string, registry.CatalogKey, error) {
Expand Down
Loading