Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
added OperatorConfig controller
- to apply configuration from OperatorConfig onto CSVs

updated Operator type in OperandRegistry to include OperatorConfig name
- this assumes OperatorConfigs are in the same namespace as registry,
  just like OperandConfig

updated RBAC to include OperatorConfig

Signed-off-by: Henry H Li <[email protected]>
  • Loading branch information
bitscuit committed Mar 29, 2024
commit 1ca74549d5dce999972df848f68cbfda6517806f
3 changes: 3 additions & 0 deletions api/v1alpha1/operandregistry_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ type Operator struct {
// SubscriptionConfig is used to override operator configuration.
// +optional
SubscriptionConfig *olmv1alpha1.SubscriptionConfig `json:"subscriptionConfig,omitempty"`
// OperatorConfig is the name of the OperatorConfig
// +optional
OperatorConfig string `json:"operatorConfig,omitempty"`
}

// +kubebuilder:validation:Enum=public;private
Expand Down
10 changes: 10 additions & 0 deletions api/v1alpha1/operatorconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ type OperatorConfigList struct {
Items []OperatorConfig `json:"items"`
}

// GetOperator obtains the operator definition with the operand name.
func (r *OperatorConfig) GetConfigForOperator(name string) *ServiceOperatorConfig {
for _, o := range r.Spec.Services {
if o.Name == name {
return &o
}
}
return nil
}

func init() {
SchemeBuilder.Register(&OperatorConfig{}, &OperatorConfigList{})
}
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-03-20T18:18:08Z"
createdAt: "2024-03-29T03:05:22Z"
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.0'
Expand Down Expand Up @@ -701,6 +701,9 @@ spec:
- operandbindinfos
- operandbindinfos/status
- operandbindinfos/finalizers
- operatorconfigs
- operatorconfigs/status
- operatorconfigs/finalizers
verbs:
- create
- delete
Expand Down
3 changes: 3 additions & 0 deletions bundle/manifests/operator.ibm.com_operandregistries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ spec:
is not set, the operator namespace is the same as OperandRegistry
Namespace
type: string
operatorConfig:
description: OperatorConfig is the name of the OperatorConfig
type: string
packageName:
description: Name of the package that defines the applications.
type: string
Expand Down
3 changes: 3 additions & 0 deletions config/crd/bases/operator.ibm.com_operandregistries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ spec:
is not set, the operator namespace is the same as OperandRegistry
Namespace
type: string
operatorConfig:
description: OperatorConfig is the name of the OperatorConfig
type: string
packageName:
description: Name of the package that defines the applications.
type: string
Expand Down
3 changes: 3 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ rules:
- operandbindinfos
- operandbindinfos/status
- operandbindinfos/finalizers
- operatorconfigs
- operatorconfigs/status
- operatorconfigs/finalizers
- verbs:
- create
- delete
Expand Down
112 changes: 110 additions & 2 deletions controllers/operatorconfig/operatorconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,22 @@ package operatorconfig
import (
"context"

"github.com/barkimedes/go-deepcopy"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"

operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1"
deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator"
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
)

// OperatorConfigReconciler reconciles a OperatorConfig object
Expand All @@ -47,14 +58,111 @@ type Reconciler struct {
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)

// TODO(user): your logic here
instance := &operatorv1alpha1.OperandRequest{}
if err := r.Client.Get(ctx, req.NamespacedName, instance); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}

klog.Infof("Reconciling OperatorConfig for request: %s, %s", instance.Namespace, instance.Name)

for _, v := range instance.Spec.Requests {
reqBlock := v
registry, err := r.GetOperandRegistry(ctx, instance.GetRegistryKey(reqBlock))
if err != nil {
return ctrl.Result{}, err
}
for _, u := range reqBlock.Operands {
operand := u
operator := registry.GetOperator(operand.Name)
if operator.OperatorConfig == "" {
break
}

var sub *olmv1alpha1.Subscription
sub, err = r.GetSubscription(ctx, operator.Name, operator.Namespace, registry.Namespace, operator.PackageName)
if err != nil {
return ctrl.Result{}, err
}

var csv *olmv1alpha1.ClusterServiceVersion
csv, err = r.GetClusterServiceVersion(ctx, sub)
if err != nil {
return ctrl.Result{}, err
}

klog.Infof("Fetching OperatorConfig: %s", operator.OperatorConfig)
config := &operatorv1alpha1.OperatorConfig{}
if err := r.Client.Get(ctx, types.NamespacedName{
Name: operator.OperatorConfig,
Namespace: registry.Namespace,
}, config); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
serviceConfig := config.GetConfigForOperator(operator.Name)
if serviceConfig == nil {
klog.Infof("OperatorConfig: %s, does not have configuration for operator: %s", operator.OperatorConfig, operator.Name)
return ctrl.Result{}, nil
}

copyToCast, err := deepcopy.Anything(csv)
if err != nil {
return ctrl.Result{}, err
}
csvToUpdate := copyToCast.(*olmv1alpha1.ClusterServiceVersion)
klog.Infof("Applying OperatorConfig: %s to Operator: %s via CSV: %s, %s", operator.OperatorConfig, operator.Name, csv.Name, csv.Namespace)
return r.configCsv(ctx, csvToUpdate, serviceConfig)
}
}
return ctrl.Result{}, nil
}

func (r *Reconciler) configCsv(ctx context.Context, csv *olmv1alpha1.ClusterServiceVersion, config *operatorv1alpha1.ServiceOperatorConfig) (ctrl.Result, error) {
if config.Replicas != nil {
csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Replicas = config.Replicas
}
if config.Affinity != nil {
csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Affinity = config.Affinity
}
if config.TopologySpreadConstraints != nil {
csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.TopologySpreadConstraints = config.TopologySpreadConstraints
}
if err := r.Client.Update(ctx, csv); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}

func (r *Reconciler) requestsFromMapFunc(ctx context.Context) handler.MapFunc {
return func(object client.Object) []reconcile.Request {
requests := []reconcile.Request{}

operandRequests, _ := r.ListOperandRequests(ctx, nil)
for _, req := range operandRequests.Items {
r := reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: req.Namespace,
Name: req.Name,
},
}
requests = append(requests, r)
}
return requests
}
}

// SetupWithManager sets up the controller with the Manager.
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
ctx := context.Background()
return ctrl.NewControllerManagedBy(mgr).
For(&operatorv1alpha1.OperatorConfig{}).
For(&operatorv1alpha1.OperandRequest{}).
Watches(&source.Kind{Type: &operatorv1alpha1.OperatorConfig{}}, handler.EnqueueRequestsFromMapFunc(r.requestsFromMapFunc(ctx)), builder.WithPredicates(predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return true
},
DeleteFunc: func(e event.DeleteEvent) bool {
// Evaluates to false if the object has been confirmed deleted.
return !e.DeleteStateUnknown
},
Comment on lines +159 to +165
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if a update event on OperandRequest should trigger the reconciliation as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The predicates here are for events to the OperatorConfig CR not, OperandRequest. And if no predicate is specified for an event, then those events will be reconciled

})).
Complete(r)
}