Skip to content

Commit

Permalink
*: add xenon post-start.sh radondb#135
Browse files Browse the repository at this point in the history
  • Loading branch information
zhyass committed Jul 13, 2021
1 parent 69462a1 commit 0ecebe4
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 57 deletions.
4 changes: 4 additions & 0 deletions cluster/container/init_sidecar.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
5 changes: 1 addition & 4 deletions cluster/container/xenon.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ limitations under the License.
package container

import (
"fmt"

corev1 "k8s.io/api/core/v1"

"github.com/radondb/radondb-mysql-kubernetes/cluster"
Expand Down Expand Up @@ -55,11 +53,10 @@ func (c *xenon) getEnvVars() []corev1.EnvVar {

// getLifecycle get the container lifecycle.
func (c *xenon) getLifecycle() *corev1.Lifecycle {
arg := fmt.Sprintf("until (xenoncli xenon ping && xenoncli cluster add %s) > /dev/null 2>&1; do sleep 2; done", c.CreatePeers())
return &corev1.Lifecycle{
PostStart: &corev1.Handler{
Exec: &corev1.ExecAction{
Command: []string{"sh", "-c", arg},
Command: []string{"sh", "-c", "/scripts/post-start.sh"},
},
},
}
Expand Down
28 changes: 9 additions & 19 deletions cluster/syncer/config_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ func NewConfigMapSyncer(cli client.Client, c *cluster.Cluster) syncer.Interface
}

cm.Data = map[string]string{
"my.cnf": data,
"leader-start.sh": buildLeaderStart(c),
"leader-stop.sh": buildLeaderStop(c),
"my.cnf": data,
"post-start.sh": buildPostStart(c),
}

return nil
Expand Down Expand Up @@ -118,20 +117,11 @@ func writeConfigs(cfg *ini.File) (string, error) {
return buf.String(), nil
}

// buildLeaderStart build the leader-start.sh.
func buildLeaderStart(c *cluster.Cluster) string {
return fmt.Sprintf(`#!/usr/bin/env bash
curl -X PATCH -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -H "Content-Type: application/json-patch+json" \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/%s/pods/$HOSTNAME \
-d '[{"op": "replace", "path": "/metadata/labels/role", "value": "leader"}]'
`, c.Namespace)
}

// buildLeaderStop build the leader-stop.sh.
func buildLeaderStop(c *cluster.Cluster) string {
return fmt.Sprintf(`#!/usr/bin/env bash
curl -X PATCH -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -H "Content-Type: application/json-patch+json" \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/%s/pods/$HOSTNAME \
-d '[{"op": "replace", "path": "/metadata/labels/role", "value": "follower"}]'
`, c.Namespace)
// buildPostStart build the post-start.sh.
func buildPostStart(c *cluster.Cluster) string {
return fmt.Sprintf(`#!/bin/sh
until (xenoncli xenon ping && xenoncli cluster add %s); do
sleep 2
done
`, c.CreatePeers())
}
88 changes: 83 additions & 5 deletions sidecar/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -94,10 +99,13 @@ func NewConfig() *Config {
electionTimeout = 10000
}

existMySQLData, _ := checkIfPathExists(fmt.Sprintf("%s/mysql", dataPath))

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"),

Expand All @@ -120,6 +128,8 @@ func NewConfig() *Config {

AdmitDefeatHearbeatCount: int32(admitDefeatHearbeatCount),
ElectionTimeout: int32(electionTimeout),

existMySQLData: existMySQLData,
}
}

Expand All @@ -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
}

Expand Down Expand Up @@ -254,3 +264,71 @@ func (cfg *Config) buildClientConfig() (*ini.File, error) {

return conf, nil
}

func (cfg *Config) buildPostStart() ([]byte, error) {
ordinal, err := getOrdinal(cfg.HostName)
if err != nil {
return nil, err
}
host := fmt.Sprintf("%s.%s.%s", cfg.HostName, cfg.ServiceName, cfg.NameSpace)

str := fmt.Sprintf(`#!/bin/sh
while true; do
info=$(curl -i -X GET -u root:%s http://%s:%d/v1/xenon/ping)
code=$(echo $info|grep "HTTP"|awk '{print $2}')
if [ "$code" -eq "200" ]; then
break
fi
done
`, cfg.RootPassword, host, utils.XenonPeerPort)

if ordinal == 0 {
str = fmt.Sprintf(`%s
for i in $(seq 12); do
curl -i -X POST -u root:%s http://%s:%d/v1/raft/trytoleader
sleep 5
curl -i -X GET -u root:%s http://%s:%d/v1/raft/status | grep LEADER
if [ $? -eq 0 ] ; then
echo "trytoleader success"
break
fi
if [ $i -eq 12 ]; then
echo "wait trytoleader failed"
fi
done
`, str, cfg.RootPassword, host, utils.XenonPeerPort, cfg.RootPassword, host, utils.XenonPeerPort)
} else {
str = fmt.Sprintf(`%s
i=0
while [ $i -lt %d ]; do
curl -i -X POST -d '{"address": "%s-'$i'.%s.%s:%d"}' -u root:%s http://%s:%d/v1/cluster/add
curl -i -X POST -d '{"address": "%s:%d"}' -u root:%s http://%s-$i.%s.%s:%d/v1/cluster/add
i=$((i+1))
done
`, str, ordinal, cfg.StatefulSetName, cfg.ServiceName, cfg.NameSpace, utils.XenonPort, cfg.RootPassword,
host, utils.XenonPeerPort, host, utils.XenonPort, cfg.RootPassword, cfg.StatefulSetName,
cfg.ServiceName, cfg.NameSpace, utils.XenonPeerPort)
}

return utils.StringToBytes(str), nil
}

// buildLeaderStart build the leader-start.sh.
func (cfg *Config) buildLeaderStart() []byte {
str := fmt.Sprintf(`#!/usr/bin/env bash
curl -X PATCH -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -H "Content-Type: application/json-patch+json" \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/%s/pods/$HOSTNAME \
-d '[{"op": "replace", "path": "/metadata/labels/role", "value": "leader"}]'
`, cfg.NameSpace)
return utils.StringToBytes(str)
}

// buildLeaderStop build the leader-stop.sh.
func (cfg *Config) buildLeaderStop() []byte {
str := fmt.Sprintf(`#!/usr/bin/env bash
curl -X PATCH -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -H "Content-Type: application/json-patch+json" \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/%s/pods/$HOSTNAME \
-d '[{"op": "replace", "path": "/metadata/labels/role", "value": "follower"}]'
`, cfg.NameSpace)
return utils.StringToBytes(str)
}
53 changes: 27 additions & 26 deletions sidecar/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,37 @@ func runInitCommand(cfg *Config) error {
return fmt.Errorf("failed to save extra.cnf: %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 {
return fmt.Errorf("failed to copy scripts: %s", err)
// build post-start.sh.
bashPostStartPath := path.Join(scriptsPath, "post-start.sh")
if cfg.existMySQLData {
if err = copyFile(path.Join(configMapPath, "post-start.sh"), bashPostStartPath); err != nil {
return fmt.Errorf("failed to copy scripts: %s", err)
}
if err = os.Chmod(bashPostStartPath, os.FileMode(0755)); err != nil {
return fmt.Errorf("failed to chmod scripts: %s", err)
}
} else {
bashPostStart, err := cfg.buildPostStart()
if err != nil {
return fmt.Errorf("failed to build post-start.sh: %s", err)
}
if err = ioutil.WriteFile(bashPostStartPath, bashPostStart, os.FileMode(0755)); err != nil {
return fmt.Errorf("failed to write post-start.sh: %s", err)
}
}
if err = os.Chmod(leaderStartPath, os.FileMode(0755)); err != nil {
return fmt.Errorf("failed to chmod scripts: %s", err)

// build leader-start.sh.
bashLeaderStart := cfg.buildLeaderStart()
leaderStartPath := path.Join(scriptsPath, "leader-start.sh")
if err = ioutil.WriteFile(leaderStartPath, bashLeaderStart, os.FileMode(0755)); err != nil {
return fmt.Errorf("failed to write leader-start.sh: %s", err)
}

// copy leader-stop.sh from config-map to scripts mount.
// build leader-stop.sh.
bashLeaderStop := cfg.buildLeaderStop()
leaderStopPath := path.Join(scriptsPath, "leader-stop.sh")
if err = copyFile(path.Join(configMapPath, "leader-stop.sh"), leaderStopPath); err != nil {
return fmt.Errorf("failed to copy scripts: %s", err)
}
if err = os.Chmod(leaderStopPath, os.FileMode(0755)); err != nil {
return fmt.Errorf("failed to chmod scripts: %s", err)
if err = ioutil.WriteFile(leaderStopPath, bashLeaderStop, os.FileMode(0755)); err != nil {
return fmt.Errorf("failed to write leader-stop.sh: %s", err)
}

// for install tokudb.
Expand All @@ -152,17 +167,3 @@ func runInitCommand(cfg *Config) error {
log.Info("init command success")
return nil
}

// checkIfPathExists check if the path exists.
func checkIfPathExists(path string) (bool, error) {
f, 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
}

err = f.Close()
return true, err
}
19 changes: 16 additions & 3 deletions sidecar/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -114,5 +113,19 @@ 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
}

// checkIfPathExists check if the path exists.
func checkIfPathExists(path string) (bool, error) {
f, 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
}

err = f.Close()
return true, err
}

0 comments on commit 0ecebe4

Please sign in to comment.