Skip to content

Commit f494f51

Browse files
authored
Enable support to configure maxVolumesPerNode (#76)
* Enable support to configure maxVolumesPerNode Signed-off-by: Mayank Sachan <[email protected]> * Fix linter Signed-off-by: Mayank Sachan <[email protected]> * Fix CVEs Signed-off-by: Mayank Sachan <[email protected]> * Add UT Signed-off-by: Mayank Sachan <[email protected]> * Add MaxVolumesPerNode field in IBMObjectCSI CR Signed-off-by: Mayank Sachan <[email protected]> * update CRD Signed-off-by: Mayank Sachan <[email protected]> * Add testcases Signed-off-by: Mayank Sachan <[email protected]> * Cache namespace scoped resources under ibm-object-csi-operator ns and required cluster scoped resources Signed-off-by: Mayank Sachan <[email protected]> * Rename finalizer and use label selector for caching * Use label selector for caching * Error out if failed to get cluster details Signed-off-by: Mayank Sachan <[email protected]> * Update namespace for configmap to kube-system ns --------- Signed-off-by: Mayank Sachan <[email protected]>
1 parent 684c06f commit f494f51

File tree

12 files changed

+229
-57
lines changed

12 files changed

+229
-57
lines changed

api/v1alpha1/ibmobjectcsi_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ type IBMObjectCSINodeSpec struct {
6969
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
7070

7171
Resources ResourcesSpec `json:"resources,omitempty"`
72+
73+
// +kubebuilder:validation:Optional
74+
MaxVolumesPerNode string `json:"maxVolumesPerNode,omitempty"`
7275
}
7376

7477
// IBMObjectCSIControllerSpec defines the desired state of IBMObjectCSIController

config/crd/bases/objectdriver.csi.ibm.com_ibmobjectcsis.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,8 @@ spec:
19731973
description: PullPolicy describes a policy for if/when to pull
19741974
a container image
19751975
type: string
1976+
maxVolumesPerNode:
1977+
type: string
19761978
repository:
19771979
type: string
19781980
resources:

controllers/constants/constants.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ const (
7575
CSINodePriorityClassName = "system-node-critical"
7676
CSIControllerPriorityClassName = "system-cluster-critical"
7777

78-
ResourceReqLimitsConfigMap = "cos-csi-driver-configmap"
79-
ObjectCSIDriver = "ibm-object-csi"
78+
ParamsConfigMap = "managed-addon-ibm-object-csi-driver"
79+
ParamsConfigMapNamespace = "kube-system"
80+
ObjectCSIDriver = "ibm-object-csi"
8081

8182
RetainPolicyTag = "retain"
8283

@@ -104,13 +105,25 @@ const (
104105

105106
InfraProviderPlatformIBM = "IBMCloud"
106107
InfraProviderType = "VPC"
108+
109+
MaxVolumesPerNodeEnv = "MAX_VOLUMES_PER_NODE"
110+
//ConfigMap keys
111+
MaxVolumesPerNodeCMKey = "maxVolumesPerNode"
112+
NodeServerCPURequestCMKey = "CSINodeCPURequest"
113+
NodeServerMemoryRequestCMKey = "CSINodeMemoryRequest"
114+
NodeServerCPULimitCMKey = "CSINodeCPULimit"
115+
NodeServerMemoryLimitCMKey = "CSINodeMemoryLimit"
107116
)
108117

109118
var CommonCSIResourceLabels = map[string]string{
110119
"app.kubernetes.io/part-of": CSIDriverName,
111120
"app.kubernetes.io/managed-by": CSIOperatorName,
112121
}
113122

123+
var CommonCSIResourceLabelForCaching = map[string]string{
124+
"app.kubernetes.io/part-of": CSIDriverName,
125+
}
126+
114127
// GetResourceName returns the name of a resource for a CSI driver
115128
func GetResourceName(name string) string {
116129
return fmt.Sprintf("%s-%s", ObjectCSIDriver, name)

controllers/ibmobjectcsi_controller.go

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,15 @@ type IBMObjectCSIReconciler struct {
101101
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
102102
func (r *IBMObjectCSIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (reconcile.Result, error) {
103103
reqLogger := csiLog.WithValues("Request.Namespace", req.Namespace, "Request.Name", req.Name)
104-
reqLogger.Info("Reconciling IBMObjectCSI")
105104
r.ControllerHelper.Log = csiLog
106105

107106
// Check if the reconcile was triggered by the ConfigMap events
108-
if req.Name == constants.ResourceReqLimitsConfigMap {
109-
reqLogger.Info("Reconcile triggered by ConfigMap event")
107+
if req.Namespace == constants.ParamsConfigMapNamespace && req.Name == constants.ParamsConfigMap {
108+
reqLogger.Info("Reconcile triggered by create/update event on ConfigMap")
110109
// Handle the update of IBMObjectCSI
111110
return r.handleConfigMapReconcile(ctx, req)
112111
}
112+
reqLogger.Info("Reconciling IBMObjectCSI")
113113

114114
// Fetch the CSIDriver instance
115115
instance := crutils.New(&objectdriverv1alpha1.IBMObjectCSI{})
@@ -163,6 +163,31 @@ func (r *IBMObjectCSIReconciler) Reconcile(ctx context.Context, req ctrl.Request
163163
}
164164
originalStatus := *instance.Status.DeepCopy()
165165

166+
// Fetch the ConfigMap instance
167+
configMap := &corev1.ConfigMap{}
168+
err = r.Get(ctx, types.NamespacedName{Name: constants.ParamsConfigMap, Namespace: constants.ParamsConfigMapNamespace}, configMap)
169+
if err != nil {
170+
if errors.IsNotFound(err) {
171+
reqLogger.Info("ConfigMap not found. Retry after 5 seconds...", "name", constants.ParamsConfigMap, "namespace", constants.ParamsConfigMapNamespace)
172+
return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
173+
}
174+
reqLogger.Error(err, "Failed to get ConfigMap", constants.ParamsConfigMap)
175+
// Error reading the object - requeue the request.
176+
return reconcile.Result{}, err
177+
}
178+
179+
if crUpdateRequired := checkIfupdateCRFromConfigMapRequired(instance.Unwrap(), configMap); crUpdateRequired {
180+
// Update the instance in the Kubernetes API server
181+
reqLogger.Info("IBMObjectCSI spec is not in sync with configmap data. Updating IBMObjectCSI CR...")
182+
err = r.Update(ctx, instance.Unwrap())
183+
if err != nil {
184+
reqLogger.Error(err, "Failed to update IBMObjectCSI instance as per configMap data")
185+
return reconcile.Result{}, err
186+
}
187+
reqLogger.Info("IBMObjectCSI CR is updated as per configmap data")
188+
return reconcile.Result{}, nil
189+
}
190+
166191
// create the resources if not exist
167192
for _, rec := range []reconciler{
168193
r.reconcileCSIDriver,
@@ -208,25 +233,14 @@ func (r *IBMObjectCSIReconciler) handleConfigMapReconcile(ctx context.Context, r
208233
err := r.Get(ctx, req.NamespacedName, configMap)
209234
if err != nil {
210235
if errors.IsNotFound(err) {
211-
reqLogger.Info("ConfigMap", req.Name, "not found in namespace", req.Namespace)
212-
// what action should be taken when cm is not found?
213-
} else {
214-
reqLogger.Error(err, "Failed to get ConfigMap", req.Name)
215-
// Error reading the object - requeue the request.
216-
return reconcile.Result{}, err
236+
reqLogger.Info("ConfigMap not found. Ignoring configmap event...", "name", req.Name, "namespace", req.Namespace)
237+
return reconcile.Result{}, nil
217238
}
239+
reqLogger.Error(err, "Failed to get ConfigMap", req.Name)
240+
// Error reading the object - requeue the request.
241+
return reconcile.Result{}, err
218242
}
219243

220-
//get values from configMap
221-
CSINodeCPURequest := configMap.Data["CSINodeCPURequest"]
222-
CSINodeMemoryRequest := configMap.Data["CSINodeMemoryRequest"]
223-
CSINodeCPULimit := configMap.Data["CSINodeCPULimit"]
224-
CSINodeMemoryLimit := configMap.Data["CSINodeMemoryLimit"]
225-
226-
reqLogger.Info("The resource requests and limits fetched from configmap",
227-
"CSINodeCPURequest", CSINodeCPURequest, "CSINodeMemoryRequest", CSINodeMemoryRequest,
228-
"CSINodeCPULimit", CSINodeCPULimit, "CSINodeMemoryLimit", CSINodeMemoryLimit)
229-
230244
// Fetch the IBMObjectCSI instance
231245
instance := &objectdriverv1alpha1.IBMObjectCSI{}
232246

@@ -240,21 +254,18 @@ func (r *IBMObjectCSIReconciler) handleConfigMapReconcile(ctx context.Context, r
240254
}
241255
reqLogger.Info("IBMObjectCSI CR fetched successfully")
242256

243-
// Update the IBMObjectCSI instance with values from ConfigMap
244-
instance.Spec.Node.Resources.Requests.CPU = CSINodeCPURequest
245-
instance.Spec.Node.Resources.Requests.Memory = CSINodeMemoryRequest
246-
instance.Spec.Node.Resources.Limits.CPU = CSINodeCPULimit
247-
instance.Spec.Node.Resources.Limits.Memory = CSINodeMemoryLimit
248-
249-
// Update the instance in the Kubernetes API server
250-
reqLogger.Info("Updating IBMObjectCSI CR with resource requests and limits for Node pods")
251-
err = r.Update(ctx, instance)
252-
if err != nil {
253-
reqLogger.Error(err, "Failed to update IBMObjectCSI instance with ConfigMap values")
254-
return reconcile.Result{}, err
257+
if crUpdateRequired := checkIfupdateCRFromConfigMapRequired(instance, configMap); crUpdateRequired {
258+
// Update the instance in the Kubernetes API server
259+
reqLogger.Info("IBMObjectCSI spec is not in sync with configmap data. Updating IBMObjectCSI CR...")
260+
err = r.Update(ctx, instance)
261+
if err != nil {
262+
reqLogger.Error(err, "Failed to update IBMObjectCSI instance as per configMap data")
263+
return reconcile.Result{}, err
264+
}
265+
reqLogger.Info("IBMObjectCSI CR is updated as per configmap data")
266+
return reconcile.Result{}, nil
255267
}
256-
reqLogger.Info("IBMObjectCSI CR is getting updated. Node pods will get restarted to reflect updated resource requests and limits")
257-
268+
reqLogger.Info("IBMObjectCSI spec is already in sync with configmap data. IBMObjectCSI CR update is not needed")
258269
return reconcile.Result{}, nil
259270
}
260271

@@ -383,7 +394,11 @@ func (r *IBMObjectCSIReconciler) reconcileClusterRoleBinding(instance *crutils.I
383394
}
384395

385396
func (r *IBMObjectCSIReconciler) reconcileStorageClasses(instance *crutils.IBMObjectCSI) error {
397+
logger := csiLog.WithValues("reconcileStorageClasses")
398+
logger.Info("Entry")
399+
defer logger.Info("Exit")
386400
storageClasses := r.getStorageClasses(instance)
401+
logger.Info("Number of storageclasses to be reonciled", len(storageClasses))
387402
return r.ControllerHelper.ReconcileStorageClasses(storageClasses)
388403
}
389404

@@ -603,6 +618,43 @@ func (r *IBMObjectCSIReconciler) getClusterRoles(instance *crutils.IBMObjectCSI)
603618
}
604619
}
605620

621+
func checkIfupdateCRFromConfigMapRequired(instance *objectdriverv1alpha1.IBMObjectCSI, cm *corev1.ConfigMap) bool {
622+
crUpdateRequired := false
623+
624+
if val, ok := cm.Data[constants.NodeServerCPURequestCMKey]; ok {
625+
if instance.Spec.Node.Resources.Requests.CPU != val {
626+
instance.Spec.Node.Resources.Requests.CPU = val
627+
crUpdateRequired = true
628+
}
629+
}
630+
if val, ok := cm.Data[constants.NodeServerMemoryRequestCMKey]; ok {
631+
if instance.Spec.Node.Resources.Requests.Memory != val {
632+
instance.Spec.Node.Resources.Requests.Memory = val
633+
crUpdateRequired = true
634+
}
635+
}
636+
if val, ok := cm.Data[constants.NodeServerCPULimitCMKey]; ok {
637+
if instance.Spec.Node.Resources.Limits.CPU != val {
638+
instance.Spec.Node.Resources.Limits.CPU = val
639+
crUpdateRequired = true
640+
}
641+
}
642+
if val, ok := cm.Data[constants.NodeServerMemoryLimitCMKey]; ok {
643+
if instance.Spec.Node.Resources.Limits.Memory != val {
644+
instance.Spec.Node.Resources.Limits.Memory = val
645+
crUpdateRequired = true
646+
}
647+
}
648+
649+
if val, ok := cm.Data[constants.MaxVolumesPerNodeCMKey]; ok {
650+
if instance.Spec.Node.MaxVolumesPerNode != val {
651+
instance.Spec.Node.MaxVolumesPerNode = val
652+
crUpdateRequired = true
653+
}
654+
}
655+
return crUpdateRequired
656+
}
657+
606658
// SetupWithManager sets up the controller with the Manager.
607659
func (r *IBMObjectCSIReconciler) SetupWithManager(mgr ctrl.Manager) error {
608660
return ctrl.NewControllerManagedBy(mgr).
@@ -619,16 +671,16 @@ func configMapPredicate() predicate.Predicate {
619671
triggerReconcile := predicate.Funcs{
620672
CreateFunc: func(e event.CreateEvent) bool {
621673
configmap := e.Object.(*corev1.ConfigMap)
622-
if configmap.Name == constants.ResourceReqLimitsConfigMap {
623-
logger.Info("Create detected on the configmap", "configmap", configmap.Name)
674+
if configmap.Namespace == constants.ParamsConfigMapNamespace && configmap.Name == constants.ParamsConfigMap {
675+
logger.Info("Configmap created", "name", configmap.Name, "namespace", configmap.Namespace)
624676
return true
625677
}
626678
return false
627679
},
628680
UpdateFunc: func(e event.UpdateEvent) bool {
629681
configmap := e.ObjectNew.(*corev1.ConfigMap)
630-
if configmap.Name == constants.ResourceReqLimitsConfigMap {
631-
logger.Info("Update detected on the configmap", "configmap", configmap.Name)
682+
if configmap.Namespace == constants.ParamsConfigMapNamespace && configmap.Name == constants.ParamsConfigMap {
683+
logger.Info("Update event on the configmap", configmap.Name, "namespace", configmap.Namespace)
632684
return true
633685
}
634686
return false

0 commit comments

Comments
 (0)