From 0d14eacdb15eeb48ad9bda945cd49938a2d29e33 Mon Sep 17 00:00:00 2001 From: rchikatw Date: Wed, 8 May 2024 13:54:49 +0530 Subject: [PATCH] Changes to onboarding token api to include quota in body Signed-off-by: rchikatw --- controllers/storagecluster/storageclient.go | 2 +- controllers/util/provider.go | 11 ++++-- services/types.go | 5 ++- .../handlers/onboardingtokens/handler.go | 39 +++++++++++++++++-- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/controllers/storagecluster/storageclient.go b/controllers/storagecluster/storageclient.go index 9aeb0671f7..19254da491 100644 --- a/controllers/storagecluster/storageclient.go +++ b/controllers/storagecluster/storageclient.go @@ -31,7 +31,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) + token, err := util.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, nil) 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 ed84914960..35db1f49a2 100644 --- a/controllers/util/provider.go +++ b/controllers/util/provider.go @@ -19,15 +19,20 @@ 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". -func GenerateOnboardingToken(tokenLifetimeInHours int, privateKeyPath string) (string, error) { +// 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) { tokenExpirationDate := time.Now(). Add(time.Duration(tokenLifetimeInHours) * time.Hour). Unix() - payload, err := json.Marshal(services.OnboardingTicket{ + ticket := services.OnboardingTicket{ ID: uuid.New().String(), ExpirationDate: tokenExpirationDate, - }) + } + if storageQuotaInGiB != nil { + ticket.StorageQuotaInGiB = *storageQuotaInGiB + } + payload, err := json.Marshal(ticket) if err != nil { return "", fmt.Errorf("failed to marshal the payload: %v", err) } diff --git a/services/types.go b/services/types.go index fdc862f630..d4a77a27da 100644 --- a/services/types.go +++ b/services/types.go @@ -1,6 +1,7 @@ package services type OnboardingTicket struct { - ID string `json:"id"` - ExpirationDate int64 `json:"expirationDate,string"` + ID string `json:"id"` + ExpirationDate int64 `json:"expirationDate,string"` + StorageQuotaInGiB uint `json:"storageQuotaInGiB,omitempty"` } diff --git a/services/ux-backend/handlers/onboardingtokens/handler.go b/services/ux-backend/handlers/onboardingtokens/handler.go index 5947b371e0..6c9a70b55e 100644 --- a/services/ux-backend/handlers/onboardingtokens/handler.go +++ b/services/ux-backend/handlers/onboardingtokens/handler.go @@ -1,29 +1,62 @@ package onboardingtokens import ( + "encoding/json" "fmt" "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" ) 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) { switch r.Method { case "POST": - handlePost(w, tokenLifetimeInHours) + handlePost(w, r, tokenLifetimeInHours) default: handleUnsupportedMethod(w, r) } } -func handlePost(w http.ResponseWriter, tokenLifetimeInHours int) { - if onboardingToken, err := util.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath); err != nil { +func handlePost(w http.ResponseWriter, r *http.Request, tokenLifetimeInHours int) { + 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("a); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if quota.Value == 0 { + http.Error(w, fmt.Sprintf("invalid value sent in request body, value should be greater than 0: %v", 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) + } + if onboardingToken, err := util.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath, storageQuotaInGiB); err != nil { klog.Errorf("failed to get onboardig token: %v", err) w.WriteHeader(http.StatusInternalServerError) w.Header().Set("Content-Type", handlers.ContentTypeTextPlain)