Skip to content

Commit

Permalink
Merge pull request #221 from vbnrh/mirror-api-changes
Browse files Browse the repository at this point in the history
Create or update StorageClusterPeer
  • Loading branch information
openshift-merge-bot[bot] authored Oct 4, 2024
2 parents 22d492b + b4e0f4f commit 8c27440
Show file tree
Hide file tree
Showing 18 changed files with 704 additions and 227 deletions.
85 changes: 29 additions & 56 deletions addons/agent_mirrorpeer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,12 @@ package addons

import (
"context"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"log/slog"
"strconv"
"time"

obv1alpha1 "github.com/kube-object-storage/lib-bucket-provisioner/pkg/apis/objectbucket.io/v1alpha1"
ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1"
multiclusterv1alpha1 "github.com/red-hat-storage/odf-multicluster-orchestrator/api/v1alpha1"
"github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils"
Expand Down Expand Up @@ -118,14 +115,21 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request)
return ctrl.Result{}, nil
}

hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.SpokeClient, mirrorPeer, true)

if err != nil {
logger.Error("Failed to check if storage client ref exists", "error", err)
return ctrl.Result{}, err
}

logger.Info("Creating S3 buckets")
err = r.createS3(ctx, mirrorPeer, scr.Namespace)
err = r.createS3(ctx, mirrorPeer, scr.Namespace, hasStorageClientRef)
if err != nil {
logger.Error("Failed to create ODR S3 resources", "error", err)
return ctrl.Result{}, err
}

