github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/configuration/template_merger_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 "reflect" 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 "sigs.k8s.io/controller-runtime/pkg/client" 31 32 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 33 cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core" 34 "github.com/1aal/kubeblocks/pkg/controller/component" 35 testapps "github.com/1aal/kubeblocks/pkg/testutil/apps" 36 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 37 ) 38 39 var _ = Describe("TemplateMergerTest", func() { 40 41 baseConfig := ` 42 [mysqld] 43 log-bin=master-bin 44 gtid_mode=OFF 45 consensus_auto_leader_transfer=ON 46 max_connections=1000 47 ` 48 extendConfig := ` 49 [mysqld] 50 default_storage_engine=xengine 51 log_error_verbosity=3 52 xengine_compression_per_level=kNoCompression:KZSTD:kZSTD 53 xengine_db_total_write_buffer_size=307 54 xengine_block_cache_size=307 55 xengine_row_cache_size=102 56 max_connections=666 57 ` 58 const ( 59 baseCMName = "base-cm" 60 updatedCMName = "updated-cm" 61 62 testConfigSpecName = "test-config" 63 testClusterName = "test-cluster" 64 testConfigName = "my.cnf" 65 ) 66 67 var ( 68 mockClient *testutil.K8sClientMockHelper 69 templateBuilder *configTemplateBuilder 70 configSpec appsv1alpha1.ComponentConfigSpec 71 configConstraintObj *appsv1alpha1.ConfigConstraint 72 73 baseCMObject *corev1.ConfigMap 74 updatedCMObject *corev1.ConfigMap 75 ) 76 77 BeforeEach(func() { 78 mockClient = testutil.NewK8sMockClient() 79 configConstraintObj = testapps.CheckedCreateCustomizedObj(&testCtx, 80 "resources/mysql-config-constraint.yaml", 81 &appsv1alpha1.ConfigConstraint{}) 82 baseCMObject = &corev1.ConfigMap{ 83 Data: map[string]string{ 84 testConfigName: baseConfig, 85 }, 86 } 87 updatedCMObject = &corev1.ConfigMap{ 88 Data: map[string]string{ 89 testConfigName: extendConfig, 90 }, 91 } 92 baseCMObject.SetName(baseCMName) 93 baseCMObject.SetNamespace("default") 94 updatedCMObject.SetName(updatedCMName) 95 updatedCMObject.SetNamespace("default") 96 97 configSpec = appsv1alpha1.ComponentConfigSpec{ 98 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 99 Name: testConfigSpecName, 100 TemplateRef: baseCMObject.GetName(), 101 Namespace: "default", 102 }, 103 ConfigConstraintRef: configConstraintObj.GetName(), 104 } 105 106 templateBuilder = newTemplateBuilder( 107 testClusterName, 108 "default", 109 &appsv1alpha1.Cluster{ 110 ObjectMeta: metav1.ObjectMeta{ 111 Name: testClusterName, 112 Namespace: "default", 113 }, 114 }, nil, nil, nil) 115 Expect(templateBuilder.injectBuiltInObjectsAndFunctions( 116 &corev1.PodSpec{}, nil, &component.SynthesizedComponent{}, nil)).Should(Succeed()) 117 118 mockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult([]client.Object{ 119 baseCMObject, 120 updatedCMObject, 121 configConstraintObj, 122 }), testutil.WithAnyTimes())) 123 }) 124 125 AfterEach(func() { 126 mockClient.Finish() 127 }) 128 129 Context("with patch Merge", func() { 130 It("mergerConfigTemplate patch policy", func() { 131 importedTemplate := &appsv1alpha1.LegacyRenderedTemplateSpec{ 132 ConfigTemplateExtension: appsv1alpha1.ConfigTemplateExtension{ 133 Namespace: "default", 134 // Name: configSpec.Name, 135 TemplateRef: updatedCMObject.GetName(), 136 Policy: appsv1alpha1.PatchPolicy, 137 }, 138 } 139 140 tmpCM := baseCMObject.DeepCopy() 141 mergedData, err := mergerConfigTemplate(importedTemplate, templateBuilder, configSpec, tmpCM.Data, ctx, mockClient.Client()) 142 Expect(err).To(Succeed()) 143 144 configReaders, err := cfgcore.LoadRawConfigObject(mergedData, configConstraintObj.Spec.FormatterConfig, configSpec.Keys) 145 Expect(err).Should(Succeed()) 146 Expect(configReaders).Should(HaveLen(1)) 147 configObject := configReaders[testConfigName] 148 Expect(configObject.Get("gtid_mode")).Should(BeEquivalentTo("OFF")) 149 Expect(configObject.Get("consensus_auto_leader_transfer")).Should(BeEquivalentTo("ON")) 150 Expect(configObject.Get("default_storage_engine")).Should(BeEquivalentTo("xengine")) 151 Expect(configObject.Get("log_error_verbosity")).Should(BeEquivalentTo("3")) 152 Expect(configObject.Get("max_connections")).Should(BeEquivalentTo("666")) 153 Expect(configObject.Get("xengine_compression_per_level")).Should(BeEquivalentTo("kNoCompression:KZSTD:kZSTD")) 154 Expect(configObject.Get("xengine_block_cache_size")).Should(BeEquivalentTo("307")) 155 }) 156 }) 157 158 Context("with replace Merge", func() { 159 It("test mergerConfigTemplate replace policy", func() { 160 importedTemplate := &appsv1alpha1.LegacyRenderedTemplateSpec{ 161 ConfigTemplateExtension: appsv1alpha1.ConfigTemplateExtension{ 162 Namespace: "default", 163 TemplateRef: updatedCMObject.GetName(), 164 Policy: appsv1alpha1.ReplacePolicy, 165 }, 166 } 167 168 tmpCM := baseCMObject.DeepCopy() 169 mergedData, err := mergerConfigTemplate(importedTemplate, templateBuilder, configSpec, tmpCM.Data, ctx, mockClient.Client()) 170 Expect(err).Should(Succeed()) 171 Expect(reflect.DeepEqual(mergedData, updatedCMObject.Data)).Should(BeTrue()) 172 173 configReaders, err := cfgcore.LoadRawConfigObject(mergedData, configConstraintObj.Spec.FormatterConfig, configSpec.Keys) 174 Expect(err).Should(Succeed()) 175 Expect(configReaders).Should(HaveLen(1)) 176 configObject := configReaders[testConfigName] 177 Expect(configObject.Get("gtid_mode")).Should(BeNil()) 178 Expect(configObject.Get("consensus_auto_leader_transfer")).Should(BeNil()) 179 Expect(configObject.Get("default_storage_engine")).Should(BeEquivalentTo("xengine")) 180 Expect(configObject.Get("max_connections")).Should(BeEquivalentTo("666")) 181 }) 182 }) 183 184 Context("with only add Merge", func() { 185 It("test mergerConfigTemplate add policy", func() { 186 importedTemplate := &appsv1alpha1.LegacyRenderedTemplateSpec{ 187 ConfigTemplateExtension: appsv1alpha1.ConfigTemplateExtension{ 188 Namespace: "default", 189 TemplateRef: updatedCMObject.GetName(), 190 Policy: appsv1alpha1.OnlyAddPolicy, 191 }, 192 } 193 194 tmpCM := baseCMObject.DeepCopy() 195 _, err := mergerConfigTemplate(importedTemplate, templateBuilder, configSpec, tmpCM.Data, ctx, mockClient.Client()) 196 Expect(err).ShouldNot(Succeed()) 197 }) 198 }) 199 200 Context("with none Merge", func() { 201 It("test mergerConfigTemplate none policy", func() { 202 importedTemplate := &appsv1alpha1.LegacyRenderedTemplateSpec{ 203 ConfigTemplateExtension: appsv1alpha1.ConfigTemplateExtension{ 204 Namespace: "default", 205 TemplateRef: updatedCMObject.GetName(), 206 Policy: appsv1alpha1.NoneMergePolicy, 207 }, 208 } 209 210 tmpCM := baseCMObject.DeepCopy() 211 mergedData, err := mergerConfigTemplate(importedTemplate, templateBuilder, configSpec, tmpCM.Data, ctx, mockClient.Client()) 212 Expect(err).Should(Succeed()) 213 Expect(reflect.DeepEqual(mergedData, updatedCMObject.Data)).Should(BeTrue()) 214 }) 215 }) 216 217 Context("failed test", func() { 218 It("test mergerConfigTemplate function", func() { 219 importedTemplate := &appsv1alpha1.LegacyRenderedTemplateSpec{ 220 ConfigTemplateExtension: appsv1alpha1.ConfigTemplateExtension{ 221 Namespace: "default", 222 TemplateRef: updatedCMObject.GetName(), 223 Policy: "", 224 }, 225 } 226 227 tmpCM := baseCMObject.DeepCopy() 228 _, err := mergerConfigTemplate(importedTemplate, templateBuilder, configSpec, tmpCM.Data, ctx, mockClient.Client()) 229 Expect(err).ShouldNot(Succeed()) 230 }) 231 232 It("not configconstraint", func() { 233 importedTemplate := &appsv1alpha1.LegacyRenderedTemplateSpec{ 234 ConfigTemplateExtension: appsv1alpha1.ConfigTemplateExtension{ 235 Namespace: "default", 236 TemplateRef: updatedCMObject.GetName(), 237 Policy: "none", 238 }, 239 } 240 241 tmpCM := baseCMObject.DeepCopy() 242 tmpConfigSpec := configSpec.DeepCopy() 243 tmpConfigSpec.ConfigConstraintRef = "" 244 _, err := mergerConfigTemplate(importedTemplate, templateBuilder, *tmpConfigSpec, tmpCM.Data, ctx, mockClient.Client()) 245 Expect(err).ShouldNot(Succeed()) 246 }) 247 248 It("not formatter", func() { 249 importedTemplate := &appsv1alpha1.LegacyRenderedTemplateSpec{ 250 ConfigTemplateExtension: appsv1alpha1.ConfigTemplateExtension{ 251 Namespace: "default", 252 TemplateRef: updatedCMObject.GetName(), 253 Policy: "none", 254 }, 255 } 256 257 tmpCM := baseCMObject.DeepCopy() 258 tmpConfigSpec := configSpec.DeepCopy() 259 tmpConfigSpec.ConfigConstraintRef = "not_exist" 260 _, err := mergerConfigTemplate(importedTemplate, templateBuilder, *tmpConfigSpec, tmpCM.Data, ctx, mockClient.Client()) 261 Expect(err).ShouldNot(Succeed()) 262 }) 263 }) 264 })