Skip to content

Commit

Permalink
*: Add inCluster related API and xenon checker (radondb#596)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
runkecheng authored Jul 13, 2022
1 parent 1f1a875 commit 2ea05b9
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 2 deletions.
22 changes: 22 additions & 0 deletions build/xenon/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM golang:1.16 as builder

WORKDIR /
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go env -w GOPROXY=https://goproxy.cn,direct;
#     go mod download
RUN  go mod download

# Copy the go source
COPY cmd/xenon/main.go cmd/xenon/main.go
COPY utils/ utils/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o bin/xenonchecker cmd/xenon/main.go

FROM radondb/xenon:1.1.5-alpha

COPY --from=builder /bin/xenonchecker /xenonchecker
1 change: 1 addition & 0 deletions cmd/staticcheck.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
checks=[ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022", "-ST1001"]
88 changes: 88 additions & 0 deletions cmd/xenon/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"log"
"os"

. "github.com/radondb/radondb-mysql-kubernetes/utils"
)

var (
ns string
podName string
)

func init() {
ns = os.Getenv("NAMESPACE")
podName = os.Getenv("POD_NAME")
}

func main() {
switch os.Args[1] {
case "leaderStart":
if err := leaderStart(); err != nil {
log.Fatalf("leaderStart failed: %v", err)
}
case "leaderStop":
if err := leaderStop(); err != nil {
log.Fatalf("leaderStop failed: %v", err)
}
case "liveness":
if err := liveness(); err != nil {
log.Fatalf("liveness failed: %v", err)
}
case "readiness":
if err := readiness(); err != nil {
log.Fatalf("readiness failed: %v", err)
}
case "postStart":
if err := postStart(); err != nil {
log.Fatalf("postStart failed: %v", err)
}
case "preStop":
if err := preStop(); err != nil {
log.Fatalf("postStop failed: %v", err)
}
default:
log.Fatalf("Usage: %s leaderStart|leaderStop|liveness|readiness|postStart|preStop", os.Args[0])
}
}

// TODO
func leaderStart() error {
return nil
}

func leaderStop() error {
return PatchRoleLabelTo(myself(string(Follower)))
}

func liveness() error {
return XenonPingMyself()
}

func readiness() error {
role := GetRole()
if role != string(Leader) {
return PatchRoleLabelTo(myself(role))
}
return nil
}

// TODO
func postStart() error {
return nil
}

// TODO
func preStop() error {
return nil
}

func myself(role string) MySQLNode {
return MySQLNode{
PodName: podName,
Namespace: ns,
Role: role,
}
}
21 changes: 20 additions & 1 deletion mysqlcluster/container/xenon.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,26 @@ func (c *xenon) getCommand() []string {

// getEnvVars get the container env.
func (c *xenon) getEnvVars() []corev1.EnvVar {
return nil
return []corev1.EnvVar{
{
Name: "NameSpace",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.namespace",
},
},
},
{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.name",
},
},
},
}
}

// getLifecycle get the container lifecycle.
Expand Down
21 changes: 20 additions & 1 deletion mysqlcluster/container/xenon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,26 @@ func TestGetXenonCommand(t *testing.T) {
}

func TestGetXenonEnvVar(t *testing.T) {
assert.Nil(t, xenonCase.Env)
assert.Equal(t, []corev1.EnvVar{
{
Name: "NameSpace",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.namespace",
},
},
},
{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.name",
},
},
},
}, xenonCase.Env)
}

func TestGetXenonLifecycle(t *testing.T) {
Expand Down
81 changes: 81 additions & 0 deletions utils/incluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package utils

import (
"context"
"encoding/json"
"fmt"
"log"
"os/exec"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

type raftStatus struct {
Leader string `json:"leader"`
State string `json:"state"`
Nodes []string `json:"nodes"`
}

type MySQLNode struct {
PodName string
Namespace string
Role string
}

func GetClientSet() (*kubernetes.Clientset, error) {
// Creates the in-cluster config
config, err := rest.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("failed to create in-cluster config: %v", err)
}
// Creates the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, fmt.Errorf("failed to create clientset: %v", err)
}
return clientset, nil
}

func PatchRoleLabelTo(n MySQLNode) error {
// Creates the clientset
clientset, err := GetClientSet()
if err != nil {
return fmt.Errorf("failed to create clientset: %v", err)
}
patch := fmt.Sprintf(`{"metadata":{"labels":{"role":"%s"}}}`, n.Role)
_, err = clientset.CoreV1().Pods(n.Namespace).Patch(context.TODO(), n.PodName, types.MergePatchType, []byte(patch), metav1.PatchOptions{})
if err != nil {
return fmt.Errorf("failed to patch pod role label: %v", err)
}
return nil
}

func XenonPingMyself() error {
args := []string{"xenon", "ping"}
cmd := exec.Command("xenoncli", args...)
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to exec xenoncli xenon ping: %v", err)
}
return nil
}

func GetRaftStatus() *raftStatus {
args := []string{"raft", "status"}
cmd := exec.Command("xenoncli", args...)
res, err := cmd.Output()
if err != nil {
log.Fatalf("failed to exec xenoncli raft status: %v", err)
}
raftStatus := raftStatus{}
if err := json.Unmarshal(res, &raftStatus); err != nil {
log.Fatalf("failed to unmarshal raft status: %v", err)
}
return &raftStatus
}

func GetRole() string {
return GetRaftStatus().State
}

0 comments on commit 2ea05b9

Please sign in to comment.