Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ manifests: controller-gen ## Generate manifests e.g. CRD, RBAC etc.
generate: controller-gen ## Generate code e.g. API etc.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

bundle-manifests:
bundle-manifests: yq
$(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle \
-q --overwrite --version $(OPERATOR_VERSION) $(BUNDLE_METADATA_OPTS)
$(OPERATOR_SDK) bundle validate ./bundle
Expand Down
2 changes: 2 additions & 0 deletions api/v1alpha1/operandregistry_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ type Operator struct {
// OperatorConfig is the name of the OperatorConfig
// +optional
OperatorConfig string `json:"operatorConfig,omitempty"`
// UserManaged is a flag to indicate whether operator is managed by user
UserManaged bool `json:"userManaged,omitempty"`
}

// +kubebuilder:validation:Enum=public;private
Expand Down
1 change: 0 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ metadata:
categories: Developer Tools, Monitoring, Logging & Tracing, Security
certified: "false"
containerImage: icr.io/cpopen/odlm:latest
createdAt: "2024-04-04T03:40:45Z"
createdAt: "2024-08-27T18:18:40Z"
description: The Operand Deployment Lifecycle Manager provides a Kubernetes CRD-based API to manage the lifecycle of operands.
nss.operator.ibm.com/managed-operators: ibm-odlm
olm.skipRange: '>=1.2.0 <4.3.5'
Expand Down Expand Up @@ -664,15 +664,15 @@ spec:
ephemeral-storage: 256Mi
memory: 200Mi
securityContext:
seccompProfile:
type: RuntimeDefault
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
serviceAccount: operand-deployment-lifecycle-manager
serviceAccountName: operand-deployment-lifecycle-manager
terminationGracePeriodSeconds: 10
Expand Down
4 changes: 4 additions & 0 deletions bundle/manifests/operator.ibm.com_operandregistries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,10 @@ spec:
items:
type: string
type: array
userManaged:
description: UserManaged is a flag to indicate whether operator
is managed by user
type: boolean
required:
- channel
- name
Expand Down
2 changes: 1 addition & 1 deletion common/Makefile.common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ fetch-test-crds:

CONTROLLER_GEN ?= $(shell pwd)/common/bin/controller-gen
controller-gen: ## Download controller-gen locally if necessary.
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.1)
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0)

KIND ?= $(shell pwd)/common/bin/kind
kind: ## Download kind locally if necessary.
Expand Down
2 changes: 1 addition & 1 deletion common/scripts/lint_go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
# limitations under the License.
#

GOGC=25 golangci-lint run -c ./common/config/.golangci.yml --timeout=180s
GOGC=25 golangci-lint run -c ./common/config/.golangci.yml --timeout=300s
4 changes: 4 additions & 0 deletions config/crd/bases/operator.ibm.com_operandregistries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2051,6 +2051,10 @@ spec:
items:
type: string
type: array
userManaged:
description: UserManaged is a flag to indicate whether operator
is managed by user
type: boolean
required:
- channel
- name
Expand Down
25 changes: 13 additions & 12 deletions controllers/operandrequest/operandrequest_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,18 +238,19 @@ func (r *Reconciler) checkFinalizer(ctx context.Context, requestInstance *operat
for _, m := range requestInstance.Status.Members {
remainingOperands.Add(m.Name)
}
existingSub := &olmv1alpha1.SubscriptionList{}

opts := []client.ListOption{
client.MatchingLabels(map[string]string{constant.OpreqLabel: "true"}),
}

if err := r.Client.List(ctx, existingSub, opts...); err != nil {
return err
}
if len(existingSub.Items) == 0 {
return nil
}
// TODO: update to check OperandRequest status to see if member is user managed or not
// existingSub := &olmv1alpha1.SubscriptionList{}

// opts := []client.ListOption{
// client.MatchingLabels(map[string]string{constant.OpreqLabel: "true"}),
// }

// if err := r.Client.List(ctx, existingSub, opts...); err != nil {
// return err
// }
// if len(existingSub.Items) == 0 {
// return nil
// }
// Delete all the subscriptions that created by current request
if err := r.absentOperatorsAndOperands(ctx, requestInstance, &remainingOperands); err != nil {
return err
Expand Down
12 changes: 7 additions & 5 deletions controllers/operandrequest/reconcile_operand.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,12 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper
}
}

