Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
132 changes: 74 additions & 58 deletions controllers/operandrequest/reconcile_operand.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,53 +99,67 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper
namespace := r.GetOperatorNamespace(opdRegistry.InstallMode, opdRegistry.Namespace)

sub, err := r.GetSubscription(ctx, operatorName, namespace, registryInstance.Namespace, opdRegistry.PackageName)

if sub == nil && err == nil {
klog.Warningf("There is no Subscription %s or %s in the namespace %s and %s", operatorName, opdRegistry.PackageName, namespace, registryInstance.Namespace)
continue

} else if err != nil {
if err != nil {
merr.Add(errors.Wrapf(err, "failed to get the Subscription %s in the namespace %s and %s", operatorName, namespace, registryInstance.Namespace))
return merr
}

if _, ok := sub.Labels[constant.OpreqLabel]; !ok {
// Subscription existing and not managed by OperandRequest controller
klog.Warningf("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace)
}
if !opdRegistry.UserManaged {
if sub == nil {
klog.Warningf("There is no Subscription %s or %s in the namespace %s and %s", operatorName, opdRegistry.PackageName, namespace, registryInstance.Namespace)
continue
}

// It the installplan is not created yet, ODLM will try later
if sub.Status.Install == nil || sub.Status.InstallPlanRef.Name == "" {
klog.Warningf("The Installplan for Subscription %s is not ready. Will check it again", sub.Name)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex)
continue
}
if _, ok := sub.Labels[constant.OpreqLabel]; !ok {
// Subscription existing and not managed by OperandRequest controller
klog.Warningf("Subscription %s in the namespace %s isn't created by ODLM", sub.Name, sub.Namespace)
}

// If the installplan is deleted after is completed, ODLM won't block the CR update.
ipName := sub.Status.InstallPlanRef.Name
ipNamespace := sub.Namespace
ip := &olmv1alpha1.InstallPlan{}
ipKey := types.NamespacedName{
Name: ipName,
Namespace: ipNamespace,
}
if err := r.Client.Get(ctx, ipKey, ip); err != nil {
if !apierrors.IsNotFound(err) {
merr.Add(errors.Wrapf(err, "failed to get Installplan"))
// It the installplan is not created yet, ODLM will try later
if sub.Status.Install == nil || sub.Status.InstallPlanRef.Name == "" {
klog.Warningf("The Installplan for Subscription %s is not ready. Will check it again", sub.Name)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorInstalling, "", &r.Mutex)
continue
}
} else if ip.Status.Phase == olmv1alpha1.InstallPlanPhaseFailed {
klog.Errorf("installplan %s/%s is failed", ipNamespace, ipName)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
continue

// If the installplan is deleted after is completed, ODLM won't block the CR update.
ipName := sub.Status.InstallPlanRef.Name
ipNamespace := sub.Namespace
ip := &olmv1alpha1.InstallPlan{}
ipKey := types.NamespacedName{
Name: ipName,
Namespace: ipNamespace,
}
if err := r.Client.Get(ctx, ipKey, ip); err != nil {
if !apierrors.IsNotFound(err) {
merr.Add(errors.Wrapf(err, "failed to get Installplan"))
}
} else if ip.Status.Phase == olmv1alpha1.InstallPlanPhaseFailed {
klog.Errorf("installplan %s/%s is failed", ipNamespace, ipName)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
continue
}

}

csv, err := r.GetClusterServiceVersion(ctx, sub)
var csv *olmv1alpha1.ClusterServiceVersion

// If can't get CSV, requeue the request
if err != nil {
merr.Add(err)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
continue
if opdRegistry.UserManaged {
csvList, err := r.GetClusterServiceVersionListFromPackage(ctx, opdRegistry.PackageName, opdRegistry.Namespace)
if err != nil {
merr.Add(err)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
continue
}
csv = csvList[0]
} else {
csv, err = r.GetClusterServiceVersion(ctx, sub)
// If can't get CSV, requeue the request
if err != nil {
merr.Add(err)
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
continue
}
}

if csv == nil {
Expand All @@ -154,26 +168,28 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper
continue
}

if err := r.DeleteRedundantCSV(ctx, csv.Name, csv.Namespace, registryKey.Namespace, opdRegistry.PackageName); err != nil {
merr.Add(errors.Wrapf(err, "failed to delete the redundant ClusterServiceVersion %s in the namespace %s", csv.Name, csv.Namespace))
requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
continue
}

// find the OperandRequest which has the same operator's channel version 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 err := r.DeleteRedundantCSV(ctx, csv.Name, csv.Namespace, registryKey.Namespace, opdRegistry.PackageName); err != nil {
// merr.Add(errors.Wrapf(err, "failed to delete the redundant ClusterServiceVersion %s in the namespace %s", csv.Name, csv.Namespace))
// requestInstance.SetMemberStatus(operand.Name, operatorv1alpha1.OperatorFailed, "", &r.Mutex)
// continue
// }

if !opdRegistry.UserManaged {
// find the OperandRequest which has the same operator's channel version 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") {
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 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,11 +201,11 @@ 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
}
err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Name, configInstance.Namespace, csv, requestInstance, operand.Name, sub.Namespace, &r.Mutex)
err = r.reconcileCRwithConfig(ctx, opdConfig, configInstance.Name, configInstance.Namespace, csv, requestInstance, operand.Name, csv.Namespace, &r.Mutex)
if err != nil {
merr.Add(err)
requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex)
Expand All @@ -203,7 +219,7 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper
}

} else {
err = r.reconcileCRwithRequest(ctx, requestInstance, operand, types.NamespacedName{Name: requestInstance.Name, Namespace: requestInstance.Namespace}, i, sub.Namespace, &r.Mutex)
err = r.reconcileCRwithRequest(ctx, requestInstance, operand, types.NamespacedName{Name: requestInstance.Name, Namespace: requestInstance.Namespace}, i, csv.Namespace, &r.Mutex)
if err != nil {
merr.Add(err)
requestInstance.SetMemberStatus(operand.Name, "", operatorv1alpha1.ServiceFailed, &r.Mutex)
Expand Down
Loading