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  })