diff --git a/addons/blue_secret_controller_test.go b/addons/blue_secret_controller_test.go new file mode 100644 index 00000000..f12ce434 --- /dev/null +++ b/addons/blue_secret_controller_test.go @@ -0,0 +1,143 @@ +package addons + +import ( + "context" + "testing" + + ocsv1 "github.com/red-hat-storage/ocs-operator/api/v1" + "github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils" + rookv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +// Define the test secret and related data +var ( + spokeClusterName = "test-cluster" + sData = map[string][]byte{ + "token": []byte("ZXlKbWMybGtJam9pTjJFelpEWmlPREV0WVRVMVpDMDBOR1psTFRnMFpEQXRORFpqTmpkalpETTVOV05oSWl3aVkyeHBaVzUwWDJsa0lqb2ljbUprTFcxcGNuSnZjaTF3WldWeUlpd2lhMlY1SWpvaVFWRkJXRmRaT1cxcU56STJTMmhCUVdWWFMyWXdaMkpSWjBkQlpVbDNUR3RJVmtaaU5HYzlQU0lzSW0xdmJsOW9iM04wSWpvaU1UY3lMak14TGpFek1TNHhPRE02TXpNd01Dd3hOekl1TXpFdU1UWTNMakUwTXpvek16QXdMREUzTWk0ek1TNDFPUzR4TlRFNk16TXdNQ0lzSW01aGJXVnpjR0ZqWlNJNkltOXdaVzV6YUdsbWRDMXpkRzl5WVdkbEluMD0="), + "cluster": []byte("b2NzLXN0b3JhZ2VjbHVzdGVyLWNlcGhjbHVzdGVy"), + } + + managedClusterSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-peer-token-ocs-storagecluster-cephcluster", + Namespace: "openshift-storage", + Labels: map[string]string{ + "app": "rook", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "ceph.rook.io/v1", + Kind: "CephCluster", + Name: "ocs-storagecluster-cephcluster", + UID: "390fa888-59c0-4212-8e3b-e426e52c800e", + }, + }, + }, + Data: sData, + Type: "kubernetes.io/rook", + } + + storageCluster = &ocsv1.StorageCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ocs-storagecluster", + Namespace: "openshift-storage", + UID: "12345678-1234-1234-1234-123456789012", + }, + } + + cephCluster = &rookv1.CephCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ocs-storagecluster-cephcluster", + Namespace: "openshift-storage", + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "ocs.openshift.io/v1", + Kind: "StorageCluster", + Name: "ocs-storagecluster", + UID: "12345678-1234-1234-1234-123456789012", + }, + }, + }, + Spec: rookv1.ClusterSpec{}, + Status: rookv1.ClusterStatus{}, + } + hubClusterSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: utils.CreateUniqueSecretName(spokeClusterName, managedClusterSecret.Namespace, storageCluster.Name), + Namespace: spokeClusterName, + Labels: map[string]string{ + utils.SecretLabelTypeKey: string(utils.SourceLabel), + }, + }, + Data: sData, + Type: "kubernetes.io/rook", + } +) + +func TestBlueSecretReconciler_Reconcile(t *testing.T) { + ctx := context.TODO() + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = ocsv1.AddToScheme(scheme) + _ = rookv1.AddToScheme(scheme) + + // Create fake clients + fakeHubClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects().Build() + fakeSpokeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(managedClusterSecret, storageCluster, cephCluster).Build() + + logger := utils.GetLogger(utils.GetZapLogger(true)) + reconciler := &BlueSecretReconciler{ + HubClient: fakeHubClient, + SpokeClient: fakeSpokeClient, + SpokeClusterName: "test-cluster", + Logger: logger, + } + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Name: managedClusterSecret.Name, + Namespace: managedClusterSecret.Namespace, + }, + } + + // Test cases + tests := []struct { + name string + req ctrl.Request + wantErr bool + }{ + { + name: "Reconcile BlueSecret successfully", + req: req, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := reconciler.Reconcile(ctx, tt.req) + if (err != nil) != tt.wantErr { + t.Errorf("Reconcile() error = %v, wantErr %v", err, tt.wantErr) + } + + reconciledSecret := &corev1.Secret{} + err = fakeHubClient.Get(ctx, types.NamespacedName{ + Name: hubClusterSecret.Name, + Namespace: hubClusterSecret.Namespace, + }, reconciledSecret) + if err != nil { + t.Errorf("Fetching the secret on hub failed %v", err) + } + if reconciledSecret.Labels[utils.SecretLabelTypeKey] != string(utils.SourceLabel) { + t.Errorf("expected label %s to be %s", utils.SecretLabelTypeKey, string(utils.SourceLabel)) + } + + }) + } +} diff --git a/addons/green_secret_controller_test.go b/addons/green_secret_controller_test.go new file mode 100644 index 00000000..4f33aaae --- /dev/null +++ b/addons/green_secret_controller_test.go @@ -0,0 +1,149 @@ +package addons + +import ( + "context" + "encoding/json" + "testing" + + ocsv1 "github.com/red-hat-storage/ocs-operator/api/v1" + "github.com/red-hat-storage/odf-multicluster-orchestrator/addons/setup" + "github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +var ( + greenSecretName = "d8433b8cb5b6d99c4d785ebd6082efd19cad50c" + greenSecretNamespace = "local-cluster" + greenSecretData = map[string][]byte{ + "namespace": []byte("openshift-storage"), + "secret-origin": []byte("rook"), + "storage-cluster-name": []byte("ocs-storagecluster"), + } + + secretDataContent = map[string]string{ + "cluster": "b2NzLXN0b3JhZ2VjbHVzdGVyLWNlcGhjbHVzdGVy", + "token": "ZXlKbWMybGtJam9pTjJFelpEWmlPREV0WVRVMVpDMDBOR1psTFRnMFpEQXRORFpqTmpkalpETTVOV05oSWl3aVkyeHBaVzUwWDJsa0lqb2ljbUprTFcxcGNuSnZjaTF3WldWeUlpd2lhMlY1SWpvaVFWRkJXRmRaT1cxcU56STJTMmhCUVdWWFMyWXdaMkpSWjBkQlpVbDNUR3RJVmtaaU5HYzlQU0lzSW0xdmJsOW9iM04wSWpvaU1UY3lMak14TGpFek1TNHhPRE02TXpNd01Dd3hOekl1TXpFdU1UWTNMakUwTXpvek16QXdMREUzTWk0ek1TNDFPUzR4TlRFNk16TXdNQ0lzSW01aGJXVnpjR0ZqWlNJNkltOXdaVzV6YUdsbWRDMXpkRzl5WVdkbEluMD0=", + } + + encodedSecretData, _ = json.Marshal(secretDataContent) + + greenSecretOnHub = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: greenSecretName, + Namespace: greenSecretNamespace, + Labels: map[string]string{ + utils.SecretLabelTypeKey: string(utils.DestinationLabel), + }, + }, + Data: map[string][]byte{ + "namespace": greenSecretData["namespace"], + "secret-data": encodedSecretData, + "secret-origin": greenSecretData["secret-origin"], + "storage-cluster-name": greenSecretData["storage-cluster-name"], + }, + Type: corev1.SecretTypeOpaque, + } + + storageClusterToUpdate = &ocsv1.StorageCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ocs-storagecluster", + Namespace: "openshift-storage", + }, + Spec: ocsv1.StorageClusterSpec{ + Mirroring: ocsv1.MirroringSpec{ + PeerSecretNames: []string{}, + }, + }, + } + + syncedGreenSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: greenSecretName, + Namespace: "openshift-storage", + Labels: map[string]string{ + utils.CreatedByLabelKey: setup.TokenExchangeName, + }, + }, + Data: map[string][]byte{}, + } +) + +func TestGreenSecretReconciler_Reconcile(t *testing.T) { + ctx := context.TODO() + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = ocsv1.AddToScheme(scheme) + + fakeHubClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(greenSecretOnHub).Build() + fakeSpokeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(storageClusterToUpdate).Build() + + logger := utils.GetLogger(utils.GetZapLogger(true)) + reconciler := &GreenSecretReconciler{ + HubClient: fakeHubClient, + SpokeClient: fakeSpokeClient, + Logger: logger, + } + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Name: greenSecretOnHub.Name, + Namespace: greenSecretOnHub.Namespace, + }, + } + + // Test cases + tests := []struct { + name string + req ctrl.Request + + wantErr bool + }{ + { + name: "Reconcile GreenSecret successfully", + req: req, + + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := reconciler.Reconcile(ctx, tt.req) + if (err != nil) != tt.wantErr { + t.Errorf("Reconcile() error = %v, wantErr %v", err, tt.wantErr) + } + + if tt.name == "Reconcile GreenSecret successfully" { + reconciledSecret := &corev1.Secret{} + err = fakeSpokeClient.Get(ctx, types.NamespacedName{ + Name: syncedGreenSecret.Name, + Namespace: syncedGreenSecret.Namespace, + }, reconciledSecret) + if err != nil { + t.Errorf("Fetching the secret on spoke cluster failed %v", err) + } + if reconciledSecret.Labels[utils.CreatedByLabelKey] != setup.TokenExchangeName { + t.Errorf("expected label %s to be %s", utils.CreatedByLabelKey, setup.TokenExchangeName) + } + + // Verify storage cluster update + updatedStorageCluster := &ocsv1.StorageCluster{} + err = fakeSpokeClient.Get(ctx, types.NamespacedName{ + Name: storageClusterToUpdate.Name, + Namespace: storageClusterToUpdate.Namespace, + }, updatedStorageCluster) + if err != nil { + t.Errorf("Fetching the storage cluster failed %v", err) + } + if !utils.ContainsString(updatedStorageCluster.Spec.Mirroring.PeerSecretNames, syncedGreenSecret.Name) { + t.Errorf("expected storage cluster to be updated with secret name %s", syncedGreenSecret.Name) + } + } + }) + } +} diff --git a/addons/s3_controller_test.go b/addons/s3_controller_test.go new file mode 100644 index 00000000..aaaf398c --- /dev/null +++ b/addons/s3_controller_test.go @@ -0,0 +1,168 @@ +package addons + +import ( + "context" + "testing" + + obv1alpha1 "github.com/kube-object-storage/lib-bucket-provisioner/pkg/apis/objectbucket.io/v1alpha1" + routev1 "github.com/openshift/api/route/v1" + ocsv1 "github.com/red-hat-storage/ocs-operator/api/v1" + multiclusterv1alpha1 "github.com/red-hat-storage/odf-multicluster-orchestrator/api/v1alpha1" + "github.com/red-hat-storage/odf-multicluster-orchestrator/controllers/utils" + rookv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +var ( + s3SecretName = "test-obc" + s3SecretNamespace = "openshift-storage" + s3SecretData = map[string][]byte{ + utils.AwsAccessKeyId: []byte("test-access-key-id"), + utils.AwsSecretAccessKey: []byte("test-secret-access-key"), + } + managedS3Secret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: s3SecretName, + Namespace: s3SecretNamespace, + }, + Data: s3SecretData, + Type: corev1.SecretTypeOpaque, + } + + configMapData = map[string]string{ + S3BucketName: "test-bucket", + S3BucketRegion: "us-east-1", + } + managedConfigMap = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: s3SecretName, + Namespace: s3SecretNamespace, + }, + Data: configMapData, + } + + storageClusterOnManagedCluster = &ocsv1.StorageCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ocs-storagecluster", + Namespace: s3SecretNamespace, + }, + } + + route = &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: S3RouteName, + Namespace: s3SecretNamespace, + }, + Spec: routev1.RouteSpec{ + Host: "test-host", + }, + } + + objectBucketClaim = &obv1alpha1.ObjectBucketClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: s3SecretName, + Namespace: s3SecretNamespace, + }, + Status: obv1alpha1.ObjectBucketClaimStatus{ + Phase: obv1alpha1.ObjectBucketClaimStatusPhaseBound, + }, + } + + mirrorPeerItems = []multiclusterv1alpha1.PeerRef{ + { + ClusterName: "cluster1", + StorageClusterRef: multiclusterv1alpha1.StorageClusterRef{ + Name: "ocs-storagecluster", + Namespace: "openshift-storage", + }, + }, + { + ClusterName: "cluster2", + StorageClusterRef: multiclusterv1alpha1.StorageClusterRef{ + Name: "ocs-storagecluster", + Namespace: "openshift-storage", + }, + }, + } + mirrorPeer = multiclusterv1alpha1.MirrorPeer{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-mirrorpeer", + }, + Spec: multiclusterv1alpha1.MirrorPeerSpec{ + Type: "async", + Items: mirrorPeerItems, + }, + } +) + +func TestS3SecretReconciler_Reconcile(t *testing.T) { + ctx := context.TODO() + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = obv1alpha1.AddToScheme(scheme) + _ = routev1.AddToScheme(scheme) + _ = multiclusterv1alpha1.AddToScheme(scheme) + _ = rookv1.AddToScheme(scheme) + _ = ocsv1.AddToScheme(scheme) + + fakeHubClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&mirrorPeer).Build() + fakeSpokeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(managedS3Secret, managedConfigMap, route, objectBucketClaim, storageClusterOnManagedCluster).Build() + + logger := utils.GetLogger(utils.GetZapLogger(true)) + reconciler := &S3SecretReconciler{ + HubClient: fakeHubClient, + SpokeClient: fakeSpokeClient, + SpokeClusterName: "cluster1", + Logger: logger, + } + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Name: objectBucketClaim.Name, + Namespace: objectBucketClaim.Namespace, + }, + } + + // Test cases + tests := []struct { + name string + req ctrl.Request + wantErr bool + }{ + { + name: "Reconcile OBC successfully", + req: req, + + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + _, err := reconciler.Reconcile(ctx, tt.req) + if (err != nil) != tt.wantErr { + t.Errorf("Reconcile() error = %v, wantErr %v", err, tt.wantErr) + } + + if tt.name == "Reconcile OBC successfully" { + reconciledSecret := &corev1.Secret{} + err = fakeHubClient.Get(ctx, types.NamespacedName{ + Name: utils.CreateUniqueSecretName(reconciler.SpokeClusterName, storageClusterOnManagedCluster.Namespace, storageClusterOnManagedCluster.Name, utils.S3ProfilePrefix), + Namespace: reconciler.SpokeClusterName, + }, reconciledSecret) + if err != nil { + t.Errorf("Fetching the secret on hub cluster failed %v", err) + } + if reconciledSecret.Labels[utils.SecretLabelTypeKey] != string(utils.InternalLabel) { + t.Errorf("expected label %s to be %s", utils.SecretLabelTypeKey, string(utils.InternalLabel)) + } + } + }) + } +}