Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Joaquim Moreno Prusi <joaquim@redhat.com>
Signed-off-by: Per Goncalves da Silva <pegoncal@redhat.com>

Co-authored-by: Per Goncalves da Silva <pegoncal@redhat.com>
  • Loading branch information
jmprusi and Per Goncalves da Silva committed Jul 6, 2023
1 parent 61b563f commit fff05ac
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 33 deletions.
3 changes: 2 additions & 1 deletion config/samples/operators_v1alpha1_operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ metadata:
app.kubernetes.io/created-by: operator-controller
name: operator-sample
spec:
packageName: argocd-operator
packageName: zookeeper-operator
version: 0.16.2
4 changes: 2 additions & 2 deletions internal/controllers/operator_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (r *OperatorReconciler) reconcile(ctx context.Context, op *operatorsv1alpha
}
// Ensure a BundleDeployment exists with its bundle source from the bundle
// image we just looked up in the solution.
dep := r.generateExpectedBundleDeployment(*op, bundleImage, bundleProvisioner)
dep := r.generateExpectedBundleDeployment(*op, bundleImage, bundleProvisioner, bundleEntity)
if err := r.ensureBundleDeployment(ctx, dep); err != nil {
// originally Reason: operatorsv1alpha1.ReasonInstallationFailed
op.Status.InstalledBundleResource = ""
Expand Down Expand Up @@ -260,7 +260,7 @@ func (r *OperatorReconciler) getBundleEntityFromSolution(solution *solver.Soluti
return nil, fmt.Errorf("entity for package %q not found in solution", packageName)
}

func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string, bundleProvisioner string) *unstructured.Unstructured {
func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string, bundleProvisioner string, bundleEntity *entities.BundleEntity) *unstructured.Unstructured {

Check warning on line 263 in internal/controllers/operator_controller.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'bundleEntity' seems to be unused, consider removing or renaming it as _ (revive)
// We use unstructured here to avoid problems of serializing default values when sending patches to the apiserver.
// If you use a typed object, any default values from that struct get serialized into the JSON patch, which could
// cause unrelated fields to be patched back to the default value even though that isn't the intention. Using an
Expand Down
3 changes: 3 additions & 0 deletions internal/controllers/variable_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ func NewVariableSource(cl client.Client) variablesources.NestedVariableSource {
func(inputVariableSource input.VariableSource) (input.VariableSource, error) {
return variablesources.NewOperatorVariableSource(cl, inputVariableSource), nil
},
func(inputVariableSource input.VariableSource) (input.VariableSource, error) {
return variablesources.NewBundleDeploymentVariableSource(cl, inputVariableSource), nil
},
func(inputVariableSource input.VariableSource) (input.VariableSource, error) {
return variablesources.NewBundlesAndDepsVariableSource(inputVariableSource), nil
},
Expand Down
63 changes: 41 additions & 22 deletions internal/resolution/entities/bundle_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ const (

// ----

type ChannelProperties struct {
property.Channel
Replaces string `json:"replaces,omitempty"`
Skips []string `json:"skips,omitempty"`
SkipRange string `json:"skipRange,omitempty"`
}

type propertyRequirement bool

const (
Expand All @@ -46,6 +39,10 @@ type PackageRequired struct {

type GVK property.GVK

type Replaces struct {
Replaces string `json:"replaces"`
}

func (g GVK) String() string {
return fmt.Sprintf(`group:"%s" version:"%s" kind:"%s"`, g.Group, g.Version, g.Kind)
}
Expand All @@ -64,15 +61,16 @@ type BundleEntity struct {
*input.Entity

// these properties are lazy loaded as they are requested
bundlePackage *property.Package
providedGVKs []GVK
requiredGVKs []GVKRequired
requiredPackages []PackageRequired
channelProperties *ChannelProperties
semVersion *semver.Version
bundlePath string
mediaType string
mu sync.RWMutex
bundlePackage *property.Package
providedGVKs []GVK
requiredGVKs []GVKRequired
requiredPackages []PackageRequired
channel *property.Channel
replaces *Replaces
semVersion *semver.Version
bundlePath string
mediaType string
mu sync.RWMutex
}

func NewBundleEntity(entity *input.Entity) *BundleEntity {
Expand Down Expand Up @@ -121,14 +119,35 @@ func (b *BundleEntity) ChannelName() (string, error) {
if err := b.loadChannelProperties(); err != nil {
return "", err
}
return b.channelProperties.ChannelName, nil
return b.channel.ChannelName, nil
}

func (b *BundleEntity) ChannelProperties() (*ChannelProperties, error) {
func (b *BundleEntity) Channel() (*property.Channel, error) {
if err := b.loadChannelProperties(); err != nil {
return nil, err
}
return b.channelProperties, nil
return b.channel, nil
}

func (b *BundleEntity) Replaces() (string, error) {
if err := b.loadReplaces(); err != nil {
return "", err
}
return b.replaces.Replaces, nil
}

func (b *BundleEntity) loadReplaces() error {
b.mu.Lock()
defer b.mu.Unlock()
if b.replaces == nil {
// TODO: move property name to constant
replaces, err := loadFromEntity[Replaces](b.Entity, "olm.replaces", optional)
if err != nil {
return fmt.Errorf("error determining replaces for entity '%s': %w", b.ID, err)
}
b.replaces = &replaces
}
return nil
}

func (b *BundleEntity) BundlePath() (string, error) {
Expand Down Expand Up @@ -228,12 +247,12 @@ func (b *BundleEntity) loadRequiredPackages() error {
func (b *BundleEntity) loadChannelProperties() error {
b.mu.Lock()
defer b.mu.Unlock()
if b.channelProperties == nil {
channel, err := loadFromEntity[ChannelProperties](b.Entity, property.TypeChannel, required)
if b.channel == nil {
channel, err := loadFromEntity[property.Channel](b.Entity, property.TypeChannel, required)
if err != nil {
return fmt.Errorf("error determining bundle channel properties for entity '%s': %w", b.ID, err)
}
b.channelProperties = &channel
b.channel = &channel
}
return nil
}
Expand Down
8 changes: 4 additions & 4 deletions internal/resolution/entities/bundle_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,13 @@ var _ = Describe("BundleEntity", func() {
})
})

Describe("ChannelProperties", func() {
Describe("Channel", func() {
It("should return the bundle channel properties if present", func() {
entity := input.NewEntity("operatorhub/prometheus/0.14.0", map[string]string{
"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"}`,
})
bundleEntity := olmentity.NewBundleEntity(entity)
channelProperties, err := bundleEntity.ChannelProperties()
channelProperties, err := bundleEntity.Channel()
Expect(err).ToNot(HaveOccurred())
Expect(*channelProperties).To(Equal(olmentity.ChannelProperties{

Check failure on line 216 in internal/resolution/entities/bundle_entity_test.go

View workflow job for this annotation

GitHub Actions / unit-test-basic

undefined: olmentity.ChannelProperties

Check failure on line 216 in internal/resolution/entities/bundle_entity_test.go

View workflow job for this annotation

GitHub Actions / lint

undefined: olmentity.ChannelProperties (typecheck)
Channel: property.Channel{
Expand All @@ -226,7 +226,7 @@ var _ = Describe("BundleEntity", func() {
It("should return an error if the property is not found", func() {
entity := input.NewEntity("operatorhub/prometheus/0.14.0", map[string]string{})
bundleEntity := olmentity.NewBundleEntity(entity)
channelProperties, err := bundleEntity.ChannelProperties()
channelProperties, err := bundleEntity.Channel()
Expect(channelProperties).To(BeNil())
Expect(err.Error()).To(Equal("error determining bundle channel properties for entity 'operatorhub/prometheus/0.14.0': required property 'olm.channel' not found"))
})
Expand All @@ -235,7 +235,7 @@ var _ = Describe("BundleEntity", func() {
"olm.channel": "badChannelPropertiesStructure",
})
bundleEntity := olmentity.NewBundleEntity(entity)
channelProperties, err := bundleEntity.ChannelProperties()
channelProperties, err := bundleEntity.Channel()
Expect(channelProperties).To(BeNil())
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"))
})
Expand Down
7 changes: 7 additions & 0 deletions internal/resolution/entitysources/catalogdsource.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ func (es *CatalogdEntitySource) Iterate(ctx context.Context, fn input.IteratorFu
return nil
}

type replacesProperty struct {
Replaces string `json:"replaces"`
}

func getEntities(ctx context.Context, client client.Client) (input.EntityList, error) {
entityList := input.EntityList{}
bundleMetadatas, packageMetdatas, err := fetchMetadata(ctx, client)
Expand Down Expand Up @@ -106,6 +110,9 @@ func getEntities(ctx context.Context, client client.Client) (input.EntityList, e
if catalogScopedEntryName == bundle.Name {
channelValue, _ := json.Marshal(property.Channel{ChannelName: ch.Name, Priority: 0})
props[property.TypeChannel] = string(channelValue)
// TODO(jmprusi): Add the proper PropertyType for this
replacesValue, _ := json.Marshal(replacesProperty{Replaces: b.Replaces})
props["olm.replaces"] = string(replacesValue)
entity := input.Entity{
ID: deppy.IdentifierFromString(fmt.Sprintf("%s%s%s", bundle.Name, bundle.Spec.Package, ch.Name)),
Properties: props,
Expand Down
22 changes: 22 additions & 0 deletions internal/resolution/util/predicates/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,25 @@ func ProvidesGVK(gvk *olmentity.GVK) input.Predicate {
return false
}
}

func WithBundleImage(bundleImage string) input.Predicate {
return func(entity *input.Entity) bool {
bundleEntity := olmentity.NewBundleEntity(entity)
bundlePath, err := bundleEntity.BundlePath()
if err != nil {
return false
}
return bundlePath == bundleImage
}
}

func Replaces(bundleID string) input.Predicate {
return func(entity *input.Entity) bool {
bundleEntity := olmentity.NewBundleEntity(entity)
replaces, err := bundleEntity.Replaces()
if err != nil {
return false
}
return replaces == bundleID
}
}
4 changes: 2 additions & 2 deletions internal/resolution/util/sort/sort.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ func packageOrder(e1, e2 *entities.BundleEntity) int {
}

func channelOrder(e1, e2 *entities.BundleEntity) int {
channelProperties1, err1 := e1.ChannelProperties()
channelProperties2, err2 := e2.ChannelProperties()
channelProperties1, err1 := e1.Channel()
channelProperties2, err2 := e2.Channel()
errComp := compareErrors(err1, err2)
if errComp != 0 {
return errComp
Expand Down
32 changes: 32 additions & 0 deletions internal/resolution/variables/installed_package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package variables

import (
"fmt"

"github.com/operator-framework/deppy/pkg/deppy"
"github.com/operator-framework/deppy/pkg/deppy/constraint"
"github.com/operator-framework/deppy/pkg/deppy/input"

olmentity "github.com/operator-framework/operator-controller/internal/resolution/entities"
)

type InstalledPackageVariable struct {
*input.SimpleVariable
bundleEntities []*olmentity.BundleEntity
}

func (r *InstalledPackageVariable) BundleEntities() []*olmentity.BundleEntity {
return r.bundleEntities
}

func NewInstalledPackageVariable(bundleImage string, bundleEntities []*olmentity.BundleEntity) *InstalledPackageVariable {
id := deppy.IdentifierFromString(fmt.Sprintf("installed package %s", bundleImage))
var entityIDs []deppy.Identifier

Check failure on line 24 in internal/resolution/variables/installed_package.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `entityIDs` (prealloc)
for _, bundle := range bundleEntities {
entityIDs = append(entityIDs, bundle.ID)
}
return &InstalledPackageVariable{
SimpleVariable: input.NewSimpleVariable(id, constraint.Mandatory(), constraint.Dependency(entityIDs...)),
bundleEntities: bundleEntities,
}
}
58 changes: 58 additions & 0 deletions internal/resolution/variablesources/bundle_deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package variablesources

import (
"context"
"fmt"

"github.com/operator-framework/deppy/pkg/deppy"
"github.com/operator-framework/deppy/pkg/deppy/input"
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var _ input.VariableSource = &BundleDeploymentVariableSource{}

type BundleDeploymentVariableSource struct {
client client.Client
inputVariableSource input.VariableSource
}

func NewBundleDeploymentVariableSource(cl client.Client, inputVariableSource input.VariableSource) *BundleDeploymentVariableSource {
return &BundleDeploymentVariableSource{
client: cl,
inputVariableSource: inputVariableSource,
}
}

func (o *BundleDeploymentVariableSource) GetVariables(ctx context.Context, entitySource input.EntitySource) ([]deppy.Variable, error) {
variableSources := SliceVariableSource{}
if o.inputVariableSource != nil {
variableSources = append(variableSources, o.inputVariableSource)
}

bundleDeployments := rukpakv1alpha1.BundleDeploymentList{}
if err := o.client.List(ctx, &bundleDeployments); err != nil {
return nil, err
}

processed := map[string]struct{}{}
if len(bundleDeployments.Items) > 1 {
fmt.Println("hello")
}
for _, bundleDeployment := range bundleDeployments.Items {
sourceImage := bundleDeployment.Spec.Template.Spec.Source.Image
if sourceImage != nil && sourceImage.Ref != "" {
if _, ok := processed[sourceImage.Ref]; ok {
continue
}
processed[sourceImage.Ref] = struct{}{}
ips, err := NewInstalledPackageVariableSource(bundleDeployment.Spec.Template.Spec.Source.Image.Ref)
if err != nil {
return nil, err
}
variableSources = append(variableSources, ips)
}
}

return variableSources.GetVariables(ctx, entitySource)
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ func (b *BundlesAndDepsVariableSource) GetVariables(ctx context.Context, entityS
switch v := variable.(type) {
case *olmvariables.RequiredPackageVariable:
bundleEntityQueue = append(bundleEntityQueue, v.BundleEntities()...)
case *olmvariables.InstalledPackageVariable:
bundleEntityQueue = append(bundleEntityQueue, v.BundleEntities()...)
}
}

Expand Down
Loading

0 comments on commit fff05ac

Please sign in to comment.