Skip to content

Commit fff05ac

Browse files
jmprusiPer Goncalves da Silva
and
Per Goncalves da Silva
committed
wip
Signed-off-by: Joaquim Moreno Prusi <[email protected]> Signed-off-by: Per Goncalves da Silva <[email protected]> Co-authored-by: Per Goncalves da Silva <[email protected]>
1 parent 61b563f commit fff05ac

File tree

13 files changed

+259
-33
lines changed

13 files changed

+259
-33
lines changed

config/samples/operators_v1alpha1_operator.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ metadata:
99
app.kubernetes.io/created-by: operator-controller
1010
name: operator-sample
1111
spec:
12-
packageName: argocd-operator
12+
packageName: zookeeper-operator
13+
version: 0.16.2

internal/controllers/operator_controller.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func (r *OperatorReconciler) reconcile(ctx context.Context, op *operatorsv1alpha
174174
}
175175
// Ensure a BundleDeployment exists with its bundle source from the bundle
176176
// image we just looked up in the solution.
177-
dep := r.generateExpectedBundleDeployment(*op, bundleImage, bundleProvisioner)
177+
dep := r.generateExpectedBundleDeployment(*op, bundleImage, bundleProvisioner, bundleEntity)
178178
if err := r.ensureBundleDeployment(ctx, dep); err != nil {
179179
// originally Reason: operatorsv1alpha1.ReasonInstallationFailed
180180
op.Status.InstalledBundleResource = ""
@@ -260,7 +260,7 @@ func (r *OperatorReconciler) getBundleEntityFromSolution(solution *solver.Soluti
260260
return nil, fmt.Errorf("entity for package %q not found in solution", packageName)
261261
}
262262

263-
func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string, bundleProvisioner string) *unstructured.Unstructured {
263+
func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string, bundleProvisioner string, bundleEntity *entities.BundleEntity) *unstructured.Unstructured {
264264
// We use unstructured here to avoid problems of serializing default values when sending patches to the apiserver.
265265
// If you use a typed object, any default values from that struct get serialized into the JSON patch, which could
266266
// cause unrelated fields to be patched back to the default value even though that isn't the intention. Using an

internal/controllers/variable_source.go

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ func NewVariableSource(cl client.Client) variablesources.NestedVariableSource {
2929
func(inputVariableSource input.VariableSource) (input.VariableSource, error) {
3030
return variablesources.NewOperatorVariableSource(cl, inputVariableSource), nil
3131
},
32+
func(inputVariableSource input.VariableSource) (input.VariableSource, error) {
33+
return variablesources.NewBundleDeploymentVariableSource(cl, inputVariableSource), nil
34+
},
3235
func(inputVariableSource input.VariableSource) (input.VariableSource, error) {
3336
return variablesources.NewBundlesAndDepsVariableSource(inputVariableSource), nil
3437
},

internal/resolution/entities/bundle_entity.go

+41-22
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ const (
2525

2626
// ----
2727

28-
type ChannelProperties struct {
29-
property.Channel
30-
Replaces string `json:"replaces,omitempty"`
31-
Skips []string `json:"skips,omitempty"`
32-
SkipRange string `json:"skipRange,omitempty"`
33-
}
34-
3528
type propertyRequirement bool
3629

3730
const (
@@ -46,6 +39,10 @@ type PackageRequired struct {
4639

4740
type GVK property.GVK
4841

42+
type Replaces struct {
43+
Replaces string `json:"replaces"`
44+
}
45+
4946
func (g GVK) String() string {
5047
return fmt.Sprintf(`group:"%s" version:"%s" kind:"%s"`, g.Group, g.Version, g.Kind)
5148
}
@@ -64,15 +61,16 @@ type BundleEntity struct {
6461
*input.Entity
6562

6663
// these properties are lazy loaded as they are requested
67-
bundlePackage *property.Package
68-
providedGVKs []GVK
69-
requiredGVKs []GVKRequired
70-
requiredPackages []PackageRequired
71-
channelProperties *ChannelProperties
72-
semVersion *semver.Version
73-
bundlePath string
74-
mediaType string
75-
mu sync.RWMutex
64+
bundlePackage *property.Package
65+
providedGVKs []GVK
66+
requiredGVKs []GVKRequired
67+
requiredPackages []PackageRequired
68+
channel *property.Channel
69+
replaces *Replaces
70+
semVersion *semver.Version
71+
bundlePath string
72+
mediaType string
73+
mu sync.RWMutex
7674
}
7775

7876
func NewBundleEntity(entity *input.Entity) *BundleEntity {
@@ -121,14 +119,35 @@ func (b *BundleEntity) ChannelName() (string, error) {
121119
if err := b.loadChannelProperties(); err != nil {
122120
return "", err
123121
}
124-
return b.channelProperties.ChannelName, nil
122+
return b.channel.ChannelName, nil
125123
}
126124

127-
func (b *BundleEntity) ChannelProperties() (*ChannelProperties, error) {
125+
func (b *BundleEntity) Channel() (*property.Channel, error) {
128126
if err := b.loadChannelProperties(); err != nil {
129127
return nil, err
130128
}
131-
return b.channelProperties, nil
129+
return b.channel, nil
130+
}
131+
132+
func (b *BundleEntity) Replaces() (string, error) {
133+
if err := b.loadReplaces(); err != nil {
134+
return "", err
135+
}
136+
return b.replaces.Replaces, nil
137+
}
138+
139+
func (b *BundleEntity) loadReplaces() error {
140+
b.mu.Lock()
141+
defer b.mu.Unlock()
142+
if b.replaces == nil {
143+
// TODO: move property name to constant
144+
replaces, err := loadFromEntity[Replaces](b.Entity, "olm.replaces", optional)
145+
if err != nil {
146+
return fmt.Errorf("error determining replaces for entity '%s': %w", b.ID, err)
147+
}
148+
b.replaces = &replaces
149+
}
150+
return nil
132151
}
133152

134153
func (b *BundleEntity) BundlePath() (string, error) {
@@ -228,12 +247,12 @@ func (b *BundleEntity) loadRequiredPackages() error {
228247
func (b *BundleEntity) loadChannelProperties() error {
229248
b.mu.Lock()
230249
defer b.mu.Unlock()
231-
if b.channelProperties == nil {
232-
channel, err := loadFromEntity[ChannelProperties](b.Entity, property.TypeChannel, required)
250+
if b.channel == nil {
251+
channel, err := loadFromEntity[property.Channel](b.Entity, property.TypeChannel, required)
233252
if err != nil {
234253
return fmt.Errorf("error determining bundle channel properties for entity '%s': %w", b.ID, err)
235254
}
236-
b.channelProperties = &channel
255+
b.channel = &channel
237256
}
238257
return nil
239258
}

internal/resolution/entities/bundle_entity_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -205,13 +205,13 @@ var _ = Describe("BundleEntity", func() {
205205
})
206206
})
207207

208-
Describe("ChannelProperties", func() {
208+
Describe("Channel", func() {
209209
It("should return the bundle channel properties if present", func() {
210210
entity := input.NewEntity("operatorhub/prometheus/0.14.0", map[string]string{
211211
"olm.channel": `{"channelName":"beta","priority":0, "replaces": "bundle.v1.0.0", "skips": ["bundle.v0.9.0", "bundle.v0.9.6"], "skipRange": ">=0.9.0 <=0.9.6"}`,
212212
})
213213
bundleEntity := olmentity.NewBundleEntity(entity)
214-
channelProperties, err := bundleEntity.ChannelProperties()
214+
channelProperties, err := bundleEntity.Channel()
215215
Expect(err).ToNot(HaveOccurred())
216216
Expect(*channelProperties).To(Equal(olmentity.ChannelProperties{
217217
Channel: property.Channel{
@@ -226,7 +226,7 @@ var _ = Describe("BundleEntity", func() {
226226
It("should return an error if the property is not found", func() {
227227
entity := input.NewEntity("operatorhub/prometheus/0.14.0", map[string]string{})
228228
bundleEntity := olmentity.NewBundleEntity(entity)
229-
channelProperties, err := bundleEntity.ChannelProperties()
229+
channelProperties, err := bundleEntity.Channel()
230230
Expect(channelProperties).To(BeNil())
231231
Expect(err.Error()).To(Equal("error determining bundle channel properties for entity 'operatorhub/prometheus/0.14.0': required property 'olm.channel' not found"))
232232
})
@@ -235,7 +235,7 @@ var _ = Describe("BundleEntity", func() {
235235
"olm.channel": "badChannelPropertiesStructure",
236236
})
237237
bundleEntity := olmentity.NewBundleEntity(entity)
238-
channelProperties, err := bundleEntity.ChannelProperties()
238+
channelProperties, err := bundleEntity.Channel()
239239
Expect(channelProperties).To(BeNil())
240240
Expect(err.Error()).To(Equal("error determining bundle channel properties for entity 'operatorhub/prometheus/0.14.0': property 'olm.channel' ('badChannelPropertiesStructure') could not be parsed: invalid character 'b' looking for beginning of value"))
241241
})

internal/resolution/entitysources/catalogdsource.go

+7
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ func (es *CatalogdEntitySource) Iterate(ctx context.Context, fn input.IteratorFu
7171
return nil
7272
}
7373

74+
type replacesProperty struct {
75+
Replaces string `json:"replaces"`
76+
}
77+
7478
func getEntities(ctx context.Context, client client.Client) (input.EntityList, error) {
7579
entityList := input.EntityList{}
7680
bundleMetadatas, packageMetdatas, err := fetchMetadata(ctx, client)
@@ -106,6 +110,9 @@ func getEntities(ctx context.Context, client client.Client) (input.EntityList, e
106110
if catalogScopedEntryName == bundle.Name {
107111
channelValue, _ := json.Marshal(property.Channel{ChannelName: ch.Name, Priority: 0})
108112
props[property.TypeChannel] = string(channelValue)
113+
// TODO(jmprusi): Add the proper PropertyType for this
114+
replacesValue, _ := json.Marshal(replacesProperty{Replaces: b.Replaces})
115+
props["olm.replaces"] = string(replacesValue)
109116
entity := input.Entity{
110117
ID: deppy.IdentifierFromString(fmt.Sprintf("%s%s%s", bundle.Name, bundle.Spec.Package, ch.Name)),
111118
Properties: props,

internal/resolution/util/predicates/predicates.go

+22
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,25 @@ func ProvidesGVK(gvk *olmentity.GVK) input.Predicate {
5656
return false
5757
}
5858
}
59+
60+
func WithBundleImage(bundleImage string) input.Predicate {
61+
return func(entity *input.Entity) bool {
62+
bundleEntity := olmentity.NewBundleEntity(entity)
63+
bundlePath, err := bundleEntity.BundlePath()
64+
if err != nil {
65+
return false
66+
}
67+
return bundlePath == bundleImage
68+
}
69+
}
70+
71+
func Replaces(bundleID string) input.Predicate {
72+
return func(entity *input.Entity) bool {
73+
bundleEntity := olmentity.NewBundleEntity(entity)
74+
replaces, err := bundleEntity.Replaces()
75+
if err != nil {
76+
return false
77+
}
78+
return replaces == bundleID
79+
}
80+
}

internal/resolution/util/sort/sort.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func packageOrder(e1, e2 *entities.BundleEntity) int {
5555
}
5656

5757
func channelOrder(e1, e2 *entities.BundleEntity) int {
58-
channelProperties1, err1 := e1.ChannelProperties()
59-
channelProperties2, err2 := e2.ChannelProperties()
58+
channelProperties1, err1 := e1.Channel()
59+
channelProperties2, err2 := e2.Channel()
6060
errComp := compareErrors(err1, err2)
6161
if errComp != 0 {
6262
return errComp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package variables
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/operator-framework/deppy/pkg/deppy"
7+
"github.com/operator-framework/deppy/pkg/deppy/constraint"
8+
"github.com/operator-framework/deppy/pkg/deppy/input"
9+
10+
olmentity "github.com/operator-framework/operator-controller/internal/resolution/entities"
11+
)
12+
13+
type InstalledPackageVariable struct {
14+
*input.SimpleVariable
15+
bundleEntities []*olmentity.BundleEntity
16+
}
17+
18+
func (r *InstalledPackageVariable) BundleEntities() []*olmentity.BundleEntity {
19+
return r.bundleEntities
20+
}
21+
22+
func NewInstalledPackageVariable(bundleImage string, bundleEntities []*olmentity.BundleEntity) *InstalledPackageVariable {
23+
id := deppy.IdentifierFromString(fmt.Sprintf("installed package %s", bundleImage))
24+
var entityIDs []deppy.Identifier
25+
for _, bundle := range bundleEntities {
26+
entityIDs = append(entityIDs, bundle.ID)
27+
}
28+
return &InstalledPackageVariable{
29+
SimpleVariable: input.NewSimpleVariable(id, constraint.Mandatory(), constraint.Dependency(entityIDs...)),
30+
bundleEntities: bundleEntities,
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package variablesources
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/operator-framework/deppy/pkg/deppy"
8+
"github.com/operator-framework/deppy/pkg/deppy/input"
9+
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
)
12+
13+
var _ input.VariableSource = &BundleDeploymentVariableSource{}
14+
15+
type BundleDeploymentVariableSource struct {
16+
client client.Client
17+
inputVariableSource input.VariableSource
18+
}
19+
20+
func NewBundleDeploymentVariableSource(cl client.Client, inputVariableSource input.VariableSource) *BundleDeploymentVariableSource {
21+
return &BundleDeploymentVariableSource{
22+
client: cl,
23+
inputVariableSource: inputVariableSource,
24+
}
25+
}
26+
27+
func (o *BundleDeploymentVariableSource) GetVariables(ctx context.Context, entitySource input.EntitySource) ([]deppy.Variable, error) {
28+
variableSources := SliceVariableSource{}
29+
if o.inputVariableSource != nil {
30+
variableSources = append(variableSources, o.inputVariableSource)
31+
}
32+
33+
bundleDeployments := rukpakv1alpha1.BundleDeploymentList{}
34+
if err := o.client.List(ctx, &bundleDeployments); err != nil {
35+
return nil, err
36+
}
37+
38+
processed := map[string]struct{}{}
39+
if len(bundleDeployments.Items) > 1 {
40+
fmt.Println("hello")
41+
}
42+
for _, bundleDeployment := range bundleDeployments.Items {
43+
sourceImage := bundleDeployment.Spec.Template.Spec.Source.Image
44+
if sourceImage != nil && sourceImage.Ref != "" {
45+
if _, ok := processed[sourceImage.Ref]; ok {
46+
continue
47+
}
48+
processed[sourceImage.Ref] = struct{}{}
49+
ips, err := NewInstalledPackageVariableSource(bundleDeployment.Spec.Template.Spec.Source.Image.Ref)
50+
if err != nil {
51+
return nil, err
52+
}
53+
variableSources = append(variableSources, ips)
54+
}
55+
}
56+
57+
return variableSources.GetVariables(ctx, entitySource)
58+
}

internal/resolution/variablesources/bundles_and_dependencies.go

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ func (b *BundlesAndDepsVariableSource) GetVariables(ctx context.Context, entityS
4545
switch v := variable.(type) {
4646
case *olmvariables.RequiredPackageVariable:
4747
bundleEntityQueue = append(bundleEntityQueue, v.BundleEntities()...)
48+
case *olmvariables.InstalledPackageVariable:
49+
bundleEntityQueue = append(bundleEntityQueue, v.BundleEntities()...)
4850
}
4951
}
5052

0 commit comments

Comments
 (0)