github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/configuration/pipeline_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 "strconv" 25 26 . "github.com/onsi/ginkgo/v2" 27 . "github.com/onsi/gomega" 28 29 "github.com/golang/mock/gomock" 30 appsv1 "k8s.io/api/apps/v1" 31 corev1 "k8s.io/api/core/v1" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "sigs.k8s.io/controller-runtime/pkg/client" 34 35 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 36 cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core" 37 cfgutil "github.com/1aal/kubeblocks/pkg/configuration/util" 38 "github.com/1aal/kubeblocks/pkg/controller/builder" 39 "github.com/1aal/kubeblocks/pkg/controller/component" 40 "github.com/1aal/kubeblocks/pkg/controller/factory" 41 intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil" 42 testapps "github.com/1aal/kubeblocks/pkg/testutil/apps" 43 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 44 ) 45 46 var _ = Describe("ConfigurationPipelineTest", func() { 47 48 const testConfigFile = "postgresql.conf" 49 50 var clusterObj *appsv1alpha1.Cluster 51 var clusterVersionObj *appsv1alpha1.ClusterVersion 52 var clusterDefObj *appsv1alpha1.ClusterDefinition 53 var clusterComponent *component.SynthesizedComponent 54 var configMapObj *corev1.ConfigMap 55 var configConstraint *appsv1alpha1.ConfigConstraint 56 var configurationObj *appsv1alpha1.Configuration 57 var k8sMockClient *testutil.K8sClientMockHelper 58 59 mockStatefulSet := func() *appsv1.StatefulSet { 60 envConfig := factory.BuildEnvConfig(clusterObj, clusterComponent) 61 stsObj, err := factory.BuildSts(intctrlutil.RequestCtx{ 62 Ctx: ctx, 63 Log: logger, 64 }, clusterObj, clusterComponent, envConfig.Name) 65 Expect(err).Should(Succeed()) 66 return stsObj 67 } 68 69 mockAPIResource := func(lazyFetcher testutil.Getter) { 70 k8sMockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult( 71 []client.Object{ 72 clusterDefObj, 73 clusterVersionObj, 74 clusterObj, 75 clusterObj, 76 configMapObj, 77 configConstraint, 78 configurationObj, 79 }, lazyFetcher), testutil.WithAnyTimes())) 80 k8sMockClient.MockCreateMethod(testutil.WithCreateReturned(testutil.WithCreatedSucceedResult(), testutil.WithAnyTimes())) 81 k8sMockClient.MockPatchMethod(testutil.WithPatchReturned(func(obj client.Object, patch client.Patch) error { 82 switch v := obj.(type) { 83 case *appsv1alpha1.Configuration: 84 if client.ObjectKeyFromObject(obj) == client.ObjectKeyFromObject(configurationObj) { 85 configurationObj.Spec = *v.Spec.DeepCopy() 86 configurationObj.Status = *v.Status.DeepCopy() 87 } 88 } 89 return nil 90 }, testutil.WithAnyTimes())) 91 k8sMockClient.MockStatusMethod(). 92 EXPECT(). 93 Patch(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). 94 DoAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error { 95 switch v := obj.(type) { 96 case *appsv1alpha1.Configuration: 97 if client.ObjectKeyFromObject(obj) == client.ObjectKeyFromObject(configurationObj) { 98 configurationObj.Status = *v.Status.DeepCopy() 99 } 100 } 101 return nil 102 }).AnyTimes() 103 } 104 105 BeforeEach(func() { 106 // Add any setup steps that needs to be executed before each test 107 k8sMockClient = testutil.NewK8sMockClient() 108 clusterObj, clusterDefObj, clusterVersionObj, _ = newAllFieldsClusterObj(nil, nil, false) 109 clusterComponent = newAllFieldsComponent(clusterDefObj, clusterVersionObj) 110 configMapObj = testapps.NewConfigMap("default", mysqlConfigName, 111 testapps.SetConfigMapData(testConfigFile, ` 112 bgwriter_delay = '200ms' 113 bgwriter_flush_after = '64' 114 bgwriter_lru_maxpages = '1000' 115 bgwriter_lru_multiplier = '10.0' 116 bytea_output = 'hex' 117 check_function_bodies = 'True' 118 checkpoint_completion_target = '0.9' 119 checkpoint_flush_after = '32' 120 checkpoint_timeout = '15min' 121 max_connections = '1000' 122 `)) 123 configurationObj = builder.NewConfigurationBuilder(testCtx.DefaultNamespace, 124 cfgcore.GenerateComponentConfigurationName(clusterName, mysqlCompName)). 125 ClusterRef(clusterName). 126 Component(mysqlCompName). 127 GetObject() 128 configConstraint = &appsv1alpha1.ConfigConstraint{ 129 ObjectMeta: metav1.ObjectMeta{ 130 Name: mysqlConfigConstraintName, 131 }, 132 Spec: appsv1alpha1.ConfigConstraintSpec{ 133 FormatterConfig: &appsv1alpha1.FormatterConfig{ 134 Format: appsv1alpha1.Properties, 135 }, 136 }} 137 }) 138 139 AfterEach(func() { 140 k8sMockClient.Finish() 141 }) 142 143 Context("ConfigPipelineTest", func() { 144 It("NormalTest", func() { 145 By("mock configSpec keys") 146 clusterComponent.ConfigTemplates[0].Keys = []string{testConfigFile} 147 148 By("create configuration resource") 149 createPipeline := NewCreatePipeline(ReconcileCtx{ 150 ResourceCtx: &intctrlutil.ResourceCtx{ 151 Client: k8sMockClient.Client(), 152 Context: ctx, 153 Namespace: testCtx.DefaultNamespace, 154 ClusterName: clusterName, 155 ComponentName: mysqlCompName, 156 }, 157 Cluster: clusterObj, 158 ClusterVer: clusterVersionObj, 159 Component: clusterComponent, 160 PodSpec: clusterComponent.PodSpec, 161 Object: mockStatefulSet(), 162 }) 163 164 By("mock api resource for configuration") 165 mockAPIResource(func(key client.ObjectKey, obj client.Object) (bool, error) { 166 switch obj.(type) { 167 case *corev1.ConfigMap: 168 for _, renderedObj := range createPipeline.renderWrapper.renderedObjs { 169 if client.ObjectKeyFromObject(renderedObj) == key { 170 testutil.SetGetReturnedObject(obj, renderedObj) 171 return true, nil 172 } 173 } 174 } 175 return false, nil 176 }) 177 178 err := createPipeline.Prepare(). 179 UpdateConfiguration(). // reconcile Configuration 180 Configuration(). // sync Configuration 181 CreateConfigTemplate(). 182 UpdatePodVolumes(). 183 BuildConfigManagerSidecar(). 184 UpdateConfigRelatedObject(). 185 UpdateConfigurationStatus(). 186 Complete() 187 Expect(err).Should(Succeed()) 188 189 By("update configuration resource for mocking reconfiguring") 190 item := configurationObj.Spec.ConfigItemDetails[0] 191 item.ConfigFileParams = map[string]appsv1alpha1.ConfigParams{ 192 testConfigFile: { 193 Parameters: map[string]*string{ 194 "max_connections": cfgutil.ToPointer("2000"), 195 }, 196 }, 197 "other.conf": { 198 Content: cfgutil.ToPointer(`for test`), 199 }, 200 } 201 reconcileTask := NewReconcilePipeline(ReconcileCtx{ 202 ResourceCtx: createPipeline.ResourceCtx, 203 Cluster: clusterObj, 204 ClusterVer: clusterVersionObj, 205 Component: clusterComponent, 206 PodSpec: clusterComponent.PodSpec, 207 }, item, &configurationObj.Status.ConfigurationItemStatus[0], nil) 208 209 By("update configuration resource") 210 err = reconcileTask.InitConfigSpec(). 211 Configuration(). 212 ConfigMap(configSpecName). 213 ConfigConstraints(reconcileTask.ConfigSpec().ConfigConstraintRef). 214 PrepareForTemplate(). 215 RerenderTemplate(). 216 ApplyParameters(). 217 UpdateConfigVersion(strconv.FormatInt(reconcileTask.ConfigurationObj.GetGeneration(), 10)). 218 Sync(). 219 SyncStatus(). 220 Complete() 221 Expect(err).Should(Succeed()) 222 223 By("rerender configuration template") 224 reconcileTask.item.Version = "v2" 225 err = reconcileTask.InitConfigSpec(). 226 Configuration(). 227 ConfigMap(configSpecName). 228 ConfigConstraints(reconcileTask.ConfigSpec().ConfigConstraintRef). 229 PrepareForTemplate(). 230 RerenderTemplate(). 231 ApplyParameters(). 232 UpdateConfigVersion(strconv.FormatInt(reconcileTask.ConfigurationObj.GetGeneration(), 10)). 233 Sync(). 234 SyncStatus(). 235 Complete() 236 Expect(err).Should(Succeed()) 237 }) 238 }) 239 240 })