Skip to content

Commit

Permalink
feat(dashboard): support helm-dashboard plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
JacieChao committed May 26, 2023
1 parent 518a699 commit 4864363
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 6 deletions.
64 changes: 64 additions & 0 deletions cmd/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"path/filepath"
"strconv"

"github.com/cnrancher/autok3s/pkg/common"
"github.com/cnrancher/autok3s/pkg/settings"
k3dutil "github.com/k3d-io/k3d/v5/cmd/util"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"k8s.io/client-go/tools/clientcmd"
)

var (
dashboardCmd = &cobra.Command{
Use: "helm-dashboard",
Short: "Enable helm-dashboard for K3s cluster",
Example: "autok3s helm-dashboard",
}

dashboardPort = 0
)

func init() {
dashboardCmd.Flags().IntVarP(&dashboardPort, "port", "", dashboardPort, "Set http port for helm-dashboard")
}

// DashboardCommand will start a helm-dashboard server for specified K3s cluster
func DashboardCommand() *cobra.Command {
dashboardCmd.PreRunE = func(cmd *cobra.Command, args []string) error {
cfg, err := clientcmd.LoadFromFile(filepath.Join(common.CfgPath, common.KubeCfgFile))
if err != nil {
return err
}
if len(cfg.Contexts) == 0 {
logrus.Fatalln("cannot enable helm dashboard without K3s cluster")
}
return nil
}
dashboardCmd.Run = func(cmd *cobra.Command, args []string) {
if err := common.CheckCommandExist(common.HelmDashboardCommand); err != nil {
logrus.Fatalln(err)
}
if dashboardPort == 0 {
port, err := k3dutil.GetFreePort()
if err != nil {
logrus.Fatalf("failed to get free port for kube-explorer: %v", err)
}
dashboardPort = port
}
if err := settings.HelmDashboardPort.Set(strconv.Itoa(dashboardPort)); err != nil {
logrus.Fatalln(err)
}
err := common.StartHelmDashboard(dashboardCmd.Context(), strconv.Itoa(dashboardPort))
if err != nil {
logrus.Fatalln(err)
}
logrus.Infof("Helm dashboard started with 127.0.0.1:%d", dashboardPort)
}

return dashboardCmd
}
4 changes: 4 additions & 0 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func ServeCommand() *cobra.Command {
go func(ctx context.Context) {
common.InitExplorer(ctx)
}(serveCmd.Context())
// start helm-dashboard server
go func(ctx context.Context) {
common.InitDashboard(ctx)
}(serveCmd.Context())

stopChan := make(chan struct{})
go func(c chan struct{}) {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func main() {
rootCmd.AddCommand(cmd.CompletionCommand(), cmd.VersionCommand(gitVersion, gitCommit, gitTreeState, buildDate),
cmd.ListCommand(), cmd.CreateCommand(), cmd.JoinCommand(), cmd.KubectlCommand(), cmd.DeleteCommand(),
cmd.SSHCommand(), cmd.DescribeCommand(), cmd.ServeCommand(), cmd.ExplorerCommand(), cmd.UpgradeCommand(),
cmd.TelemetryCommand(), airgap.Command(), sshkey.Command())
cmd.TelemetryCommand(), airgap.Command(), sshkey.Command(), cmd.DashboardCommand())

rootCmd.PersistentPreRun = func(c *cobra.Command, args []string) {
common.InitLogger(logrus.StandardLogger())
Expand Down
5 changes: 3 additions & 2 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ var (
Steps: 20,
}
// DefaultDB default database store.
DefaultDB *Store
ExplorerWatchers map[string]context.CancelFunc
DefaultDB *Store
ExplorerWatchers map[string]context.CancelFunc
DashboardCanceled context.CancelFunc

FileManager *ConfigFileManager
)
Expand Down
120 changes: 120 additions & 0 deletions pkg/common/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package common

import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"

"github.com/cnrancher/autok3s/pkg/settings"
k3dutil "github.com/k3d-io/k3d/v5/cmd/util"
"github.com/sirupsen/logrus"

"k8s.io/client-go/tools/clientcmd"
)

const HelmDashboardCommand = "helm-dashboard"

func SwitchDashboard(ctx context.Context, enabled string) error {
if enabled == "true" {
// check if cluster list is empty
clusters, err := DefaultDB.ListCluster("")
if err != nil {
return err
}
if len(clusters) == 0 {
return errors.New("cannot enable helm-dashboard with empty cluster list")
}
}
if err := CheckCommandExist(HelmDashboardCommand); err != nil {
return err
}

// command execution validate
if err := checkDashboardCmd(); err != nil {
return err
}

isEnabled := settings.HelmDashboardEnabled.Get()
if !strings.EqualFold(isEnabled, enabled) {
if err := settings.HelmDashboardEnabled.Set(enabled); err != nil {
return err
}
if enabled == "true" {
enableDashboard(ctx)
} else {
if err := settings.HelmDashboardEnabled.Set("false"); err != nil {
return err
}
logrus.Info("Shutting down helm-dashboard...")
DashboardCanceled()
}
}

return nil
}

func InitDashboard(ctx context.Context) {
isEnabled := settings.HelmDashboardEnabled.Get()
if isEnabled == "true" {
enableDashboard(ctx)
}
}

func StartHelmDashboard(ctx context.Context, port string) error {
_ = os.Setenv(clientcmd.RecommendedConfigPathEnvVar, filepath.Join(CfgPath, KubeCfgFile))
dashboard := exec.CommandContext(ctx, HelmDashboardCommand, "-b", fmt.Sprintf("--port=%s", port))
dashboard.Stdout = os.Stdout
dashboard.Stderr = os.Stderr
if err := dashboard.Start(); err != nil {
logrus.Errorf("fail to start helm-dashboard: %v", err)
}
logrus.Infof("helm-dashboard will listen on 127.0.0.1:%s ...", port)
return dashboard.Wait()
}

func checkDashboardCmd() error {
explorerVersion := exec.Command(HelmDashboardCommand, "--version")
return explorerVersion.Run()
}

func enableDashboard(ctx context.Context) {
clusters, err := DefaultDB.ListCluster("")
if err != nil {
logrus.Errorf("failed to list clusters: %v", err)
return
}
// disable helm-dashboard if there's no cluster context
if len(clusters) == 0 {
if err := settings.HelmDashboardEnabled.Set("false"); err != nil {
logrus.Errorf("failed to disable helm-dashboard due to empty cluster list: %v", err)
return
}
logrus.Warn("disabled helm-dashboard with empty cluster list")
return
}
dashboardPort := settings.HelmDashboardPort.Get()
if dashboardPort == "" {
freePort, err := k3dutil.GetFreePort()
if err != nil {
logrus.Errorf("failed to get free port for helm-dashboard: %v", err)
return
}
dashboardPort = strconv.Itoa(freePort)
err = settings.HelmDashboardPort.Set(dashboardPort)
if err != nil {
logrus.Errorf("failed to save helm-dashboard port to settings: %v", err)
return
}
}
logrus.Info("Enable helm-dashboard server...")
dashboardCtx, cancel := context.WithCancel(ctx)
DashboardCanceled = cancel
go func(ctx context.Context, port string) {
StartHelmDashboard(ctx, port)
}(dashboardCtx, dashboardPort)
}
15 changes: 12 additions & 3 deletions pkg/server/store/settings/store.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package settings

import (
"context"
"fmt"

"github.com/cnrancher/autok3s/pkg/common"
"github.com/cnrancher/autok3s/pkg/settings"

"github.com/rancher/apiserver/pkg/apierror"
"github.com/rancher/apiserver/pkg/store/empty"
Expand All @@ -24,10 +26,17 @@ func (s *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, data ty
if err != nil {
return types.APIObject{}, err
}
err = common.DefaultDB.SaveSetting(setting)
if err != nil {
return types.APIObject{}, err
if id == settings.HelmDashboardEnabled.Name {
if err := common.SwitchDashboard(context.TODO(), setting.Value); err != nil {
return types.APIObject{}, err
}
} else {
err = common.DefaultDB.SaveSetting(setting)
if err != nil {
return types.APIObject{}, err
}
}

return s.ByID(apiOp, schema, setting.Name)
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/settings/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ var (
InstallScript = newSetting("install-script", "", "The k3s offline install script with base64 encode")
ScriptUpdateSource = newSetting("install-script-source-repo", "https://rancher-mirror.rancher.cn/k3s/k3s-install.sh", "The install script auto update source, github or aliyun oss")
PackageDownloadSource = newSetting("package-download-source", "github", "The airgap package download source, github and aliyunoss are validated.")

HelmDashboardEnabled = newSetting("helm-dashboard-enabled", "false", "The helm-dashboard is enabled or not")
HelmDashboardPort = newSetting("helm-dashboard-port", "", "The helm-dashboard server port after enabled")
)

func newSetting(
Expand Down

0 comments on commit 4864363

Please sign in to comment.