Skip to content

Commit 0c496e3

Browse files
authored
*: Add inCluster related API and xenon checker (#596)
* feat(build): init bulid folder add the dockerfile of xenon. TODO: Moving other dockerfiles to the Build directory, this requires updating related CIs first. * feat(container): Added inCluster related API and xenon checker
1 parent 2c9b73f commit 0c496e3

File tree

6 files changed

+232
-2
lines changed

6 files changed

+232
-2
lines changed

build/xenon/Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM golang:1.16 as builder
2+
3+
WORKDIR /
4+
# Copy the Go Modules manifests
5+
COPY go.mod go.mod
6+
COPY go.sum go.sum
7+
# cache deps before building and copying source so that we don't need to re-download as much
8+
# and so that source changes don't invalidate our downloaded layer
9+
RUN go env -w GOPROXY=https://goproxy.cn,direct;
10+
#     go mod download
11+
RUN  go mod download
12+
13+
# Copy the go source
14+
COPY cmd/xenon/main.go cmd/xenon/main.go
15+
COPY utils/ utils/
16+
17+
# Build
18+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o bin/xenonchecker cmd/xenon/main.go
19+
20+
FROM radondb/xenon:1.1.5-alpha
21+
22+
COPY --from=builder /bin/xenonchecker /xenonchecker

cmd/staticcheck.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
checks=[ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022", "-ST1001"]

cmd/xenon/main.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"os"
6+
7+
. "github.com/radondb/radondb-mysql-kubernetes/utils"
8+
)
9+
10+
var (
11+
ns string
12+
podName string
13+
)
14+
15+
func init() {
16+
ns = os.Getenv("NAMESPACE")
17+
podName = os.Getenv("POD_NAME")
18+
}
19+
20+
func main() {
21+
switch os.Args[1] {
22+
case "leaderStart":
23+
if err := leaderStart(); err != nil {
24+
log.Fatalf("leaderStart failed: %v", err)
25+
}
26+
case "leaderStop":
27+
if err := leaderStop(); err != nil {
28+
log.Fatalf("leaderStop failed: %v", err)
29+
}
30+
case "liveness":
31+
if err := liveness(); err != nil {
32+
log.Fatalf("liveness failed: %v", err)
33+
}
34+
case "readiness":
35+
if err := readiness(); err != nil {
36+
log.Fatalf("readiness failed: %v", err)
37+
}
38+
case "postStart":
39+
if err := postStart(); err != nil {
40+
log.Fatalf("postStart failed: %v", err)
41+
}
42+
case "preStop":
43+
if err := preStop(); err != nil {
44+
log.Fatalf("postStop failed: %v", err)
45+
}
46+
default:
47+
log.Fatalf("Usage: %s leaderStart|leaderStop|liveness|readiness|postStart|preStop", os.Args[0])
48+
}
49+
}
50+
51+
// TODO
52+
func leaderStart() error {
53+
return nil
54+
}
55+
56+
func leaderStop() error {
57+
return PatchRoleLabelTo(myself(string(Follower)))
58+
}
59+
60+
func liveness() error {
61+
return XenonPingMyself()
62+
}
63+
64+
func readiness() error {
65+
role := GetRole()
66+
if role != string(Leader) {
67+
return PatchRoleLabelTo(myself(role))
68+
}
69+
return nil
70+
}
71+
72+
// TODO
73+
func postStart() error {
74+
return nil
75+
}
76+
77+
// TODO
78+
func preStop() error {
79+
return nil
80+
}
81+
82+
func myself(role string) MySQLNode {
83+
return MySQLNode{
84+
PodName: podName,
85+
Namespace: ns,
86+
Role: role,
87+
}
88+
}

mysqlcluster/container/xenon.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,26 @@ func (c *xenon) getCommand() []string {
4848

4949
// getEnvVars get the container env.
5050
func (c *xenon) getEnvVars() []corev1.EnvVar {
51-
return nil
51+
return []corev1.EnvVar{
52+
{
53+
Name: "NameSpace",
54+
ValueFrom: &corev1.EnvVarSource{
55+
FieldRef: &corev1.ObjectFieldSelector{
56+
APIVersion: "v1",
57+
FieldPath: "metadata.namespace",
58+
},
59+
},
60+
},
61+
{
62+
Name: "POD_NAME",
63+
ValueFrom: &corev1.EnvVarSource{
64+
FieldRef: &corev1.ObjectFieldSelector{
65+
APIVersion: "v1",
66+
FieldPath: "metadata.name",
67+
},
68+
},
69+
},
70+
}
5271
}
5372

5473
// getLifecycle get the container lifecycle.

mysqlcluster/container/xenon_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,26 @@ func TestGetXenonCommand(t *testing.T) {
6868
}
6969

7070
func TestGetXenonEnvVar(t *testing.T) {
71-
assert.Nil(t, xenonCase.Env)
71+
assert.Equal(t, []corev1.EnvVar{
72+
{
73+
Name: "NameSpace",
74+
ValueFrom: &corev1.EnvVarSource{
75+
FieldRef: &corev1.ObjectFieldSelector{
76+
APIVersion: "v1",
77+
FieldPath: "metadata.namespace",
78+
},
79+
},
80+
},
81+
{
82+
Name: "POD_NAME",
83+
ValueFrom: &corev1.EnvVarSource{
84+
FieldRef: &corev1.ObjectFieldSelector{
85+
APIVersion: "v1",
86+
FieldPath: "metadata.name",
87+
},
88+
},
89+
},
90+
}, xenonCase.Env)
7291
}
7392

7493
func TestGetXenonLifecycle(t *testing.T) {

utils/incluster.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package utils
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"log"
8+
"os/exec"
9+
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/types"
12+
"k8s.io/client-go/kubernetes"
13+
"k8s.io/client-go/rest"
14+
)
15+
16+
type raftStatus struct {
17+
Leader string `json:"leader"`
18+
State string `json:"state"`
19+
Nodes []string `json:"nodes"`
20+
}
21+
22+
type MySQLNode struct {
23+
PodName string
24+
Namespace string
25+
Role string
26+
}
27+
28+
func GetClientSet() (*kubernetes.Clientset, error) {
29+
// Creates the in-cluster config
30+
config, err := rest.InClusterConfig()
31+
if err != nil {
32+
return nil, fmt.Errorf("failed to create in-cluster config: %v", err)
33+
}
34+
// Creates the clientset
35+
clientset, err := kubernetes.NewForConfig(config)
36+
if err != nil {
37+
return nil, fmt.Errorf("failed to create clientset: %v", err)
38+
}
39+
return clientset, nil
40+
}
41+
42+
func PatchRoleLabelTo(n MySQLNode) error {
43+
// Creates the clientset
44+
clientset, err := GetClientSet()
45+
if err != nil {
46+
return fmt.Errorf("failed to create clientset: %v", err)
47+
}
48+
patch := fmt.Sprintf(`{"metadata":{"labels":{"role":"%s"}}}`, n.Role)
49+
_, err = clientset.CoreV1().Pods(n.Namespace).Patch(context.TODO(), n.PodName, types.MergePatchType, []byte(patch), metav1.PatchOptions{})
50+
if err != nil {
51+
return fmt.Errorf("failed to patch pod role label: %v", err)
52+
}
53+
return nil
54+
}
55+
56+
func XenonPingMyself() error {
57+
args := []string{"xenon", "ping"}
58+
cmd := exec.Command("xenoncli", args...)
59+
if err := cmd.Run(); err != nil {
60+
return fmt.Errorf("failed to exec xenoncli xenon ping: %v", err)
61+
}
62+
return nil
63+
}
64+
65+
func GetRaftStatus() *raftStatus {
66+
args := []string{"raft", "status"}
67+
cmd := exec.Command("xenoncli", args...)
68+
res, err := cmd.Output()
69+
if err != nil {
70+
log.Fatalf("failed to exec xenoncli raft status: %v", err)
71+
}
72+
raftStatus := raftStatus{}
73+
if err := json.Unmarshal(res, &raftStatus); err != nil {
74+
log.Fatalf("failed to unmarshal raft status: %v", err)
75+
}
76+
return &raftStatus
77+
}
78+
79+
func GetRole() string {
80+
return GetRaftStatus().State
81+
}

0 commit comments

Comments
 (0)