Skip to content

Commit

Permalink
implement csi dashboard (#774)
Browse files Browse the repository at this point in the history
implement CSI dashboard

---------

Signed-off-by: xixi <[email protected]>
Signed-off-by: zwwhdls <[email protected]>
Co-authored-by: zwwhdls <[email protected]>
  • Loading branch information
Hexilee and zwwhdls authored Nov 1, 2023
1 parent 5631092 commit 1c50cfd
Show file tree
Hide file tree
Showing 53 changed files with 15,179 additions and 4 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/dashboard-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: build dashboard image

on:
workflow_dispatch:
inputs:
image_tag:
description: 'dashboard image tag'
required: false
type: string

jobs:
publish-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login Docker Hub
env:
PASSWORD: ${{ secrets.DOCKERHUB_FUSE_ACCESS_TOKEN }}
run: docker login --username chnliyong --password ${PASSWORD}
- name: build dashboard image and push
env:
DASHBOARD_TAG: ${{ inputs.image_tag }}
run: |
export DOCKER_CLI_EXPERIMENTAL=enabled
docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
docker buildx create --use --name mybuilder
make -C docker dashboard-buildx
- name: Setup upterm session
if: ${{ failure() }}
timeout-minutes: 60
uses: lhotari/action-upterm@v1
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ cov2.out
.yalc/
yalc.lock
.ropeproject
dist/
20 changes: 19 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ PKG=github.com/juicedata/juicefs-csi-driver
LDFLAGS?="-X ${PKG}/pkg/driver.driverVersion=${VERSION} -X ${PKG}/pkg/driver.gitCommit=${GIT_COMMIT} -X ${PKG}/pkg/driver.buildDate=${BUILD_DATE} -s -w"
GO111MODULE=on

GOPROXY=https://goproxy.io
GOPROXY?=https://goproxy.io
GOPATH=$(shell go env GOPATH)
GOOS=$(shell go env GOOS)
GOBIN=$(shell pwd)/bin
Expand All @@ -46,6 +46,24 @@ test:
test-sanity:
go test -v -cover ./tests/sanity/... -coverprofile=cov2.out

.PHONY: dashboard-dist
dashboard-dist:
cd dashboard-ui && yarn run build

.PHONY: dashboard
dashboard:
mkdir -p bin
go build -tags=jsoniter -ldflags ${LDFLAGS} -o bin/juicefs-csi-dashboard ./cmd/dashboard/

.PHONY: dashboard-dev
dashboard-dev: dashboard
./bin/juicefs-csi-dashboard -v=6 --dev --static-dir=./dashboard-ui/dist

.PHONY: dashboard-image
dashboard-image:
docker build --build-arg HTTP_PROXY=$(HTTP_PROXY) --build-arg HTTPS_PROXY=$(HTTPS_PROXY) --build-arg GOPROXY=$(GOPROXY) \
-t $(REGISTRY)/juicedata/csi-dashboard:$(VERSION) -f docker/dashboard.Dockerfile .

# build deploy yaml
yaml:
echo "# DO NOT EDIT: generated by 'kustomize build'" > deploy/k8s.yaml
Expand Down
197 changes: 197 additions & 0 deletions cmd/dashboard/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
Copyright 2023 Juicedata Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"context"
goflag "flag"
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"

"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"k8s.io/klog"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"

"github.com/juicedata/juicefs-csi-driver/pkg/dashboard"
)

func init() {
utilruntime.Must(corev1.AddToScheme(scheme))
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
}

const (
SysNamespaceKey = "SYS_NAMESPACE"
)

var (
scheme = runtime.NewScheme()

port uint16
devMode bool
staticDir string
)

func main() {
var cmd = &cobra.Command{
Use: "juicefs-csi-dashboard",
Short: "dashboard of juicefs csi driver",
Run: func(cmd *cobra.Command, args []string) {
run()
},
}

cmd.PersistentFlags().Uint16Var(&port, "port", 8088, "port to listen on")
cmd.PersistentFlags().BoolVar(&devMode, "dev", false, "enable dev mode")
cmd.PersistentFlags().StringVar(&staticDir, "static-dir", "", "static files to serve")

goFlag := goflag.CommandLine
klog.InitFlags(goFlag)
cmd.PersistentFlags().AddGoFlagSet(goFlag)
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}

