Skip to content
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
3 changes: 3 additions & 0 deletions api/v1alpha1/operandregistry_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ type Operator struct {
PackageName string `json:"packageName"`
// Name of the channel to track.
Channel string `json:"channel"`
// List of channels to fallback when the main channel is not available.
// +optional
FallbackChannels []string `json:"fallbackChannels,omitempty"`
// Description of a common service.
// +optional
Description string `json:"description,omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions bundle/manifests/operator.ibm.com_operandregistries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ spec:
description:
description: Description of a common service.
type: string
fallbackChannels:
description: List of channels to fallback when the main channel
is not available.
items:
type: string
type: array
installMode:
description: |-
The install mode of an operator, either namespace or cluster.
Expand Down
6 changes: 6 additions & 0 deletions config/crd/bases/operator.ibm.com_operandregistries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ spec:
description:
description: Description of a common service.
type: string
fallbackChannels:
description: List of channels to fallback when the main channel
is not available.
items:
type: string
type: array
installMode:
description: |-
The install mode of an operator, either namespace or cluster.
Expand Down
3 changes: 3 additions & 0 deletions controllers/operandbindinfo/operandbindinfo_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/onsi/gomega/gexec"
olmv1 "github.com/operator-framework/api/pkg/operators/v1"
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -92,6 +93,8 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).NotTo(HaveOccurred())
err = jaegerv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = operatorsv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())

k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme})
Expect(err).ToNot(HaveOccurred())
Expand Down
3 changes: 3 additions & 0 deletions controllers/operandconfig/operandconfig_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/onsi/gomega/gexec"
olmv1 "github.com/operator-framework/api/pkg/operators/v1"
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -93,6 +94,8 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).NotTo(HaveOccurred())
err = jaegerv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = operatorsv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())

k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme})
Expect(err).ToNot(HaveOccurred())
Expand Down
3 changes: 3 additions & 0 deletions controllers/operandregistry/operandregistry_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/onsi/gomega/gexec"
olmv1 "github.com/operator-framework/api/pkg/operators/v1"
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -92,6 +93,8 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).NotTo(HaveOccurred())
err = jaegerv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = operatorsv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())

k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme})
Expect(err).ToNot(HaveOccurred())
Expand Down
3 changes: 3 additions & 0 deletions controllers/operandrequest/operandrequest_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/onsi/gomega/gexec"
olmv1 "github.com/operator-framework/api/pkg/operators/v1"
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -86,6 +87,8 @@ var _ = BeforeSuite(func(done Done) {
Expect(err).NotTo(HaveOccurred())
err = jaegerv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = operatorsv1.AddToScheme(clientgoscheme.Scheme)
Expect(err).NotTo(HaveOccurred())

k8sClient, err = client.New(cfg, client.Options{Scheme: clientgoscheme.Scheme})
Expect(err).ToNot(HaveOccurred())
Expand Down
14 changes: 3 additions & 11 deletions controllers/operandrequest/reconcile_operand.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"regexp"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -175,17 +174,10 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper
}

if !opdRegistry.UserManaged {
// find the OperandRequest which has the same operator's channel version as existing subscription.
// find the OperandRequest which has the same operator's channel or fallback channels as existing subscription.
// ODLM will only reconcile Operand based on OperandConfig for this OperandRequest
var requestList []string
reg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`)
for anno, version := range sub.Annotations {
if reg.MatchString(anno) && version == sub.Spec.Channel {
requestList = append(requestList, anno)
}
}

