From 726d2c39c9c180a03c7ea5f981d326a644f7d983 Mon Sep 17 00:00:00 2001 From: "bing.ma" Date: Wed, 9 Oct 2024 15:59:15 +0800 Subject: [PATCH] use mysql compatible configuration and allow duplicate keys in mysqlConf field of cr --- CHANGELOG.md | 2 + .../mysql.presslabs.org_mysqlclusters.yaml | 9 +- .../mysql.presslabs.org_mysqlclusters.yaml | 9 +- examples/example-cluster.yaml | 5 +- .../mysql/v1alpha1/mysqlcluster_defaults.go | 2 +- pkg/apis/mysql/v1alpha1/mysqlcluster_types.go | 104 +++++++++++++++++- .../mysql/v1alpha1/mysqlcluster_types_test.go | 2 +- .../mysql/v1alpha1/zz_generated.deepcopy.go | 28 ----- .../mysqlbackupcron_controller_test.go | 6 +- .../internal/syncer/config_map.go | 26 ++++- pkg/internal/mysqlcluster/defaults.go | 21 ++-- pkg/internal/mysqlcluster/mysqlcluster.go | 12 +- .../mysqlcluster/mysqlcluster_test.go | 27 +++-- 13 files changed, 169 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fba55319f..2ef827896 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). * Add SidecarImage fields to `.Spec` to allow specifying custom sidecar image. ### Changed +* Change the type of `spec.mysqlConf` in the `mysqlclusters` crd to string + ### Removed ### Fixed * Avoid set read_only conflict when graceful takeover diff --git a/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml b/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml index ac7ef46d8..8c28e680f 100644 --- a/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml +++ b/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml @@ -98,13 +98,8 @@ spec: description: The number of pods from that set that must still be available after the eviction, even in the absence of the evicted pod Defaults to 50% type: string mysqlConf: - additionalProperties: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - description: A map[string]string that will be passed to my.cnf file. - type: object + description: A string that will be passed to my.cnf file, it should be compatible with mysql config format. + type: string mysqlVersion: description: 'Represents the MySQL version that will be run. The available version can be found here: https://github.com/bitpoke/mysql-operator/blob/0fd4641ce4f756a0aab9d31c8b1f1c44ee10fcb2/pkg/util/constants/constants.go#L87 This field should be set even if the Image is set to let the operator know which mysql version is running. Based on this version the operator can take decisions which features can be used. Defaults to 5.7' type: string diff --git a/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml b/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml index ff7e015f5..9dd0cce54 100644 --- a/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml +++ b/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml @@ -99,13 +99,8 @@ spec: description: The number of pods from that set that must still be available after the eviction, even in the absence of the evicted pod Defaults to 50% type: string mysqlConf: - additionalProperties: - anyOf: - - type: integer - - type: string - x-kubernetes-int-or-string: true - description: A map[string]string that will be passed to my.cnf file. - type: object + description: A string that will be passed to my.cnf file, it should be compatible with mysql config format. + type: string mysqlVersion: description: 'Represents the MySQL version that will be run. The available version can be found here: https://github.com/bitpoke/mysql-operator/blob/0fd4641ce4f756a0aab9d31c8b1f1c44ee10fcb2/pkg/util/constants/constants.go#L87 This field should be set even if the Image is set to let the operator know which mysql version is running. Based on this version the operator can take decisions which features can be used. Defaults to 5.7' type: string diff --git a/examples/example-cluster.yaml b/examples/example-cluster.yaml index 57bdf54cb..7ba1ea7b7 100644 --- a/examples/example-cluster.yaml +++ b/examples/example-cluster.yaml @@ -58,8 +58,9 @@ spec: # serverIDOffset: 100 ## Configs that will be added to my.cnf for cluster - mysqlConf: - # innodb-buffer-size: 128M + ## just write it the same way you write the MySQL configuration file + mysqlConf: |- + # innodb-buffer-size = 128M ## Specify additional pod specification diff --git a/pkg/apis/mysql/v1alpha1/mysqlcluster_defaults.go b/pkg/apis/mysql/v1alpha1/mysqlcluster_defaults.go index 78f9b1673..630166b17 100644 --- a/pkg/apis/mysql/v1alpha1/mysqlcluster_defaults.go +++ b/pkg/apis/mysql/v1alpha1/mysqlcluster_defaults.go @@ -50,7 +50,7 @@ func SetDefaults_MysqlCluster(c *MysqlCluster) { } if len(c.Spec.MysqlConf) == 0 { - c.Spec.MysqlConf = make(MysqlConf) + c.Spec.MysqlConf = "" } if len(c.Spec.MinAvailable) == 0 && *c.Spec.Replicas > 1 { diff --git a/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go b/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go index 424b3c5e4..790c2ac6b 100644 --- a/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go +++ b/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go @@ -17,6 +17,9 @@ limitations under the License. package v1alpha1 import ( + "fmt" + "strings" + core "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -100,7 +103,7 @@ type MysqlClusterSpec struct { // +optional BackupScheduleJobsHistoryLimit *int `json:"backupScheduleJobsHistoryLimit,omitempty"` - // A map[string]string that will be passed to my.cnf file. + // A string that will be passed to my.cnf file, it should be compatible with mysql config format. // +optional MysqlConf MysqlConf `json:"mysqlConf,omitempty"` @@ -175,9 +178,100 @@ type MysqlClusterSpec struct { InitFileExtraSQL []string `json:"initFileExtraSQL,omitempty"` } -// MysqlConf defines type for extra cluster configs. It's a simple map between -// string and string. -type MysqlConf map[string]intstr.IntOrString +// MysqlConf defines type for extra cluster configs. value is a mysql ini string, allow duplicate keys, like: +// replicated_do_db=db1 +// replicated_do_db=db2 +type MysqlConf string + +// Get returns the value of key, if found, mysql allow no value in config, so we need to return a bool +func (m MysqlConf) Get(key string) (string, bool) { + s := string(m) + lines := strings.Split(s, "\n") + for _, line := range lines { + if line == "" { + continue + } + keyAndValue := strings.Split(strings.TrimSpace(line), "=") + if strings.TrimSpace(keyAndValue[0]) == strings.TrimSpace(key) { + if len(keyAndValue) == 1 { + return "", true + } + if len(keyAndValue) == 2 { + return strings.TrimSpace(keyAndValue[1]), true + } + } + } + return "", false +} + +// Set a key value pair, if key already exists, it will be overwritten else it will append at the end +func (m MysqlConf) Set(key string, value string) MysqlConf { + s := string(m) + lines := strings.Split(s, "\n") + trimmedKey := strings.TrimSpace(key) + trimmedValue := strings.TrimSpace(value) + found := false + for index, line := range lines { + keyAndValue := strings.Split(strings.TrimSpace(line), "=") + if strings.TrimSpace(keyAndValue[0]) == trimmedKey { + found = true + // mysql allow bare boolean options with no value assignment,like: + // [mysqld] + // skip-name-resolve # no value here, when len(keyAndValue) == 1 + + // when len(keyAndValue) == 2 means "key = value" + if len(keyAndValue) == 1 && trimmedValue != "" || len(keyAndValue) == 2 { + // need to set key = value + lines[index] = fmt.Sprintf("%s = %s", trimmedKey, trimmedValue) + } + } + } + res := strings.Join(lines, "\n") + if !found { + if trimmedValue != "" { + res += fmt.Sprintf("\n%s = %s", trimmedKey, trimmedValue) + } else { + res += fmt.Sprintf("\n%s", trimmedKey) + } + } + return MysqlConf(res) +} + +// ToMap returns a map[string]string, to compatible with addKVConfigsToSection +func (m MysqlConf) ToMap() []map[string]intstr.IntOrString { + trimmed := strings.TrimSpace(string(m)) + res := make([]map[string]intstr.IntOrString, 0) + if trimmed == "" { + return res + } + lines := strings.Split(trimmed, "\n") + total := make(map[string]intstr.IntOrString) + for _, line := range lines { + trimmedLine := strings.TrimSpace(line) + if trimmedLine == "" { + continue + } + keyAndValue := strings.Split(trimmedLine, "=") + length := len(keyAndValue) + if length != 1 && length != 2 { + continue + } + key := strings.TrimSpace(keyAndValue[0]) + value := intstr.FromString("") + if length == 2 { + value = intstr.FromString(strings.TrimSpace(keyAndValue[1])) + } + if _, ok := total[key]; ok { + res = append(res, map[string]intstr.IntOrString{key: value}) + } else { + total[key] = value + } + } + if len(total) != 0 { + res = append(res, total) + } + return res +} // PodSpec defines type for configure cluster pod spec. type PodSpec struct { @@ -376,7 +470,6 @@ type MysqlClusterStatus struct { // +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".spec.replicas",description="The number of desired nodes" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:resource:shortName=mysql -// type MysqlCluster struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -387,7 +480,6 @@ type MysqlCluster struct { // MysqlClusterList contains a list of MysqlCluster // +kubebuilder:object:root=true -// type MysqlClusterList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/pkg/apis/mysql/v1alpha1/mysqlcluster_types_test.go b/pkg/apis/mysql/v1alpha1/mysqlcluster_types_test.go index 507a628ad..43e558fd7 100644 --- a/pkg/apis/mysql/v1alpha1/mysqlcluster_types_test.go +++ b/pkg/apis/mysql/v1alpha1/mysqlcluster_types_test.go @@ -83,7 +83,7 @@ var _ = Describe("MysqlCluster CRUD", func() { It("should populate fields defaults", func() { SetDefaults_MysqlCluster(cluster) - Expect(cluster.Spec.MysqlConf).NotTo(BeNil()) + Expect(cluster.Spec.MysqlConf).NotTo(Equal("")) }) }) diff --git a/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go index f41327f2f..a6cb02006 100644 --- a/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go @@ -259,13 +259,6 @@ func (in *MysqlClusterSpec) DeepCopyInto(out *MysqlClusterSpec) { *out = new(int) **out = **in } - if in.MysqlConf != nil { - in, out := &in.MysqlConf, &out.MysqlConf - *out = make(MysqlConf, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } in.PodSpec.DeepCopyInto(&out.PodSpec) in.VolumeSpec.DeepCopyInto(&out.VolumeSpec) if in.TmpfsSize != nil { @@ -369,27 +362,6 @@ func (in *MysqlClusterStatus) DeepCopy() *MysqlClusterStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in MysqlConf) DeepCopyInto(out *MysqlConf) { - { - in := &in - *out = make(MysqlConf, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MysqlConf. -func (in MysqlConf) DeepCopy() MysqlConf { - if in == nil { - return nil - } - out := new(MysqlConf) - in.DeepCopyInto(out) - return *out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MysqlDatabase) DeepCopyInto(out *MysqlDatabase) { *out = *in diff --git a/pkg/controller/mysqlbackupcron/mysqlbackupcron_controller_test.go b/pkg/controller/mysqlbackupcron/mysqlbackupcron_controller_test.go index 9edf47e07..7b30d9fdb 100644 --- a/pkg/controller/mysqlbackupcron/mysqlbackupcron_controller_test.go +++ b/pkg/controller/mysqlbackupcron/mysqlbackupcron_controller_test.go @@ -32,7 +32,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -170,9 +169,8 @@ var _ = Describe("MysqlBackupCron controller", func() { It("should be just one entry for a cluster", func() { // update cluster spec - cluster.Spec.MysqlConf = map[string]intstr.IntOrString{ - "something": intstr.FromString("new"), - } + cluster.Spec.MysqlConf = "something = new" + Expect(c.Update(context.TODO(), cluster)).To(Succeed()) // expect an reconcile event diff --git a/pkg/controller/mysqlcluster/internal/syncer/config_map.go b/pkg/controller/mysqlcluster/internal/syncer/config_map.go index 2ff091306..a30380955 100644 --- a/pkg/controller/mysqlcluster/internal/syncer/config_map.go +++ b/pkg/controller/mysqlcluster/internal/syncer/config_map.go @@ -94,7 +94,10 @@ fi } func buildMysqlConfData(cluster *mysqlcluster.MysqlCluster) (string, error) { - cfg := ini.Empty() + // allow duplicate key in section + cfg := ini.Empty(ini.LoadOptions{ + AllowShadows: true, + }) sec := cfg.Section("mysqld") if cluster.GetMySQLSemVer().Major == 5 { @@ -106,8 +109,13 @@ func buildMysqlConfData(cluster *mysqlcluster.MysqlCluster) (string, error) { // boolean configs addBConfigsToSection(sec, mysqlMasterSlaveBooleanConfigs) // add custom configs, would overwrite common configs - addKVConfigsToSection(sec, convertMapToKVConfig(mysqlCommonConfigs), cluster.Spec.MysqlConf) - + extraMysqld := cluster.Spec.MysqlConf.ToMap() + if extraMysqld != nil { + extraMysqld = append(extraMysqld, convertMapToKVConfig(mysqlCommonConfigs)) + } else { + extraMysqld = make([]map[string]intstr.IntOrString, 0) + } + addKVConfigsToSection(sec, extraMysqld...) // include configs from /etc/mysql/conf.d/*.cnf _, err := sec.NewBooleanKey(fmt.Sprintf("!includedir %s", ConfDPath)) if err != nil { @@ -120,7 +128,6 @@ func buildMysqlConfData(cluster *mysqlcluster.MysqlCluster) (string, error) { } return data, nil - } func convertMapToKVConfig(m map[string]string) map[string]intstr.IntOrString { @@ -146,8 +153,15 @@ func addKVConfigsToSection(s *ini.Section, extraMysqld ...map[string]intstr.IntO for _, k := range keys { value := extra[k] - if _, err := s.NewKey(k, value.String()); err != nil { - log.Error(err, "failed to add key to config section", "key", k, "value", extra[k], "section", s) + // in (m MysqlConf) ToMap() we set it to "" when spec.mysqlConf no value. + if value.String() == "" { + if _, err := s.NewBooleanKey(k); err != nil { + log.Error(err, "failed to add boolean key to config section", "key", k) + } + } else { + if _, err := s.NewKey(k, value.String()); err != nil { + log.Error(err, "failed to add key to config section", "key", k, "value", extra[k], "section", s) + } } } } diff --git a/pkg/internal/mysqlcluster/defaults.go b/pkg/internal/mysqlcluster/defaults.go index f69bbc33d..8345755f6 100644 --- a/pkg/internal/mysqlcluster/defaults.go +++ b/pkg/internal/mysqlcluster/defaults.go @@ -87,13 +87,13 @@ func (cluster *MysqlCluster) SetDefaults(opt *options.Options) { if mem := cluster.Spec.PodSpec.Resources.Requests.Memory(); mem != nil && !mem.IsZero() { var cErr error if innodbBufferPoolSize, cErr = computeInnodbBufferPoolSize(mem); cErr == nil { - setConfigIfNotSet(cluster.Spec.MysqlConf, "innodb-buffer-pool-size", humanizeSize(innodbBufferPoolSize)) + cluster.Spec.MysqlConf = setConfigIfNotSet(cluster.Spec.MysqlConf, "innodb-buffer-pool-size", humanizeSize(innodbBufferPoolSize)) } } if mem := cluster.Spec.PodSpec.Resources.Requests.Memory(); mem != nil { logFileSize := humanizeSize(computeInnodbLogFileSize(mem)) - setConfigIfNotSet(cluster.Spec.MysqlConf, "innodb-log-file-size", logFileSize) + cluster.Spec.MysqlConf = setConfigIfNotSet(cluster.Spec.MysqlConf, "innodb-log-file-size", logFileSize) } if pvc := cluster.Spec.VolumeSpec.PersistentVolumeClaim; pvc != nil { @@ -107,11 +107,13 @@ func (cluster *MysqlCluster) SetDefaults(opt *options.Options) { if cluster.IsPerconaImage() { // binlog-space-limit = totalSpace / 2 - setConfigIfNotSet(cluster.Spec.MysqlConf, "binlog-space-limit", humanizeSize(binlogSpaceLimit)) + cluster.Spec.MysqlConf = setConfigIfNotSet(cluster.Spec.MysqlConf, "binlog-space-limit", + humanizeSize(binlogSpaceLimit)) } // max-binlog-size = min(binlog-space-limit / 4, 1*gb) - setConfigIfNotSet(cluster.Spec.MysqlConf, "max-binlog-size", humanizeSize(maxBinlogSize)) + cluster.Spec.MysqlConf = setConfigIfNotSet(cluster.Spec.MysqlConf, "max-binlog-size", + humanizeSize(maxBinlogSize)) } } @@ -119,7 +121,8 @@ func (cluster *MysqlCluster) SetDefaults(opt *options.Options) { // innodb_buffer_pool_instances = min(ceil(resources.limits.cpu), floor(innodb_buffer_pool_size/1Gi)) cpuRounded := math.Ceil(float64(cpu.MilliValue()) / float64(1000)) instances := math.Max(math.Min(cpuRounded, math.Floor(float64(innodbBufferPoolSize)/float64(gb))), 1) - setConfigIfNotSet(cluster.Spec.MysqlConf, "innodb-buffer-pool-instances", intstr.FromInt(int(instances))) + cluster.Spec.MysqlConf = setConfigIfNotSet(cluster.Spec.MysqlConf, "innodb-buffer-pool-instances", + intstr.FromInt(int(instances))) } // set default xtrabackup target directory @@ -128,10 +131,12 @@ func (cluster *MysqlCluster) SetDefaults(opt *options.Options) { } } -func setConfigIfNotSet(conf api.MysqlConf, option string, value intstr.IntOrString) { - if _, ok := conf[option]; !ok { - conf[option] = value +func setConfigIfNotSet(conf api.MysqlConf, option string, value intstr.IntOrString) api.MysqlConf { + valueStr := value.String() + if valueStr == "" { + valueStr = "" } + return conf.Set(option, valueStr) } func getRequestedStorage(pvc *core.PersistentVolumeClaimSpec) *resource.Quantity { diff --git a/pkg/internal/mysqlcluster/mysqlcluster.go b/pkg/internal/mysqlcluster/mysqlcluster.go index dd8155157..3d3ab28e8 100644 --- a/pkg/internal/mysqlcluster/mysqlcluster.go +++ b/pkg/internal/mysqlcluster/mysqlcluster.go @@ -18,6 +18,7 @@ package mysqlcluster import ( "fmt" + "strconv" "strings" "github.com/blang/semver" @@ -246,10 +247,15 @@ func (c *MysqlCluster) ExporterDataSourcePort() int { extraMaxConnectionsSettings := []string{"extra_max_connections", "extra-max-connections"} for _, setting := range extraPortSettings { - if port, ok := c.Spec.MysqlConf[setting]; ok { + if port, ok := c.Spec.MysqlConf.Get(setting); ok { for _, setting := range extraMaxConnectionsSettings { - if conns, ok := c.Spec.MysqlConf[setting]; ok && conns.IntValue() > 1 { - return port.IntValue() + if conns, ok := c.Spec.MysqlConf.Get(setting); ok { + connsInt, err := strconv.Atoi(conns) + if err == nil && connsInt > 1 { + if portInt, err := strconv.Atoi(port); err == nil { + return portInt + } + } } } } diff --git a/pkg/internal/mysqlcluster/mysqlcluster_test.go b/pkg/internal/mysqlcluster/mysqlcluster_test.go index a472f8640..5af7e2208 100644 --- a/pkg/internal/mysqlcluster/mysqlcluster_test.go +++ b/pkg/internal/mysqlcluster/mysqlcluster_test.go @@ -27,7 +27,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog" "k8s.io/klog/v2/klogr" @@ -59,7 +58,7 @@ var _ = Describe("Test MySQL cluster wrapper", func() { }, Spec: api.MysqlClusterSpec{ SecretName: "sct-name", - MysqlConf: map[string]intstr.IntOrString{}, + MysqlConf: "", }, }) // set defaults @@ -72,9 +71,9 @@ var _ = Describe("Test MySQL cluster wrapper", func() { Expect(cluster.GetMysqlImage()).To(ContainSubstring("percona")) Expect(cluster.Spec.PodSpec.Resources.Requests.Memory()).To(PointTo(Equal(resource.MustParse("1Gi")))) - Expect(cluster.Spec.MysqlConf).To(HaveKey(Equal("innodb-buffer-pool-size"))) - Expect(cluster.Spec.MysqlConf).To(HaveKey(Equal("innodb-log-file-size"))) - Expect(cluster.Spec.MysqlConf).NotTo(HaveKey(Equal("max-binlog-size"))) + Expect(string(cluster.Spec.MysqlConf)).To(ContainSubstring("innodb-buffer-pool-size")) + Expect(string(cluster.Spec.MysqlConf)).To(ContainSubstring("innodb-log-file-size")) + Expect(string(cluster.Spec.MysqlConf)).NotTo(ContainSubstring("max-binlog-size")) }) It("should use init MySQL container", func() { @@ -105,7 +104,7 @@ var _ = Describe("Test MySQL cluster wrapper", func() { func(mem, cpu, expectedBufferSize, expectedBufferInstances string) { cluster = New(&api.MysqlCluster{ Spec: api.MysqlClusterSpec{ - MysqlConf: map[string]intstr.IntOrString{}, + MysqlConf: "", PodSpec: api.PodSpec{ Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ @@ -120,11 +119,17 @@ var _ = Describe("Test MySQL cluster wrapper", func() { }) cluster.SetDefaults(options.GetOptions()) - valBS := cluster.Spec.MysqlConf["innodb-buffer-pool-size"] - Expect(valBS.String()).To(Equal(expectedBufferSize)) - - valBI := cluster.Spec.MysqlConf["innodb-buffer-pool-instances"] - Expect(valBI.String()).To(Equal(expectedBufferInstances)) + valBS, found := cluster.Spec.MysqlConf.Get("innodb-buffer-pool-size") + if !found { + valBS = "0" + } + Expect(valBS).To(Equal(expectedBufferSize)) + + valBI, found := cluster.Spec.MysqlConf.Get("innodb-buffer-pool-instances") + if !found { + valBI = "0" + } + Expect(valBI).To(Equal(expectedBufferInstances)) }, // memory, cpu, innodbBufferSize, innodbBufferInstances Entry("zero", "0", "0", "0", "0"),