Skip to content

Commit 98e9d2c

Browse files
committed
add resolver
Signed-off-by: perdasilva <[email protected]>
1 parent 73014b7 commit 98e9d2c

File tree

3 files changed

+238
-38
lines changed

3 files changed

+238
-38
lines changed

internal/resolution/deppy.go

Lines changed: 0 additions & 38 deletions
This file was deleted.

internal/resolution/resolver.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package resolution
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/operator-framework/deppy/pkg/deppy/input"
8+
"github.com/operator-framework/deppy/pkg/deppy/solver"
9+
"sigs.k8s.io/controller-runtime/pkg/client"
10+
11+
"github.com/operator-framework/operator-controller/api/v1alpha1"
12+
"github.com/operator-framework/operator-controller/internal/resolution/variable_sources/olm"
13+
)
14+
15+
type OperatorResolver struct {
16+
entitySource input.EntitySource
17+
client client.Client
18+
}
19+
20+
func NewOperatorResolver(client client.Client, entitySource input.EntitySource) *OperatorResolver {
21+
return &OperatorResolver{
22+
entitySource: entitySource,
23+
client: client,
24+
}
25+
}
26+
27+
func (o *OperatorResolver) Resolve(ctx context.Context) (solver.Solution, error) {
28+
packageNames, err := o.getPackageNames(ctx)
29+
if err != nil {
30+
return nil, fmt.Errorf("failed to get package names for resolution: %w", err)
31+
}
32+
olmVariableSource := olm.NewOLMVariableSource(packageNames...)
33+
deppySolver, err := solver.NewDeppySolver(o.entitySource, olmVariableSource)
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
solution, err := deppySolver.Solve(ctx)
39+
if err != nil {
40+
return nil, err
41+
}
42+
return solution, nil
43+
}
44+
45+
func (o *OperatorResolver) getPackageNames(ctx context.Context) ([]string, error) {
46+
operatorList := v1alpha1.OperatorList{}
47+
if err := o.client.List(ctx, &operatorList); err != nil {
48+
return nil, err
49+
}
50+
var packageNames []string
51+
for _, operator := range operatorList.Items {
52+
packageNames = append(packageNames, operator.Spec.PackageName)
53+
}
54+
return packageNames, nil
55+
}

