github.com/verrazzano/verrazzano@v1.7.1/platform-operator/controllers/secrets/cloud_credential_test.go (about) 1 // Copyright (c) 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package secrets 5 6 import ( 7 "context" 8 "github.com/stretchr/testify/assert" 9 vzapi "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1" 10 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/rancher" 11 corev1 "k8s.io/api/core/v1" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 "k8s.io/apimachinery/pkg/runtime" 15 "k8s.io/apimachinery/pkg/runtime/schema" 16 fakedynamic "k8s.io/client-go/dynamic/fake" 17 k8scheme "k8s.io/client-go/kubernetes/scheme" 18 "sigs.k8s.io/controller-runtime/pkg/client" 19 fakes "sigs.k8s.io/controller-runtime/pkg/client/fake" 20 "testing" 21 ) 22 23 // TestIsCloudCredentialSecret tests isOCNECloudCredential 24 // GIVEN Namespace resource 25 // WHEN isOCNECloudCredential is called 26 // THEN true is returned if secret is cloud credential in cattle global data namespace 27 // THEN false is returned if not cloud credential or is not in cattle global data namespace 28 func TestIsCloudCredentialSecret(t *testing.T) { 29 asserts := assert.New(t) 30 ccSecret := &corev1.Secret{ 31 ObjectMeta: metav1.ObjectMeta{ 32 Name: "test-cloud-credential", 33 Namespace: rancher.CattleGlobalDataNamespace, 34 }, 35 Data: map[string][]byte{ 36 rancherCcFingerprintField: []byte("fingerprint"), 37 }, 38 } 39 nonCcSecret := &corev1.Secret{ 40 ObjectMeta: metav1.ObjectMeta{ 41 Name: "test-cloud-credential", 42 Namespace: rancher.CattleGlobalDataNamespace, 43 }, 44 } 45 ccInOtherNS := &corev1.Secret{ 46 ObjectMeta: metav1.ObjectMeta{ 47 Name: "test-cloud-credential", 48 Namespace: "verrazzano-install", 49 }, 50 Data: map[string][]byte{ 51 rancherCcFingerprintField: []byte("fingerprint"), 52 }, 53 } 54 asserts.True(isOCNECloudCredential(ccSecret)) 55 asserts.False(isOCNECloudCredential(nonCcSecret)) 56 asserts.False(isOCNECloudCredential(ccInOtherNS)) 57 } 58 59 // TestUpdateOCNEclusterCloudCreds tests checkClusterCredentials 60 // GIVEN an updated cloud credential secret and the cluster's expired copy of that secret 61 // WHEN CheckClusterCredentials is called 62 // THEN the cluster's copy of the secret should be updated to match the new cloud credential 63 func TestCheckClusterCredentials(t *testing.T) { 64 scheme := k8scheme.Scheme 65 _ = vzapi.AddToScheme(scheme) 66 dynamicClient := fakedynamic.NewSimpleDynamicClient(scheme, newClusterRepoResources()...) 67 gvr := GetOCNEClusterAPIGVRForResource("clusters") 68 // add dynamic elements to scheme 69 scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: gvr.Group, Version: gvr.Version, Kind: "Cluster" + "List"}, &unstructured.Unstructured{}) 70 ccSecretName := "test-secret" 71 clusterSecretName := "cluster-principal" //nolint:gosec //#gosec G101 72 ccSecret := &corev1.Secret{ 73 ObjectMeta: metav1.ObjectMeta{ 74 Name: ccSecretName, 75 Namespace: rancher.CattleGlobalDataNamespace, 76 }, 77 Data: map[string][]byte{ 78 rancherCcFingerprintField: []byte("fingerprint-new"), 79 rancherCcTenancyField: []byte("test-tenancy-new"), 80 rancherCcRegionField: []byte("test-region-new"), 81 }, 82 } 83 clusterSecretCopy := &corev1.Secret{ 84 ObjectMeta: metav1.ObjectMeta{ 85 Name: clusterSecretName, 86 Namespace: "cluster", 87 }, 88 Data: map[string][]byte{ 89 ociCapiFingerprintField: []byte("fingerprint"), 90 ociCapiTenancyField: []byte("test-tenancy"), 91 ociCapiRegionField: []byte("test-region"), 92 }, 93 } 94 95 vz := &vzapi.Verrazzano{} 96 97 fakeClient := fakes.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(ccSecret, vz, clusterSecretCopy).Build() 98 r := &VerrazzanoSecretsReconciler{ 99 Client: fakeClient, 100 DynamicClient: dynamicClient, 101 Scheme: scheme, 102 StatusUpdater: nil, 103 } 104 105 err := r.checkClusterCredentials(ccSecret) 106 assert.NoError(t, err) 107 updatedClusterSecretCopy := &corev1.Secret{} 108 err = r.Client.Get(context.TODO(), client.ObjectKey{Namespace: "cluster", Name: "cluster-principal"}, updatedClusterSecretCopy) 109 assert.NoError(t, err) 110 assert.Equalf(t, updatedClusterSecretCopy.Data[ociCapiFingerprintField], ccSecret.Data[rancherCcFingerprintField], "Expected fingerprint field of cloud credential copy to match updated cloud credential secret") 111 assert.Equalf(t, updatedClusterSecretCopy.Data[ociCapiTenancyField], ccSecret.Data[rancherCcTenancyField], "Expected tenancy field of cloud credential copy to match updated cloud credential secret") 112 assert.NotEqualf(t, updatedClusterSecretCopy.Data[ociCapiRegionField], ccSecret.Data[rancherCcRegionField], "Expected region field of cloud credential copy to not match updated cloud credential secret") 113 } 114 115 // TestUpdateOCNEclusterCloudCreds tests checkClusterCredentials 116 // GIVEN an updated cloud credential secret 117 // WHEN CheckClusterCredentials is called 118 // THEN the a secret should be created to match the new cloud credential, if one doesn't already exist 119 func TestCheckClusterCredentialsNoCopyOfSecret(t *testing.T) { 120 scheme := k8scheme.Scheme 121 _ = vzapi.AddToScheme(scheme) 122 dynamicClient := fakedynamic.NewSimpleDynamicClient(scheme, newClusterRepoResources()...) 123 gvr := GetOCNEClusterAPIGVRForResource("clusters") 124 // add dynamic elements to scheme 125 scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: gvr.Group, Version: gvr.Version, Kind: "Cluster" + "List"}, &unstructured.Unstructured{}) 126 ccSecretName := "test-secret" 127 ccSecret := &corev1.Secret{ 128 ObjectMeta: metav1.ObjectMeta{ 129 Name: ccSecretName, 130 Namespace: rancher.CattleGlobalDataNamespace, 131 }, 132 Data: map[string][]byte{ 133 rancherCcFingerprintField: []byte("fingerprint-new"), 134 rancherCcTenancyField: []byte("test-tenancy-new"), 135 rancherCcRegionField: []byte("test-region-new"), 136 }, 137 } 138 139 vz := &vzapi.Verrazzano{} 140 141 fakeClient := fakes.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(ccSecret, vz).Build() 142 r := &VerrazzanoSecretsReconciler{ 143 Client: fakeClient, 144 DynamicClient: dynamicClient, 145 Scheme: scheme, 146 StatusUpdater: nil, 147 } 148 149 err := r.checkClusterCredentials(ccSecret) 150 assert.NoError(t, err) 151 updatedClusterSecretCopy := &corev1.Secret{} 152 err = r.Client.Get(context.TODO(), client.ObjectKey{Namespace: "cluster", Name: "cluster-principal"}, updatedClusterSecretCopy) 153 assert.NoError(t, err) 154 assert.Equalf(t, updatedClusterSecretCopy.Data[ociCapiFingerprintField], ccSecret.Data[rancherCcFingerprintField], "Expected fingerprint field of cloud credential copy to match updated cloud credential secret") 155 assert.Equalf(t, updatedClusterSecretCopy.Data[ociCapiTenancyField], ccSecret.Data[rancherCcTenancyField], "Expected tenancy field of cloud credential copy to match updated cloud credential secret") 156 assert.NotEqualf(t, updatedClusterSecretCopy.Data[ociCapiRegionField], ccSecret.Data[rancherCcRegionField], "Expected region field of cloud credential copy to not match updated cloud credential secret") 157 } 158 159 // newClusterRepoResources creates resources that will be loaded into the dynamic k8s client 160 func newClusterRepoResources() []runtime.Object { 161 ocneCluster := &unstructured.Unstructured{ 162 Object: map[string]interface{}{ 163 "metadata": map[string]interface{}{ 164 "name": "cluster", 165 }, 166 "spec": map[string]interface{}{ 167 "genericEngineConfig": map[string]interface{}{ 168 "cloudCredentialId": "cattle-global-data:test-secret", 169 }, 170 }, 171 }, 172 } 173 gvk := schema.GroupVersionKind{ 174 Group: "management.cattle.io", 175 Version: "v3", 176 Kind: "Cluster", 177 } 178 ocneCluster.SetGroupVersionKind(gvk) 179 return []runtime.Object{ocneCluster} 180 }