func run() {
var config *rest.Config
var err error
sysNamespace := "kube-system"
if devMode {
config, err = getLocalConfig()
} else {
sysNamespace = os.Getenv(SysNamespaceKey)
gin.SetMode(gin.ReleaseMode)
config = ctrl.GetConfigOrDie()
}
if err != nil {
log.Fatalf("can't get k8s config: %v", err)
}
mgr, err := newManager(config)
if err != nil {
log.Fatalf("can't create manager: %v", err)
}
client, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatalf("can't create k8s client: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
podApi := dashboard.NewAPI(ctx, sysNamespace, mgr.GetClient(), client)
router := gin.Default()
if devMode {
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"*"},
AllowHeaders: []string{"*"},
ExposeHeaders: []string{"*"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
}
if staticDir != "" {
router.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/app")
})
router.GET("/app/*path", func(c *gin.Context) {
path := c.Param("path")
if strings.Contains(path, "..") {
c.AbortWithStatus(http.StatusForbidden)
return
}
f, err := os.Stat(filepath.Join(staticDir, path))
if os.IsNotExist(err) || f.IsDir() {
c.File(filepath.Join(staticDir, "index.html"))
return
}
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
}
c.File(filepath.Join(staticDir, path))
})
}
podApi.Handle(router.Group("/api/v1"))
addr := fmt.Sprintf(":%d", port)
srv := &http.Server{
Addr: addr,
Handler: router,
}

go func() {
log.Printf("listen on %s\n", addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
go func() {
// pprof server
log.Println(http.ListenAndServe("localhost:8089", nil))
}()
quit := make(chan os.Signal, 1)
go func() {
if err := podApi.StartManager(ctx, mgr); err != nil {
klog.Errorf("manager start error: %v", err)
}
quit <- syscall.SIGTERM
}()

signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutdown Server ...")
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server Shutdown:", err)
}
}

func getLocalConfig() (*rest.Config, error) {
home := homedir.HomeDir()
if home == "" {
home = "/root"
}
return clientcmd.BuildConfigFromFlags("", filepath.Join(home, ".kube", "config"))
}

func newManager(conf *rest.Config) (ctrl.Manager, error) {
return ctrl.NewManager(conf, ctrl.Options{
Scheme: scheme,
Port: 9442,
MetricsBindAddress: "0.0.0.0:8082",
LeaderElectionID: "dashboard.juicefs.com",
NewCache: cache.BuilderWithOptions(cache.Options{
Scheme: scheme,
}),
})
}
3 changes: 3 additions & 0 deletions dashboard-ui/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: require.resolve('@umijs/max/eslint'),
};
13 changes: 13 additions & 0 deletions dashboard-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/node_modules
/.env.local
/.umirc.local.ts
/config/config.local.ts
/src/.umi
/src/.umi-production
/src/.umi-test
/.umi
/.umi-production
/.umi-test
/dist
/.mfsu
.swc
4 changes: 4 additions & 0 deletions dashboard-ui/.husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install max verify-commit $1
4 changes: 4 additions & 0 deletions dashboard-ui/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install lint-staged --quiet
17 changes: 17 additions & 0 deletions dashboard-ui/.lintstagedrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"*.{md,json}": [
"prettier --cache --write"
],
"*.{js,jsx}": [
"max lint --fix --eslint-only",
"prettier --cache --write"
],
"*.{css,less}": [
"max lint --fix --stylelint-only",
"prettier --cache --write"
],
"*.ts?(x)": [
"max lint --fix --eslint-only",
"prettier --cache --parser=typescript --write"
]
}
2 changes: 2 additions & 0 deletions dashboard-ui/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
registry=https://registry.npmmirror.com/

3 changes: 3 additions & 0 deletions dashboard-ui/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.umi
.umi-production
8 changes: 8 additions & 0 deletions dashboard-ui/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"printWidth": 80,
"singleQuote": true,
"trailingComma": "all",
"proseWrap": "never",
"overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"]
}
3 changes: 3 additions & 0 deletions dashboard-ui/.stylelintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: require.resolve('@umijs/max/stylelint'),
};
Loading

0 comments on commit 1c50cfd

Please sign in to comment.