github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/configuration/config_template_utils_test.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package configuration 21 22 import ( 23 "context" 24 25 . "github.com/onsi/ginkgo/v2" 26 . "github.com/onsi/gomega" 27 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 ctrl "sigs.k8s.io/controller-runtime" 31 "sigs.k8s.io/controller-runtime/pkg/client" 32 "sigs.k8s.io/controller-runtime/pkg/log" 33 34 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 35 "github.com/1aal/kubeblocks/pkg/constant" 36 "github.com/1aal/kubeblocks/pkg/controller/component" 37 intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil" 38 "github.com/1aal/kubeblocks/pkg/generics" 39 testapps "github.com/1aal/kubeblocks/pkg/testutil/apps" 40 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 41 ) 42 43 var _ = Describe("generate service descriptor", func() { 44 45 cleanEnv := func() { 46 // must wait till resources deleted and no longer existed before the testcases start, 47 // otherwise if later it needs to create some new resource objects with the same name, 48 // in race conditions, it will find the existence of old objects, resulting failure to 49 // create the new objects. 50 By("clean resources") 51 52 inNS := client.InNamespace(testCtx.DefaultNamespace) 53 ml := client.HasLabels{testCtx.TestObjLabelKey} 54 55 // resources should be released in following order 56 // non-namespaced 57 testapps.ClearResources(&testCtx, generics.ConfigConstraintSignature, ml) 58 59 // namespaced 60 testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ConfigMapSignature, true, inNS, ml) 61 testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ClusterVersionSignature, true, ml) 62 testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, generics.ClusterDefinitionSignature, true, ml) 63 } 64 65 var ( 66 mockClient *testutil.K8sClientMockHelper 67 clusterDef *appsv1alpha1.ClusterDefinition 68 clusterVersion *appsv1alpha1.ClusterVersion 69 cluster *appsv1alpha1.Cluster 70 beReferencedCluster *appsv1alpha1.Cluster 71 ) 72 73 var ( 74 namespace = "default" 75 clusterName = "mycluster" 76 beReferencedClusterName = "mycluster-be-referenced" 77 clusterDefName = "test-clusterdef" 78 clusterVersionName = "test-clusterversion" 79 nginxCompName = "nginx" 80 nginxCompDefName = "nginx" 81 mysqlCompName = "mysql" 82 mysqlCompDefName = "mysql" 83 externalServiceDescriptorName = "mock-external-service-descriptor-name" 84 externalServiceDescriptorKind = "redis" 85 externalServiceDescriptorVersion = "7.0.1" 86 internalClusterServiceRefKind = "mysql" 87 internalClusterServiceRefVersion = "8.0.2" 88 secretName = beReferencedClusterName + "-conn-credential" 89 configMapRefName = beReferencedClusterName + "-configmap-ref" 90 redisServiceRefDeclarationName = "redis" 91 mysqlServiceRefDeclarationName = "mysql" 92 93 serviceRefEndpointValue = "my-mysql-0.default.svc.cluster.local" 94 serviceRefPortValue = "3306" 95 serviceRefUsernameValue = "mock-username" 96 serviceRefPasswordValue = "mock-password" 97 ) 98 99 BeforeEach(func() { 100 cleanEnv() 101 mockClient = testutil.NewK8sMockClient() 102 serviceRefDeclarations := []appsv1alpha1.ServiceRefDeclaration{ 103 { 104 Name: redisServiceRefDeclarationName, 105 ServiceRefDeclarationSpecs: []appsv1alpha1.ServiceRefDeclarationSpec{ 106 { 107 ServiceKind: externalServiceDescriptorKind, 108 ServiceVersion: externalServiceDescriptorVersion, 109 }, 110 }, 111 }, 112 { 113 Name: mysqlServiceRefDeclarationName, 114 ServiceRefDeclarationSpecs: []appsv1alpha1.ServiceRefDeclarationSpec{ 115 { 116 ServiceKind: internalClusterServiceRefKind, 117 ServiceVersion: internalClusterServiceRefVersion, 118 }, 119 }, 120 }, 121 } 122 clusterDef = testapps.NewClusterDefFactory(clusterDefName). 123 AddComponentDef(testapps.StatelessNginxComponent, nginxCompDefName). 124 AddServiceRefDeclarations(serviceRefDeclarations). 125 Create(&testCtx).GetObject() 126 clusterVersion = testapps.NewClusterVersionFactory(clusterVersionName, clusterDefName). 127 AddComponentVersion(nginxCompDefName). 128 AddInitContainerShort("nginx-init", testapps.NginxImage). 129 AddContainerShort("nginx", testapps.NginxImage). 130 Create(&testCtx).GetObject() 131 beReferencedCluster = testapps.NewClusterFactory(testCtx.DefaultNamespace, beReferencedClusterName, 132 clusterDef.Name, clusterVersion.Name). 133 AddComponent(mysqlCompName, mysqlCompDefName). 134 Create(&testCtx).GetObject() 135 136 serviceRefs := []appsv1alpha1.ServiceRef{ 137 { 138 Name: redisServiceRefDeclarationName, 139 ServiceDescriptor: externalServiceDescriptorName, 140 }, 141 { 142 Name: mysqlServiceRefDeclarationName, 143 Cluster: beReferencedCluster.Name, 144 }, 145 } 146 cluster = testapps.NewClusterFactory(testCtx.DefaultNamespace, clusterName, 147 clusterDef.Name, clusterVersion.Name). 148 AddComponent(nginxCompName, nginxCompDefName). 149 SetServiceRefs(serviceRefs). 150 Create(&testCtx).GetObject() 151 }) 152 153 AfterEach(func() { 154 mockClient.Finish() 155 cleanEnv() 156 }) 157 158 // for test GetContainerWithVolumeMount 159 Context("config template utils test", func() { 160 It("service reference config template render test", func() { 161 clusterKey := client.ObjectKeyFromObject(cluster) 162 req := ctrl.Request{ 163 NamespacedName: clusterKey, 164 } 165 reqCtx := intctrlutil.RequestCtx{ 166 Ctx: testCtx.Ctx, 167 Req: req, 168 Log: log.FromContext(ctx).WithValues("cluster", req.NamespacedName), 169 } 170 By("Create a serviceReferencesMap with SecretKeyRef and ConfigMapKeyRef for building a SynthesizedComponent Component") 171 serviceReferencesMap := map[string]*appsv1alpha1.ServiceDescriptor{ 172 redisServiceRefDeclarationName: { 173 ObjectMeta: metav1.ObjectMeta{ 174 Name: externalServiceDescriptorName, 175 Namespace: namespace, 176 }, 177 Spec: appsv1alpha1.ServiceDescriptorSpec{ 178 ServiceKind: externalServiceDescriptorKind, 179 ServiceVersion: externalServiceDescriptorVersion, 180 Endpoint: &appsv1alpha1.CredentialVar{ 181 ValueFrom: &corev1.EnvVarSource{ 182 SecretKeyRef: &corev1.SecretKeySelector{ 183 Key: constant.ServiceDescriptorEndpointKey, 184 LocalObjectReference: corev1.LocalObjectReference{ 185 Name: secretName, 186 }, 187 }, 188 }, 189 }, 190 Port: &appsv1alpha1.CredentialVar{ 191 ValueFrom: &corev1.EnvVarSource{ 192 SecretKeyRef: &corev1.SecretKeySelector{ 193 Key: constant.ServiceDescriptorPortKey, 194 LocalObjectReference: corev1.LocalObjectReference{ 195 Name: secretName, 196 }, 197 }, 198 }, 199 }, 200 Auth: &appsv1alpha1.ConnectionCredentialAuth{ 201 Username: &appsv1alpha1.CredentialVar{ 202 ValueFrom: &corev1.EnvVarSource{ 203 SecretKeyRef: &corev1.SecretKeySelector{ 204 Key: constant.ServiceDescriptorUsernameKey, 205 LocalObjectReference: corev1.LocalObjectReference{ 206 Name: secretName, 207 }, 208 }, 209 }, 210 }, 211 Password: &appsv1alpha1.CredentialVar{ 212 ValueFrom: &corev1.EnvVarSource{ 213 SecretKeyRef: &corev1.SecretKeySelector{ 214 Key: constant.ServiceDescriptorPasswordKey, 215 LocalObjectReference: corev1.LocalObjectReference{ 216 Name: secretName, 217 }, 218 }, 219 }, 220 }, 221 }, 222 }, 223 }, 224 mysqlServiceRefDeclarationName: { 225 ObjectMeta: metav1.ObjectMeta{ 226 Name: externalServiceDescriptorName, 227 Namespace: namespace, 228 }, 229 Spec: appsv1alpha1.ServiceDescriptorSpec{ 230 ServiceKind: externalServiceDescriptorKind, 231 ServiceVersion: externalServiceDescriptorVersion, 232 Endpoint: &appsv1alpha1.CredentialVar{ 233 ValueFrom: &corev1.EnvVarSource{ 234 ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ 235 Key: constant.ServiceDescriptorEndpointKey, 236 LocalObjectReference: corev1.LocalObjectReference{ 237 Name: configMapRefName, 238 }, 239 }, 240 }, 241 }, 242 Port: &appsv1alpha1.CredentialVar{ 243 ValueFrom: &corev1.EnvVarSource{ 244 ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ 245 Key: constant.ServiceDescriptorPortKey, 246 LocalObjectReference: corev1.LocalObjectReference{ 247 Name: configMapRefName, 248 }, 249 }, 250 }, 251 }, 252 Auth: &appsv1alpha1.ConnectionCredentialAuth{ 253 Username: &appsv1alpha1.CredentialVar{ 254 ValueFrom: &corev1.EnvVarSource{ 255 ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ 256 Key: constant.ServiceDescriptorUsernameKey, 257 LocalObjectReference: corev1.LocalObjectReference{ 258 Name: configMapRefName, 259 }, 260 }, 261 }, 262 }, 263 Password: &appsv1alpha1.CredentialVar{ 264 ValueFrom: &corev1.EnvVarSource{ 265 ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ 266 Key: constant.ServiceDescriptorPasswordKey, 267 LocalObjectReference: corev1.LocalObjectReference{ 268 Name: configMapRefName, 269 }, 270 }, 271 }, 272 }, 273 }, 274 }, 275 }, 276 } 277 component, err := component.BuildComponent( 278 reqCtx, 279 nil, 280 cluster, 281 clusterDef, 282 &clusterDef.Spec.ComponentDefs[0], 283 &cluster.Spec.ComponentSpecs[0], 284 serviceReferencesMap, 285 &clusterVersion.Spec.ComponentVersions[0]) 286 Expect(err).Should(Succeed()) 287 Expect(component).ShouldNot(BeNil()) 288 Expect(component.ServiceReferences).ShouldNot(BeNil()) 289 290 By("create a secret and a configmap for service reference") 291 secret := &corev1.Secret{ 292 ObjectMeta: metav1.ObjectMeta{ 293 Name: secretName, 294 Namespace: namespace, 295 }, 296 Data: map[string][]byte{ 297 constant.ServiceDescriptorPasswordKey: []byte(serviceRefPasswordValue), 298 constant.ServiceDescriptorUsernameKey: []byte(serviceRefUsernameValue), 299 constant.ServiceDescriptorEndpointKey: []byte(serviceRefEndpointValue), 300 constant.ServiceDescriptorPortKey: []byte(serviceRefPortValue), 301 }, 302 } 303 Expect(testCtx.CheckedCreateObj(ctx, secret)).Should(Succeed()) 304 Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: secret.Name, 305 Namespace: secret.Namespace}, secret)).Should(Succeed()) 306 307 configMap := &corev1.ConfigMap{ 308 ObjectMeta: metav1.ObjectMeta{ 309 Name: configMapRefName, 310 Namespace: namespace, 311 }, 312 Data: map[string]string{ 313 constant.ServiceDescriptorPasswordKey: serviceRefPasswordValue, 314 constant.ServiceDescriptorUsernameKey: serviceRefUsernameValue, 315 constant.ServiceDescriptorEndpointKey: serviceRefEndpointValue, 316 constant.ServiceDescriptorPortKey: serviceRefPortValue, 317 }, 318 } 319 Expect(testCtx.CheckedCreateObj(ctx, configMap)).Should(Succeed()) 320 Expect(k8sClient.Get(context.Background(), client.ObjectKey{Name: configMap.Name, 321 Namespace: configMap.Namespace}, configMap)).Should(Succeed()) 322 323 var v Visitor = &ComponentVisitor{component: component} 324 err = v.Visit(resolveServiceReferences(k8sClient, ctx)) 325 Expect(err).Should(Succeed()) 326 Expect(component.ServiceReferences).ShouldNot(BeNil()) 327 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Endpoint.Value).Should(Equal(serviceRefEndpointValue)) 328 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Endpoint.ValueFrom).Should(BeNil()) 329 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Port.Value).Should(Equal(serviceRefPortValue)) 330 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Port.ValueFrom).Should(BeNil()) 331 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Auth.Username.Value).Should(BeEmpty()) 332 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Auth.Username.ValueFrom.SecretKeyRef).ShouldNot(BeNil()) 333 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Auth.Password.Value).Should(BeEmpty()) 334 Expect(component.ServiceReferences[redisServiceRefDeclarationName].Spec.Auth.Password.ValueFrom.SecretKeyRef).ShouldNot(BeNil()) 335 336 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Endpoint.Value).Should(Equal(serviceRefEndpointValue)) 337 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Endpoint.ValueFrom).Should(BeNil()) 338 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Port.Value).Should(Equal(serviceRefPortValue)) 339 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Port.ValueFrom).Should(BeNil()) 340 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Auth.Username.Value).Should(BeEmpty()) 341 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Auth.Username.ValueFrom.ConfigMapKeyRef).ShouldNot(BeNil()) 342 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Auth.Password.Value).Should(BeEmpty()) 343 Expect(component.ServiceReferences[mysqlServiceRefDeclarationName].Spec.Auth.Password.ValueFrom.ConfigMapKeyRef).ShouldNot(BeNil()) 344 }) 345 }) 346 })