diff --git a/controllers/storagecluster/storageclient.go b/controllers/storagecluster/storageclient.go index 19254da491..94f935fb37 100644 --- a/controllers/storagecluster/storageclient.go +++ b/controllers/storagecluster/storageclient.go @@ -6,6 +6,7 @@ import ( 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" + "github.com/red-hat-storage/ocs-operator/v4/services" kerrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -31,7 +32,7 @@ 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.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil) + token, err := util.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil, services.ClientRole) if err != nil { return fmt.Errorf("unable to generate onboarding token: %v", err) } diff --git a/controllers/util/provider.go b/controllers/util/provider.go index 35db1f49a2..0c8517ac24 100644 --- a/controllers/util/provider.go +++ b/controllers/util/provider.go @@ -20,7 +20,7 @@ import ( // GenerateOnboardingToken generates a 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 GenerateOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotaInGiB *uint) (string, error) { +func GenerateOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, storageQuotaInGiB *uint, role services.OnboardingSubjectRole) (string, error) { tokenExpirationDate := time.Now(). Add(time.Duration(tokenLifetimeInHours) * time.Hour). Unix() @@ -28,6 +28,7 @@ func GenerateOnboardingToken(tokenLifetimeInHours int, privateKeyPath string, st ticket := services.OnboardingTicket{ ID: uuid.New().String(), ExpirationDate: tokenExpirationDate, + SubjectRole: role, } if storageQuotaInGiB != nil { ticket.StorageQuotaInGiB = *storageQuotaInGiB diff --git a/services/types.go b/services/types.go index d4a77a27da..714da01b94 100644 --- a/services/types.go +++ b/services/types.go @@ -1,7 +1,16 @@ package services +type OnboardingSubjectRole string + +const ( + ClientRole OnboardingSubjectRole = "ocs-client" + PeerRole OnboardingSubjectRole = "ocs-peer" +) + type OnboardingTicket struct { ID string `json:"id"` ExpirationDate int64 `json:"expirationDate,string"` StorageQuotaInGiB uint `json:"storageQuotaInGiB,omitempty"` + // OnboardingSubjectRole can be either ocs-client or ocs-peer + SubjectRole OnboardingSubjectRole `json:"subjectRole,string"` } diff --git a/services/ux-backend/handlers/onboardingtokens/handler.go b/services/ux-backend/handlers/onboardingtokens/handler.go index e8f4e55b41..4ea6c3ff90 100644 --- a/services/ux-backend/handlers/onboardingtokens/handler.go +++ b/services/ux-backend/handlers/onboardingtokens/handler.go @@ -5,9 +5,12 @@ import ( "fmt" "math" "net/http" + "strings" "github.com/red-hat-storage/ocs-operator/v4/controllers/util" + "github.com/red-hat-storage/ocs-operator/v4/services" "github.com/red-hat-storage/ocs-operator/v4/services/ux-backend/handlers" + "k8s.io/klog/v2" "k8s.io/utils/ptr" ) @@ -33,32 +36,44 @@ func HandleMessage(w http.ResponseWriter, r *http.Request, tokenLifetimeInHours func handlePost(w http.ResponseWriter, r *http.Request, tokenLifetimeInHours int) { var storageQuotaInGiB *uint + // to ensure backward compatibility, if the role is empty, we assume it to be client + role := services.ClientRole // 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"` + var body = struct { + SubjectRole string `json:"subjectRole"` + Value uint `json:"value"` + Unit string `json:"unit"` }{} - if err = json.NewDecoder(r.Body).Decode("a); err != nil { + if err = json.NewDecoder(r.Body).Decode(&body); 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) + if strings.ToLower(body.SubjectRole) == string(services.PeerRole) { + role = services.PeerRole + } else if strings.ToLower(body.SubjectRole) == string(services.ClientRole) || body.SubjectRole == "" { + // to ensure backward compatibility, if the role is empty, we assume it to be client + role = services.ClientRole + if body.Value == 0 || body.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, body.Value), http.StatusBadRequest) + return + } + unitAsGiB, ok := unitToGib[body.Unit] + if !ok { + http.Error(w, fmt.Sprintf("invalid Unit type sent in request body, Valid types are [Gi,Ti,Pi]: %v", body.Unit), http.StatusBadRequest) + return + } + storageQuotaInGiB = ptr.To(unitAsGiB * body.Value) + } else { + http.Error(w, fmt.Sprintf("invalid OnboardingSubjectRole sent in request body, Valid roles are [mirroring-peer,client]: %v", body.SubjectRole), 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) } - if onboardingToken, err := util.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, storageQuotaInGiB); err != nil { - klog.Errorf("failed to get onboardig token: %v", err) + + if onboardingToken, err := util.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, storageQuotaInGiB, role); err != nil { + klog.Errorf("failed to get onboarding token: %v", err) w.WriteHeader(http.StatusInternalServerError) w.Header().Set("Content-Type", handlers.ContentTypeTextPlain)