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  }