diff --git a/api/v1alpha1/cluster_types.go b/api/v1alpha1/cluster_types.go index b40a9259b..497b62489 100644 --- a/api/v1alpha1/cluster_types.go +++ b/api/v1alpha1/cluster_types.go @@ -19,7 +19,6 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! @@ -149,7 +148,7 @@ type MetricsOpts struct { // MysqlConf defines type for extra cluster configs. It's a simple map between // string and string. -type MysqlConf map[string]intstr.IntOrString +type MysqlConf map[string]string // PodSpec defines type for configure cluster pod spec. type PodSpec struct { diff --git a/cluster/cluster.go b/cluster/cluster.go index c7a981492..08b30e8f3 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -19,13 +19,15 @@ package cluster import ( "fmt" "math" + "strconv" + "strings" + "unicode" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" apiv1alpha1 "github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1" @@ -34,8 +36,8 @@ import ( // nolint: megacheck, deadcode, varcheck const ( - _ = iota // ignore first value by assigning to blank identifier - kb int64 = 1 << (10 * iota) + _ = iota // ignore first value by assigning to blank identifier + kb uint64 = 1 << (10 * iota) mb gb ) @@ -257,26 +259,59 @@ func (c *Cluster) EnsureMysqlConf() { c.Spec.MysqlOpts.MysqlConf = make(apiv1alpha1.MysqlConf) } - var defaultSize, maxSize, innodbBufferPoolSize int64 + var defaultSize, maxSize, innodbBufferPoolSize uint64 innodbBufferPoolSize = 128 * mb - conf, ok := c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] - mem := c.Spec.MysqlOpts.Resources.Requests.Memory().Value() + mem := uint64(c.Spec.MysqlOpts.Resources.Requests.Memory().Value()) cpu := c.Spec.PodSpec.Resources.Limits.Cpu().MilliValue() if mem <= 1*gb { - defaultSize = int64(0.45 * float64(mem)) - maxSize = int64(0.6 * float64(mem)) + defaultSize = uint64(0.45 * float64(mem)) + maxSize = uint64(0.6 * float64(mem)) } else { - defaultSize = int64(0.6 * float64(mem)) - maxSize = int64(0.8 * float64(mem)) + defaultSize = uint64(0.6 * float64(mem)) + maxSize = uint64(0.8 * float64(mem)) } + conf, ok := c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] if !ok { innodbBufferPoolSize = utils.Max(defaultSize, innodbBufferPoolSize) } else { - innodbBufferPoolSize = utils.Min(utils.Max(int64(conf.IntVal), innodbBufferPoolSize), maxSize) + if nums, err := sizeToBytes(conf); err != nil { + innodbBufferPoolSize = utils.Max(defaultSize, innodbBufferPoolSize) + } else { + innodbBufferPoolSize = utils.Min(utils.Max(nums, innodbBufferPoolSize), maxSize) + } } instances := math.Max(math.Min(math.Ceil(float64(cpu)/float64(1000)), math.Floor(float64(innodbBufferPoolSize)/float64(gb))), 1) - c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] = intstr.FromInt(int(innodbBufferPoolSize)) - c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"] = intstr.FromInt(int(instances)) + c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_size"] = strconv.FormatUint(innodbBufferPoolSize, 10) + c.Spec.MysqlOpts.MysqlConf["innodb_buffer_pool_instances"] = strconv.Itoa(int(instances)) +} + +// sizeToBytes parses a string formatted by ByteSize as bytes. +// K = 1024 +// M = 1024 * K +// G = 1024 * M +func sizeToBytes(s string) (uint64, error) { + s = strings.TrimSpace(s) + s = strings.ToUpper(s) + + idx := strings.IndexFunc(s, unicode.IsLetter) + if idx == -1 { + return strconv.ParseUint(s, 10, 64) + } + + nums, err := strconv.ParseUint(s[:idx], 10, 64) + if err != nil { + return 0, err + } + + switch s[idx:] { + case "K": + return nums * kb, nil + case "M": + return nums * mb, nil + case "G": + return nums * gb, nil + } + return 0, fmt.Errorf("'%s' format error, must be a positive integer with a unit of measurement like K, M or G", s) } diff --git a/cluster/syncer/config_map.go b/cluster/syncer/config_map.go index 4046b45b8..0395b650a 100644 --- a/cluster/syncer/config_map.go +++ b/cluster/syncer/config_map.go @@ -25,7 +25,6 @@ import ( "github.com/presslabs/controller-util/syncer" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/radondb/radondb-mysql-kubernetes/cluster" @@ -69,11 +68,10 @@ func buildMysqlConf(c *cluster.Cluster) (string, error) { c.EnsureMysqlConf() - addKVConfigsToSection(sec, convertMapToKVConfig(mysqlSysConfigs), convertMapToKVConfig(mysqlCommonConfigs), - convertMapToKVConfig(mysqlStaticConfigs), c.Spec.MysqlOpts.MysqlConf) + addKVConfigsToSection(sec, mysqlSysConfigs, mysqlCommonConfigs, mysqlStaticConfigs, c.Spec.MysqlOpts.MysqlConf) if c.Spec.MysqlOpts.InitTokuDB { - addKVConfigsToSection(sec, convertMapToKVConfig(mysqlTokudbConfigs)) + addKVConfigsToSection(sec, mysqlTokudbConfigs) } for _, key := range mysqlBooleanConfigs { @@ -91,7 +89,7 @@ func buildMysqlConf(c *cluster.Cluster) (string, error) { } // addKVConfigsToSection add a map[string]string to a ini.Section -func addKVConfigsToSection(s *ini.Section, extraMysqld ...map[string]intstr.IntOrString) { +func addKVConfigsToSection(s *ini.Section, extraMysqld ...map[string]string) { for _, extra := range extraMysqld { keys := []string{} for key := range extra { @@ -103,24 +101,13 @@ 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 { + if _, err := s.NewKey(k, value); err != nil { log.Error(err, "failed to add key to config section", "key", k, "value", extra[k], "section", s) } } } } -// convertMapToKVConfig convert map to kv config. -func convertMapToKVConfig(m map[string]string) map[string]intstr.IntOrString { - config := make(map[string]intstr.IntOrString) - - for key, value := range m { - config[key] = intstr.FromString(value) - } - - return config -} - // writeConfigs write to string ini.File // nolint: interfacer func writeConfigs(cfg *ini.File) (string, error) { diff --git a/config/samples/mysql_v1alpha1_cluster.yaml b/config/samples/mysql_v1alpha1_cluster.yaml index 8776c7804..6cb69d0a6 100644 --- a/config/samples/mysql_v1alpha1_cluster.yaml +++ b/config/samples/mysql_v1alpha1_cluster.yaml @@ -13,6 +13,10 @@ spec: database: qingcloud initTokuDB: true + # A simple map between string and string. + # Such as: + # mysqlConf: + # expire_logs_days: "7" mysqlConf: {} resources: diff --git a/utils/common.go b/utils/common.go index 79b0b0e7d..b6a868d85 100644 --- a/utils/common.go +++ b/utils/common.go @@ -17,7 +17,7 @@ limitations under the License. package utils // Min returns the smallest int64 that was passed in the arguments. -func Min(a, b int64) int64 { +func Min(a, b uint64) uint64 { if a < b { return a } @@ -25,7 +25,7 @@ func Min(a, b int64) int64 { } // Max returns the largest int64 that was passed in the arguments. -func Max(a, b int64) int64 { +func Max(a, b uint64) uint64 { if a > b { return a }