Skip to content

Commit

Permalink
create StorageCluster peer token secret on the hub
Browse files Browse the repository at this point in the history
Signed-off-by: Umanga Chapagain <[email protected]>
  • Loading branch information
umangachapagain committed Jul 22, 2024
1 parent 6570168 commit 25fdcf2
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 1 deletion.
48 changes: 48 additions & 0 deletions addons/agent_mirrorpeer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"log/slog"
"strconv"
Expand Down Expand Up @@ -156,6 +157,53 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, fmt.Errorf("few failures occurred while labeling RBD StorageClasses: %v", errs)
}
}

if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async {
if mirrorPeer.Status.Phase == multiclusterv1alpha1.ExchangedSecret {
logger.Info("Cleaning up stale onboarding token", "Token", string(mirrorPeer.GetUID()))
err = deleteStorageClusterPeerTokenSecret(ctx, r.HubClient, r.SpokeClusterName, string(mirrorPeer.GetUID()))
if err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
if mirrorPeer.Status.Phase == multiclusterv1alpha1.ExchangingSecret {
var token corev1.Secret
err = r.HubClient.Get(ctx, types.NamespacedName{Namespace: r.SpokeClusterName, Name: string(mirrorPeer.GetUID())}, &token)
if err != nil && !errors.IsNotFound(err) {
return ctrl.Result{}, err
}
if err == nil {
// TODO: Replace it with exported type from ocs-operator
type OnboardingTicket struct {
ID string `json:"id"`
ExpirationDate int64 `json:"expirationDate,string"`
StorageQuotaInGiB uint `json:"storageQuotaInGiB,omitempty"`
}
var ticketData OnboardingTicket
err = json.Unmarshal(token.Data["storagecluster-peer-token"], &ticketData)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed to unmarshal onboarding ticket message. %w", err)
}
if ticketData.ExpirationDate > time.Now().Unix() {
logger.Info("Onboarding token has not expired yet. Not renewing it.", "Token", token.Name, "ExpirationDate", ticketData.ExpirationDate)
return ctrl.Result{}, nil
}
logger.Info("Onboarding token has expired. Deleting it", "Token", token.Name)
err = deleteStorageClusterPeerTokenSecret(ctx, r.HubClient, r.SpokeClusterName, string(mirrorPeer.GetUID()))
if err != nil {
return ctrl.Result{}, err
}
}
logger.Info("Creating a new onboarding token", "Token", token.Name)
err = createStorageClusterPeerTokenSecret(ctx, r.HubClient, r.Scheme, r.SpokeClusterName, "openshift-storage", mirrorPeer, scr) //TODO: get odfOperatorNamespace from addon flags
if err != nil {
logger.Error("Failed to create StorageCluster peer token on the hub.", "error", err)
return ctrl.Result{}, err
}
}
}

return ctrl.Result{}, nil
}

Expand Down
106 changes: 106 additions & 0 deletions addons/onboarding_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package addons

import (
"context"
"crypto/tls"
"fmt"
"io"
"net/http"
"os"

"github.com/red-hat-storage/odf-multicluster-orchestrator/api/v1alpha1"
multiclusterv1alpha1 "github.com/red-hat-storage/odf-multicluster-orchestrator/api/v1alpha1"
"github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func requestStorageClusterPeerToken(ctx context.Context, proxyServiceNamespace string) (string, error) {
token, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil {
return "", err
}
url := fmt.Sprintf("https://ux-backend-proxy.%s.svc.cluster.local:8888/onboarding-tokens", proxyServiceNamespace)
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}

req, err := http.NewRequestWithContext(ctx, "POST", url, nil)
if err != nil {
return "", err
}

req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(token)))

resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}

if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf(http.StatusText(resp.StatusCode))
}

return string(body), nil
}

func createStorageClusterPeerTokenSecret(ctx context.Context, client client.Client, scheme *runtime.Scheme, spokeClusterName string, odfOperatorNamespace string, mirrorPeer multiclusterv1alpha1.MirrorPeer, storageClusterRef *v1alpha1.StorageClusterRef) error {
uniqueSecretName := string(mirrorPeer.GetUID())
var storageClusterPeerTokenSecret corev1.Secret
err := client.Get(ctx, types.NamespacedName{Namespace: spokeClusterName, Name: uniqueSecretName}, &storageClusterPeerTokenSecret)
if err != nil && !errors.IsNotFound(err) {
return fmt.Errorf("got an error. %w", err)
}
if err == nil {
return errors.NewAlreadyExists(corev1.Resource("string"), uniqueSecretName)
}

token, err := requestStorageClusterPeerToken(ctx, odfOperatorNamespace)
if err != nil {
return fmt.Errorf("unable to generate StorageClusterPeer token. %w", err)
}

customData := make(map[string][]byte, 2)
customData["storagecluster-peer-token"] = []byte(token)
customData[utils.NamespaceKey] = []byte(storageClusterRef.Namespace)

expectedStorageClusterPeerTokenSecret, err := generateBlueSecret(corev1.Secret{}, utils.InternalLabel, uniqueSecretName, storageClusterRef.Name, spokeClusterName, customData)
if err != nil {
return fmt.Errorf("unable to generate secret from StorageClusterPeer token. %w", err)
}

err = controllerutil.SetOwnerReference(&mirrorPeer, expectedStorageClusterPeerTokenSecret, scheme)
if err != nil {
return fmt.Errorf("unable to generate secret from StorageClusterPeer token. %w", err)
}

return client.Create(ctx, expectedStorageClusterPeerTokenSecret)
}

func deleteStorageClusterPeerTokenSecret(ctx context.Context, client client.Client, tokenNamespace string, tokenName string) error {
token := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: tokenName,
Namespace: tokenNamespace,
},
}

err := client.Delete(ctx, token)
if err != nil && !errors.IsNotFound(err) {
return err
}
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ rules:
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["ocs.openshift.io"]
resources: ["storageclusters"]
verbs: ["get", "list", "watch", "update"]
verbs: ["get", "list", "watch", "create", "update"]
- apiGroups: ["objectbucket.io"]
resources: ["objectbucketclaims"]
verbs: ["get", "create", "list", "watch", "delete"]
Expand Down

0 comments on commit 25fdcf2

Please sign in to comment.