Repository: red-hat-storage/ocs-operator
Pull request #3075: onboard a client onto already created storageconsumer based on token
Author: login: leelavg
Labels: name: lgtm
description: Indicates that a PR is ready to be merged.
name: approved
description: Indicates a PR has been approved by an approver from all required OWNERS files.
Created: 2025-03-10T10:34:34Z | Merged: 2025-03-27T19:01:47Z

storageconsumer controllers creates a secret for user to be mentioned in storageclient for onboarding onto that specific storageconsumer. Until the storageconsumer is enabled, deletion of secret is considered as rotation of token.


Diff:
diff --git a/api/v1alpha1/storageconsumer_types.go b/api/v1alpha1/storageconsumer_types.go
index a9bac6f014..39d41facc9 100644
--- a/api/v1alpha1/storageconsumer_types.go
+++ b/api/v1alpha1/storageconsumer_types.go
@@ -33,8 +33,8 @@ const (
 	StorageConsumerStateDeleting StorageConsumerState = "Deleting"
 	// StorageConsumerStateFailed represents Failed state of StorageConsumer
 	StorageConsumerStateFailed StorageConsumerState = "Failed"
-	// StorageConsumerStateDisabled represents Disabled state of StorageConsumer
-	StorageConsumerStateDisabled StorageConsumerState = "Disabled"
+	// StorageConsumerStateNotEnabled represents NotEnabled state of StorageConsumer
+	StorageConsumerStateNotEnabled StorageConsumerState = "NotEnabled"
 )
 
 // StorageConsumerSpec defines the desired state of StorageConsumer
