From f308c6c20c1d9ea18924a46a41aa5b59e0819e2f Mon Sep 17 00:00:00 2001 From: zhyass <34016424+zhyass@users.noreply.github.com> Date: Mon, 12 Jul 2021 17:58:56 +0800 Subject: [PATCH] *: add xenon post-start.sh #135 --- cluster/container/init_sidecar.go | 4 ++ sidecar/config.go | 73 ++++++++++++++++++++++++++++--- sidecar/init.go | 10 +++++ sidecar/util.go | 20 +++++++-- 4 files changed, 99 insertions(+), 8 deletions(-) diff --git a/cluster/container/init_sidecar.go b/cluster/container/init_sidecar.go index f0300d7d1..f25311fe6 100644 --- a/cluster/container/init_sidecar.go +++ b/cluster/container/init_sidecar.go @@ -69,6 +69,10 @@ func (c *initSidecar) getEnvVars() []corev1.EnvVar { Name: "SERVICE_NAME", Value: c.GetNameForResource(utils.HeadlessSVC), }, + { + Name: "STATEFULSET_NAME", + Value: c.GetNameForResource(utils.StatefulSet), + }, { Name: "ADMIT_DEFEAT_HEARBEAT_COUNT", Value: strconv.Itoa(int(*c.Spec.XenonOpts.AdmitDefeatHearbeatCount)), diff --git a/sidecar/config.go b/sidecar/config.go index 2dbff0820..2451129c4 100644 --- a/sidecar/config.go +++ b/sidecar/config.go @@ -34,6 +34,8 @@ type Config struct { NameSpace string // The name of the headless service. ServiceName string + // The name of the statefulset. + StatefulSetName string // The password of the root user. RootPassword string @@ -70,6 +72,9 @@ type Config struct { AdmitDefeatHearbeatCount int32 // The parameter in xenon means election timeout(ms)。 ElectionTimeout int32 + + // Whether the MySQL data exists. + existMySQLData bool } // NewConfig returns a pointer to Config. @@ -94,10 +99,13 @@ func NewConfig() *Config { electionTimeout = 10000 } + existMySQLData, _ := checkIfDataExists() + return &Config{ - HostName: getEnvValue("POD_HOSTNAME"), - NameSpace: getEnvValue("NAMESPACE"), - ServiceName: getEnvValue("SERVICE_NAME"), + HostName: getEnvValue("POD_HOSTNAME"), + NameSpace: getEnvValue("NAMESPACE"), + ServiceName: getEnvValue("SERVICE_NAME"), + StatefulSetName: getEnvValue("STATEFULSET_NAME"), RootPassword: getEnvValue("MYSQL_ROOT_PASSWORD"), @@ -120,6 +128,8 @@ func NewConfig() *Config { AdmitDefeatHearbeatCount: int32(admitDefeatHearbeatCount), ElectionTimeout: int32(electionTimeout), + + existMySQLData: existMySQLData, } } @@ -128,11 +138,11 @@ func (cfg *Config) buildExtraConfig(filePath string) (*ini.File, error) { conf := ini.Empty() sec := conf.Section("mysqld") - id, err := generateServerID(cfg.HostName) + ordinal, err := getOrdinal(cfg.HostName) if err != nil { return nil, err } - if _, err := sec.NewKey("server-id", strconv.Itoa(id)); err != nil { + if _, err := sec.NewKey("server-id", strconv.Itoa(mysqlServerIDOffset+ordinal)); err != nil { return nil, err } @@ -254,3 +264,56 @@ func (cfg *Config) buildClientConfig() (*ini.File, error) { return conf, nil } + +func (cfg *Config) buildBashPostStart() ([]byte, error) { + var str1, str2, str3 string + ordinal, err := getOrdinal(cfg.HostName) + if err != nil { + return nil, err + } + selfPeer := fmt.Sprintf("%s.%s.%s:%d", cfg.HostName, cfg.ServiceName, cfg.NameSpace, utils.XenonPeerPort) + + str1 = fmt.Sprintf(`#!/bin/sh +while true; do + info=$(curl -i -X GET -u root:%s http://%s/v1/xenon/ping) + code=$(echo $info|grep "HTTP"|awk '{print $2}') + if [ "$code" -eq "200" ]; then + break + fi +done + +if [ $ordinal -eq 0 ]; then`, cfg.RootPassword, selfPeer) + + if cfg.existMySQLData { + str2 = ` + echo "do nothing"` + } else { + str2 = fmt.Sprintf(` + for i in $(seq 11); do + curl -i -X POST -u root:%s http://%s/v1/raft/trytoleader + sleep 5 + curl -i -X GET -u root:%s http://%s/v1/raft/status | grep LEADER + if [ $? -eq 0 ] ; then + break + fi + if [ $i -eq 11 ]; then + echo "wait trytoleader failed" + fi + done`, cfg.RootPassword, selfPeer, cfg.RootPassword, selfPeer) + } + + str3 = fmt.Sprintf(` +else + i=0 + while [ $i -lt %d ]; do + curl -i -X POST -d '{"address": "%s-$i.%s.%s:%d"}' -u root:%s http://%s/v1/cluster/add + curl -i -X POST -d '{"address": "%s"}' -u root:%s http://%s-$i.%s.%s:%d/v1/cluster/add + i=$((i+1)) + done +fi +`, ordinal, cfg.StatefulSetName, cfg.ServiceName, cfg.NameSpace, utils.XenonPeerPort, cfg.RootPassword, selfPeer, + selfPeer, cfg.RootPassword, cfg.StatefulSetName, cfg.ServiceName, cfg.NameSpace, utils.XenonPeerPort, + ) + + return utils.StringToBytes(str1 + str2 + str3), nil +} diff --git a/sidecar/init.go b/sidecar/init.go index eb414af10..76a8dfd09 100644 --- a/sidecar/init.go +++ b/sidecar/init.go @@ -115,6 +115,16 @@ func runInitCommand(cfg *Config) error { return fmt.Errorf("failed to save extra.cnf: %s", err) } + // build post-start.sh. + bashPostStart, err := cfg.buildBashPostStart() + if err != nil { + return fmt.Errorf("failed to build post-start.sh: %s", err) + } + bashPostStartPath := path.Join(scriptsPath, "post-start.sh") + if err = ioutil.WriteFile(bashPostStartPath, bashPostStart, 0644); err != nil { + return fmt.Errorf("failed to write post-start.sh: %s", err) + } + // copy leader-start.sh from config-map to scripts mount. leaderStartPath := path.Join(scriptsPath, "leader-start.sh") if err = copyFile(path.Join(configMapPath, "leader-start.sh"), leaderStartPath); err != nil { diff --git a/sidecar/util.go b/sidecar/util.go index 4bdf077a9..24d28dd6e 100644 --- a/sidecar/util.go +++ b/sidecar/util.go @@ -102,8 +102,7 @@ func getEnvValue(key string) string { return value } -// Generate mysql server-id from pod ordinal index. -func generateServerID(name string) (int, error) { +func getOrdinal(name string) (int, error) { idx := strings.LastIndexAny(name, "-") if idx == -1 { return -1, fmt.Errorf("failed to extract ordinal from hostname: %s", name) @@ -114,5 +113,20 @@ func generateServerID(name string) (int, error) { log.Error(err, "failed to extract ordinal form hostname", "hostname", name) return -1, fmt.Errorf("failed to extract ordinal from hostname: %s", name) } - return mysqlServerIDOffset + ordinal, nil + return ordinal, nil +} + +// nolint: gosec +func checkIfDataExists() (bool, error) { + path := fmt.Sprintf("%s/mysql", dataPath) + _, err := os.Open(path) + + if os.IsNotExist(err) { + return false, nil + } else if err != nil { + log.Error(err, "failed to open file", "file", path) + return false, err + } + + return true, nil }