if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") {
channels := []string{opdRegistry.Channel}
if channels = append(channels, opdRegistry.FallbackChannels...); !util.Contains(channels, sub.Spec.Channel) {
klog.Infof("Subscription %s in the namespace %s is NOT managed by %s/%s, Skip reconciling Operands", sub.Name, sub.Namespace, requestInstance.Namespace, requestInstance.Name)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
continue
Expand Down
25 changes: 10 additions & 15 deletions controllers/operandrequest/reconcile_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance

// check if sub.Spec.Channel and opt.Channel are valid semantic version
// set annotation channel back to previous one if sub.Spec.Channel is lower than opt.Channel
// To avoid upgrade from one maintenance version to another maintenance version like from v3 to v3.23
subChanel := util.FindSemantic(sub.Spec.Channel)
optChannel := util.FindSemantic(opt.Channel)
if semver.IsValid(subChanel) && semver.IsValid(optChannel) && semver.Compare(subChanel, optChannel) < 0 {
Expand All @@ -249,11 +250,11 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance
} else {
requestInstance.SetNotFoundOperatorFromRegistryCondition(operand.Name, operatorv1alpha1.ResourceTypeSub, corev1.ConditionFalse, mu)

if minChannel := util.FindMinSemver(sub.Annotations, sub.Spec.Channel); minChannel != "" {
if minChannel := util.FindMinSemverFromAnnotations(sub.Annotations, sub.Spec.Channel); minChannel != "" {
sub.Spec.Channel = minChannel
}

// update the spec iff channel in sub matches channel in opreg
// update the spec iff channel in sub matches channel
if sub.Spec.Channel == opt.Channel {
isMatchedChannel = true
sub.Spec.CatalogSource = opt.SourceName
Expand Down Expand Up @@ -422,7 +423,7 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN
}
}

uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, sub)
uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, op.InstallMode, sub)
if !uninstallOperand && !uninstallOperator {
if err = r.updateSubscription(ctx, requestInstance, sub); err != nil {
requestInstance.SetMemberStatus(op.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
Expand Down Expand Up @@ -731,21 +732,15 @@ func CheckSingletonServices(operator string) bool {
// It returns two boolean values: uninstallOperator and uninstallOperand.
// If uninstallOperator is true, it means the operator should be uninstalled.
// If uninstallOperand is true, it means the operand should be uninstalled.
func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1alpha1.Subscription) (bool, bool) {
func checkSubAnnotationsForUninstall(reqName, reqNs, opName, installMode string, sub *olmv1alpha1.Subscription) (bool, bool) {
uninstallOperator := true
uninstallOperand := true

var curChannel string
if sub.GetAnnotations() != nil {
curChannel = sub.Annotations[reqNs+"."+reqName+"."+opName+"/request"]
}

delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/request")
delete(sub.Annotations, reqNs+"."+reqName+"."+opName+"/operatorNamespace")

var opreqNsSlice []string
var operatorNameSlice []string
var channelSlice []string
namespaceReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/operatorNamespace`)
channelReg, _ := regexp.Compile(`^(.*)\.(.*)\.(.*)\/request`)

Expand All @@ -755,7 +750,6 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1al
}

if channelReg.MatchString(key) {
channelSlice = append(channelSlice, value)
// Extract the operator name from the key
keyParts := strings.Split(key, "/")
annoPrefix := strings.Split(keyParts[0], ".")
Expand All @@ -773,10 +767,11 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1al
uninstallOperator = false
}

// If the removed/uninstalled <prefix>/request annotation's value is NOT the same as all other <prefix>/request annotation's values.
// or the operator namespace in one of remaining annotation is the same as the operator name in removed/uninstalled <prefix>/request
// the operand should NOT be uninstalled.
if util.Differs(channelSlice, curChannel) || util.Contains(operatorNameSlice, opName) {
// When one of following conditions are met, the operand will NOT be uninstalled:
// 1. operator is not uninstalled AND intallMode is no-op.
// 2. operator is uninstalled AND at least one other <prefix>/operatorNamespace annotation exists.
// 2. remaining <prefix>/request annotation's values contain the same operator name
if (!uninstallOperator && installMode == operatorv1alpha1.InstallModeNoop) || (uninstallOperator && len(opreqNsSlice) != 0) || util.Contains(operatorNameSlice, opName) {
uninstallOperand = false
}

Expand Down
Loading