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
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
120 changes: 68 additions & 52 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 @@ -160,20 +174,22 @@ func (r *Reconciler) reconcileOperand(ctx context.Context, requestInstance *oper
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 !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