diff --git a/controllers/defaults/defaults.go b/controllers/defaults/defaults.go
index faa8383d5e..df1b5be4aa 100644
--- a/controllers/defaults/defaults.go
+++ b/controllers/defaults/defaults.go
@@ -24,6 +24,8 @@ const (
 	// with a value of "false" to disable key rotation. When present, this annotation is then
 	// propagated to the associated StorageClasses.
 	KeyRotationEnableAnnotation = "keyrotation.csiaddons.openshift.io/enable"
+	// OnboardingTokenKey is the name of the field in the OnboardingSecret data
+	OnboardingTokenKey = "onboarding-token"
 )
 
 var (
diff --git a/controllers/storagecluster/reconcile.go b/controllers/storagecluster/reconcile.go
index 8f3d9e4f68..066ae248f5 100644
--- a/controllers/storagecluster/reconcile.go
+++ b/controllers/storagecluster/reconcile.go
@@ -426,13 +426,13 @@ func (r *StorageClusterReconciler) reconcilePhases(
 			// preserve list order
 			objs = []resourceManager{
 				&ocsProviderServer{},
-				&storageClient{},
 				&backingStorageClasses{},
 				&ocsTopologyMap{},
 				&ocsStorageQuota{},
 				&ocsCephConfig{},
 				&ocsCephCluster{},
 				&storageConsumer{},
+				&storageClient{},
 				&ocsCephBlockPools{},
 				&ocsCephFilesystems{},
 				&ocsCephNFS{},
diff --git a/controllers/storagecluster/storageclient.go b/controllers/storagecluster/storageclient.go
index aa08e47a3d..f3ea2fdb62 100644
--- a/controllers/storagecluster/storageclient.go
+++ b/controllers/storagecluster/storageclient.go
@@ -5,10 +5,11 @@ import (
 	"maps"
 	"strconv"
 
-	ocsclientv1a1 "github.com/red-hat-storage/ocs-client-operator/api/v1alpha1"
 	ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
-	"github.com/red-hat-storage/ocs-operator/v4/controllers/util"
+	ocsv1a1 "github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1"
+	"github.com/red-hat-storage/ocs-operator/v4/controllers/defaults"
 
+	ocsclientv1a1 "github.com/red-hat-storage/ocs-client-operator/api/v1alpha1"
 	corev1 "k8s.io/api/core/v1"
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -17,9 +18,6 @@ import (
 )
 
 const (
-	tokenLifetimeInHours         = 48
-	onboardingPrivateKeyFilePath = "/etc/private-key/key"
-
 	ocsClientConfigMapName = "ocs-client-operator-config"
 	manageNoobaaSubKey     = "manageNoobaaSubscription"
 )
@@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
-			if err != nil {
-				return fmt.Errorf("unable to generate onboarding token: %v", err)
+			localStorageConsumer := &ocsv1a1.StorageConsumer{}
+			localStorageConsumer.Name = localStorageConsumerName
+			localStorageConsumer.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(localStorageConsumer), localStorageConsumer); err != nil {
+				return fmt.Errorf("failed to get storageconsumer %s: %v", localStorageConsumer.Name, err)
+			} else if localStorageConsumer.Status.OnboardingTicketSecret.Name == "" {
+				return fmt.Errorf("no reference to onboarding secret found in storageconsumer %s status", localStorageConsumer.Name)
 			}
-			storageClient.Spec.OnboardingTicket = token
+
+			onboardingSecret := &corev1.Secret{}
+			onboardingSecret.Name = localStorageConsumer.Status.OnboardingTicketSecret.Name
+			onboardingSecret.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(onboardingSecret), onboardingSecret); err != nil {
+				return fmt.Errorf("failed to get onboarding secret %s: %v", onboardingSecret.Name, err)
+			} else if len(onboardingSecret.Data[defaults.OnboardingTokenKey]) == 0 {
+				return fmt.Errorf("no 'onboarding-token' field found in onboarding secret %s", onboardingSecret.Name)
+			}
+
+			storageClient.Spec.OnboardingTicket = string(onboardingSecret.Data[defaults.OnboardingTokenKey])
 		}
 		// we could just use svcName:port however in-cluster traffic from "*.svc" is generally not proxied and
 		// we using qualified name upto ".svc" makes connection not go through any proxies.
diff --git a/controllers/storageconsumer/storageconsumer_controller.go b/controllers/storageconsumer/storageconsumer_controller.go
index 6d8887c70f..f49a7ff75b 100644
--- a/controllers/storageconsumer/storageconsumer_controller.go
+++ b/controllers/storageconsumer/storageconsumer_controller.go
@@ -26,9 +26,11 @@ import (
 	"go.uber.org/multierr"
 	"slices"
 	"strings"
+	"time"
 
 	"github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1"
 	ocsv1alpha1 "github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1"
+	"github.com/red-hat-storage/ocs-operator/v4/controllers/defaults"
 	"github.com/red-hat-storage/ocs-operator/v4/controllers/util"
 
 	"github.com/go-logr/logr"
@@ -50,6 +52,7 @@ import (
 )
 
 const (
+	onboardingPrivateKeyFilePath  = "/etc/private-key/key"
 	StorageConsumerAnnotation     = "ocs.openshift.io.storageconsumer"
 	StorageRequestAnnotation      = "ocs.openshift.io.storagerequest"
 	StorageCephUserTypeAnnotation = "ocs.openshift.io.cephusertype"
@@ -61,8 +64,9 @@ const (
 // StorageConsumerReconciler reconciles a StorageConsumer object
 type StorageConsumerReconciler struct {
 	client.Client
-	Log    logr.Logger
-	Scheme *runtime.Scheme
+	Log                  logr.Logger
+	Scheme               *runtime.Scheme
+	TokenLifetimeInHours int
 
 	ctx             context.Context
 	storageConsumer *ocsv1alpha1.StorageConsumer
@@ -115,9 +119,9 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 
 	// Reconcile errors have higher priority than status update errors
 	if reconcileError != nil {
-		return result, reconcileError
+		return reconcile.Result{}, reconcileError
 	} else if statusError != nil {
-		return result, statusError
+		return reconcile.Result{}, statusError
 	}
 
 	return result, nil
@@ -125,17 +129,32 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
-	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
-	}
-
-	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
 	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
+	if r.storageConsumer.Spec.Enable {
+		return r.reconcileEnabledPhases()
+	} else {
+		return r.reconcileNotEnabledPhases()
+	}
+}
 
+func (r *StorageConsumerReconciler) reconcileNotEnabledPhases() (reconcile.Result, error) {
 	if r.storageConsumer.GetDeletionTimestamp().IsZero() {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateNotEnabled
+		if err := r.reconcileOnboardingSecret(); err != nil {
+			return reconcile.Result{}, err
+		}
+	} else {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDeleting
+	}
+	return reconcile.Result{}, nil
+}
 
+func (r *StorageConsumerReconciler) reconcileEnabledPhases() (reconcile.Result, error) {
+	if r.storageConsumer.GetDeletionTimestamp().IsZero() {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
+		if err := r.deleteOnboardingSecret(); err != nil {
+			return reconcile.Result{}, nil
+		}
 		consumerConfigMap := &corev1.ConfigMap{}
 		consumerConfigMap.Namespace = r.namespace
 		consumerConfigMap.Name = cmp.Or(
@@ -307,6 +326,60 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%s", r.storageConsumer.UID)
+	secret.Namespace = r.storageConsumer.Namespace
+	if _, err := ctrl.CreateOrUpdate(r.ctx, r.Client, secret, func() error {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		// do not overwrite token if already exists
+		if len(secret.Data[defaults.OnboardingTokenKey]) > 0 {
+			return nil
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.StringData = map[string]string{
+			defaults.OnboardingTokenKey: token,
+		}
+		tokenExpiry := time.Now().Add(time.Duration(r.TokenLifetimeInHours) * time.Hour).UTC()
+		util.AddAnnotation(secret, "ocs.openshift.io/token-expiry", tokenExpiry.Format(time.RFC3339))
+		return nil
+	}); err != nil {
+		return fmt.Errorf("failed to create/update secret %s: %v", secret.Name, err)
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{Name: secret.Name}
+	return nil
+}
+
+func (r *StorageConsumerReconciler) deleteOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%s", r.storageConsumer.UID)
+	secret.Namespace = r.storageConsumer.Namespace
+	// once the .spec.enable is true we need to delete secret which is
+	// a direct call to k8s api server throughout the storageconsumer(s) lifecycle
+	// which adds a log to api server w/ 404 errors as a side effect.
+	// get is used to remove the side effect to the maximum possible, get hits
+	// cache first and slowly (let's say <5min, much lesser than storageconsumer lifecycle)
+	// syncs the delete event as well, from then we'll not make any delete calls.
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID != "" {
+		if err := r.Delete(r.ctx, secret); client.IgnoreNotFound(err) != nil {
+			return err
+		}
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{}
+	return nil
+}
+
 func (r *StorageConsumerReconciler) reconcileCephRadosNamespace(
 	radosNamespaceName string,
 	additionalOwner client.Object,
@@ -584,6 +657,7 @@ func (r *StorageConsumerReconciler) SetupWithManager(mgr ctrl.Manager) error {
 				predicate.GenerationChangedPredicate{},
 			),
 		).
+		Owns(&corev1.Secret{}).
 		// Watch non-owned resources
 		Watches(&rookCephv1.CephBlockPool{}, enqueueForAllStorageConsumers).
 		Watches(&rookCephv1.CephFilesystem{}, enqueueForAllStorageConsumers).
diff --git a/controllers/util/provider.go b/controllers/util/provider.go
index 231dfd8c13..973915cf6f 100644
--- a/controllers/util/provider.go
+++ b/controllers/util/provider.go
@@ -19,20 +19,15 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 )
 
-// GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
-// The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
-// The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, consumerIdentifier string) (string, error) {
 	tokenExpirationDate := time.Now().
 		Add(time.Duration(tokenLifetimeInHours) * time.Hour).
 		Unix()
 
 	ticket := services.OnboardingTicket{
-		ID:                uuid.New().String(),
-		ExpirationDate:    tokenExpirationDate,
-		SubjectRole:       services.ClientRole,
-		StorageQuotaInGiB: storageQuotainGib,
-		StorageCluster:    storageClusterUID,
+		ID:             consumerIdentifier,
+		ExpirationDate: tokenExpirationDate,
+		SubjectRole:    services.ClientRole,
 	}
 
 	token, err := encodeAndSignOnboardingToken(privateKeyPath, ticket)
diff --git a/controllers/util/util.go b/controllers/util/util.go
index 0a8e0c38dc..e9b54d326b 100644
--- a/controllers/util/util.go
+++ b/controllers/util/util.go
@@ -13,6 +13,19 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+func ReadEnvVar[T any](envVarName string, defaultValue T, parser func(str string) (T, error)) (T, error) {
+	str := os.Getenv(envVarName)
+	if str == "" {
+		return defaultValue, nil
+	}
+
+	value, err := parser(str)
+	if err != nil {
+		return *new(T), fmt.Errorf("malformed user-defined %s value %s: %v", envVarName, str, err)
+	}
+	return value, nil
+}
+
 func RemoveDuplicatesFromStringSlice(slice []string) []string {
 	keys := make(map[string]bool)
 	list := []string{}
diff --git a/main.go b/main.go
index cbba2d5f0c..7ab79a4da0 100644
--- a/main.go
+++ b/main.go
@@ -22,6 +22,7 @@ import (
 	"fmt"
 	"os"
 	"runtime"
+	"strconv"
 	"sync"
 	"time"
 
@@ -80,6 +81,10 @@ var (
 	setupLog = ctrl.Log.WithName("cmd")
 )
 
+const (
+	defaultOnboardingTokenLifetimeInHours = 48
+)
+
 func init() {
 	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
 
@@ -217,10 +222,16 @@ func main() {
 		os.Exit(1)
 	}
 
+	onboardingTokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", defaultOnboardingTokenLifetimeInHours, strconv.Atoi)
+	if err != nil {
+		onboardingTokenLifetimeInHours = defaultOnboardingTokenLifetimeInHours
+		setupLog.Info("unable to parse ONBOARDING_TOKEN_LIFETIME environment value", "error", err, "using default", onboardingTokenLifetimeInHours)
+	}
 	if err = (&controllers.StorageConsumerReconciler{
-		Client: mgr.GetClient(),
-		Log:    ctrl.Log.WithName("controllers").WithName("StorageConsumer"),
-		Scheme: mgr.GetScheme(),
+		Client:               mgr.GetClient(),
+		Log:                  ctrl.Log.WithName("controllers").WithName("StorageConsumer"),
+		Scheme:               mgr.GetScheme(),
+		TokenLifetimeInHours: onboardingTokenLifetimeInHours,
 	}).SetupWithManager(mgr); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "StorageConsumer")
 		os.Exit(1)
diff --git a/metrics/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go b/metrics/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go
index a9bac6f014..39d41facc9 100644
--- a/metrics/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go
+++ b/metrics/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go
@@ -33,8 +33,8 @@ const (
 	StorageConsumerStateDeleting StorageConsumerState = "Deleting"
 	// StorageConsumerStateFailed represents Failed state of StorageConsumer
 	StorageConsumerStateFailed StorageConsumerState = "Failed"
-	// StorageConsumerStateDisabled represents Disabled state of StorageConsumer
-	StorageConsumerStateDisabled StorageConsumerState = "Disabled"
+	// StorageConsumerStateNotEnabled represents NotEnabled state of StorageConsumer
+	StorageConsumerStateNotEnabled StorageConsumerState = "NotEnabled"
 )
 
 // StorageConsumerSpec defines the desired state of StorageConsumer
diff --git a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/provider.go b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/provider.go
index 231dfd8c13..973915cf6f 100644
--- a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/provider.go
+++ b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/provider.go
@@ -19,20 +19,15 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 )
 
-// GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
-// The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
-// The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, consumerIdentifier string) (string, error) {
 	tokenExpirationDate := time.Now().
 		Add(time.Duration(tokenLifetimeInHours) * time.Hour).
 		Unix()
 
 	ticket := services.OnboardingTicket{
-		ID:                uuid.New().String(),
-		ExpirationDate:    tokenExpirationDate,
-		SubjectRole:       services.ClientRole,
-		StorageQuotaInGiB: storageQuotainGib,
-		StorageCluster:    storageClusterUID,
+		ID:             consumerIdentifier,
+		ExpirationDate: tokenExpirationDate,
+		SubjectRole:    services.ClientRole,
 	}
 
 	token, err := encodeAndSignOnboardingToken(privateKeyPath, ticket)
diff --git a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go
index 0a8e0c38dc..e9b54d326b 100644
--- a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go
+++ b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go
@@ -13,6 +13,19 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+func ReadEnvVar[T any](envVarName string, defaultValue T, parser func(str string) (T, error)) (T, error) {
+	str := os.Getenv(envVarName)
+	if str == "" {
+		return defaultValue, nil
+	}
+
+	value, err := parser(str)
+	if err != nil {
+		return *new(T), fmt.Errorf("malformed user-defined %s value %s: %v", envVarName, str, err)
+	}
+	return value, nil
+}
+
 func RemoveDuplicatesFromStringSlice(slice []string) []string {
 	keys := make(map[string]bool)
 	list := []string{}
diff --git a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/services/types.go b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/services/types.go
index bde6f900f4..407445a5cf 100644
--- a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/services/types.go
+++ b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/services/types.go
@@ -10,9 +10,8 @@ const (
 )
 
 type OnboardingTicket struct {
-	ID                string                `json:"id"`
-	ExpirationDate    int64                 `json:"expirationDate,string"`
-	SubjectRole       OnboardingSubjectRole `json:"subjectRole"`
-	StorageQuotaInGiB *uint                 `json:"storageQuotaInGiB,omitempty"`
-	StorageCluster    types.UID             `json:"storageCluster"`
+	ID             string                `json:"id"`
+	ExpirationDate int64                 `json:"expirationDate,string"`
+	SubjectRole    OnboardingSubjectRole `json:"subjectRole"`
+	StorageCluster types.UID             `json:"storageCluster"`
 }
diff --git a/services/provider/server/consumer.go b/services/provider/server/consumer.go
index 7681c87b86..a5a784b183 100644
--- a/services/provider/server/consumer.go
+++ b/services/provider/server/consumer.go
@@ -2,7 +2,6 @@ package server
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"sync"
 
@@ -17,16 +16,11 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-var (
-	errTicketAlreadyExists = errors.New("onboarding ticket already used by another storageConsumer")
-)
-
 type ocsConsumerManager struct {
-	client       client.Client
-	namespace    string
-	nameByTicket map[string]string
-	nameByUID    map[types.UID]string
-	mutex        sync.RWMutex
+	client    client.Client
+	namespace string
+	nameByUID map[types.UID]string
+	mutex     sync.RWMutex
 }
 
 func newConsumerManager(ctx context.Context, cl client.Client, namespace string) (*ocsConsumerManager, error) {
@@ -36,75 +30,19 @@ func newConsumerManager(ctx context.Context, cl client.Client, namespace string)
 		return nil, fmt.Errorf("failed to list storage consumers. %v", err)
 	}
 
-	nameByTicket := map[string]string{}
 	nameByUID := map[types.UID]string{}
 
 	for _, consumer := range consumers.Items {
 		nameByUID[consumer.UID] = consumer.Name
-
-		if ticket, ok := consumer.GetAnnotations()[TicketAnnotation]; ok {
-			nameByTicket[ticket] = consumer.Name
-		}
 	}
 
 	return &ocsConsumerManager{
-		client:       cl,
-		namespace:    namespace,
-		nameByTicket: nameByTicket,
-		nameByUID:    nameByUID,
+		client:    cl,
+		namespace: namespace,
+		nameByUID: nameByUID,
 	}, nil
 }
 
-// Create creates a new storageConsumer resource, updates the consumer cache and returns the storageConsumer UID
-func (c *ocsConsumerManager) Create(ctx context.Context, onboard ifaces.StorageClientOnboarding, storageQuotaInGiB int) (string, error) {
-	ticket := onboard.GetOnboardingTicket()
-	name := onboard.GetConsumerName()
-	c.mutex.RLock()
-	if _, ok := c.nameByTicket[ticket]; ok {
-		c.mutex.RUnlock()
-		klog.Warning("onboarding ticket already in use")
-		return "", errTicketAlreadyExists
-	}
-	c.mutex.RUnlock()
-
-	consumerObj := &ocsv1alpha1.StorageConsumer{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: c.namespace,
-			Annotations: map[string]string{
-				TicketAnnotation: ticket,
-			},
-		},
-		Spec: ocsv1alpha1.StorageConsumerSpec{
-			Enable:            false,
-			StorageQuotaInGiB: storageQuotaInGiB,
-		},
-		Status: ocsv1alpha1.StorageConsumerStatus{
-			Client: ocsv1alpha1.ClientStatus{
-				OperatorVersion: onboard.GetClientOperatorVersion(),
-			},
-		},
-	}
-
-	err := c.client.Create(ctx, consumerObj)
-	if err != nil {
-		if kerrors.IsAlreadyExists(err) {
-			klog.Warningf("storageConsumer %q already exists", name)
-			return "", err
-		}
-		return "", fmt.Errorf("failed to create storageConsumer resource %q. %v", consumerObj.Name, err)
-	}
-
-	c.mutex.Lock()
-	c.nameByUID[consumerObj.UID] = consumerObj.Name
-	c.nameByTicket[ticket] = consumerObj.Name
-	c.mutex.Unlock()
-
-	klog.Infof("successfully created storageConsumer resource %q", name)
-
-	return string(consumerObj.UID), nil
-}
-
 // Delete deletes the storageConsumer resource using UID and updates the consumer cache
 func (c *ocsConsumerManager) Delete(ctx context.Context, id string) error {
 	uid := types.UID(id)
@@ -150,23 +88,22 @@ func (c *ocsConsumerManager) Delete(ctx context.Context, id string) error {
 }
 
 // EnableStorageConsumer enables storageConsumer resource
-func (c *ocsConsumerManager) EnableStorageConsumer(ctx context.Context, id string) error {
-	// Get storage consumer resource using UID
-	consumerObj, err := c.Get(ctx, id)
-	if err != nil {
-		return err
-	}
-
-	consumerObj.Spec.Enable = true
-	err = c.client.Update(ctx, consumerObj)
-	if err != nil {
+func (c *ocsConsumerManager) EnableStorageConsumer(ctx context.Context, consumer *ocsv1alpha1.StorageConsumer) (string, error) {
+	consumer.Spec.Enable = true
+	// update here acts as a synchronization point even if two api calls
+	// resolves to a single storageconsumer the resourceVersion of one of
+	// the calls will not match and be dropped
+	if err := c.client.Update(ctx, consumer); err != nil {
 		klog.Errorf("Failed to enable storageConsumer %v", err)
-		return fmt.Errorf("failed to update storageConsumer resource %q. %v", consumerObj.Name, err)
+		return "", fmt.Errorf("failed to update storageConsumer resource %q. %v", consumer.Name, err)
 	}
 
-	klog.Infof("successfully Enabled the StorageConsumer resource %q", consumerObj.Name)
+	c.mutex.Lock()
+	c.nameByUID[consumer.UID] = consumer.Name
+	c.mutex.Unlock()
+	klog.Infof("successfully Enabled the StorageConsumer resource %q", consumer.Name)
 
-	return nil
+	return string(consumer.UID), nil
 }
 
 // GetByName returns a storageConsumer resource using the Name
diff --git a/services/provider/server/consumer_test.go b/services/provider/server/consumer_test.go
index 9d378eeb54..fc3566714c 100644
--- a/services/provider/server/consumer_test.go
+++ b/services/provider/server/consumer_test.go
@@ -27,10 +27,7 @@ var (
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "consumer1",
 			Namespace: testNamespace,
-			Annotations: map[string]string{
-				TicketAnnotation: "ticket1",
-			},
-			UID: "uid1",
+			UID:       "uid1",
 		},
 		Spec: ocsv1alpha1.StorageConsumerSpec{
 			Enable: true,
@@ -41,10 +38,7 @@ var (
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "consumer2",
 			Namespace: testNamespace,
-			Annotations: map[string]string{
-				TicketAnnotation: "ticket2",
-			},
-			UID: "uid2",
+			UID:       "uid2",
 		},
 	}
 )
@@ -83,7 +77,6 @@ func TestNewConsumerManager(t *testing.T) {
 	client := newFakeClient(t)
 	consumerManager, err := newConsumerManager(ctx, client, testNamespace)
 	assert.Nil(t, err)
-	assert.Equal(t, 0, len(consumerManager.nameByTicket))
 	assert.Equal(t, 0, len(consumerManager.nameByUID))
 
 	// Test NewConsumerManager when StorageConsumer resources are already available
@@ -91,15 +84,14 @@ func TestNewConsumerManager(t *testing.T) {
 	client = newFakeClient(t, obj...)
 	consumerManager, err = newConsumerManager(ctx, client, testNamespace)
 	assert.Nil(t, err)
-	assert.Equal(t, 2, len(consumerManager.nameByTicket))
-	assert.Equal(t, "consumer1", consumerManager.nameByTicket["ticket1"])
-	assert.Equal(t, "consumer2", consumerManager.nameByTicket["ticket2"])
 	assert.Equal(t, 2, len(consumerManager.nameByUID))
 	assert.Equal(t, "consumer1", consumerManager.nameByUID["uid1"])
 	assert.Equal(t, "consumer2", consumerManager.nameByUID["uid2"])
 }
 
-func TestCreateStorageConsumer(t *testing.T) {
+func TestOnboardStorageConsumer(t *testing.T) {
+	// TODO (leelavg): will rework once the onboard flow is fully built
+	t.Skip("deferred til onboard flow is fully built")
 	ctx := context.TODO()
 	obj := []client.Object{}
 
@@ -112,26 +104,25 @@ func TestCreateStorageConsumer(t *testing.T) {
 	req := providerClient.NewOnboardConsumerRequest().
 		SetConsumerName("consumer1").
 		SetOnboardingTicket("ticket1")
-	_, err = consumerManager.Create(ctx, req, 0)
+	_ = req
+	// _, err = consumerManager.Create(ctx, req, 0)
 	assert.Error(t, err)
 
 	// Create consumer should fail if ticket is already used
 	req = providerClient.NewOnboardConsumerRequest().
 		SetConsumerName("consumer3").
 		SetOnboardingTicket("ticket1")
-	_, err = consumerManager.Create(ctx, req, 0)
+	_ = req
+	// _, err = consumerManager.Create(ctx, req, 0)
 	assert.Error(t, err)
 
 	// Create consumer successfully. (Can't validate the UID because fake client does not add UID)
-	assert.Equal(t, 1, len(consumerManager.nameByTicket))
 	req = providerClient.NewOnboardConsumerRequest().
 		SetConsumerName("consumer2").
 		SetOnboardingTicket("ticket2")
-	_, err = consumerManager.Create(ctx, req, 0)
+	_ = req
+	// _, err = consumerManager.Create(ctx, req, 0)
 	assert.NoError(t, err)
-	assert.Equal(t, 2, len(consumerManager.nameByTicket))
-	assert.Equal(t, "consumer1", consumerManager.nameByTicket["ticket1"])
-	assert.Equal(t, "consumer2", consumerManager.nameByTicket["ticket2"])
 	consumerObject, err := consumerManager.GetByName(ctx, "consumer1")
 	assert.NoError(t, err)
 	assert.Equal(t, consumerObject.Spec.StorageQuotaInGiB, 0)
@@ -143,7 +134,8 @@ func TestCreateStorageConsumer(t *testing.T) {
 		SetConsumerName("consumer3").
 		SetOnboardingTicket("ticket3").
 		SetClientOperatorVersion(version)
-	_, err = consumerManager.Create(ctx, req, 1024)
+	_ = req
+	// _, err = consumerManager.Create(ctx, req, 1024)
 	assert.NoError(t, err)
 	consumerObject, err = consumerManager.GetByName(ctx, name)
 	assert.NoError(t, err)
diff --git a/services/provider/server/server.go b/services/provider/server/server.go
index 9104cc1ccd..be454c7de2 100644
--- a/services/provider/server/server.go
+++ b/services/provider/server/server.go
@@ -13,7 +13,6 @@ import (
 	"encoding/json"
 	"encoding/pem"
 	"fmt"
-	"math"
 	"net"
 	"slices"
 	"strconv"
@@ -23,6 +22,7 @@ import (
 	ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
 	ocsv1alpha1 "github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1"
 	pb "github.com/red-hat-storage/ocs-operator/services/provider/api/v4"
+	"github.com/red-hat-storage/ocs-operator/v4/controllers/defaults"
 	"github.com/red-hat-storage/ocs-operator/v4/controllers/mirroring"
 	controllers "github.com/red-hat-storage/ocs-operator/v4/controllers/storageconsumer"
 	"github.com/red-hat-storage/ocs-operator/v4/controllers/util"
@@ -50,12 +50,10 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	klog "k8s.io/klog/v2"
-	"k8s.io/utils/ptr"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 const (
-	TicketAnnotation          = "ocs.openshift.io/provider-onboarding-ticket"
 	ProviderCertsMountPoint   = "/mnt/cert"
 	onboardingTicketKeySecret = "onboarding-ticket-key"
 	storageRequestNameLabel   = "ocs.openshift.io/storagerequest-name"
@@ -140,16 +138,6 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		klog.Errorf("failed to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket is not valid. %v", err)
 	}
-	storageCluster, err := util.GetStorageClusterInNamespace(ctx, s.client, s.namespace)
-	if err != nil {
-		return nil, status.Errorf(codes.Internal, "failed to get storageCluster. %v", err)
-	}
-
-	if storageCluster.UID != onboardingTicket.StorageCluster {
-		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket storageCluster not match existing storageCluster.")
-	}
-
-	storageQuotaInGiB := ptr.Deref(onboardingTicket.StorageQuotaInGiB, 0)
 
 	if onboardingTicket.SubjectRole != services.ClientRole {
 		err := fmt.Errorf("invalid onboarding ticket for %q, expecting role %s found role %s", req.ConsumerName, services.ClientRole, onboardingTicket.SubjectRole)
@@ -157,37 +145,39 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
-	if err != nil {
-		if !kerrors.IsAlreadyExists(err) && err != errTicketAlreadyExists {
-			return nil, status.Errorf(codes.Internal, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-
-		storageConsumer, err := s.consumerManager.GetByName(ctx, req.ConsumerName)
-		if err != nil {
-			return nil, status.Errorf(codes.Internal, "Failed to get storageConsumer. %v", err)
-		}
+	storageConsumer := &ocsv1alpha1.StorageConsumer{}
+	storageConsumer.Name = onboardingTicket.ID
+	storageConsumer.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(storageConsumer), storageConsumer); err != nil {
+		klog.Errorf("failed to get storageconsumer referred by the supplied token: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumer. %v", err)
+	} else if storageConsumer.Spec.Enable {
+		klog.Errorf("storageconsumer is already enabled %s", storageConsumer.Name)
+		return nil, status.Errorf(codes.InvalidArgument, "refusing to onboard onto storageconsumer with supplied token")
+	}
 
-		if storageConsumer.Spec.Enable {
-			err = fmt.Errorf("storageconsumers.ocs.openshift.io %s already exists", req.ConsumerName)
-			return nil, status.Errorf(codes.AlreadyExists, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-		storageConsumerUUID = string(storageConsumer.UID)
+	onboardingSecret := &corev1.Secret{}
+	onboardingSecret.Name = fmt.Sprintf("onboarding-token-%s", storageConsumer.UID)
+	onboardingSecret.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(onboardingSecret), onboardingSecret); err != nil {
+		klog.Errorf("failed to get onboarding secret corresponding to storageconsumer %s: %v", storageConsumer.Name, err)
+		return nil, status.Errorf(codes.Internal, "failed to get onboarding secret. %v", err)
+	}
+	if req.OnboardingTicket != string(onboardingSecret.Data[defaults.OnboardingTokenKey]) {
+		klog.Errorf("supplied onboarding ticket does not match storageconsumer secret")
+		return nil, status.Errorf(codes.InvalidArgument, "supplied onboarding ticket does not match mapped secret")
 	}
 
+	storageConsumerUUID, err := s.consumerManager.EnableStorageConsumer(ctx, storageConsumer)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to onboard on storageConsumer resource. %v", err)
+	}
 	return &pb.OnboardConsumerResponse{StorageConsumerUUID: storageConsumerUUID}, nil
 }
 
 // AcknowledgeOnboarding acknowledge the onboarding is complete
 func (s *OCSProviderServer) AcknowledgeOnboarding(ctx context.Context, req *pb.AcknowledgeOnboardingRequest) (*pb.AcknowledgeOnboardingResponse, error) {
-
-	if err := s.consumerManager.EnableStorageConsumer(ctx, req.StorageConsumerUUID); err != nil {
-		if kerrors.IsNotFound(err) {
-			return nil, status.Errorf(codes.NotFound, "storageConsumer not found. %v", err)
-		}
-		return nil, status.Errorf(codes.Internal, "Failed to update the storageConsumer. %v", err)
-	}
-	return &pb.AcknowledgeOnboardingResponse{}, nil
+	return nil, status.Errorf(codes.Unimplemented, "Not expecting a two step onboarding process")
 }
 
 // GetStorageConfig RPC call to onboard a new OCS consumer cluster.
@@ -203,8 +193,8 @@ func (s *OCSProviderServer) GetStorageConfig(ctx context.Context, req *pb.Storag
 
 	// Verify Status
 	switch consumerObj.Status.State {
-	case ocsv1alpha1.StorageConsumerStateDisabled:
-		return nil, status.Errorf(codes.FailedPrecondition, "storageConsumer is in disabled state")
+	case ocsv1alpha1.StorageConsumerStateNotEnabled:
+		return nil, status.Errorf(codes.FailedPrecondition, "storageConsumer is in not enabled")
 	case ocsv1alpha1.StorageConsumerStateFailed:
 		// TODO: get correct error message from the storageConsumer status
 		return nil, status.Errorf(codes.Internal, "storageConsumer status failed")
@@ -621,14 +611,7 @@ func decodeAndValidateTicket(ticket string, pubKey *rsa.PublicKey) (*services.On
 	}
 
 	switch ticketData.SubjectRole {
-	case services.ClientRole:
-		if ticketData.StorageQuotaInGiB != nil {
-			quota := *ticketData.StorageQuotaInGiB
-			if quota > math.MaxInt {
-				return nil, fmt.Errorf("invalid value sent in onboarding ticket, storage quota should be greater than 0 and less than %v: %v", math.MaxInt, quota)
-			}
-		}
-	case services.PeerRole:
+	case services.ClientRole, services.PeerRole:
 	default:
 		return nil, fmt.Errorf("invalid onboarding ticket subject role")
 	}
diff --git a/services/types.go b/services/types.go
index bde6f900f4..407445a5cf 100644
--- a/services/types.go
+++ b/services/types.go
@@ -10,9 +10,8 @@ const (
 )
 
 type OnboardingTicket struct {
-	ID                string                `json:"id"`
-	ExpirationDate    int64                 `json:"expirationDate,string"`
-	SubjectRole       OnboardingSubjectRole `json:"subjectRole"`
-	StorageQuotaInGiB *uint                 `json:"storageQuotaInGiB,omitempty"`
-	StorageCluster    types.UID             `json:"storageCluster"`
+	ID             string                `json:"id"`
+	ExpirationDate int64                 `json:"expirationDate,string"`
+	SubjectRole    OnboardingSubjectRole `json:"subjectRole"`
+	StorageCluster types.UID             `json:"storageCluster"`
 }
diff --git a/services/ux-backend/handlers/onboarding/clienttokens/handler.go b/services/ux-backend/handlers/onboarding/clienttokens/handler.go
deleted file mode 100644
index 3d32567239..0000000000
--- a/services/ux-backend/handlers/onboarding/clienttokens/handler.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package clienttokens
-
-import (
-	"encoding/json"
-	"fmt"
-	"math"
-	"net/http"
-
-	"github.com/red-hat-storage/ocs-operator/v4/controllers/util"
-	"github.com/red-hat-storage/ocs-operator/v4/services/ux-backend/handlers"
-
-	"k8s.io/klog/v2"
-	"k8s.io/utils/ptr"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-const (
-	onboardingPrivateKeyFilePath = "/etc/private-key/key"
-)
-
-var unitToGib = map[string]uint{
-	"Gi": 1,
-	"Ti": 1024,
-	"Pi": 1024 * 1024,
-}
-
-func HandleMessage(w http.ResponseWriter, r *http.Request, tokenLifetimeInHours int, cl client.Client, namespace string) {
-	switch r.Method {
-	case "POST":
-		handlePost(w, r, tokenLifetimeInHours, cl, namespace)
-	default:
-		handleUnsupportedMethod(w, r)
-	}
-}
-
-func handlePost(w http.ResponseWriter, r *http.Request, tokenLifetimeInHours int, cl client.Client, namespace string) {
-	var storageQuotaInGiB *uint
-	// When ContentLength is 0 that means request body is empty and
-	// storage quota is unlimited
-	var err error
-	if r.ContentLength != 0 {
-		var quota = struct {
-			Value uint   `json:"value"`
-			Unit  string `json:"unit"`
-		}{}
-		if err = json.NewDecoder(r.Body).Decode(&quota); err != nil {
-			http.Error(w, err.Error(), http.StatusBadRequest)
-			return
-		}
-
-		if quota.Value == 0 || quota.Value > math.MaxInt {
-			http.Error(w, fmt.Sprintf("invalid value sent in request body, value should be greater than 0 and less than %v: %v", math.MaxInt, quota.Value), http.StatusBadRequest)
-			return
-		}
-		unitAsGiB, ok := unitToGib[quota.Unit]
-		if !ok {
-			http.Error(w, fmt.Sprintf("invalid Unit type sent in request body, Valid types are [Gi,Ti,Pi]: %v", quota.Unit), http.StatusBadRequest)
-			return
-		}
-		storageQuotaInGiB = ptr.To(unitAsGiB * quota.Value)
-	}
-
-	storageCluster, err := util.GetStorageClusterInNamespace(r.Context(), cl, namespace)
-	if err != nil {
-		http.Error(w, err.Error(), http.StatusInternalServerError)
-		return
-	}
-
-	if onboardingToken, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, storageQuotaInGiB, storageCluster.UID); err != nil {
-		klog.Errorf("failed to get onboarding token: %v", err)
-		w.WriteHeader(http.StatusInternalServerError)
-		w.Header().Set("Content-Type", handlers.ContentTypeTextPlain)
-
-		if _, err := w.Write([]byte("Failed to generate token")); err != nil {
-			klog.Errorf("failed write data to response writer, %v", err)
-		}
-	} else {
-		klog.Info("onboarding token generated successfully")
-		w.WriteHeader(http.StatusOK)
-		w.Header().Set("Content-Type", handlers.ContentTypeTextPlain)
-
-		if _, err = w.Write([]byte(onboardingToken)); err != nil {
-			klog.Errorf("failed write data to response writer: %v", err)
-		}
-	}
-
-}
-
-func handleUnsupportedMethod(w http.ResponseWriter, r *http.Request) {
-	klog.Infof("Only POST method should be used to send data to this endpoint %s", r.URL.Path)
-	w.WriteHeader(http.StatusMethodNotAllowed)
-	w.Header().Set("Content-Type", handlers.ContentTypeTextPlain)
-	w.Header().Set("Allow", "POST")
-
-	if _, err := w.Write([]byte(fmt.Sprintf("Unsupported method : %s", r.Method))); err != nil {
-		klog.Errorf("failed write data to response writer: %v", err)
-	}
-}
diff --git a/services/ux-backend/main.go b/services/ux-backend/main.go
index 43c64d5973..a80dcba5a8 100644
--- a/services/ux-backend/main.go
+++ b/services/ux-backend/main.go
@@ -10,7 +10,6 @@ import (
 	ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
 	"github.com/red-hat-storage/ocs-operator/v4/controllers/util"
 	"github.com/red-hat-storage/ocs-operator/v4/services/ux-backend/handlers/expandstorage"
-	"github.com/red-hat-storage/ocs-operator/v4/services/ux-backend/handlers/onboarding/clienttokens"
 	"github.com/red-hat-storage/ocs-operator/v4/services/ux-backend/handlers/onboarding/peertokens"
 	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
 	storagev1 "k8s.io/api/storage/v1"
@@ -26,35 +25,21 @@ type serverConfig struct {
 	tlsEnabled           bool
 }
 
-func readEnvVar[T any](envVarName string, defaultValue T, parser func(str string) (T, error)) (T, error) {
-	str := os.Getenv(envVarName)
-	if str == "" {
-		klog.Infof("no user-defined %s provided, defaulting to %v", envVarName, defaultValue)
-		return defaultValue, nil
-	}
-
-	value, err := parser(str)
-	if err != nil {
-		return *new(T), fmt.Errorf("malformed user-defined %s value %s: %v", envVarName, str, err)
-	}
-	return value, nil
-}
-
 func loadAndValidateServerConfig() (*serverConfig, error) {
 	var config serverConfig
 	var err error
 
-	config.tokenLifetimeInHours, err = readEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
+	config.tokenLifetimeInHours, err = util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
 	if err != nil {
 		return nil, err
 	}
 
-	config.listenPort, err = readEnvVar("UX_BACKEND_PORT", 8080, strconv.Atoi)
+	config.listenPort, err = util.ReadEnvVar("UX_BACKEND_PORT", 8080, strconv.Atoi)
 	if err != nil {
 		return nil, err
 	}
 
-	config.tlsEnabled, err = readEnvVar("TLS_ENABLED", false, strconv.ParseBool)
+	config.tlsEnabled, err = util.ReadEnvVar("TLS_ENABLED", false, strconv.ParseBool)
 	if err != nil {
 		return nil, err
 	}
@@ -94,16 +79,6 @@ func main() {
 		klog.Exitf("failed to create kube client: %v", err)
 	}
 
-	// TODO: remove '/onboarding-tokens' in the future
-	http.HandleFunc("/onboarding-tokens", func(w http.ResponseWriter, r *http.Request) {
-		// Set the Deprecation header
-		w.Header().Set("Deprecation", "true") // Standard "Deprecation" header
-		w.Header().Set("Link", "/onboarding/client-tokens; rel=\"alternate\"")
-		clienttokens.HandleMessage(w, r, config.tokenLifetimeInHours, cl, namespace)
-	})
-	http.HandleFunc("/onboarding/client-tokens", func(w http.ResponseWriter, r *http.Request) {
-		clienttokens.HandleMessage(w, r, config.tokenLifetimeInHours, cl, namespace)
-	})
 	http.HandleFunc("/onboarding/peer-tokens", func(w http.ResponseWriter, r *http.Request) {
 		peertokens.HandleMessage(w, r, config.tokenLifetimeInHours, cl, namespace)
 	})
diff --git a/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go b/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go
index a9bac6f014..39d41facc9 100644
--- a/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go
+++ b/vendor/github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1/storageconsumer_types.go
@@ -33,8 +33,8 @@ const (
 	StorageConsumerStateDeleting StorageConsumerState = "Deleting"
 	// StorageConsumerStateFailed represents Failed state of StorageConsumer
 	StorageConsumerStateFailed StorageConsumerState = "Failed"
-	// StorageConsumerStateDisabled represents Disabled state of StorageConsumer
-	StorageConsumerStateDisabled StorageConsumerState = "Disabled"
+	// StorageConsumerStateNotEnabled represents NotEnabled state of StorageConsumer
+	StorageConsumerStateNotEnabled StorageConsumerState = "NotEnabled"
 )
 
 // StorageConsumerSpec defines the desired state of StorageConsumer


Reviews:
user: login: rewantsoni
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-12T06:07:32Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T07:17:28Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T07:18:19Z
user: login: rewantsoni
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-20T09:06:34Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T09:39:57Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T09:41:35Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T09:42:02Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T09:53:42Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T09:54:22Z
user: login: rewantsoni
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T09:55:29Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T09:58:17Z
user: login: rewantsoni
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T10:02:35Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T07:53:49Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T07:54:37Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T10:37:12Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T10:37:23Z
user: login: rewantsoni
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-21T11:09:47Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T07:22:02Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T07:22:42Z
user: login: nb-ohad
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T12:43:50Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T06:11:03Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T07:52:23Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:54:19Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:54:44Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:54:58Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:55:16Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:55:24Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:55:34Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:55:39Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:55:50Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:55:57Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T08:56:07Z
user: login: nb-ohad
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:15:21Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:26:53Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:27:26Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:31:36Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:33:03Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:34:43Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:39:00Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:40:01Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:42:22Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:43:06Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:44:19Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:46:50Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:47:18Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:48:50Z
user: login: nb-ohad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:53:13Z
user: login: nb-ohad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:54:35Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:56:21Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:32:07Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:32:26Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:35:18Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:21:16Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:21:25Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:21:35Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:21:44Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:21:51Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:22:13Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:22:20Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:22:23Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:22:42Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:03Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:12Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:21Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:27Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:33Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:38Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:44Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:50Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:23:59Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T05:24:00Z
user: login: nb-ohad
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T14:36:21Z
user: login: nb-ohad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T14:46:06Z
user: login: nb-ohad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T14:48:39Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T15:04:30Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T15:20:46Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T15:20:51Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T15:21:02Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T15:21:07Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T15:21:13Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T15:21:18Z
user: login: nb-ohad
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:30:06Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:47:29Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:47:36Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:47:42Z
user: login: leelavg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:47:52Z

Review comments:
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
path: services/provider/server/server.go
user: login: rewantsoni
body: Instead of fetching each consumer, getting the secret attached and comparing the onboarding ticket in the secret, why not add the consumer name to the onboarding ticket struct?
created_at: 2025-03-12T06:01:49Z
author_association: MEMBER
diff_hunk: @@ -135,11 +139,50 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
 
+	secret := &corev1.Secret{}
+	secret.Name = r.storageConsumer.Name
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: rewantsoni
body: Should we add an annotation to storageConsumer that points to the onboarding ticket secret for that conusmer? 
created_at: 2025-03-12T06:03:42Z
author_association: MEMBER
diff_hunk: @@ -161,22 +188,17 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
+	storageConsumerUUID, err := s.consumerManager.OnboardClient(ctx, consumerName, req, int(storageQuotaInGiB))
 	if err != nil {
-		if !kerrors.IsAlreadyExists(err) && err != errTicketAlreadyExists {
-			return nil, status.Errorf(codes.Internal, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-
-		storageConsumer, err := s.consumerManager.GetByName(ctx, req.ConsumerName)
-		if err != nil {
-			return nil, status.Errorf(codes.Internal, "Failed to get storageConsumer. %v", err)
-		}
-
-		if storageConsumer.Spec.Enable {
-			err = fmt.Errorf("storageconsumers.ocs.openshift.io %s already exists", req.ConsumerName)
-			return nil, status.Errorf(codes.AlreadyExists, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-		storageConsumerUUID = string(storageConsumer.UID)
+		return nil, status.Errorf(codes.Internal, "failed to onboard on storageConsumer resource. %v", err)
+	}
+	storageConsumer, err := s.consumerManager.Get(ctx, storageConsumerUUID)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to get storageConsumer. %v", err)
+	}
+	if storageConsumer.Spec.Enable {
+		err = fmt.Errorf("storageconsumers.ocs.openshift.io %s already exists", storageConsumer.Name)
+		return nil, status.Errorf(codes.AlreadyExists, "failed to onboard on storageConsumer resources. %v", err)
path: services/provider/server/server.go
user: login: rewantsoni
body: Since we are not creating the consumer anymore in this rpc, could we update the err message to be something more meaningful like "storageconsumer already has a client attached to it"?
created_at: 2025-03-12T06:06:49Z
author_association: MEMBER
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
path: services/provider/server/server.go
user: login: leelavg
body: we could do that after a small discussion as it implies the token will be applicable only to the specific storageconsumer.
created_at: 2025-03-12T07:17:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,11 +139,50 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
 
+	secret := &corev1.Secret{}
+	secret.Name = r.storageConsumer.Name
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: the intention was to have the same name for consumer & secret, didn't get your suggestion.
created_at: 2025-03-12T07:18:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -39,18 +41,23 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/handler"
 	"sigs.k8s.io/controller-runtime/pkg/predicate"
 
+	"github.com/google/uuid"
 	nbv1 "github.com/noobaa/noobaa-operator/v5/pkg/apis/noobaa/v1alpha1"
 	ocsv1alpha1 "github.com/red-hat-storage/ocs-operator/api/v4/v1alpha1"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 )
 
 const (
+	tokenLifetimeInHours          = 48
+	onboardingPrivateKeyFilePath  = "/etc/private-key/key"
 	StorageConsumerAnnotation     = "ocs.openshift.io.storageconsumer"
 	StorageRequestAnnotation      = "ocs.openshift.io.storagerequest"
 	StorageCephUserTypeAnnotation = "ocs.openshift.io.cephusertype"
 	StorageProfileLabel           = "ocs.openshift.io/storageprofile"
 	ConsumerUUIDLabel             = "ocs.openshift.io/storageconsumer-uuid"
 	StorageConsumerNameLabel      = "ocs.openshift.io/storageconsumer-name"
+	ownerIndexName                = "index:ownerUID"
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: rewantsoni
body: We can reuse this from util package
created_at: 2025-03-20T08:43:02Z
author_association: MEMBER
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		secret := &corev1.Secret{}
+		secret.Name = consumer.Name
+		secret.Namespace = s.namespace
+		if err := s.client.Get(ctx, client.ObjectKeyFromObject(secret), secret); client.IgnoreNotFound(err) != nil {
+			klog.Errorf("failed to list secrets in the namespace. %v", err)
path: services/provider/server/server.go
user: login: rewantsoni
body: ```suggestion
			klog.Errorf("failed to get secret %s in the namespace. %v", secretname, err)
```
created_at: 2025-03-20T08:49:56Z
author_association: MEMBER
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		secret := &corev1.Secret{}
+		secret.Name = consumer.Name
path: services/provider/server/server.go
user: login: rewantsoni
body: If the name of the secret is different it will fail, which can happen in case the we have the name specified in the spec
created_at: 2025-03-20T08:52:08Z
author_association: MEMBER
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		secret := &corev1.Secret{}
+		secret.Name = consumer.Name
+		secret.Namespace = s.namespace
+		if err := s.client.Get(ctx, client.ObjectKeyFromObject(secret), secret); client.IgnoreNotFound(err) != nil {
+			klog.Errorf("failed to list secrets in the namespace. %v", err)
+			return nil, status.Errorf(codes.Internal, "failed to list secrets in the namespace. %v", err)
path: services/provider/server/server.go
user: login: rewantsoni
body: ```suggestion
			return nil, status.Errorf(codes.Internal, "failed to get secret in the namespace. %v", err)
```
created_at: 2025-03-20T08:52:27Z
author_association: MEMBER
diff_hunk: @@ -161,37 +188,24 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
+	storageConsumerUUID, err := s.consumerManager.OnboardClient(ctx, consumerName, req, int(storageQuotaInGiB), onboardingTicket.ID)
 	if err != nil {
-		if !kerrors.IsAlreadyExists(err) && err != errTicketAlreadyExists {
-			return nil, status.Errorf(codes.Internal, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-
-		storageConsumer, err := s.consumerManager.GetByName(ctx, req.ConsumerName)
-		if err != nil {
-			return nil, status.Errorf(codes.Internal, "Failed to get storageConsumer. %v", err)
-		}
-
-		if storageConsumer.Spec.Enable {
-			err = fmt.Errorf("storageconsumers.ocs.openshift.io %s already exists", req.ConsumerName)
-			return nil, status.Errorf(codes.AlreadyExists, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-		storageConsumerUUID = string(storageConsumer.UID)
+		return nil, status.Errorf(codes.Internal, "failed to onboard on storageConsumer resource. %v", err)
+	}
+	storageConsumer, err := s.consumerManager.Get(ctx, storageConsumerUUID)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to get storageConsumer. %v", err)
+	}
+	if storageConsumer.Spec.Enable {
path: services/provider/server/server.go
user: login: rewantsoni
body: You are setting enable to true inside the consumerManager.OnboardClient and are checking if it is enabled here 
created_at: 2025-03-20T08:57:08Z
author_association: MEMBER
diff_hunk: @@ -55,7 +55,7 @@ import (
 )
 
 const (
-	TicketAnnotation          = "ocs.openshift.io/provider-onboarding-ticket"
+	TicketAnnotation          = controllers.TicketAnnotation
path: services/provider/server/server.go
user: login: rewantsoni
body: Why are you not using controllers.TicketAnnotation directly?
created_at: 2025-03-20T09:01:51Z
author_association: MEMBER
diff_hunk: @@ -47,7 +48,13 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storagecluster.UID,
+				uuid.New().String(),
+			)
path: controllers/storagecluster/storageclient.go
user: login: rewantsoni
body: Reading the secret of the local Consumer for the token instead of generating it here will come in an upcoming PR?
created_at: 2025-03-20T09:04:53Z
author_association: MEMBER
diff_hunk: @@ -135,9 +142,71 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
 
+	secretList := &corev1.SecretList{}
+	if err := r.List(
+		r.ctx,
+		secretList,
+		client.MatchingFields{ownerIndexName: string(r.storageConsumer.UID)},
+		client.InNamespace(r.storageConsumer.Namespace),
+	); err != nil {
+		return reconcile.Result{}, err
+	} else if len(secretList.Items) > 1 {
+		return reconcile.Result{}, fmt.Errorf("expected 1 secret containing onboarding token for %s but found %d", r.storageConsumer.Name, len(secretList.Items))
+	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: rewantsoni
body: Since we already know the secret name why not get the secret directly instead of listing it?
created_at: 2025-03-20T09:06:29Z
author_association: MEMBER
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		secret := &corev1.Secret{}
+		secret.Name = consumer.Name
path: services/provider/server/server.go
user: login: leelavg
body: > name specified in the spec
- not atm and not sure we want even that should be configurable 🤔 
created_at: 2025-03-20T09:39:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -161,37 +188,24 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
+	storageConsumerUUID, err := s.consumerManager.OnboardClient(ctx, consumerName, req, int(storageQuotaInGiB), onboardingTicket.ID)
 	if err != nil {
-		if !kerrors.IsAlreadyExists(err) && err != errTicketAlreadyExists {
-			return nil, status.Errorf(codes.Internal, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-
-		storageConsumer, err := s.consumerManager.GetByName(ctx, req.ConsumerName)
-		if err != nil {
-			return nil, status.Errorf(codes.Internal, "Failed to get storageConsumer. %v", err)
-		}
-
-		if storageConsumer.Spec.Enable {
-			err = fmt.Errorf("storageconsumers.ocs.openshift.io %s already exists", req.ConsumerName)
-			return nil, status.Errorf(codes.AlreadyExists, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-		storageConsumerUUID = string(storageConsumer.UID)
+		return nil, status.Errorf(codes.Internal, "failed to onboard on storageConsumer resource. %v", err)
+	}
+	storageConsumer, err := s.consumerManager.Get(ctx, storageConsumerUUID)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to get storageConsumer. %v", err)
+	}
+	if storageConsumer.Spec.Enable {
path: services/provider/server/server.go
user: login: leelavg
body: ah, missed it, my intention was to club err and also check for enable.
created_at: 2025-03-20T09:41:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -55,7 +55,7 @@ import (
 )
 
 const (
-	TicketAnnotation          = "ocs.openshift.io/provider-onboarding-ticket"
+	TicketAnnotation          = controllers.TicketAnnotation
path: services/provider/server/server.go
user: login: leelavg
body: atm, to reduce the changes.
created_at: 2025-03-20T09:42:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,7 +48,13 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storagecluster.UID,
+				uuid.New().String(),
+			)
path: controllers/storagecluster/storageclient.go
user: login: leelavg
body: yes.
created_at: 2025-03-20T09:53:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,9 +142,71 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
 
+	secretList := &corev1.SecretList{}
+	if err := r.List(
+		r.ctx,
+		secretList,
+		client.MatchingFields{ownerIndexName: string(r.storageConsumer.UID)},
+		client.InNamespace(r.storageConsumer.Namespace),
+	); err != nil {
+		return reconcile.Result{}, err
+	} else if len(secretList.Items) > 1 {
+		return reconcile.Result{}, fmt.Errorf("expected 1 secret containing onboarding token for %s but found %d", r.storageConsumer.Name, len(secretList.Items))
+	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: we don't want to tie ourselves with the name and so going via ownerrefs.
created_at: 2025-03-20T09:54:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		secret := &corev1.Secret{}
+		secret.Name = consumer.Name
path: services/provider/server/server.go
user: login: rewantsoni
body: consumer spec, the name of the secret that has all the resources can be different from the consumer name. We should get the secret name from either the status or have a check if the secret name under spec is specified use that
created_at: 2025-03-20T09:55:29Z
author_association: MEMBER
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		secret := &corev1.Secret{}
+		secret.Name = consumer.Name
path: services/provider/server/server.go
user: login: leelavg
body: > from either the status
- we aren't mentioning the secret anywhere as per older discussions
created_at: 2025-03-20T09:58:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		secret := &corev1.Secret{}
+		secret.Name = consumer.Name
path: services/provider/server/server.go
user: login: rewantsoni
body: ack, got confused for a bit can resolve now
created_at: 2025-03-20T10:02:35Z
author_association: MEMBER
diff_hunk: @@ -135,6 +135,33 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.Internal, "failed to get public key to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 	}
 
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
path: services/provider/server/server.go
user: login: leelavg
body: changed to use an id tying storageconsumer with token.
created_at: 2025-03-21T07:53:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,11 +139,50 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
 
+	secret := &corev1.Secret{}
+	secret.Name = r.storageConsumer.Name
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: changed to have predictable naming.
created_at: 2025-03-21T07:54:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,9 +142,71 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
 
+	secretList := &corev1.SecretList{}
+	if err := r.List(
+		r.ctx,
+		secretList,
+		client.MatchingFields{ownerIndexName: string(r.storageConsumer.UID)},
+		client.InNamespace(r.storageConsumer.Namespace),
+	); err != nil {
+		return reconcile.Result{}, err
+	} else if len(secretList.Items) > 1 {
+		return reconcile.Result{}, fmt.Errorf("expected 1 secret containing onboarding token for %s but found %d", r.storageConsumer.Name, len(secretList.Items))
+	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-21T10:37:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -161,37 +188,24 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
+	storageConsumerUUID, err := s.consumerManager.OnboardClient(ctx, consumerName, req, int(storageQuotaInGiB), onboardingTicket.ID)
 	if err != nil {
-		if !kerrors.IsAlreadyExists(err) && err != errTicketAlreadyExists {
-			return nil, status.Errorf(codes.Internal, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-
-		storageConsumer, err := s.consumerManager.GetByName(ctx, req.ConsumerName)
-		if err != nil {
-			return nil, status.Errorf(codes.Internal, "Failed to get storageConsumer. %v", err)
-		}
-
-		if storageConsumer.Spec.Enable {
-			err = fmt.Errorf("storageconsumers.ocs.openshift.io %s already exists", req.ConsumerName)
-			return nil, status.Errorf(codes.AlreadyExists, "failed to create storageConsumer %q. %v", req.ConsumerName, err)
-		}
-		storageConsumerUUID = string(storageConsumer.UID)
+		return nil, status.Errorf(codes.Internal, "failed to onboard on storageConsumer resource. %v", err)
+	}
+	storageConsumer, err := s.consumerManager.Get(ctx, storageConsumerUUID)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to get storageConsumer. %v", err)
+	}
+	if storageConsumer.Spec.Enable {
path: services/provider/server/server.go
user: login: leelavg
body: removed.
created_at: 2025-03-21T10:37:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -134,10 +140,8 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
-	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+	if err := r.reconcileOnboardingSecret(); err != nil {
+		return reconcile.Result{}, err
 	}
 
 	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: rewantsoni
body: We should not reconcile the other resources if consumer is not enabled
created_at: 2025-03-21T11:05:17Z
author_association: MEMBER
diff_hunk: @@ -220,6 +290,11 @@ func (r *StorageConsumerReconciler) own(resource metav1.Object) error {
 
 // SetupWithManager sets up the controller with the Manager.
 func (r *StorageConsumerReconciler) SetupWithManager(mgr ctrl.Manager) error {
+	ctx := context.Background()
+	if err := mgr.GetCache().IndexField(ctx, &corev1.Secret{}, util.OwnerUIDIndexName, util.OwnersIndexFieldFunc); err != nil {
+		return fmt.Errorf("unable to set up FieldIndexer for Secret's owner uid: %v", err)
+	}
+
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: rewantsoni
body: We are not listing based on the ownerIndex do we need this?
created_at: 2025-03-21T11:07:40Z
author_association: MEMBER
diff_hunk: @@ -134,10 +140,8 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
-	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+	if err := r.reconcileOnboardingSecret(); err != nil {
+		return reconcile.Result{}, err
 	}
 
 	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-24T07:22:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -220,6 +290,11 @@ func (r *StorageConsumerReconciler) own(resource metav1.Object) error {
 
 // SetupWithManager sets up the controller with the Manager.
 func (r *StorageConsumerReconciler) SetupWithManager(mgr ctrl.Manager) error {
+	ctx := context.Background()
+	if err := mgr.GetCache().IndexField(ctx, &corev1.Secret{}, util.OwnerUIDIndexName, util.OwnersIndexFieldFunc); err != nil {
+		return fmt.Errorf("unable to set up FieldIndexer for Secret's owner uid: %v", err)
+	}
+
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done, but didn't change the rename of index in other file as it is good to prefix fields w/ some string, here `index:...`
created_at: 2025-03-24T07:22:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -134,6 +140,9 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
+	if err := r.reconcileOnboardingSecret(); err != nil {
+		return reconcile.Result{}, err
+	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: I would expect to see a clear separation between
`reconcileEnabledPhases` and `reconcileNonEnabledPhases`
created_at: 2025-03-24T12:27:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: This decision should happen outside of this function.
The entire reconcile flow need to be separated into 2 cases, Enabled vs Not-Enabled. 
This is important, if not you will find yourself adding an `if Enabled` and `if !Enabled` all across the reconcile function. 
created_at: 2025-03-24T12:28:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,8 +52,8 @@ const (
 	EnableCephfsKey             = "ROOK_CSI_ENABLE_CEPHFS"
 
 	// This is the name for the FieldIndex
-	OwnerUIDIndexName   = "ownerUID"
-	AnnotationIndexName = "annotation"
+	OwnerUIDIndexName   = "index:ownerUID"
+	AnnotationIndexName = "index:annotation"
path: controllers/util/k8sutil.go
user: login: nb-ohad
body: is there a reason for this change? it this meant to align us with some best practice or a convention we have in our codebases? 
created_at: 2025-03-24T12:29:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -22,13 +22,13 @@ import (
 // GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
 // The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
 // The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID, salt string) (string, error) {
 	tokenExpirationDate := time.Now().
 		Add(time.Duration(tokenLifetimeInHours) * time.Hour).
 		Unix()
 
 	ticket := services.OnboardingTicket{
-		ID:                uuid.New().String(),
+		ID:                salt,
path: controllers/util/provider.go
user: login: nb-ohad
body: Can you please explain how this make any sense?
created_at: 2025-03-24T12:30:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
+		// if not enabled, ensure secret presence
+		if secret.UID == "" {
+			if err := r.own(secret); err != nil {
+				return err
+			}
+			storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+			if err != nil {
+				return err
+			}
+			salt := uuid.New().String()
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storageCluster.UID,
+				salt,
+			)
+			if err != nil {
+				return err
+			}
+			secret.Data = map[string][]byte{
+				"ticket": []byte(token),
+			}
+			util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(tokenLifetimeInHours*time.Hour).UTC().String())
+			// as salt is random we are annotating it on secret as well to read later if we fail to annotate consumer in current reconcile
+			util.AddAnnotation(secret, TicketAnnotation, salt)
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: Bad strategy, if the intent of salt is to be an identifier and not a just random junk, you need to be able to consistently reproduce it.  Please reuse something that already exists or use a conversion of something that already exists. 


Suggestion: A fixed length hash of the (clusterd + storage cluster name) 
created_at: 2025-03-24T12:35:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
+		// if not enabled, ensure secret presence
+		if secret.UID == "" {
+			if err := r.own(secret); err != nil {
+				return err
+			}
+			storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+			if err != nil {
+				return err
+			}
+			salt := uuid.New().String()
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storageCluster.UID,
+				salt,
+			)
+			if err != nil {
+				return err
+			}
+			secret.Data = map[string][]byte{
+				"ticket": []byte(token),
+			}
+			util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(tokenLifetimeInHours*time.Hour).UTC().String())
+			// as salt is random we are annotating it on secret as well to read later if we fail to annotate consumer in current reconcile
+			util.AddAnnotation(secret, TicketAnnotation, salt)
+			r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+			if err := r.Create(r.ctx, secret); err != nil {
+				return err
+			}
+			// annotating on consumer helps us validate the identity during onboard
+			util.AddAnnotation(r.storageConsumer, TicketAnnotation, salt)
+			if err := r.Update(r.ctx, r.storageConsumer); err != nil {
+				return fmt.Errorf("failed to add ticket reference to storageconsumer %s: %v", r.storageConsumer.Name, err)
+			}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: If you have a way to recognize either the secret or the consumer, you should have a way to get from one to another without the need for special annotation
created_at: 2025-03-24T12:37:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: What about the case where the secret exists but the key does not?
created_at: 2025-03-24T12:38:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
+		// if not enabled, ensure secret presence
+		if secret.UID == "" {
+			if err := r.own(secret); err != nil {
+				return err
+			}
+			storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+			if err != nil {
+				return err
+			}
+			salt := uuid.New().String()
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storageCluster.UID,
+				salt,
+			)
+			if err != nil {
+				return err
+			}
+			secret.Data = map[string][]byte{
+				"ticket": []byte(token),
+			}
+			util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(tokenLifetimeInHours*time.Hour).UTC().String())
+			// as salt is random we are annotating it on secret as well to read later if we fail to annotate consumer in current reconcile
+			util.AddAnnotation(secret, TicketAnnotation, salt)
+			r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+			if err := r.Create(r.ctx, secret); err != nil {
+				return err
+			}
+			// annotating on consumer helps us validate the identity during onboard
+			util.AddAnnotation(r.storageConsumer, TicketAnnotation, salt)
+			if err := r.Update(r.ctx, r.storageConsumer); err != nil {
+				return fmt.Errorf("failed to add ticket reference to storageconsumer %s: %v", r.storageConsumer.Name, err)
+			}
+		} else if r.storageConsumer.GetAnnotations()[TicketAnnotation] == "" {
+			// annotation ought to exist on the secret as we place it during creation which is resistant against cache latency
+			util.AddAnnotation(r.storageConsumer, TicketAnnotation, secret.GetAnnotations()[TicketAnnotation])
+			if err := r.Update(r.ctx, r.storageConsumer); err != nil {
+				return fmt.Errorf("failed to add ticket reference to storageconsumer %s: %v", r.storageConsumer.Name, err)
+			}
+		}
+		r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+			Name: secret.Name,
+		}
+		return nil
+	} else if secret.UID != "" {
+		// if enabled, ensure secret absence
+		r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{}
+		if err := r.Delete(r.ctx, secret); client.IgnoreNotFound(err) != nil {
+			return err
+		}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: This need to move to the `EnabledReconsilePhases`?
created_at: 2025-03-24T12:39:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,16 +16,12 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-var (
-	errTicketAlreadyExists = errors.New("onboarding ticket already used by another storageConsumer")
-)
-
 type ocsConsumerManager struct {
-	client       client.Client
-	namespace    string
-	nameByTicket map[string]string
-	nameByUID    map[types.UID]string
-	mutex        sync.RWMutex
+	client         client.Client
+	namespace      string
+	nameByTicketID map[string]string
path: services/provider/server/consumer.go
user: login: nb-ohad
body: Is there really a need for this map to exists after all of the changes? We had a need because we didn't had the consumer up and running yet
created_at: 2025-03-24T12:41:23Z
author_association: CONTRIBUTOR
path: services/provider/server/consumer.go
user: login: nb-ohad
body: I believe most the changes to this code are not aligned with agreed design. Let's revisit the changes here after we complete the review
created_at: 2025-03-24T12:42:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -140,6 +140,28 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		klog.Errorf("failed to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket is not valid. %v", err)
 	}
+
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		if consumer.GetAnnotations()[TicketAnnotation] == onboardingTicket.ID {
+			consumerName = consumer.Name
+			break
+		}
+	}
+	if consumerName == "" {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageConsumer found for supplied onboarding ticket")
+	}
path: services/provider/server/server.go
user: login: nb-ohad
body: If you have the ticket, you shouldn't need to list consumers or secrets. 
created_at: 2025-03-24T12:43:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -66,7 +67,13 @@ func handlePost(w http.ResponseWriter, r *http.Request, tokenLifetimeInHours int
 		return
 	}
 
-	if onboardingToken, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, storageQuotaInGiB, storageCluster.UID); err != nil {
+	if onboardingToken, err := util.GenerateClientOnboardingToken(
+		tokenLifetimeInHours,
+		onboardingPrivateKeyFilePath,
+		storageQuotaInGiB,
+		storageCluster.UID,
+		uuid.New().String(),
path: services/ux-backend/handlers/onboarding/clienttokens/handler.go
user: login: nb-ohad
body: Why is this still existing?
created_at: 2025-03-24T12:43:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,8 +52,8 @@ const (
 	EnableCephfsKey             = "ROOK_CSI_ENABLE_CEPHFS"
 
 	// This is the name for the FieldIndex
-	OwnerUIDIndexName   = "ownerUID"
-	AnnotationIndexName = "annotation"
+	OwnerUIDIndexName   = "index:ownerUID"
+	AnnotationIndexName = "index:annotation"
path: controllers/util/k8sutil.go
user: login: leelavg
body: > convention we have in our codebases
- yes, we were prefixing the index to differentiate them with any field path while setting the indexer.
created_at: 2025-03-25T06:11:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: that's an outside involvement and user needs to delete the secret to regenerate it.
created_at: 2025-03-25T07:52:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -134,6 +140,9 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
+	if err := r.reconcileOnboardingSecret(); err != nil {
+		return reconcile.Result{}, err
+	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: only did partially for upcoming changes (moving from storagerequest to storageclient) to rearrange the reconcile steps.

a doubt, how to handle b/n storageconsumer existence & deletion w/ enable & notenable then?
```
if enable {
 if time-stamp-not-zero { ... }
 else { ... }
} else {
 if time-stamp-not-zero { ... }
 else { ... }
}
```
created_at: 2025-03-25T08:54:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: moved this to outside of the step.
created_at: 2025-03-25T08:54:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -22,13 +22,13 @@ import (
 // GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
 // The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
 // The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID, salt string) (string, error) {
 	tokenExpirationDate := time.Now().
 		Add(time.Duration(tokenLifetimeInHours) * time.Hour).
 		Unix()
 
 	ticket := services.OnboardingTicket{
-		ID:                uuid.New().String(),
+		ID:                salt,
path: controllers/util/provider.go
user: login: leelavg
body: named the var correctly.
created_at: 2025-03-25T08:54:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
+		// if not enabled, ensure secret presence
+		if secret.UID == "" {
+			if err := r.own(secret); err != nil {
+				return err
+			}
+			storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+			if err != nil {
+				return err
+			}
+			salt := uuid.New().String()
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storageCluster.UID,
+				salt,
+			)
+			if err != nil {
+				return err
+			}
+			secret.Data = map[string][]byte{
+				"ticket": []byte(token),
+			}
+			util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(tokenLifetimeInHours*time.Hour).UTC().String())
+			// as salt is random we are annotating it on secret as well to read later if we fail to annotate consumer in current reconcile
+			util.AddAnnotation(secret, TicketAnnotation, salt)
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: using storageconsumer name directly as the identifier.
created_at: 2025-03-25T08:55:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
+		// if not enabled, ensure secret presence
+		if secret.UID == "" {
+			if err := r.own(secret); err != nil {
+				return err
+			}
+			storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+			if err != nil {
+				return err
+			}
+			salt := uuid.New().String()
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storageCluster.UID,
+				salt,
+			)
+			if err != nil {
+				return err
+			}
+			secret.Data = map[string][]byte{
+				"ticket": []byte(token),
+			}
+			util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(tokenLifetimeInHours*time.Hour).UTC().String())
+			// as salt is random we are annotating it on secret as well to read later if we fail to annotate consumer in current reconcile
+			util.AddAnnotation(secret, TicketAnnotation, salt)
+			r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+			if err := r.Create(r.ctx, secret); err != nil {
+				return err
+			}
+			// annotating on consumer helps us validate the identity during onboard
+			util.AddAnnotation(r.storageConsumer, TicketAnnotation, salt)
+			if err := r.Update(r.ctx, r.storageConsumer); err != nil {
+				return fmt.Errorf("failed to add ticket reference to storageconsumer %s: %v", r.storageConsumer.Name, err)
+			}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: ack, done.
created_at: 2025-03-25T08:55:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +183,71 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) reconcileOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	}
+
+	if !r.storageConsumer.Spec.Enable {
+		// if not enabled, ensure secret presence
+		if secret.UID == "" {
+			if err := r.own(secret); err != nil {
+				return err
+			}
+			storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+			if err != nil {
+				return err
+			}
+			salt := uuid.New().String()
+			token, err := util.GenerateClientOnboardingToken(
+				tokenLifetimeInHours,
+				onboardingPrivateKeyFilePath,
+				nil,
+				storageCluster.UID,
+				salt,
+			)
+			if err != nil {
+				return err
+			}
+			secret.Data = map[string][]byte{
+				"ticket": []byte(token),
+			}
+			util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(tokenLifetimeInHours*time.Hour).UTC().String())
+			// as salt is random we are annotating it on secret as well to read later if we fail to annotate consumer in current reconcile
+			util.AddAnnotation(secret, TicketAnnotation, salt)
+			r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+			if err := r.Create(r.ctx, secret); err != nil {
+				return err
+			}
+			// annotating on consumer helps us validate the identity during onboard
+			util.AddAnnotation(r.storageConsumer, TicketAnnotation, salt)
+			if err := r.Update(r.ctx, r.storageConsumer); err != nil {
+				return fmt.Errorf("failed to add ticket reference to storageconsumer %s: %v", r.storageConsumer.Name, err)
+			}
+		} else if r.storageConsumer.GetAnnotations()[TicketAnnotation] == "" {
+			// annotation ought to exist on the secret as we place it during creation which is resistant against cache latency
+			util.AddAnnotation(r.storageConsumer, TicketAnnotation, secret.GetAnnotations()[TicketAnnotation])
+			if err := r.Update(r.ctx, r.storageConsumer); err != nil {
+				return fmt.Errorf("failed to add ticket reference to storageconsumer %s: %v", r.storageConsumer.Name, err)
+			}
+		}
+		r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+			Name: secret.Name,
+		}
+		return nil
+	} else if secret.UID != "" {
+		// if enabled, ensure secret absence
+		r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{}
+		if err := r.Delete(r.ctx, secret); client.IgnoreNotFound(err) != nil {
+			return err
+		}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: moved.
created_at: 2025-03-25T08:55:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,16 +16,12 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-var (
-	errTicketAlreadyExists = errors.New("onboarding ticket already used by another storageConsumer")
-)
-
 type ocsConsumerManager struct {
-	client       client.Client
-	namespace    string
-	nameByTicket map[string]string
-	nameByUID    map[types.UID]string
-	mutex        sync.RWMutex
+	client         client.Client
+	namespace      string
+	nameByTicketID map[string]string
path: services/provider/server/consumer.go
user: login: leelavg
body: removed.
created_at: 2025-03-25T08:55:39Z
author_association: CONTRIBUTOR
path: services/provider/server/consumer.go
user: login: leelavg
body: made changes.
created_at: 2025-03-25T08:55:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -140,6 +140,28 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		klog.Errorf("failed to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket is not valid. %v", err)
 	}
+
+	// get the consumer corresponding to this ticket
+	storageConsumerList := &ocsv1alpha1.StorageConsumerList{}
+	if err := s.client.List(ctx, storageConsumerList, client.InNamespace(s.namespace)); err != nil {
+		klog.Errorf("failed to get storageconsumers in the namespace: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumers. %v", err)
+	} else if len(storageConsumerList.Items) < 1 {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageconsumers exist in the namespace")
+	}
+
+	consumerName := ""
+	for idx := range storageConsumerList.Items {
+		consumer := &storageConsumerList.Items[idx]
+		if consumer.GetAnnotations()[TicketAnnotation] == onboardingTicket.ID {
+			consumerName = consumer.Name
+			break
+		}
+	}
+	if consumerName == "" {
+		return nil, status.Errorf(codes.FailedPrecondition, "no storageConsumer found for supplied onboarding ticket")
+	}
path: services/provider/server/server.go
user: login: leelavg
body: ack, done.
created_at: 2025-03-25T08:55:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -66,7 +67,13 @@ func handlePost(w http.ResponseWriter, r *http.Request, tokenLifetimeInHours int
 		return
 	}
 
-	if onboardingToken, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, storageQuotaInGiB, storageCluster.UID); err != nil {
+	if onboardingToken, err := util.GenerateClientOnboardingToken(
+		tokenLifetimeInHours,
+		onboardingPrivateKeyFilePath,
+		storageQuotaInGiB,
+		storageCluster.UID,
+		uuid.New().String(),
path: services/ux-backend/handlers/onboarding/clienttokens/handler.go
user: login: leelavg
body: ack, removed.
created_at: 2025-03-25T08:56:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
-			if err != nil {
-				return fmt.Errorf("unable to generate onboarding token: %v", err)
+			localStorageConsumer := &ocsv1a1.StorageConsumer{}
+			localStorageConsumer.Name = localStorageConsumerName
+			localStorageConsumer.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(localStorageConsumer), localStorageConsumer); err != nil {
+				return fmt.Errorf("failed to get storageconsumer %s: %v", localStorageConsumer.Name, err)
+			} else if localStorageConsumer.Status.OnboardingTicketSecret.Name == "" {
+				return fmt.Errorf("no reference to secret found in storageconsumer %s status", localStorageConsumer.Name)
path: controllers/storagecluster/storageclient.go
user: login: nb-ohad
body: ```suggestion
				return fmt.Errorf("no reference to onboarding secret found in storageconsumer %s status", localStorageConsumer.Name)
```
created_at: 2025-03-26T15:47:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
-			if err != nil {
-				return fmt.Errorf("unable to generate onboarding token: %v", err)
+			localStorageConsumer := &ocsv1a1.StorageConsumer{}
+			localStorageConsumer.Name = localStorageConsumerName
+			localStorageConsumer.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(localStorageConsumer), localStorageConsumer); err != nil {
+				return fmt.Errorf("failed to get storageconsumer %s: %v", localStorageConsumer.Name, err)
+			} else if localStorageConsumer.Status.OnboardingTicketSecret.Name == "" {
+				return fmt.Errorf("no reference to secret found in storageconsumer %s status", localStorageConsumer.Name)
+			}
+
+			onboardingTicketSecret := &corev1.Secret{}
+			onboardingTicketSecret.Name = localStorageConsumer.Status.OnboardingTicketSecret.Name
+			onboardingTicketSecret.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(onboardingTicketSecret), onboardingTicketSecret); err != nil {
+				return fmt.Errorf("failed to get onboarding ticket secret %s: %v", onboardingTicketSecret.Name, err)
path: controllers/storagecluster/storageclient.go
user: login: nb-ohad
body: ```suggestion
				return fmt.Errorf("failed to get onboarding secret %s: %v", onboardingTicketSecret.Name, err)
```
created_at: 2025-03-26T15:49:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
-			if err != nil {
-				return fmt.Errorf("unable to generate onboarding token: %v", err)
+			localStorageConsumer := &ocsv1a1.StorageConsumer{}
+			localStorageConsumer.Name = localStorageConsumerName
+			localStorageConsumer.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(localStorageConsumer), localStorageConsumer); err != nil {
+				return fmt.Errorf("failed to get storageconsumer %s: %v", localStorageConsumer.Name, err)
+			} else if localStorageConsumer.Status.OnboardingTicketSecret.Name == "" {
+				return fmt.Errorf("no reference to secret found in storageconsumer %s status", localStorageConsumer.Name)
+			}
+
+			onboardingTicketSecret := &corev1.Secret{}
+			onboardingTicketSecret.Name = localStorageConsumer.Status.OnboardingTicketSecret.Name
+			onboardingTicketSecret.Namespace = storagecluster.Namespace
path: controllers/storagecluster/storageclient.go
user: login: nb-ohad
body: ```suggestion
			onboardingSecret := &corev1.Secret{}
			onboardingSecret.Name = localStorageConsumer.Status.OnboardingTicketSecret.Name
			onboardingSecret.Namespace = storagecluster.Namespace
```
created_at: 2025-03-26T15:49:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
path: controllers/storagecluster/storageclient.go
user: login: nb-ohad
body: Are we expecting to see consumer creation code here in a future PR?
created_at: 2025-03-26T15:50:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -134,10 +138,13 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
 	if !r.storageConsumer.Spec.Enable {
 		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		return reconcile.Result{}, r.createOnboardingSecret()
+	} else {
+		if err := r.deleteOnboardingSecret(); err != nil {
+			return reconcile.Result{}, err
+		}
 	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: I would like to see 2 different reconcile phases called from the reconcile function based on enablement.
The code path should be completely separated 

Also the code below this line should only run on enabled storage consumers
Preferably, just rename this function to `reconcileEnabledPhases` and create another func `reconicleNonEnabledPhases` 
created_at: 2025-03-26T15:52:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: Can we please stop with all of the hashes? what is wrong with just `onboarding-token-<uuid>`?
created_at: 2025-03-26T15:54:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: Why do we need the storagecluster uid inside the onboarding token? What is it used for?
created_at: 2025-03-26T15:56:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: Suggestion to make the code more readable:
```suggestion
		tokenExpiry := time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC()
		util.AddAnnotation(secret, "token-expiry", tokenExpiry.String())
```
created_at: 2025-03-26T15:59:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: Annotations should have domain. use the same one we are always using
created_at: 2025-03-26T16:00:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: This will not cover the case where the secret exists but does not contain an onboarding token
created_at: 2025-03-26T16:01:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: shouldn't this say "onbarding-token"?
created_at: 2025-03-26T16:01:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: Where is the owner ref?
created_at: 2025-03-26T16:02:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
+			return err
+		}
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+		Name: secret.Name,
+	}
+	return nil
+}
+
+func (r *StorageConsumerReconciler) deleteOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: See prev comment about secret name
created_at: 2025-03-26T16:02:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
+			return err
+		}
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+		Name: secret.Name,
+	}
+	return nil
+}
+
+func (r *StorageConsumerReconciler) deleteOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: There is not reason to get something just to delete it
created_at: 2025-03-26T16:02:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,8 +52,8 @@ const (
 	EnableCephfsKey             = "ROOK_CSI_ENABLE_CEPHFS"
 
 	// This is the name for the FieldIndex
-	OwnerUIDIndexName   = "ownerUID"
-	AnnotationIndexName = "annotation"
+	OwnerUIDIndexName   = "index:ownerUID"
+	AnnotationIndexName = "index:annotation"
path: controllers/util/k8sutil.go
user: login: nb-ohad
body: Any reason to include this in this PR?
created_at: 2025-03-26T16:03:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,20 +19,16 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 )
 
-// GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
-// The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
-// The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageClusterUID types.UID, consumerIdentifier string) (string, error) {
 	tokenExpirationDate := time.Now().
 		Add(time.Duration(tokenLifetimeInHours) * time.Hour).
 		Unix()
 
 	ticket := services.OnboardingTicket{
-		ID:                uuid.New().String(),
-		ExpirationDate:    tokenExpirationDate,
-		SubjectRole:       services.ClientRole,
-		StorageQuotaInGiB: storageQuotainGib,
-		StorageCluster:    storageClusterUID,
+		ID:             consumerIdentifier,
+		ExpirationDate: tokenExpirationDate,
+		SubjectRole:    services.ClientRole,
+		StorageCluster: storageClusterUID,
path: controllers/util/provider.go
user: login: nb-ohad
body: Do we really need this in the token?
created_at: 2025-03-26T16:04:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +218,16 @@ func main() {
 		os.Exit(1)
 	}
 
+	tokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
path: main.go
user: login: nb-ohad
body: The context here is not specific to onboarding?
```suggestion
	onboardingTokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
```
created_at: 2025-03-26T16:06:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,73 +30,35 @@ func newConsumerManager(ctx context.Context, cl client.Client, namespace string)
 		return nil, fmt.Errorf("failed to list storage consumers. %v", err)
 	}
 
-	nameByTicket := map[string]string{}
 	nameByUID := map[types.UID]string{}
 
 	for _, consumer := range consumers.Items {
 		nameByUID[consumer.UID] = consumer.Name
-
-		if ticket, ok := consumer.GetAnnotations()[TicketAnnotation]; ok {
-			nameByTicket[ticket] = consumer.Name
-		}
 	}
 
 	return &ocsConsumerManager{
-		client:       cl,
-		namespace:    namespace,
-		nameByTicket: nameByTicket,
-		nameByUID:    nameByUID,
+		client:    cl,
+		namespace: namespace,
+		nameByUID: nameByUID,
 	}, nil
 }
 
-// Create creates a new storageConsumer resource, updates the consumer cache and returns the storageConsumer UID
-func (c *ocsConsumerManager) Create(ctx context.Context, onboard ifaces.StorageClientOnboarding, storageQuotaInGiB int) (string, error) {
path: services/provider/server/consumer.go
user: login: nb-ohad
body: Is this the only function that does away? what about EnableStorageConsumer? Delete? AddAnnotation? RemoveAnnotation?
created_at: 2025-03-26T16:08:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,73 +30,35 @@ func newConsumerManager(ctx context.Context, cl client.Client, namespace string)
 		return nil, fmt.Errorf("failed to list storage consumers. %v", err)
 	}
 
-	nameByTicket := map[string]string{}
 	nameByUID := map[types.UID]string{}
 
 	for _, consumer := range consumers.Items {
 		nameByUID[consumer.UID] = consumer.Name
-
-		if ticket, ok := consumer.GetAnnotations()[TicketAnnotation]; ok {
-			nameByTicket[ticket] = consumer.Name
-		}
 	}
 
 	return &ocsConsumerManager{
-		client:       cl,
-		namespace:    namespace,
-		nameByTicket: nameByTicket,
-		nameByUID:    nameByUID,
+		client:    cl,
+		namespace: namespace,
+		nameByUID: nameByUID,
 	}, nil
 }
 
-// Create creates a new storageConsumer resource, updates the consumer cache and returns the storageConsumer UID
-func (c *ocsConsumerManager) Create(ctx context.Context, onboard ifaces.StorageClientOnboarding, storageQuotaInGiB int) (string, error) {
-	ticket := onboard.GetOnboardingTicket()
-	name := onboard.GetConsumerName()
-	c.mutex.RLock()
-	if _, ok := c.nameByTicket[ticket]; ok {
-		c.mutex.RUnlock()
-		klog.Warning("onboarding ticket already in use")
-		return "", errTicketAlreadyExists
-	}
-	c.mutex.RUnlock()
-
-	consumerObj := &ocsv1alpha1.StorageConsumer{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: c.namespace,
-			Annotations: map[string]string{
-				TicketAnnotation: ticket,
-			},
-		},
-		Spec: ocsv1alpha1.StorageConsumerSpec{
-			Enable:            false,
-			StorageQuotaInGiB: storageQuotaInGiB,
-		},
-		Status: ocsv1alpha1.StorageConsumerStatus{
-			Client: ocsv1alpha1.ClientStatus{
-				OperatorVersion: onboard.GetClientOperatorVersion(),
-			},
-		},
-	}
-
-	err := c.client.Create(ctx, consumerObj)
-	if err != nil {
-		if kerrors.IsAlreadyExists(err) {
-			klog.Warningf("storageConsumer %q already exists", name)
-			return "", err
-		}
-		return "", fmt.Errorf("failed to create storageConsumer resource %q. %v", consumerObj.Name, err)
-	}
-
+func (c *ocsConsumerManager) OnboardClient(ctx context.Context, consumer *ocsv1alpha1.StorageConsumer) (string, error) {
path: services/provider/server/consumer.go
user: login: nb-ohad
body: What is the difference between this new one and enable?
created_at: 2025-03-26T16:09:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -140,6 +137,30 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		klog.Errorf("failed to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket is not valid. %v", err)
 	}
+
+	storageConsumer := &ocsv1alpha1.StorageConsumer{}
+	storageConsumer.Name = onboardingTicket.ID
+	storageConsumer.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(storageConsumer), storageConsumer); err != nil {
+		klog.Errorf("failed to get storageconsumer referred by the supplied token: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumer. %v", err)
+	} else if storageConsumer.Spec.Enable {
+		klog.Errorf("storageconsumer is already enabled %s", storageConsumer.Name)
+		return nil, status.Errorf(codes.InvalidArgument, "refusing to onboard onto storageconsumer with supplied token")
+	}
+
+	onboardingSecret := &corev1.Secret{}
+	onboardingSecret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(storageConsumer.UID)))
+	onboardingSecret.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(onboardingSecret), onboardingSecret); err != nil {
+		klog.Errorf("failed to get onboarding secret corresponding to storageconsumer %s: %v", storageConsumer.Name, err)
+		return nil, status.Errorf(codes.Internal, "failed to get onboarding secret. %v", err)
+	}
+	if req.OnboardingTicket != string(onboardingSecret.Data["ticket"]) {
+		klog.Errorf("supplied onboarding ticket does not match storageconsumer secret")
+		return nil, status.Errorf(codes.InvalidArgument, "supplied onboarding ticket does not match mapped secret")
+	}
+
 	storageCluster, err := util.GetStorageClusterInNamespace(ctx, s.client, s.namespace)
path: services/provider/server/server.go
user: login: nb-ohad
body: The check for storage cluster is not needed anymore. We are already verifying the existence of a consumer that is inherently tied to a storage cluster 
created_at: 2025-03-26T16:13:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -140,6 +137,30 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		klog.Errorf("failed to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket is not valid. %v", err)
 	}
+
+	storageConsumer := &ocsv1alpha1.StorageConsumer{}
+	storageConsumer.Name = onboardingTicket.ID
+	storageConsumer.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(storageConsumer), storageConsumer); err != nil {
+		klog.Errorf("failed to get storageconsumer referred by the supplied token: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumer. %v", err)
+	} else if storageConsumer.Spec.Enable {
+		klog.Errorf("storageconsumer is already enabled %s", storageConsumer.Name)
+		return nil, status.Errorf(codes.InvalidArgument, "refusing to onboard onto storageconsumer with supplied token")
+	}
+
+	onboardingSecret := &corev1.Secret{}
+	onboardingSecret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(storageConsumer.UID)))
+	onboardingSecret.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(onboardingSecret), onboardingSecret); err != nil {
+		klog.Errorf("failed to get onboarding secret corresponding to storageconsumer %s: %v", storageConsumer.Name, err)
+		return nil, status.Errorf(codes.Internal, "failed to get onboarding secret. %v", err)
+	}
+	if req.OnboardingTicket != string(onboardingSecret.Data["ticket"]) {
+		klog.Errorf("supplied onboarding ticket does not match storageconsumer secret")
+		return nil, status.Errorf(codes.InvalidArgument, "supplied onboarding ticket does not match mapped secret")
+	}
path: services/provider/server/server.go
user: login: nb-ohad
body: Move checks that need to load stuff after all static content checks (like SubjectRule) 
created_at: 2025-03-26T16:14:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -149,45 +170,22 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket storageCluster not match existing storageCluster.")
 	}
 
-	storageQuotaInGiB := ptr.Deref(onboardingTicket.StorageQuotaInGiB, 0)
-
 	if onboardingTicket.SubjectRole != services.ClientRole {
 		err := fmt.Errorf("invalid onboarding ticket for %q, expecting role %s found role %s", req.ConsumerName, services.ClientRole, onboardingTicket.SubjectRole)
 		klog.Error(err)
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
+	storageConsumerUUID, err := s.consumerManager.OnboardClient(ctx, storageConsumer)
path: services/provider/server/server.go
user: login: nb-ohad
body: ???
```suggestion
	storageConsumerUUID, err := s.consumerManager.EnableStorageConsumer(ctx, storageConsumer)
```
created_at: 2025-03-26T16:14:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -621,13 +619,6 @@ func decodeAndValidateTicket(ticket string, pubKey *rsa.PublicKey) (*services.On
 	}
 
 	switch ticketData.SubjectRole {
-	case services.ClientRole:
-		if ticketData.StorageQuotaInGiB != nil {
-			quota := *ticketData.StorageQuotaInGiB
-			if quota > math.MaxInt {
-				return nil, fmt.Errorf("invalid value sent in onboarding ticket, storage quota should be greater than 0 and less than %v: %v", math.MaxInt, quota)
-			}
-		}
path: services/provider/server/server.go
user: login: nb-ohad
body: Why?
created_at: 2025-03-26T16:15:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
path: controllers/storagecluster/storageclient.go
user: login: leelavg
body: yes, via #3068
created_at: 2025-03-26T16:26:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -134,10 +138,13 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
 	if !r.storageConsumer.Spec.Enable {
 		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		return reconcile.Result{}, r.createOnboardingSecret()
+	} else {
+		if err := r.deleteOnboardingSecret(); err != nil {
+			return reconcile.Result{}, err
+		}
 	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: I was waiting for svg/rns to create the base, nevertheless, will do.
created_at: 2025-03-26T16:27:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: 1. maxLen given by this hash is 10 digits which is much shorter than uuid 36 chars still ensuring the uniqueness
2. storageconsumer uuid is the one which finally gets realised in storageclient status and not exposed in a simple list of secrets
3. sry, I forgot the point you raised against using uuid
created_at: 2025-03-26T16:31:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: not required for clientToken but for peerToken and it is just set, will remove.
created_at: 2025-03-26T16:33:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,8 +52,8 @@ const (
 	EnableCephfsKey             = "ROOK_CSI_ENABLE_CEPHFS"
 
 	// This is the name for the FieldIndex
-	OwnerUIDIndexName   = "ownerUID"
-	AnnotationIndexName = "annotation"
+	OwnerUIDIndexName   = "index:ownerUID"
+	AnnotationIndexName = "index:annotation"
path: controllers/util/k8sutil.go
user: login: leelavg
body: from https://github.com/red-hat-storage/ocs-operator/pull/3075#discussion_r2011379661
we were prefixing the index to differentiate them with any field path while setting the indexer.

but will remove
created_at: 2025-03-26T16:34:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: from https://github.com/red-hat-storage/ocs-operator/pull/3075#discussion_r2011508516
that's an outside involvement and user needs to delete the secret to regenerate it.
created_at: 2025-03-26T16:39:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: the first step in this condition was adding the owner L191.
created_at: 2025-03-26T16:40:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
+			return err
+		}
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+		Name: secret.Name,
+	}
+	return nil
+}
+
+func (r *StorageConsumerReconciler) deleteOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: once enabled we always try to delete the secret and delete hits the api for which I saw a (similar) customer report stating their audit logs are filled w/ 404.

other way I thought of was to delete if not found in our status but that's reading our own status for taking a decision.

so, trying to get which hits cache and then hitting kube api if exists.
created_at: 2025-03-26T16:42:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,20 +19,16 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 )
 
-// GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
-// The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
-// The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageClusterUID types.UID, consumerIdentifier string) (string, error) {
 	tokenExpirationDate := time.Now().
 		Add(time.Duration(tokenLifetimeInHours) * time.Hour).
 		Unix()
 
 	ticket := services.OnboardingTicket{
-		ID:                uuid.New().String(),
-		ExpirationDate:    tokenExpirationDate,
-		SubjectRole:       services.ClientRole,
-		StorageQuotaInGiB: storageQuotainGib,
-		StorageCluster:    storageClusterUID,
+		ID:             consumerIdentifier,
+		ExpirationDate: tokenExpirationDate,
+		SubjectRole:    services.ClientRole,
+		StorageCluster: storageClusterUID,
path: controllers/util/provider.go
user: login: leelavg
body: by this, I suppose StorageCluster, ... not required for clientToken but for peerToken and it is just set, will remove.
created_at: 2025-03-26T16:43:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,73 +30,35 @@ func newConsumerManager(ctx context.Context, cl client.Client, namespace string)
 		return nil, fmt.Errorf("failed to list storage consumers. %v", err)
 	}
 
-	nameByTicket := map[string]string{}
 	nameByUID := map[types.UID]string{}
 
 	for _, consumer := range consumers.Items {
 		nameByUID[consumer.UID] = consumer.Name
-
-		if ticket, ok := consumer.GetAnnotations()[TicketAnnotation]; ok {
-			nameByTicket[ticket] = consumer.Name
-		}
 	}
 
 	return &ocsConsumerManager{
-		client:       cl,
-		namespace:    namespace,
-		nameByTicket: nameByTicket,
-		nameByUID:    nameByUID,
+		client:    cl,
+		namespace: namespace,
+		nameByUID: nameByUID,
 	}, nil
 }
 
-// Create creates a new storageConsumer resource, updates the consumer cache and returns the storageConsumer UID
-func (c *ocsConsumerManager) Create(ctx context.Context, onboard ifaces.StorageClientOnboarding, storageQuotaInGiB int) (string, error) {
path: services/provider/server/consumer.go
user: login: leelavg
body: my mistake I was fixated w/ OnboardClient and total forgot EnableStorageConsumer.

AddAnnotation & RemoveAnnotation are part of DR and I suppose they'll stay.

Delete - I believe we are yet to decide deletion flow.
created_at: 2025-03-26T16:44:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,73 +30,35 @@ func newConsumerManager(ctx context.Context, cl client.Client, namespace string)
 		return nil, fmt.Errorf("failed to list storage consumers. %v", err)
 	}
 
-	nameByTicket := map[string]string{}
 	nameByUID := map[types.UID]string{}
 
 	for _, consumer := range consumers.Items {
 		nameByUID[consumer.UID] = consumer.Name
-
-		if ticket, ok := consumer.GetAnnotations()[TicketAnnotation]; ok {
-			nameByTicket[ticket] = consumer.Name
-		}
 	}
 
 	return &ocsConsumerManager{
-		client:       cl,
-		namespace:    namespace,
-		nameByTicket: nameByTicket,
-		nameByUID:    nameByUID,
+		client:    cl,
+		namespace: namespace,
+		nameByUID: nameByUID,
 	}, nil
 }
 
-// Create creates a new storageConsumer resource, updates the consumer cache and returns the storageConsumer UID
-func (c *ocsConsumerManager) Create(ctx context.Context, onboard ifaces.StorageClientOnboarding, storageQuotaInGiB int) (string, error) {
-	ticket := onboard.GetOnboardingTicket()
-	name := onboard.GetConsumerName()
-	c.mutex.RLock()
-	if _, ok := c.nameByTicket[ticket]; ok {
-		c.mutex.RUnlock()
-		klog.Warning("onboarding ticket already in use")
-		return "", errTicketAlreadyExists
-	}
-	c.mutex.RUnlock()
-
-	consumerObj := &ocsv1alpha1.StorageConsumer{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: c.namespace,
-			Annotations: map[string]string{
-				TicketAnnotation: ticket,
-			},
-		},
-		Spec: ocsv1alpha1.StorageConsumerSpec{
-			Enable:            false,
-			StorageQuotaInGiB: storageQuotaInGiB,
-		},
-		Status: ocsv1alpha1.StorageConsumerStatus{
-			Client: ocsv1alpha1.ClientStatus{
-				OperatorVersion: onboard.GetClientOperatorVersion(),
-			},
-		},
-	}
-
-	err := c.client.Create(ctx, consumerObj)
-	if err != nil {
-		if kerrors.IsAlreadyExists(err) {
-			klog.Warningf("storageConsumer %q already exists", name)
-			return "", err
-		}
-		return "", fmt.Errorf("failed to create storageConsumer resource %q. %v", consumerObj.Name, err)
-	}
-
+func (c *ocsConsumerManager) OnboardClient(ctx context.Context, consumer *ocsv1alpha1.StorageConsumer) (string, error) {
path: services/provider/server/consumer.go
user: login: leelavg
body: my mistake I was fixated w/ OnboardClient and total forgot EnableStorageConsumer.
created_at: 2025-03-26T16:46:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -149,45 +170,22 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket storageCluster not match existing storageCluster.")
 	}
 
-	storageQuotaInGiB := ptr.Deref(onboardingTicket.StorageQuotaInGiB, 0)
-
 	if onboardingTicket.SubjectRole != services.ClientRole {
 		err := fmt.Errorf("invalid onboarding ticket for %q, expecting role %s found role %s", req.ConsumerName, services.ClientRole, onboardingTicket.SubjectRole)
 		klog.Error(err)
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
+	storageConsumerUUID, err := s.consumerManager.OnboardClient(ctx, storageConsumer)
path: services/provider/server/server.go
user: login: leelavg
body: my mistake I was fixated w/ OnboardClient and total forgot EnableStorageConsumer.
created_at: 2025-03-26T16:47:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -621,13 +619,6 @@ func decodeAndValidateTicket(ticket string, pubKey *rsa.PublicKey) (*services.On
 	}
 
 	switch ticketData.SubjectRole {
-	case services.ClientRole:
-		if ticketData.StorageQuotaInGiB != nil {
-			quota := *ticketData.StorageQuotaInGiB
-			if quota > math.MaxInt {
-				return nil, fmt.Errorf("invalid value sent in onboarding ticket, storage quota should be greater than 0 and less than %v: %v", math.MaxInt, quota)
-			}
-		}
path: services/provider/server/server.go
user: login: leelavg
body: my mistake in removing the `case`, I should've removed only the quota check.
created_at: 2025-03-26T16:48:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: Why can't we be helpful here? What is the side effect? 
created_at: 2025-03-26T16:53:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
+			return err
+		}
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+		Name: secret.Name,
+	}
+	return nil
+}
+
+func (r *StorageConsumerReconciler) deleteOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: But delete with a 404 answer need to be treated as a success. Either way you don't need a get for that.
created_at: 2025-03-26T16:54:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: depends on how it was removed, if it was copied by admin and something else got it removed we'll generate new one which'll not match old one.
created_at: 2025-03-26T16:56:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: will be changed to use uuid for discoverability.
created_at: 2025-03-26T17:32:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: will be checked and updated if empty.
created_at: 2025-03-26T17:32:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
+			return err
+		}
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+		Name: secret.Name,
+	}
+	return nil
+}
+
+func (r *StorageConsumerReconciler) deleteOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: as discussed, once the `.spec.enable` is set to true we need to delete secret which is a direct call to k8s api server throughout the storageconsumer (s) lifecycle which adds a log to api server w/ 404 errors as a side effect.

get is used to remove the side effect to the maximum possible, get hits cache first and slowly (let's say <5min) syncs the delete event as well, from then we'll not make any delete calls.






created_at: 2025-03-26T17:35:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
-			if err != nil {
-				return fmt.Errorf("unable to generate onboarding token: %v", err)
+			localStorageConsumer := &ocsv1a1.StorageConsumer{}
+			localStorageConsumer.Name = localStorageConsumerName
+			localStorageConsumer.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(localStorageConsumer), localStorageConsumer); err != nil {
+				return fmt.Errorf("failed to get storageconsumer %s: %v", localStorageConsumer.Name, err)
+			} else if localStorageConsumer.Status.OnboardingTicketSecret.Name == "" {
+				return fmt.Errorf("no reference to secret found in storageconsumer %s status", localStorageConsumer.Name)
path: controllers/storagecluster/storageclient.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:21:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
-			if err != nil {
-				return fmt.Errorf("unable to generate onboarding token: %v", err)
+			localStorageConsumer := &ocsv1a1.StorageConsumer{}
+			localStorageConsumer.Name = localStorageConsumerName
+			localStorageConsumer.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(localStorageConsumer), localStorageConsumer); err != nil {
+				return fmt.Errorf("failed to get storageconsumer %s: %v", localStorageConsumer.Name, err)
+			} else if localStorageConsumer.Status.OnboardingTicketSecret.Name == "" {
+				return fmt.Errorf("no reference to secret found in storageconsumer %s status", localStorageConsumer.Name)
+			}
+
+			onboardingTicketSecret := &corev1.Secret{}
+			onboardingTicketSecret.Name = localStorageConsumer.Status.OnboardingTicketSecret.Name
+			onboardingTicketSecret.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(onboardingTicketSecret), onboardingTicketSecret); err != nil {
+				return fmt.Errorf("failed to get onboarding ticket secret %s: %v", onboardingTicketSecret.Name, err)
path: controllers/storagecluster/storageclient.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:21:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
-			if err != nil {
-				return fmt.Errorf("unable to generate onboarding token: %v", err)
+			localStorageConsumer := &ocsv1a1.StorageConsumer{}
+			localStorageConsumer.Name = localStorageConsumerName
+			localStorageConsumer.Namespace = storagecluster.Namespace
+			if err := r.Get(r.ctx, client.ObjectKeyFromObject(localStorageConsumer), localStorageConsumer); err != nil {
+				return fmt.Errorf("failed to get storageconsumer %s: %v", localStorageConsumer.Name, err)
+			} else if localStorageConsumer.Status.OnboardingTicketSecret.Name == "" {
+				return fmt.Errorf("no reference to secret found in storageconsumer %s status", localStorageConsumer.Name)
+			}
+
+			onboardingTicketSecret := &corev1.Secret{}
+			onboardingTicketSecret.Name = localStorageConsumer.Status.OnboardingTicketSecret.Name
+			onboardingTicketSecret.Namespace = storagecluster.Namespace
path: controllers/storagecluster/storageclient.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:21:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,11 +40,25 @@ func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluste
 	storageClient.Name = storagecluster.Name
 	_, err := controllerutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error {
 		if storageClient.Status.ConsumerID == "" {
-			token, err := util.GenerateClientOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, storagecluster.UID)
path: controllers/storagecluster/storageclient.go
user: login: leelavg
body: deferred.
created_at: 2025-03-27T05:21:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -134,10 +138,13 @@ func (r *StorageConsumerReconciler) initReconciler(request reconcile.Request) {
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
 	if !r.storageConsumer.Spec.Enable {
 		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		return reconcile.Result{}, r.createOnboardingSecret()
+	} else {
+		if err := r.deleteOnboardingSecret(); err != nil {
+			return reconcile.Result{}, err
+		}
 	}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:21:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:22:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:22:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:22:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:22:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:22:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: deferred.
created_at: 2025-03-27T05:23:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -174,6 +181,59 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 	return reconcile.Result{}, nil
 }
 
+func (r *StorageConsumerReconciler) createOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
+		return fmt.Errorf("failed to get secret %s: %v", secret.Name, err)
+	} else if secret.UID == "" {
+		if err := r.own(secret); err != nil {
+			return err
+		}
+		storageCluster, err := util.GetStorageClusterInNamespace(r.ctx, r.Client, r.namespace)
+		if err != nil {
+			return err
+		}
+		token, err := util.GenerateClientOnboardingToken(
+			r.TokenLifetimeInHours,
+			onboardingPrivateKeyFilePath,
+			storageCluster.UID,
+			r.storageConsumer.Name,
+		)
+		if err != nil {
+			return err
+		}
+		secret.Data = map[string][]byte{
+			"ticket": []byte(token),
+		}
+		util.AddAnnotation(secret, "token-expiry-utc", time.Now().Add(time.Duration(r.TokenLifetimeInHours)*time.Hour).UTC().String())
+		r.Log.Info("creating secret containing onboarding token for", "StorageConsumer", r.storageConsumer.Name, "Secret", secret.Name)
+		if err := r.Create(r.ctx, secret); err != nil {
+			return err
+		}
+	}
+	r.storageConsumer.Status.OnboardingTicketSecret = corev1.LocalObjectReference{
+		Name: secret.Name,
+	}
+	return nil
+}
+
+func (r *StorageConsumerReconciler) deleteOnboardingSecret() error {
+	secret := &corev1.Secret{}
+	secret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(r.storageConsumer.UID)))
+	secret.Namespace = r.storageConsumer.Namespace
+	if err := r.get(secret); client.IgnoreNotFound(err) != nil {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: deferred.
created_at: 2025-03-27T05:23:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,8 +52,8 @@ const (
 	EnableCephfsKey             = "ROOK_CSI_ENABLE_CEPHFS"
 
 	// This is the name for the FieldIndex
-	OwnerUIDIndexName   = "ownerUID"
-	AnnotationIndexName = "annotation"
+	OwnerUIDIndexName   = "index:ownerUID"
+	AnnotationIndexName = "index:annotation"
path: controllers/util/k8sutil.go
user: login: leelavg
body: removed.
created_at: 2025-03-27T05:23:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,20 +19,16 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 )
 
-// GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
-// The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
-// The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageClusterUID types.UID, consumerIdentifier string) (string, error) {
 	tokenExpirationDate := time.Now().
 		Add(time.Duration(tokenLifetimeInHours) * time.Hour).
 		Unix()
 
 	ticket := services.OnboardingTicket{
-		ID:                uuid.New().String(),
-		ExpirationDate:    tokenExpirationDate,
-		SubjectRole:       services.ClientRole,
-		StorageQuotaInGiB: storageQuotainGib,
-		StorageCluster:    storageClusterUID,
+		ID:             consumerIdentifier,
+		ExpirationDate: tokenExpirationDate,
+		SubjectRole:    services.ClientRole,
+		StorageCluster: storageClusterUID,
path: controllers/util/provider.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:23:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +218,16 @@ func main() {
 		os.Exit(1)
 	}
 
+	tokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
path: main.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:23:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,73 +30,35 @@ func newConsumerManager(ctx context.Context, cl client.Client, namespace string)
 		return nil, fmt.Errorf("failed to list storage consumers. %v", err)
 	}
 
-	nameByTicket := map[string]string{}
 	nameByUID := map[types.UID]string{}
 
 	for _, consumer := range consumers.Items {
 		nameByUID[consumer.UID] = consumer.Name
-
-		if ticket, ok := consumer.GetAnnotations()[TicketAnnotation]; ok {
-			nameByTicket[ticket] = consumer.Name
-		}
 	}
 
 	return &ocsConsumerManager{
-		client:       cl,
-		namespace:    namespace,
-		nameByTicket: nameByTicket,
-		nameByUID:    nameByUID,
+		client:    cl,
+		namespace: namespace,
+		nameByUID: nameByUID,
 	}, nil
 }
 
-// Create creates a new storageConsumer resource, updates the consumer cache and returns the storageConsumer UID
-func (c *ocsConsumerManager) Create(ctx context.Context, onboard ifaces.StorageClientOnboarding, storageQuotaInGiB int) (string, error) {
path: services/provider/server/consumer.go
user: login: leelavg
body: fixed.
created_at: 2025-03-27T05:23:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,73 +30,35 @@ func newConsumerManager(ctx context.Context, cl client.Client, namespace string)
 		return nil, fmt.Errorf("failed to list storage consumers. %v", err)
 	}
 
-	nameByTicket := map[string]string{}
 	nameByUID := map[types.UID]string{}
 
 	for _, consumer := range consumers.Items {
 		nameByUID[consumer.UID] = consumer.Name
-
-		if ticket, ok := consumer.GetAnnotations()[TicketAnnotation]; ok {
-			nameByTicket[ticket] = consumer.Name
-		}
 	}
 
 	return &ocsConsumerManager{
-		client:       cl,
-		namespace:    namespace,
-		nameByTicket: nameByTicket,
-		nameByUID:    nameByUID,
+		client:    cl,
+		namespace: namespace,
+		nameByUID: nameByUID,
 	}, nil
 }
 
-// Create creates a new storageConsumer resource, updates the consumer cache and returns the storageConsumer UID
-func (c *ocsConsumerManager) Create(ctx context.Context, onboard ifaces.StorageClientOnboarding, storageQuotaInGiB int) (string, error) {
-	ticket := onboard.GetOnboardingTicket()
-	name := onboard.GetConsumerName()
-	c.mutex.RLock()
-	if _, ok := c.nameByTicket[ticket]; ok {
-		c.mutex.RUnlock()
-		klog.Warning("onboarding ticket already in use")
-		return "", errTicketAlreadyExists
-	}
-	c.mutex.RUnlock()
-
-	consumerObj := &ocsv1alpha1.StorageConsumer{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: c.namespace,
-			Annotations: map[string]string{
-				TicketAnnotation: ticket,
-			},
-		},
-		Spec: ocsv1alpha1.StorageConsumerSpec{
-			Enable:            false,
-			StorageQuotaInGiB: storageQuotaInGiB,
-		},
-		Status: ocsv1alpha1.StorageConsumerStatus{
-			Client: ocsv1alpha1.ClientStatus{
-				OperatorVersion: onboard.GetClientOperatorVersion(),
-			},
-		},
-	}
-
-	err := c.client.Create(ctx, consumerObj)
-	if err != nil {
-		if kerrors.IsAlreadyExists(err) {
-			klog.Warningf("storageConsumer %q already exists", name)
-			return "", err
-		}
-		return "", fmt.Errorf("failed to create storageConsumer resource %q. %v", consumerObj.Name, err)
-	}
-
+func (c *ocsConsumerManager) OnboardClient(ctx context.Context, consumer *ocsv1alpha1.StorageConsumer) (string, error) {
path: services/provider/server/consumer.go
user: login: leelavg
body: fixed.
created_at: 2025-03-27T05:23:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -140,6 +137,30 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		klog.Errorf("failed to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket is not valid. %v", err)
 	}
+
+	storageConsumer := &ocsv1alpha1.StorageConsumer{}
+	storageConsumer.Name = onboardingTicket.ID
+	storageConsumer.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(storageConsumer), storageConsumer); err != nil {
+		klog.Errorf("failed to get storageconsumer referred by the supplied token: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumer. %v", err)
+	} else if storageConsumer.Spec.Enable {
+		klog.Errorf("storageconsumer is already enabled %s", storageConsumer.Name)
+		return nil, status.Errorf(codes.InvalidArgument, "refusing to onboard onto storageconsumer with supplied token")
+	}
+
+	onboardingSecret := &corev1.Secret{}
+	onboardingSecret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(storageConsumer.UID)))
+	onboardingSecret.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(onboardingSecret), onboardingSecret); err != nil {
+		klog.Errorf("failed to get onboarding secret corresponding to storageconsumer %s: %v", storageConsumer.Name, err)
+		return nil, status.Errorf(codes.Internal, "failed to get onboarding secret. %v", err)
+	}
+	if req.OnboardingTicket != string(onboardingSecret.Data["ticket"]) {
+		klog.Errorf("supplied onboarding ticket does not match storageconsumer secret")
+		return nil, status.Errorf(codes.InvalidArgument, "supplied onboarding ticket does not match mapped secret")
+	}
+
 	storageCluster, err := util.GetStorageClusterInNamespace(ctx, s.client, s.namespace)
path: services/provider/server/server.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:23:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -140,6 +137,30 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		klog.Errorf("failed to validate onboarding ticket for consumer %q. %v", req.ConsumerName, err)
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket is not valid. %v", err)
 	}
+
+	storageConsumer := &ocsv1alpha1.StorageConsumer{}
+	storageConsumer.Name = onboardingTicket.ID
+	storageConsumer.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(storageConsumer), storageConsumer); err != nil {
+		klog.Errorf("failed to get storageconsumer referred by the supplied token: %v", err)
+		return nil, status.Errorf(codes.Internal, "failed to get storageconsumer. %v", err)
+	} else if storageConsumer.Spec.Enable {
+		klog.Errorf("storageconsumer is already enabled %s", storageConsumer.Name)
+		return nil, status.Errorf(codes.InvalidArgument, "refusing to onboard onto storageconsumer with supplied token")
+	}
+
+	onboardingSecret := &corev1.Secret{}
+	onboardingSecret.Name = fmt.Sprintf("onboarding-token-%d", util.FnvHash(string(storageConsumer.UID)))
+	onboardingSecret.Namespace = s.namespace
+	if err := s.client.Get(ctx, client.ObjectKeyFromObject(onboardingSecret), onboardingSecret); err != nil {
+		klog.Errorf("failed to get onboarding secret corresponding to storageconsumer %s: %v", storageConsumer.Name, err)
+		return nil, status.Errorf(codes.Internal, "failed to get onboarding secret. %v", err)
+	}
+	if req.OnboardingTicket != string(onboardingSecret.Data["ticket"]) {
+		klog.Errorf("supplied onboarding ticket does not match storageconsumer secret")
+		return nil, status.Errorf(codes.InvalidArgument, "supplied onboarding ticket does not match mapped secret")
+	}
path: services/provider/server/server.go
user: login: leelavg
body: done.
created_at: 2025-03-27T05:23:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -149,45 +170,22 @@ func (s *OCSProviderServer) OnboardConsumer(ctx context.Context, req *pb.Onboard
 		return nil, status.Errorf(codes.InvalidArgument, "onboarding ticket storageCluster not match existing storageCluster.")
 	}
 
-	storageQuotaInGiB := ptr.Deref(onboardingTicket.StorageQuotaInGiB, 0)
-
 	if onboardingTicket.SubjectRole != services.ClientRole {
 		err := fmt.Errorf("invalid onboarding ticket for %q, expecting role %s found role %s", req.ConsumerName, services.ClientRole, onboardingTicket.SubjectRole)
 		klog.Error(err)
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
 
-	storageConsumerUUID, err := s.consumerManager.Create(ctx, req, int(storageQuotaInGiB))
+	storageConsumerUUID, err := s.consumerManager.OnboardClient(ctx, storageConsumer)
path: services/provider/server/server.go
user: login: leelavg
body: fixed.
created_at: 2025-03-27T05:23:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -621,13 +619,6 @@ func decodeAndValidateTicket(ticket string, pubKey *rsa.PublicKey) (*services.On
 	}
 
 	switch ticketData.SubjectRole {
-	case services.ClientRole:
-		if ticketData.StorageQuotaInGiB != nil {
-			quota := *ticketData.StorageQuotaInGiB
-			if quota > math.MaxInt {
-				return nil, fmt.Errorf("invalid value sent in onboarding ticket, storage quota should be greater than 0 and less than %v: %v", math.MaxInt, quota)
-			}
-		}
path: services/provider/server/server.go
user: login: leelavg
body: fixed.
created_at: 2025-03-27T05:24:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,11 +17,9 @@ import (
 )
 
 const (
-	tokenLifetimeInHours         = 48
-	onboardingPrivateKeyFilePath = "/etc/private-key/key"
-
-	ocsClientConfigMapName = "ocs-client-operator-config"
-	manageNoobaaSubKey     = "manageNoobaaSubscription"
+	onboaringTokenSecretKey = "onboarding-token"
path: controllers/storagecluster/storageclient.go
user: login: nb-ohad
body: ```suggestion
	onboaringTokenKey = "onboarding-token"
```
created_at: 2025-03-27T13:58:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,32 +129,49 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
+	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
 	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	} else {
+		if err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: There is no need for the negative case to be first
```suggestion
	if r.storageConsumer.Spec.Enable {
		if err := r.reconcileEnabledPhases(); err != nil {
			return reconcile.Result{}, err
		}
	} else {
		if err := r.reconcileNonEnabledPhases(); err != nil {
			return reconcile.Result{}, err
		}
		```
created_at: 2025-03-27T14:11:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,32 +129,49 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
+	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
 	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	} else {
+		if err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
 	}
+	return reconcile.Result{}, nil
+}
 
-	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
-	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
-
+func (r *StorageConsumerReconciler) reconcileNonEnabledPhases() error {
 	if r.storageConsumer.GetDeletionTimestamp().IsZero() {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: We need to change "Disabled" to something else. The term disabled does not fit this use case anymore
created_at: 2025-03-27T14:13:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,32 +129,49 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
+	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
 	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	} else {
+		if err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
 	}
+	return reconcile.Result{}, nil
+}
 
-	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
-	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
-
+func (r *StorageConsumerReconciler) reconcileNonEnabledPhases() error {
 	if r.storageConsumer.GetDeletionTimestamp().IsZero() {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
+		if err := r.reconcileOnboardingSecret(); err != nil {
+			return err
+		}
+	} else {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDeleting
+	}
+	return nil
+}
 
+func (r *StorageConsumerReconciler) reconcileEnabledPhases() error {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: We should also return a result here
created_at: 2025-03-27T14:16:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -284,10 +305,14 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 		clusterID := util.GetClusterID(r.ctx, r.Client, &r.Log)
 		if clusterID != "" && !strings.Contains(r.storageConsumer.Name, clusterID) {
 			if err := r.reconcileNoobaaAccount(); err != nil {
-				return reconcile.Result{}, err
+				return err
 			}
 		}
 
+		if err := r.deleteOnboardingSecret(); err != nil {
+			return nil
+		}
+
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: This should go to the top to ensure we don't have a secret before creation of any resources
created_at: 2025-03-27T14:17:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,20 +19,15 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 )
 
-// GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
-// The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
-// The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, consumerIdentifier string) (string, error) {
path: controllers/util/provider.go
user: login: nb-ohad
body: Who is going to use this father these changes? why are we keeping this flow
created_at: 2025-03-27T14:21:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +218,16 @@ func main() {
 		os.Exit(1)
 	}
 
+	onboardingTokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
+	if err != nil {
+		setupLog.Error(err, "unable to parse ONBOARDING_TOKEN_LIFETIME environment value")
+		os.Exit(1)
+	}
path: main.go
user: login: nb-ohad
body: No env var we use a default
created_at: 2025-03-27T14:21:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,16 +16,11 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-var (
-	errTicketAlreadyExists = errors.New("onboarding ticket already used by another storageConsumer")
-)
-
 type ocsConsumerManager struct {
-	client       client.Client
-	namespace    string
-	nameByTicket map[string]string
-	nameByUID    map[types.UID]string
-	mutex        sync.RWMutex
+	client    client.Client
+	namespace string
+	nameByUID map[types.UID]string
+	mutex     sync.RWMutex
path: services/provider/server/consumer.go
user: login: nb-ohad
body: One other question. Does the mutex make any more sense?
Are we trying to protect more then just access to the map and in that case isn't a sync map makes more sense
created_at: 2025-03-27T14:25:00Z
author_association: CONTRIBUTOR
path: services/provider/server/consumer.go
user: login: nb-ohad
body: Is there a reason for keeping AddAnnotation and RemoveAnnotation? 
created_at: 2025-03-27T14:27:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,20 +19,15 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 )
 
-// GenerateClientOnboardingToken generates a ocs-client token valid for a duration of "tokenLifetimeInHours".
-// The token content is predefined and signed by the private key which'll be read from supplied "privateKeyPath".
-// The storageQuotaInGiB is optional, and it is used to limit the storage of PVC in the application cluster.
-func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotainGib *uint, storageClusterUID types.UID) (string, error) {
+func GenerateClientOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, consumerIdentifier string) (string, error) {
path: controllers/util/provider.go
user: login: nb-ohad
body: Resolved as of an offline discussion 
created_at: 2025-03-27T14:46:06Z
author_association: CONTRIBUTOR
path: services/provider/server/consumer.go
user: login: nb-ohad
body: Apparently this is part of our maintenance mode implementation
created_at: 2025-03-27T14:48:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,16 +16,11 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-var (
-	errTicketAlreadyExists = errors.New("onboarding ticket already used by another storageConsumer")
-)
-
 type ocsConsumerManager struct {
-	client       client.Client
-	namespace    string
-	nameByTicket map[string]string
-	nameByUID    map[types.UID]string
-	mutex        sync.RWMutex
+	client    client.Client
+	namespace string
+	nameByUID map[types.UID]string
+	mutex     sync.RWMutex
path: services/provider/server/consumer.go
user: login: leelavg
body: I'd still want to stick w/ normal map w/ lock due to typing guarantees and the docs https://pkg.go.dev/sync#Map also says against it unless specialized in some some nature.
```
The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.
```
created_at: 2025-03-27T15:04:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,11 +17,9 @@ import (
 )
 
 const (
-	tokenLifetimeInHours         = 48
-	onboardingPrivateKeyFilePath = "/etc/private-key/key"
-
-	ocsClientConfigMapName = "ocs-client-operator-config"
-	manageNoobaaSubKey     = "manageNoobaaSubscription"
+	onboaringTokenSecretKey = "onboarding-token"
path: controllers/storagecluster/storageclient.go
user: login: leelavg
body: done.
created_at: 2025-03-27T15:20:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,32 +129,49 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
+	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
 	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	} else {
+		if err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T15:20:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,32 +129,49 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
+	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
 	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	} else {
+		if err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
 	}
+	return reconcile.Result{}, nil
+}
 
-	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
-	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
-
+func (r *StorageConsumerReconciler) reconcileNonEnabledPhases() error {
 	if r.storageConsumer.GetDeletionTimestamp().IsZero() {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T15:21:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,32 +129,49 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
+	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
 	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	} else {
+		if err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
 	}
+	return reconcile.Result{}, nil
+}
 
-	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
-	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
-
+func (r *StorageConsumerReconciler) reconcileNonEnabledPhases() error {
 	if r.storageConsumer.GetDeletionTimestamp().IsZero() {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
+		if err := r.reconcileOnboardingSecret(); err != nil {
+			return err
+		}
+	} else {
+		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDeleting
+	}
+	return nil
+}
 
+func (r *StorageConsumerReconciler) reconcileEnabledPhases() error {
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T15:21:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -284,10 +305,14 @@ func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error)
 		clusterID := util.GetClusterID(r.ctx, r.Client, &r.Log)
 		if clusterID != "" && !strings.Contains(r.storageConsumer.Name, clusterID) {
 			if err := r.reconcileNoobaaAccount(); err != nil {
-				return reconcile.Result{}, err
+				return err
 			}
 		}
 
+		if err := r.deleteOnboardingSecret(); err != nil {
+			return nil
+		}
+
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T15:21:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +218,16 @@ func main() {
 		os.Exit(1)
 	}
 
+	onboardingTokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
+	if err != nil {
+		setupLog.Error(err, "unable to parse ONBOARDING_TOKEN_LIFETIME environment value")
+		os.Exit(1)
+	}
path: main.go
user: login: leelavg
body: done.
created_at: 2025-03-27T15:21:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -34,7 +34,8 @@ const (
 	// StorageConsumerStateFailed represents Failed state of StorageConsumer
 	StorageConsumerStateFailed StorageConsumerState = "Failed"
 	// StorageConsumerStateDisabled represents Disabled state of StorageConsumer
-	StorageConsumerStateDisabled StorageConsumerState = "Disabled"
+	StorageConsumerStateDisabled   StorageConsumerState = "Disabled"
path: api/v1alpha1/storageconsumer_types.go
user: login: nb-ohad
body: Is there a reason to keep this one? 
created_at: 2025-03-27T16:22:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -34,7 +34,8 @@ const (
 	// StorageConsumerStateFailed represents Failed state of StorageConsumer
 	StorageConsumerStateFailed StorageConsumerState = "Failed"
 	// StorageConsumerStateDisabled represents Disabled state of StorageConsumer
-	StorageConsumerStateDisabled StorageConsumerState = "Disabled"
+	StorageConsumerStateDisabled   StorageConsumerState = "Disabled"
+	StorageConsumerStateNotEnabled StorageConsumerState = "NotEnabled"
path: api/v1alpha1/storageconsumer_types.go
user: login: nb-ohad
body: This value needs a comment similar to the other ones
created_at: 2025-03-27T16:22:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,17 +129,39 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
-	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
-	}
-
-	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
 	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
+	if r.storageConsumer.Spec.Enable {
+		if result, err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		} else if !result.IsZero() {
+			return result, nil
+		}
+	} else {
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	}
+	return reconcile.Result{}, nil
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: nb-ohad
body: ```suggestion
	if r.storageConsumer.Spec.Enable {
		return r.reconcileEnabledPhases();
	} else {
		return r.reconcileNonEnabledPhases(); 
	}
```
created_at: 2025-03-27T16:27:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +218,16 @@ func main() {
 		os.Exit(1)
 	}
 
+	onboardingTokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
+	if err != nil {
+		onboardingTokenLifetimeInHours = 48
path: main.go
user: login: nb-ohad
body: ```suggestion
		onboardingTokenLifetimeInHours = deafultOnboardingLifetimeInHours
```
created_at: 2025-03-27T16:29:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -34,7 +34,8 @@ const (
 	// StorageConsumerStateFailed represents Failed state of StorageConsumer
 	StorageConsumerStateFailed StorageConsumerState = "Failed"
 	// StorageConsumerStateDisabled represents Disabled state of StorageConsumer
-	StorageConsumerStateDisabled StorageConsumerState = "Disabled"
+	StorageConsumerStateDisabled   StorageConsumerState = "Disabled"
path: api/v1alpha1/storageconsumer_types.go
user: login: leelavg
body: removed.
created_at: 2025-03-27T16:47:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -34,7 +34,8 @@ const (
 	// StorageConsumerStateFailed represents Failed state of StorageConsumer
 	StorageConsumerStateFailed StorageConsumerState = "Failed"
 	// StorageConsumerStateDisabled represents Disabled state of StorageConsumer
-	StorageConsumerStateDisabled StorageConsumerState = "Disabled"
+	StorageConsumerStateDisabled   StorageConsumerState = "Disabled"
+	StorageConsumerStateNotEnabled StorageConsumerState = "NotEnabled"
path: api/v1alpha1/storageconsumer_types.go
user: login: leelavg
body: done.
created_at: 2025-03-27T16:47:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -125,17 +129,39 @@ func (r *StorageConsumerReconciler) Reconcile(ctx context.Context, request recon
 }
 
 func (r *StorageConsumerReconciler) reconcilePhases() (reconcile.Result, error) {
-
-	if !r.storageConsumer.Spec.Enable {
-		r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateDisabled
-		return reconcile.Result{}, nil
-	}
-
-	r.storageConsumer.Status.State = v1alpha1.StorageConsumerStateConfiguring
 	r.storageConsumer.Status.CephResources = []*ocsv1alpha1.CephResourcesSpec{}
+	if r.storageConsumer.Spec.Enable {
+		if result, err := r.reconcileEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		} else if !result.IsZero() {
+			return result, nil
+		}
+	} else {
+		if err := r.reconcileNonEnabledPhases(); err != nil {
+			return reconcile.Result{}, err
+		}
+	}
+	return reconcile.Result{}, nil
path: controllers/storageconsumer/storageconsumer_controller.go
user: login: leelavg
body: done.
created_at: 2025-03-27T16:47:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +218,16 @@ func main() {
 		os.Exit(1)
 	}
 
+	onboardingTokenLifetimeInHours, err := util.ReadEnvVar("ONBOARDING_TOKEN_LIFETIME", 48, strconv.Atoi)
+	if err != nil {
+		onboardingTokenLifetimeInHours = 48
path: main.go
user: login: leelavg
body: done.
created_at: 2025-03-27T16:47:52Z
author_association: CONTRIBUTOR

PR comments:
user: login: leelavg
created_at: 2025-03-25T12:56:33Z
body: rebased.
author_association: CONTRIBUTOR
user: login: leelavg
created_at: 2025-03-27T13:07:24Z
body: rebased.
author_association: CONTRIBUTOR
user: login: nb-ohad
created_at: 2025-03-27T16:54:42Z
body: /lgtm
author_association: CONTRIBUTOR
user: login: leelavg
created_at: 2025-03-27T18:00:38Z
body: /hold testing.

just for ref:
```
>  time.Now().Add(time.Duration(5) * time.Hour).UTC().Format(time.RFC3339)
: 2025-03-27T23:21:59Z
>  time.Now().Add(time.Duration(5) * time.Hour).UTC().String()
: 2025-03-27 23:22:06.252270578 +0000 UTC
```
author_association: CONTRIBUTOR
user: login: leelavg
created_at: 2025-03-27T18:35:39Z
body: /unhold tested as follows

```
> oc get storageclient  -oyaml
apiVersion: v1
items:
- apiVersion: ocs.openshift.io/v1alpha1
  kind: StorageClient
  metadata:
    annotations:
      ocs.openshift.io/provider-side-state: 801daf80689e96cb99f92ad9ffa86d25
      ocs.openshift.io/storageclient.default: "true"
      ocs.openshift.io/subscription.channel: operator-sdk-run-bundle
    creationTimestamp: "2025-03-27T17:16:18Z"
    finalizers:
    - storageclient.ocs.openshift.io
    generation: 4
    name: ocs-storagecluster
    resourceVersion: "9743711"
    uid: 20ea6eb4-7fc1-44f4-98ca-81ad818f78b9
  spec:
    onboardingTicket: eyJpZCI6ImludGVybmFsIiwiZXhwaXJhdGlvbkRhdGUiOiIxNzQzMjY4NTY0Iiwic3ViamVjdFJvbGUiOiJvY3MtY2xpZW50Iiwic3RvcmFnZUNsdXN0ZXIiOiIifQ==.L7J7EpiAE3C+DKdksDFdLf0HKcxnJgdLDyrd5eAANtmr+SPCTMknQbQbUkZTslCuBL/4cG5H4wjLE9oOju47WAOc7bd+aOX0GBLNoC+L0gD8UrK1jLxq3todjSCNitYFvgtC/1qcPzDJj9j16w3rgBFgeSHxU5gbsX0RWKY+u/BdjVDwWdxeprvB8doDhGZUuPWt1xNsURXg95MxDkWQZKaAVh8XDvSzx+Xle7Ra77NcjR8W+rtOu2vCMkVfDSPAnBgmV/rOtzf3VGULjW9RisUsG/wG5Pk0UKnL7l5c4QILC+x7wZ4TpBAJ+i01PFPR5WMz5BYR4zY4my4VXDrEPPQtID9dzz7A25qGxio+yTfn2POC2vGiUkmacUKxeP8AAPnsiilPWeN0dcE62OvXP6lCCqu6+j4nZ2OlRc96Uu5CX+VdcUmWr/le84F3lZyyxOUBEFNXF8/tsHnRc+TGdvK0favl+WynYrh8Zl6VcTdmtEoZ/ZO2TMLrlCl8iIUyEtyajf7k3LNiP4CUCUFfNlCcfoZngWPO3LjXyZ+prHm0PSAhL0fW+4YQiwUEMqSVf9Phu2uOMB8Dd9UG0eTjOnP/vM58TU2vJFXfGCsByEZx4mdL/avXJdJykbXwxOw8WwLKTvEOApEM7qZGjQyxBOz6rT8fDoSeeRoywVz8oJM=
    storageProviderEndpoint: ocs-provider-server.openshift-storage.svc:50051
  status:
    id: 39cbdbd1-ca63-4c2e-a1f0-47a6caab0c27
    phase: Connected
kind: List
metadata:
  resourceVersion: ""

> oc get storageconsumer -oyaml
apiVersion: v1
items:
- apiVersion: ocs.openshift.io/v1alpha1
  kind: StorageConsumer
  metadata:
    creationTimestamp: "2025-03-27T17:15:44Z"
    generation: 2
    name: internal
    namespace: openshift-storage
    ownerReferences:
    - apiVersion: ocs.openshift.io/v1
      blockOwnerDeletion: true
      controller: true
      kind: StorageCluster
      name: ocs-storagecluster
      uid: 33a33f5a-03c4-474e-800a-4cd3fc1c5056
    resourceVersion: "9743709"
    uid: 39cbdbd1-ca63-4c2e-a1f0-47a6caab0c27
  spec:
    enable: true
    resourceNameMappingConfigMap:
      name: storageconsumer-internal
    storageClasses:
    - name: ocs-storagecluster-ceph-rbd
    - name: ocs-storagecluster-cephfs
    volumeGroupSnapshotClasses:
    - name: ocs-storagecluster-ceph-rbd-groupsnapclass
    - name: ocs-storagecluster-cephfs-groupsnapclass
    volumeSnapshotClasses:
    - name: ocs-storagecluster-rbdplugin-snapclass
    - name: ocs-storagecluster-cephfsplugin-snapclass
  status:
    cephResources:
    - kind: NooBaaAccount
      name: internal
      status: Rejected
    client:
      clientId: 20ea6eb4-7fc1-44f4-98ca-81ad818f78b9
      clusterId: b4d7e6b7-ed7e-483e-bea0-76a388c226d0
      clusterName: resoni-c1.ocs.syseng.devcluster.openshift.com
      name: ocs-storagecluster
      operatorNamespace: openshift-storage
      operatorVersion: 4.19.0
      platformVersion: 4.18.4
    lastHeartbeat: "2025-03-27T18:31:15Z"
    onboardingTicketSecret:
      name: ""
    resourceNameMappingConfigMap:
      name: storageconsumer-internal
    state: Configuring
kind: List
metadata:
  resourceVersion: ""

> oc get cephblockpoolradosnamespace,cephfilesystemsubvolumegroup,cephclients
NAME                                                                                 PHASE   BLOCKPOOL                          AGE
cephblockpoolradosnamespace.ceph.rook.io/ocs-storagecluster-cephblockpool-internal   Ready   ocs-storagecluster-cephblockpool   2m27s

NAME                                                 PHASE   FILESYSTEM                          QUOTA   AGE
cephfilesystemsubvolumegroup.ceph.rook.io/internal   Ready   ocs-storagecluster-cephfilesystem           2m27s

NAME                                                                          PHASE   AGE
cephclient.ceph.rook.io/cephfs-node-c7798322de691b52cd45873b3394d062          Ready   2m28s
cephclient.ceph.rook.io/cephfs-provisioner-c7798322de691b52cd45873b3394d062   Ready   2m28s
cephclient.ceph.rook.io/rbd-node-c7798322de691b52cd45873b3394d062             Ready   2m28s
cephclient.ceph.rook.io/rbd-provisioner-c7798322de691b52cd45873b3394d062      Ready   2m28s
```
author_association: CONTRIBUTOR
user: login: leelavg
created_at: 2025-03-27T18:44:33Z
body: /unhold
author_association: CONTRIBUTOR
user: login: nb-ohad
created_at: 2025-03-27T18:54:13Z
body: /override ci/prow/ci-bundle-ocs-operator-bundle
/override ci/prow/images
/override ci/prow/ocs-operator-bundle-e2e-aws
author_association: CONTRIBUTOR
user: login: openshift-ci[bot]
created_at: 2025-03-27T18:54:20Z
body: @nb-ohad: Overrode contexts on behalf of nb-ohad: ci/prow/ci-bundle-ocs-operator-bundle, ci/prow/images, ci/prow/ocs-operator-bundle-e2e-aws

<details>

In response to [this](https://github.com/red-hat-storage/ocs-operator/pull/3075#issuecomment-2759111269):

>/override ci/prow/ci-bundle-ocs-operator-bundle
>/override ci/prow/images
>/override ci/prow/ocs-operator-bundle-e2e-aws


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>
author_association: CONTRIBUTOR
user: login: nb-ohad
created_at: 2025-03-27T18:57:16Z
body: /lgtm
author_association: CONTRIBUTOR
user: login: openshift-ci[bot]
created_at: 2025-03-27T18:57:24Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/red-hat-storage/ocs-operator/pull/3075#" title="Author self-approved">leelavg</a>*, *<a href="https://github.com/red-hat-storage/ocs-operator/pull/3075#issuecomment-2759117896" title="LGTM">nb-ohad</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=red-hat-storage%2Focs-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/red-hat-storage/ocs-operator/blob/main/OWNERS)~~ [nb-ohad]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: CONTRIBUTOR