diff --git a/common/pkg/testutils/capitest/request/items.go b/common/pkg/testutils/capitest/request/items.go index a0313cb70..5444bd4b8 100644 --- a/common/pkg/testutils/capitest/request/items.go +++ b/common/pkg/testutils/capitest/request/items.go @@ -21,8 +21,8 @@ import ( const ( ClusterName = "test-cluster" - KubeadmConfigTemplateRequestObjectName = "test-kubeadmconfigtemplate" - KubeadmControlPlaneTemplateRequestObjectName = "test-kubeadmcontrolplanetemplate" + kubeadmConfigTemplateRequestObjectName = "test-kubeadmconfigtemplate" + kubeadmControlPlaneTemplateRequestObjectName = "test-kubeadmcontrolplanetemplate" Namespace = corev1.NamespaceDefault ) @@ -45,7 +45,16 @@ func NewRequestItem( } } -func NewKubeadmConfigTemplateRequestItem(uid types.UID) runtimehooksv1.GeneratePatchesRequestItem { +func NewKubeadmConfigTemplateRequestItem( + uid types.UID, +) runtimehooksv1.GeneratePatchesRequestItem { + return NewKubeadmConfigTemplateRequest(uid, kubeadmConfigTemplateRequestObjectName) +} + +func NewKubeadmConfigTemplateRequest( + uid types.UID, + name string, +) runtimehooksv1.GeneratePatchesRequestItem { return NewRequestItem( &bootstrapv1.KubeadmConfigTemplate{ TypeMeta: metav1.TypeMeta{ @@ -53,7 +62,7 @@ func NewKubeadmConfigTemplateRequestItem(uid types.UID) runtimehooksv1.GenerateP Kind: "KubeadmConfigTemplate", }, ObjectMeta: metav1.ObjectMeta{ - Name: KubeadmConfigTemplateRequestObjectName, + Name: name, Namespace: Namespace, }, Spec: bootstrapv1.KubeadmConfigTemplateSpec{ @@ -75,8 +84,9 @@ func NewKubeadmConfigTemplateRequestItem(uid types.UID) runtimehooksv1.GenerateP ) } -func NewKubeadmControlPlaneTemplateRequestItem( +func NewKubeadmControlPlaneTemplateRequest( uid types.UID, + name string, ) runtimehooksv1.GeneratePatchesRequestItem { return NewRequestItem( &controlplanev1.KubeadmControlPlaneTemplate{ @@ -85,7 +95,7 @@ func NewKubeadmControlPlaneTemplateRequestItem( Kind: "KubeadmControlPlaneTemplate", }, ObjectMeta: metav1.ObjectMeta{ - Name: KubeadmControlPlaneTemplateRequestObjectName, + Name: name, Namespace: Namespace, }, Spec: controlplanev1.KubeadmControlPlaneTemplateSpec{ @@ -113,6 +123,12 @@ func NewKubeadmControlPlaneTemplateRequestItem( ) } +func NewKubeadmControlPlaneTemplateRequestItem( + uid types.UID, +) runtimehooksv1.GeneratePatchesRequestItem { + return NewKubeadmControlPlaneTemplateRequest(uid, kubeadmControlPlaneTemplateRequestObjectName) +} + func NewAWSClusterTemplateRequestItem( uid types.UID, existingSpec ...capav1.AWSClusterTemplateSpec, diff --git a/pkg/handlers/aws/mutation/metapatch_handler_test.go b/pkg/handlers/aws/mutation/metapatch_handler_test.go index a1a2ddc84..ea952363d 100644 --- a/pkg/handlers/aws/mutation/metapatch_handler_test.go +++ b/pkg/handlers/aws/mutation/metapatch_handler_test.go @@ -156,6 +156,14 @@ func TestGeneratePatches(t *testing.T) { imageregistries.VariableName, ) + imageregistrycredentialstests.TestGenerateMirrorPatches( + t, + metaPatchGeneratorFunc(mgr), + mgr.GetClient(), + clusterconfig.MetaVariableName, + imageregistries.VariableName, + ) + amitests.TestControlPlaneGeneratePatches( t, metaPatchGeneratorFunc(mgr), diff --git a/pkg/handlers/docker/mutation/metapatch_handler_test.go b/pkg/handlers/docker/mutation/metapatch_handler_test.go index f6334174d..d3dea97f2 100644 --- a/pkg/handlers/docker/mutation/metapatch_handler_test.go +++ b/pkg/handlers/docker/mutation/metapatch_handler_test.go @@ -112,4 +112,12 @@ func TestGeneratePatches(t *testing.T) { clusterconfig.MetaVariableName, imageregistries.VariableName, ) + + imageregistrycredentialstests.TestGenerateMirrorPatches( + t, + metaPatchGeneratorFunc(mgr), + mgr.GetClient(), + clusterconfig.MetaVariableName, + imageregistries.VariableName, + ) } diff --git a/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_mirror_patches.go b/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_mirror_patches.go new file mode 100644 index 000000000..9dd8aa2ad --- /dev/null +++ b/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_mirror_patches.go @@ -0,0 +1,262 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/onsi/gomega" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/storage/names" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest/request" +) + +const ( + validMirrorCredentialsSecretName = "my-mirror-registry-credentials" + validMirrorCASecretName = "myregistry-mirror-cacert" + //nolint:gosec // Does not contain hard coded credentials. + cpRegistryAsMirrorCreds = "kubeadmControlPlaneRegistryAsMirrorCreds" + //nolint:gosec // Does not contain hard coded credentials. + workerRegistryAsMirrorCreds = "kubeadmConfigTemplateRegistryAsMirrorCreds" + registryStaticCredentialsSecretSuffix = "registry-config" +) + +func TestGenerateMirrorPatches( + t *testing.T, + generatorFunc func() mutation.GeneratePatches, + fakeClient client.Client, + variableName string, + variablePath ...string, +) { + t.Helper() + + require.NoError( + t, + fakeClient.Create( + context.Background(), + newRegistryCredentialsSecret(validMirrorCredentialsSecretName, request.Namespace), + ), + ) + + require.NoError( + t, + fakeClient.Create( + context.Background(), + newMirrorSecret(validMirrorCASecretName, request.Namespace), + ), + ) + + // Server side apply does not work with the fake client, hack around it by pre-creating empty Secrets + // https://github.com/kubernetes-sigs/controller-runtime/issues/2341 + require.NoError( + t, + fakeClient.Create( + context.Background(), + newEmptySecret( + fmt.Sprintf( + "%s-%s", + cpRegistryAsMirrorCreds, + registryStaticCredentialsSecretSuffix, + ), + request.Namespace, + ), + ), + ) + + require.NoError( + t, + fakeClient.Create( + context.Background(), + newEmptySecret( + fmt.Sprintf( + "%s-%s", + workerRegistryAsMirrorCreds, + registryStaticCredentialsSecretSuffix, + ), + request.Namespace, + ), + ), + ) + + capitest.ValidateGeneratePatches( + t, + generatorFunc, + capitest.PatchTestDef{ + Name: "files added in KubeadmControlPlaneTemplate for registry with mirror without CA Certificate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", + Mirror: &v1alpha1.RegistryMirror{}, + }, + }, + variablePath..., + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + ), + }, + }, + }, + capitest.PatchTestDef{ + Name: "files added in KubeadmControlPlaneTemplate for registry with mirror with CA Certificate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://mirror-registry.com", + Credentials: &v1alpha1.ImageCredentials{ + SecretRef: &corev1.ObjectReference{ + Name: validSecretName, + }, + }, + Mirror: &v1alpha1.RegistryMirror{ + SecretRef: &corev1.ObjectReference{ + Name: validMirrorCASecretName, + }, + }, + }, + }, + variablePath..., + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequest("", cpRegistryAsMirrorCreds), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/certs/mirror.pem", + ), + ), + }, + }, + }, + capitest.PatchTestDef{ + Name: "files added in KubeadmConfigTemplate for registry mirror wihthout CA certificate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", + Mirror: &v1alpha1.RegistryMirror{}, + }, + }, + variablePath..., + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + ), + }, + }, + }, + capitest.PatchTestDef{ + Name: "files added in KubeadmConfigTemplate for registry mirror with secret for CA certificate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://mirror-registry.io", + Credentials: &v1alpha1.ImageCredentials{ + SecretRef: &corev1.ObjectReference{ + Name: validSecretName, + }, + }, + Mirror: &v1alpha1.RegistryMirror{ + SecretRef: &corev1.ObjectReference{ + Name: validMirrorCASecretName, + }, + }, + }, + }, + variablePath..., + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequest("", workerRegistryAsMirrorCreds), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/containerd/certs.d/_default/hosts.toml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/certs/mirror.pem", + ), + ), + }, + }, + }, + ) +} + +func newMirrorSecret(name, namespace string) *corev1.Secret { + secretData := map[string][]byte{ + "ca.crt": []byte("myCACert"), + } + return &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: secretData, + Type: corev1.SecretTypeOpaque, + } +} diff --git a/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go b/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go index 2dd351ea3..764048397 100644 --- a/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go @@ -5,6 +5,7 @@ package tests import ( "context" + "fmt" "testing" "github.com/onsi/gomega" @@ -22,8 +23,11 @@ import ( ) const ( - validSecretName = "myregistry-credentials" - validMirrorSecretName = "myregistry-mirror-cacert" + validSecretName = "myregistry-credentials" + //nolint:gosec // Does not contain hard coded credentials. + cpRegistryCreds = "kubeadmControlPlaneRegistryWithCredentials" + //nolint:gosec // Does not contain hard coded credentials. + workerRegistryCreds = "kubeadmConfigTemplateRegistryWithCreds" ) func TestGeneratePatches( @@ -35,8 +39,6 @@ func TestGeneratePatches( ) { t.Helper() - // Server side apply does not work with the fake client, hack around it by pre-creating empty Secrets - // https://github.com/kubernetes-sigs/controller-runtime/issues/2341 require.NoError( t, fakeClient.Create( @@ -45,30 +47,25 @@ func TestGeneratePatches( ), ) - require.NoError( - t, - fakeClient.Create( - context.Background(), - newMirrorSecret(validMirrorSecretName, request.Namespace), - ), - ) - + // Server side apply does not work with the fake client, hack around it by pre-creating empty Secrets + // https://github.com/kubernetes-sigs/controller-runtime/issues/2341 require.NoError( t, fakeClient.Create( context.Background(), newEmptySecret( - request.KubeadmControlPlaneTemplateRequestObjectName+"-registry-config", + fmt.Sprintf("%s-%s", cpRegistryCreds, registryStaticCredentialsSecretSuffix), request.Namespace, ), ), ) + require.NoError( t, fakeClient.Create( context.Background(), newEmptySecret( - request.KubeadmConfigTemplateRequestObjectName+"-registry-config", + fmt.Sprintf("%s-%s", workerRegistryCreds, registryStaticCredentialsSecretSuffix), request.Namespace, ), ), @@ -153,7 +150,7 @@ func TestGeneratePatches( variablePath..., ), }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + RequestItem: request.NewKubeadmControlPlaneTemplateRequest("", cpRegistryCreds), ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ { Operation: "add", @@ -198,72 +195,6 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ - Name: "files added in KubeadmControlPlaneTemplate for registry with mirror without CA Certificate", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", - Mirror: &v1alpha1.RegistryMirror{}, - }, - }, - variablePath..., - ), - }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/containerd/certs.d/_default/hosts.toml", - ), - ), - }, - }, - }, - capitest.PatchTestDef{ - Name: "files added in KubeadmControlPlaneTemplate for registry with mirror with CA Certificate", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://mirror-registry.com", - Credentials: &v1alpha1.ImageCredentials{ - SecretRef: &corev1.ObjectReference{ - Name: validSecretName, - }, - }, - Mirror: &v1alpha1.RegistryMirror{ - SecretRef: &corev1.ObjectReference{ - Name: validMirrorSecretName, - }, - }, - }, - }, - variablePath..., - ), - }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/containerd/certs.d/_default/hosts.toml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/certs/mirror.pem", - ), - ), - }, - }, - }, capitest.PatchTestDef{ Name: "files added in KubeadmConfigTemplate for ECR without a Secret", Vars: []runtimehooksv1.Variable{ @@ -345,7 +276,7 @@ func TestGeneratePatches( }, ), }, - RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + RequestItem: request.NewKubeadmConfigTemplateRequest("", workerRegistryCreds), ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ { Operation: "add", @@ -382,93 +313,6 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ - Name: "files added in KubeadmConfigTemplate for registry mirror with no CA certificate", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://my-registry.io", - Credentials: &v1alpha1.ImageCredentials{ - SecretRef: &corev1.ObjectReference{ - Name: validSecretName, - }, - }, - Mirror: &v1alpha1.RegistryMirror{}, - }, - }, - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - map[string]any{ - "machineDeployment": map[string]any{ - "class": names.SimpleNameGenerator.GenerateName("worker-"), - }, - }, - ), - }, - RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/containerd/certs.d/_default/hosts.toml", - ), - ), - }, - }, - }, - capitest.PatchTestDef{ - Name: "files added in KubeadmConfigTemplate for registry mirror with secret for CA certificate", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://mirror-registry.com", - Credentials: &v1alpha1.ImageCredentials{ - SecretRef: &corev1.ObjectReference{ - Name: validSecretName, - }, - }, - Mirror: &v1alpha1.RegistryMirror{ - SecretRef: &corev1.ObjectReference{ - Name: validMirrorSecretName, - }, - }, - }, - }, - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - map[string]any{ - "machineDeployment": map[string]any{ - "class": names.SimpleNameGenerator.GenerateName("worker-"), - }, - }, - ), - }, - RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/containerd/certs.d/_default/hosts.toml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/certs/mirror.pem", - ), - ), - }, - }, - }, capitest.PatchTestDef{ Name: "error for a registry with no credentials", Vars: []runtimehooksv1.Variable{ @@ -507,24 +351,7 @@ func newRegistryCredentialsSecret(name, namespace string) *corev1.Secret { } } -func newMirrorSecret(name, namespace string) *corev1.Secret { - secretData := map[string][]byte{ - "ca.crt": []byte("myCACert"), - } - return &corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Data: secretData, - Type: corev1.SecretTypeOpaque, - } -} - +//nolint:unparam //namespace can change in future testcases func newEmptySecret(name, namespace string) *corev1.Secret { return &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{