internal/resolution/resolver_test.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package resolution_test
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"testing"
7+
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
"github.com/operator-framework/deppy/pkg/deppy"
11+
"github.com/operator-framework/deppy/pkg/deppy/input"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
16+
17+
"github.com/operator-framework/operator-controller/api/v1alpha1"
18+
"github.com/operator-framework/operator-controller/internal/resolution"
19+
)
20+
21+
func TestOperatorResolver(t *testing.T) {
22+
RegisterFailHandler(Fail)
23+
RunSpecs(t, "Operator Resolver Suite")
24+
}
25+
26+
func FakeClient(objects ...client.Object) client.Client {
27+
scheme := runtime.NewScheme()
28+
if err := v1alpha1.AddToScheme(scheme); err != nil {
29+
panic(fmt.Sprintf("error creating fake client: %s", err))
30+
}
31+
return fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build()
32+
}
33+
34+
var testEntityCache = map[deppy.Identifier]input.Entity{
35+
"operatorhub/prometheus/0.37.0": *input.NewEntity("operatorhub/prometheus/0.37.0", map[string]string{
36+
"olm.bundle.path": `"quay.io/operatorhubio/prometheus@sha256:3e281e587de3d03011440685fc4fb782672beab044c1ebadc42788ce05a21c35"`,
37+
"olm.channel": "{\"channelName\":\"beta\",\"priority\":0,\"replaces\":\"prometheusoperator.0.32.0\"}",
38+
"olm.gvk": "[{\"group\":\"monitoring.coreos.com\",\"kind\":\"Alertmanager\",\"version\":\"v1\"}, {\"group\":\"monitoring.coreos.com\",\"kind\":\"Prometheus\",\"version\":\"v1\"}]",
39+
"olm.package": "{\"packageName\":\"prometheus\",\"version\":\"0.37.0\"}",
40+
}),
41+
"operatorhub/prometheus/0.47.0": *input.NewEntity("operatorhub/prometheus/0.47.0", map[string]string{
42+
"olm.bundle.path": `"quay.io/operatorhubio/prometheus@sha256:5b04c49d8d3eff6a338b56ec90bdf491d501fe301c9cdfb740e5bff6769a21ed"`,
43+
"olm.channel": "{\"channelName\":\"beta\",\"priority\":0,\"replaces\":\"prometheusoperator.0.37.0\"}",
44+
"olm.gvk": "[{\"group\":\"monitoring.coreos.com\",\"kind\":\"Alertmanager\",\"version\":\"v1\"}, {\"group\":\"monitoring.coreos.com\",\"kind\":\"Prometheus\",\"version\":\"v1alpha1\"}]",
45+
"olm.package": "{\"packageName\":\"prometheus\",\"version\":\"0.47.0\"}",
46+
}),
47+
"operatorhub/packageA/2.0.0": *input.NewEntity("operatorhub/packageA/2.0.0", map[string]string{
48+
"olm.bundle.path": `"foo.io/packageA/packageA:v2.0.0"`,
49+
"olm.channel": "{\"channelName\":\"stable\",\"priority\":0}",
50+
"olm.gvk": "[{\"group\":\"foo.io\",\"kind\":\"Foo\",\"version\":\"v1\"}]",
51+
"olm.package": "{\"packageName\":\"packageA\",\"version\":\"2.0.0\"}",
52+
}),
53+
}
54+
55+
var _ = Describe("OperatorResolver", func() {
56+
It("should resolve the packages described by the available Operator resources", func() {
57+
resources := []client.Object{
58+
&v1alpha1.Operator{
59+
ObjectMeta: metav1.ObjectMeta{
60+
Name: "prometheus",
61+
},
62+
Spec: v1alpha1.OperatorSpec{
63+
PackageName: "prometheus",
64+
},
65+
},
66+
&v1alpha1.Operator{
67+
ObjectMeta: metav1.ObjectMeta{
68+
Name: "packageA",
69+
},
70+
Spec: v1alpha1.OperatorSpec{
71+
PackageName: "packageA",
72+
},
73+
},
74+
}
75+
client := FakeClient(resources...)
76+
entitySource := input.NewCacheQuerier(testEntityCache)
77+
resolver := resolution.NewOperatorResolver(client, entitySource)
78+
solution, err := resolver.Resolve(context.Background())
79+
Expect(err).ToNot(HaveOccurred())
80+
Expect(solution).To(HaveLen(3))
81+
Expect(solution["operatorhub/packageA/2.0.0"]).To(BeTrue())
82+
Expect(solution["operatorhub/prometheus/0.47.0"]).To(BeTrue())
83+
Expect(solution["operatorhub/prometheus/0.37.0"]).To(BeFalse())
84+
})
85+
86+
It("should not return an error if there are not Operator resources", func() {
87+
var resources []client.Object
88+
client := FakeClient(resources...)
89+
entitySource := input.NewCacheQuerier(testEntityCache)
90+
resolver := resolution.NewOperatorResolver(client, entitySource)
91+
solution, err := resolver.Resolve(context.Background())
92+
Expect(err).ToNot(HaveOccurred())
93+
Expect(solution).To(HaveLen(0))
94+
})
95+
96+
It("should return an error if the entity source throws an error", func() {
97+
resource := &v1alpha1.Operator{
98+
ObjectMeta: metav1.ObjectMeta{
99+
Name: "prometheus",
100+
},
101+
Spec: v1alpha1.OperatorSpec{
102+
PackageName: "prometheus",
103+
},
104+
}
105+
client := FakeClient(resource)
106+
entitySource := FailEntitySource{}
107+
resolver := resolution.NewOperatorResolver(client, entitySource)
108+
solution, err := resolver.Resolve(context.Background())
109+
Expect(solution).To(BeNil())
110+
Expect(err).To(HaveOccurred())
111+
})
112+
113+
It("should return an error if the client throws an error", func() {
114+
client := NewFailClientWithError(fmt.Errorf("something bad happened"))
115+
entitySource := input.NewCacheQuerier(testEntityCache)
116+
resolver := resolution.NewOperatorResolver(client, entitySource)
117+
solution, err := resolver.Resolve(context.Background())
118+
Expect(solution).To(BeNil())
119+
Expect(err).To(HaveOccurred())
120+
})
121+
})
122+
123+
var _ input.EntitySource = &FailEntitySource{}
124+
125+
type FailEntitySource struct{}
126+
127+
func (f FailEntitySource) Get(ctx context.Context, id deppy.Identifier) *input.Entity {
128+
return nil
129+
}
130+
131+
func (f FailEntitySource) Filter(ctx context.Context, filter input.Predicate) (input.EntityList, error) {
132+
return nil, fmt.Errorf("error calling filter in entity source")
133+
}
134+
135+
func (f FailEntitySource) GroupBy(ctx context.Context, fn input.GroupByFunction) (input.EntityListMap, error) {
136+
return nil, fmt.Errorf("error calling group by in entity source")
137+
}
138+
139+
func (f FailEntitySource) Iterate(ctx context.Context, fn input.IteratorFunction) error {
140+
return fmt.Errorf("error calling iterate in entity source")
141+
}
142+
143+
var _ client.Client = &FailClient{}
144+
145+
type FailClient struct {
146+
client.Client
147+
err error
148+
}
149+
150+
func NewFailClientWithError(err error) client.Client {
151+
return &FailClient{
152+
Client: FakeClient(),
153+
err: err,
154+
}
155+
}
156+
157+
func (f FailClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
158+
return f.err
159+
}
160+
161+
func (f FailClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
162+
return f.err
163+
}
164+
165+
func (f FailClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
166+
return f.err
167+
}
168+
169+
func (f FailClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
170+
return f.err
171+
}
172+
173+
func (f FailClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
174+
return f.err
175+
}
176+
177+
func (f FailClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
178+
return f.err
179+
}
180+
181+
func (f FailClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
182+
return f.err
183+
}

0 commit comments

Comments
 (0)