if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") {
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
if !opdRegistry.UserManaged {
if len(requestList) == 0 || !util.Contains(requestList, requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request") {
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
}
}

klog.V(3).Info("Generating customresource base on ClusterServiceVersion: ", csv.GetName())
Expand All @@ -185,7 +187,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper
if err == nil {
// Check the requested Service Config if exist in specific OperandConfig
opdConfig := configInstance.GetService(operand.Name)
if opdConfig == nil {
if opdConfig == nil && !opdRegistry.UserManaged {
klog.V(2).Infof("There is no service: %s from the OperandConfig instance: %s/%s, Skip reconciling Operands", operand.Name, registryKey.Namespace, req.Registry)
continue
}
Expand Down
27 changes: 24 additions & 3 deletions controllers/operandrequest/reconcile_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,22 @@ func (r *Reconciler) reconcileSubscription(ctx context.Context, requestInstance
namespace := r.GetOperatorNamespace(opt.InstallMode, opt.Namespace)
sub, err := r.GetSubscription(ctx, opt.Name, namespace, registryInstance.Namespace, opt.PackageName)

if opt.UserManaged {
klog.Infof("Skip installing operator %s because it is managed by user", opt.PackageName)
if sub == nil {
return errors.New("operator" + opt.Name + " is user managed, but no Subscription exists, waiting...")
}
sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/request"] = opt.Channel
sub.Annotations[requestInstance.Namespace+"."+requestInstance.Name+"."+operand.Name+"/operatorNamespace"] = namespace
if err = r.updateSubscription(ctx, requestInstance, sub); err != nil {
requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorFailed, "", mu)
return err
}
requestInstance.SetMemberStatus(opt.Name, operatorv1alpha1.OperatorUpdating, "", mu)
// requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorRunning, operatorv1alpha1.ServiceRunning, mu)
return nil
}

if sub == nil && err == nil {
if opt.InstallMode == operatorv1alpha1.InstallModeNoop {
requestInstance.SetNoSuitableRegistryCondition(registryKey.String(), opt.Name+" is in maintenance status", operatorv1alpha1.ResourceTypeOperandRegistry, corev1.ConditionTrue, &r.Mutex)
Expand Down Expand Up @@ -403,9 +419,10 @@ func (r *Reconciler) uninstallOperatorsAndOperands(ctx context.Context, operandN
}

if _, ok := sub.Labels[constant.OpreqLabel]; !ok {
// Subscription existing and not managed by OperandRequest controller
klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace)
return nil
if !op.UserManaged {
klog.V(2).Infof("Subscription %s in the namespace %s isn't created by ODLM and isn't user managed", sub.Name, sub.Namespace)
return nil
}
}

uninstallOperator, uninstallOperand := checkSubAnnotationsForUninstall(requestInstance.ObjectMeta.Name, requestInstance.ObjectMeta.Namespace, op.Name, sub)
Expand Down Expand Up @@ -694,6 +711,10 @@ func checkSubAnnotationsForUninstall(reqName, reqNs, opName string, sub *olmv1al
uninstallOperator = false
}

if _, ok := sub.Labels[constant.OpreqLabel]; !ok {
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.
Expand Down
7 changes: 7 additions & 0 deletions controllers/operandrequest/reconcile_operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"k8s.io/apimachinery/pkg/types"

operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/v4/api/v1alpha1"
"github.com/IBM/operand-deployment-lifecycle-manager/v4/controllers/constant"
)

func TestGenerateClusterObjects(t *testing.T) {
Expand Down Expand Up @@ -125,6 +126,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) {
reqNsA + "." + reqNameA + "." + opNameA + "/request": opChannelA,
reqNsA + "." + reqNameA + "." + opNameA + "/operatorNamespace": reqNsA,
},
Labels: map[string]string{
constant.OpreqLabel: "true",
},
},
}

Expand All @@ -147,6 +151,9 @@ func TestCheckSubAnnotationsForUninstall(t *testing.T) {
reqNsB + "." + reqNameB + "." + opNameB + "/request": opChannelB,
reqNsB + "." + reqNameB + "." + opNameB + "/operatorNamespace": reqNsB,
},
Labels: map[string]string{
constant.OpreqLabel: "true",
},
},
}

Expand Down