if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async {
if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async && !hasStorageClientRef {
clusterFSIDs := make(map[string]string)
logger.Info("Fetching clusterFSIDs")
err = r.fetchClusterFSIDs(ctx, &mirrorPeer, clusterFSIDs)
Expand Down Expand Up @@ -159,7 +163,7 @@ func (r *MirrorPeerReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}
}

if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async {
if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async && hasStorageClientRef {
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()))
Expand Down Expand Up @@ -309,60 +313,27 @@ func (r *MirrorPeerReconciler) labelRBDStorageClasses(ctx context.Context, stora
return errs
}

func (r *MirrorPeerReconciler) createS3(ctx context.Context, mirrorPeer multiclusterv1alpha1.MirrorPeer, scNamespace string) error {
noobaaOBC, err := r.getS3bucket(ctx, mirrorPeer, scNamespace)
if err != nil {
if errors.IsNotFound(err) {
r.Logger.Info("ODR ObjectBucketClaim not found, creating new one", "MirrorPeer", mirrorPeer.Name, "namespace", scNamespace)
err = r.SpokeClient.Create(ctx, noobaaOBC)
if err != nil {
r.Logger.Error("Failed to create ODR ObjectBucketClaim", "error", err, "MirrorPeer", mirrorPeer.Name, "namespace", scNamespace)
return err
}
func (r *MirrorPeerReconciler) createS3(ctx context.Context, mirrorPeer multiclusterv1alpha1.MirrorPeer, scNamespace string, hasStorageClientRef bool) error {
bucketCount := 1
if hasStorageClientRef {
bucketCount = 2
}
for index := 0; index < bucketCount; index++ {
bucketNamespace := utils.GetEnv("ODR_NAMESPACE", scNamespace)
var bucketName string
if hasStorageClientRef {
bucketName = utils.GenerateBucketName(mirrorPeer, mirrorPeer.Spec.Items[index].StorageClusterRef.Name)
} else {
r.Logger.Error("Failed to retrieve ODR ObjectBucketClaim", "error", err, "MirrorPeer", mirrorPeer.Name, "namespace", scNamespace)
bucketName = utils.GenerateBucketName(mirrorPeer)
}
operationResult, err := utils.CreateOrUpdateObjectBucketClaim(ctx, r.SpokeClient, bucketName, bucketNamespace)
if err != nil {
return err
}
} else {
r.Logger.Info("ODR ObjectBucketClaim already exists, no action needed", "MirrorPeer", mirrorPeer.Name, "namespace", scNamespace)
}
return nil
}

func (r *MirrorPeerReconciler) getS3bucket(ctx context.Context, mirrorPeer multiclusterv1alpha1.MirrorPeer, scNamespace string) (*obv1alpha1.ObjectBucketClaim, error) {
var peerAccumulator string
for _, peer := range mirrorPeer.Spec.Items {
peerAccumulator += peer.ClusterName
}
checksum := sha1.Sum([]byte(peerAccumulator))

bucketGenerateName := utils.BucketGenerateName
// truncate to bucketGenerateName + "-" + first 12 (out of 20) byte representations of sha1 checksum
bucket := fmt.Sprintf("%s-%s", bucketGenerateName, hex.EncodeToString(checksum[:]))[0 : len(bucketGenerateName)+1+12]
namespace := utils.GetEnv("ODR_NAMESPACE", scNamespace)

noobaaOBC := &obv1alpha1.ObjectBucketClaim{
ObjectMeta: metav1.ObjectMeta{
Name: bucket,
Namespace: namespace,
},
Spec: obv1alpha1.ObjectBucketClaimSpec{
BucketName: bucket,
StorageClassName: namespace + ".noobaa.io",
},
r.Logger.Info(fmt.Sprintf("ObjectBucketClaim %s was %s in namespace %s", bucketName, operationResult, bucketNamespace))
}

err := r.SpokeClient.Get(ctx, types.NamespacedName{Name: bucket, Namespace: namespace}, noobaaOBC)
if err != nil {
if errors.IsNotFound(err) {
r.Logger.Info("ObjectBucketClaim not found, will be created", "bucket", bucket, "namespace", namespace)
} else {
r.Logger.Error("Failed to get ObjectBucketClaim", "error", err, "bucket", bucket, "namespace", namespace)
}
} else {
r.Logger.Info("ObjectBucketClaim retrieved successfully", "bucket", bucket, "namespace", namespace)
}
return noobaaOBC, err
return nil
}

// enableMirroring is a wrapper function around toggleMirroring to enable mirroring in a storage cluster
Expand Down Expand Up @@ -548,7 +519,9 @@ func (r *MirrorPeerReconciler) deleteGreenSecret(ctx context.Context, spokeClust
// deleteS3 deletes the S3 bucket in the storage cluster namespace, each new mirrorpeer generates
// a new bucket, so we do not need to check if the bucket is being used by another mirrorpeer
func (r *MirrorPeerReconciler) deleteS3(ctx context.Context, mirrorPeer multiclusterv1alpha1.MirrorPeer, scNamespace string) error {
noobaaOBC, err := r.getS3bucket(ctx, mirrorPeer, scNamespace)
bucketName := utils.GenerateBucketName(mirrorPeer)
bucketNamespace := utils.GetEnv("ODR_NAMESPACE", scNamespace)
noobaaOBC, err := utils.GetObjectBucketClaim(ctx, r.SpokeClient, bucketName, bucketNamespace)
if err != nil {
if errors.IsNotFound(err) {
r.Logger.Info("ODR ObjectBucketClaim not found, skipping deletion", "namespace", scNamespace, "MirrorPeer", mirrorPeer.Name)
Expand Down
29 changes: 25 additions & 4 deletions addons/agent_mirrorpeer_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,27 @@ import (
)

var (
odfInfoConfigMap = corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "odf-info",
Namespace: "test-namespace", // Use a generic namespace
UID: types.UID("268e6cdb-54fc-4f10-afab-67b106880be3"),
},
Data: map[string]string{
"test-namespace_test-storagecluster.config.yaml": `
version: 4.17.0-95.stable
deploymentType: internal
clients: []
storageCluster:
namespacedName:
namespace: test-namespace
name: test-storagecluster
storageProviderEndpoint: ""
cephClusterFSID: 986532da-8dba-4d35-a8d2-12f037712b39
storageSystemName: ocs-storagecluster-storagesystem
`,
},
}
mpItems = []multiclusterv1alpha1.PeerRef{
{
ClusterName: "cluster1",
Expand Down Expand Up @@ -123,7 +144,7 @@ func TestMirrorPeerReconcile(t *testing.T) {
Namespace: pr.StorageClusterRef.Namespace,
},
Spec: ocsv1.StorageClusterSpec{
Mirroring: ocsv1.MirroringSpec{
Mirroring: &ocsv1.MirroringSpec{
Enabled: false,
PeerSecretNames: secretNames,
},
Expand All @@ -141,7 +162,7 @@ func TestMirrorPeerReconcile(t *testing.T) {
rcm.Data = make(map[string]string)
rcm.Data[RookCSIEnableKey] = "false"

fakeSpokeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&storageCluster, &rcm, &clusterPeerToken, &exchangedSecret1, &exchangedSecret2, rbdStorageClass, cephfsStorageClass).Build()
fakeSpokeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&storageCluster, &rcm, &clusterPeerToken, &exchangedSecret1, &exchangedSecret2, rbdStorageClass, cephfsStorageClass, &odfInfoConfigMap).Build()

r := MirrorPeerReconciler{
HubClient: fakeHubClient,
Expand Down Expand Up @@ -198,7 +219,7 @@ func TestDisableMirroring(t *testing.T) {
Namespace: pr.StorageClusterRef.Namespace,
},
Spec: ocsv1.StorageClusterSpec{
Mirroring: ocsv1.MirroringSpec{
Mirroring: &ocsv1.MirroringSpec{
Enabled: true,
},
},
Expand Down Expand Up @@ -283,7 +304,7 @@ func TestDeleteGreenSecret(t *testing.T) {
}

func TestDeleteS3(t *testing.T) {
bucketName := "odrbucket-b1b922184baf"
bucketName := utils.GenerateBucketName(mirrorPeer)
ctx := context.TODO()
scheme := mgrScheme
fakeHubClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&mirrorpeer1).Build()
Expand Down
2 changes: 1 addition & 1 deletion addons/green_secret_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var (
Namespace: "openshift-storage",
},
Spec: ocsv1.StorageClusterSpec{
Mirroring: ocsv1.MirroringSpec{
Mirroring: &ocsv1.MirroringSpec{
PeerSecretNames: []string{},
},
},
Expand Down
6 changes: 4 additions & 2 deletions api/v1alpha1/mirrorpeer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ const (

// StorageClusterRef holds a reference to a StorageCluster
type StorageClusterRef struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Name string `json:"name"`

// +kubebuilder:validation:Optional
Namespace string `json:"namespace,omitempty"`
}

// PeerRef holds a reference to a mirror peer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ spec:
type: string
required:
- name
- namespace
type: object
required:
- clusterName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ spec:
type: string
required:
- name
- namespace
type: object
required:
- clusterName
Expand Down
12 changes: 12 additions & 0 deletions controllers/drpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ func (r *DRPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
return ctrl.Result{}, err
}

// Check if the MirrorPeer contains StorageClient reference
hasStorageClientRef, err := utils.IsStorageClientType(ctx, r.HubClient, *mirrorPeer, false)
if err != nil {
logger.Error("Failed to determine if MirrorPeer contains StorageClient reference", "error", err)
return ctrl.Result{}, err
}

if hasStorageClientRef {
logger.Info("MirrorPeer contains StorageClient reference. Skipping creation of VolumeReplicationClasses", "MirrorPeer", mirrorPeer.Name)
return ctrl.Result{}, nil
}

if mirrorPeer.Spec.Type == multiclusterv1alpha1.Async {
clusterFSIDs := make(map[string]string)
logger.Info("Fetching cluster FSIDs")
Expand Down
20 changes: 19 additions & 1 deletion controllers/drpolicy_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package controllers
import (
"context"
"fmt"
"os"
"testing"

ramenv1alpha1 "github.com/ramendr/ramen/api/v1alpha1"
multiclusterv1alpha1 "github.com/red-hat-storage/odf-multicluster-orchestrator/api/v1alpha1"
"github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils"
viewv1beta1 "github.com/stolostron/multicloud-operators-foundation/pkg/apis/view/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -100,6 +102,7 @@ func TestDRPolicyReconcile(t *testing.T) {

func getFakeDRPolicyReconciler(drpolicy *ramenv1alpha1.DRPolicy, mp *multiclusterv1alpha1.MirrorPeer) DRPolicyReconciler {
scheme := mgrScheme
os.Setenv("POD_NAMESPACE", "openshift-operators")
ns1 := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: cName1,
Expand Down Expand Up @@ -139,8 +142,23 @@ func getFakeDRPolicyReconciler(drpolicy *ramenv1alpha1.DRPolicy, mp *multicluste
},
Type: "multicluster.odf.openshift.io/secret-type",
}
odfClientInfoConfigMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "odf-client-info",
Namespace: os.Getenv("POD_NAMESPACE"),
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: viewv1beta1.GroupVersion.String(),
Kind: "ManagedClusterView",
Name: "mcv-1",
UID: "mcv-uid",
},
},
},
Data: map[string]string{},
}

fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(drpolicy, mp, ns1, ns2, &hubSecret1, &hubSecret2).Build()
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(drpolicy, mp, ns1, ns2, &hubSecret1, &hubSecret2, odfClientInfoConfigMap).Build()

r := DRPolicyReconciler{
HubClient: fakeClient,
Expand Down
2 changes: 1 addition & 1 deletion controllers/managedclusterview_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (r *ManagedClusterViewReconciler) SetupWithManager(mgr ctrl.Manager) error
}

func hasODFInfoInScope(mc *viewv1beta1.ManagedClusterView) bool {
if mc.Spec.Scope.Name == ODFInfoConfigMapName && mc.Spec.Scope.Resource == ConfigMapResourceType {
if mc.Spec.Scope.Name == utils.ODFInfoConfigMapName && mc.Spec.Scope.Resource == ConfigMapResourceType {
return true
}
return false
Expand Down
Loading

0 comments on commit 8c27440

Please sign in to comment.