-
Notifications
You must be signed in to change notification settings - Fork 185
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
controllers: ensure default storageclient exists in provider mode
Signed-off-by: Leela Venkaiah G <[email protected]>
- Loading branch information
Showing
11 changed files
with
176 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package storagecluster | ||
|
||
import ( | ||
"fmt" | ||
|
||
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/services" | ||
kerrors "k8s.io/apimachinery/pkg/api/errors" | ||
cutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||
) | ||
|
||
const ( | ||
storageClientName = "local-storageclient" | ||
|
||
tokenLifetimeInHours = 48 | ||
onboardingPrivateKeyFilePath = "/etc/private-key/key" | ||
) | ||
|
||
type storageClient struct{} | ||
|
||
var _ resourceManager = &storageClient{} | ||
|
||
func (s *storageClient) ensureCreated(r *StorageClusterReconciler, storagecluster *ocsv1.StorageCluster) (reconcile.Result, error) { | ||
|
||
if !storagecluster.Spec.AllowRemoteStorageConsumers { | ||
r.Log.Info("Spec.AllowRemoteStorageConsumers is disabled") | ||
return s.ensureDeleted(r, storagecluster) | ||
} | ||
|
||
storageClient := &ocsclientv1a1.StorageClient{} | ||
storageClient.Name = storageClientName | ||
storageClient.Namespace = r.OperatorNamespace | ||
_, err := cutil.CreateOrUpdate(r.ctx, r.Client, storageClient, func() error { | ||
if storageClient.Status.ConsumerID == "" { | ||
token, err := services.GenerateOnboardingToken(tokenLifetimeInHours, onboardingPrivateKeyFilePath) | ||
if err != nil { | ||
return fmt.Errorf("unable to generate onboarding token: %v", err) | ||
} | ||
storageClient.Spec.OnboardingTicket = token | ||
} | ||
storageClient.Spec.StorageProviderEndpoint = storagecluster.Status.StorageProviderEndpoint | ||
return nil | ||
}) | ||
if err != nil { | ||
r.Log.Error(err, "Failed to create local StorageClient CR") | ||
return reconcile.Result{}, nil | ||
} | ||
|
||
return reconcile.Result{}, nil | ||
} | ||
|
||
func (s *storageClient) ensureDeleted(r *StorageClusterReconciler, _ *ocsv1.StorageCluster) (reconcile.Result, error) { | ||
storageClient := &ocsclientv1a1.StorageClient{} | ||
storageClient.Name = storageClientName | ||
storageClient.Namespace = r.OperatorNamespace | ||
if err := r.Delete(r.ctx, storageClient); err != nil && !kerrors.IsNotFound(err) { | ||
r.Log.Error(err, "Failed to initiate deletion of local StorageClient CR") | ||
return reconcile.Result{}, err | ||
} | ||
return reconcile.Result{}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package services | ||
|
||
import ( | ||
"crypto" | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/sha256" | ||
"crypto/x509" | ||
"encoding/base64" | ||
"encoding/json" | ||
"encoding/pem" | ||
"fmt" | ||
"os" | ||
"time" | ||
|
||
"github.com/google/uuid" | ||
) | ||
|
||
// 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) { | ||
tokenExpirationDate := time.Now(). | ||
Add(time.Duration(tokenLifetimeInHours) * time.Hour). | ||
Unix() | ||
|
||
payload, err := json.Marshal(OnboardingTicket{ | ||
ID: uuid.New().String(), | ||
ExpirationDate: tokenExpirationDate, | ||
}) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to marshal the payload: %v", err) | ||
} | ||
|
||
encodedPayload := base64.StdEncoding.EncodeToString(payload) | ||
// Before signing, we need to hash our message | ||
// The hash is what we actually sign | ||
msgHash := sha256.New() | ||
_, err = msgHash.Write(payload) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to hash onboarding token payload: %v", err) | ||
} | ||
|
||
privateKey, err := readAndDecodePrivateKey(privateKeyPath) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to read and decode private key: %v", err) | ||
} | ||
|
||
msgHashSum := msgHash.Sum(nil) | ||
// In order to generate the signature, we provide a random number generator, | ||
// our private key, the hashing algorithm that we used, and the hash sum | ||
// of our message | ||
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, msgHashSum) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to sign private key: %v", err) | ||
} | ||
|
||
encodedSignature := base64.StdEncoding.EncodeToString(signature) | ||
return fmt.Sprintf("%s.%s", encodedPayload, encodedSignature), nil | ||
} | ||
|
||
func readAndDecodePrivateKey(privateKeyPath string) (*rsa.PrivateKey, error) { | ||
pemString, err := os.ReadFile(privateKeyPath) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read private key: %v", err) | ||
} | ||
|
||
Block, _ := pem.Decode(pemString) | ||
privateKey, err := x509.ParsePKCS1PrivateKey(Block.Bytes) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to parse private key: %v", err) | ||
} | ||
return privateKey, nil | ||
} |
Oops, something went wrong.