重构架构
This commit is contained in:
46
internal/cli/init/cfg.go
Normal file
46
internal/cli/init/cfg.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package initcmd
|
||||
|
||||
import (
|
||||
"sunhpc/internal/middler/auth"
|
||||
"sunhpc/pkg/logger"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// NewConfigCmd 创建 "init config" 命令
|
||||
func NewInitCfgCmd() *cobra.Command {
|
||||
var (
|
||||
force bool
|
||||
path string
|
||||
verbose bool
|
||||
)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "生成默认配置文件",
|
||||
Long: `
|
||||
在指定路径生成 SunHPC 默认配置文件 (sunhpc.yaml)
|
||||
|
||||
示例:
|
||||
sunhpc init config # 生成默认配置文件
|
||||
sunhpc init config -f # 强制覆盖已有配置文件
|
||||
sunhpc init config -p /etc/sunhpc/sunhpc.yaml # 指定路径
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := auth.RequireRoot(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("✅ 配置文件已生成", zap.String("path", path))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// 定义局部 flags
|
||||
cmd.Flags().BoolVarP(&force, "force", "f", false, "强制覆盖已有配置文件")
|
||||
cmd.Flags().StringVarP(&path, "path", "p", "", "指定配置文件路径")
|
||||
cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "显示详细日志")
|
||||
|
||||
return cmd
|
||||
}
|
||||
53
internal/cli/init/db.go
Normal file
53
internal/cli/init/db.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package initcmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sunhpc/internal/middler/auth"
|
||||
"sunhpc/pkg/config"
|
||||
"sunhpc/pkg/database"
|
||||
"sunhpc/pkg/logger"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewInitDBCmd() *cobra.Command {
|
||||
var force bool
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "db",
|
||||
Short: "初始化数据库",
|
||||
Long: `初始化SQLite数据库,创建所有表结构和默认数据。
|
||||
|
||||
示例:
|
||||
sunhpc init db # 初始化数据库
|
||||
sunhpc init db --force # 强制重新初始化`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := auth.RequireRoot(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debug("执行数据库初始化...")
|
||||
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载配置失败: %w", err)
|
||||
}
|
||||
|
||||
// 初始化数据库
|
||||
db, err := database.GetInstance(&cfg.Database, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("数据库连接失败: %w", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
if err := db.InitTables(force); err != nil {
|
||||
return fmt.Errorf("数据库初始化失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVarP(&force, "force", "f", false, "强制重新初始化")
|
||||
return cmd
|
||||
}
|
||||
19
internal/cli/init/init.go
Normal file
19
internal/cli/init/init.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package initcmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// 仅定义 Cmd, 注册子命令,只负责组装命令树,尽量不包含业务逻辑
|
||||
func NewInitCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "初始化集群配置",
|
||||
Long: "初始化 SunHPC 配置文件、数据库、系统参数及相关服务",
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewInitDBCmd())
|
||||
cmd.AddCommand(NewInitCfgCmd())
|
||||
|
||||
return cmd
|
||||
}
|
||||
69
internal/cli/root.go
Normal file
69
internal/cli/root.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
initcmd "sunhpc/internal/cli/init"
|
||||
"sunhpc/pkg/config"
|
||||
"sunhpc/pkg/logger"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
cfgFile string
|
||||
verbose bool
|
||||
noColor bool
|
||||
)
|
||||
|
||||
func NewRootCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "sunhpc",
|
||||
Short: "SunHPC - HPC集群一体化运维工具",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
// 加载全局配置(只加载一次)
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
// 配置加载失败,使用默认日志配置初始化
|
||||
logger.Warnf("加载配置失败,使用默认日志配置: %v", err)
|
||||
logger.Init(logger.LogConfig{})
|
||||
return
|
||||
}
|
||||
|
||||
// 3. 初始化全局日志(全局只执行一次)
|
||||
logger.Init(logger.LogConfig{
|
||||
Verbose: cfg.Log.Verbose,
|
||||
ShowColor: !cfg.Log.ShowColor,
|
||||
LogFile: cfg.Log.LogFile,
|
||||
})
|
||||
},
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
},
|
||||
}
|
||||
|
||||
cmd.PersistentFlags().StringVarP(
|
||||
&config.CLIParams.Config,
|
||||
"config", "c",
|
||||
"", "配置文件路径 (默认:/etc/sunhpc/config.yaml)")
|
||||
|
||||
cmd.PersistentFlags().BoolVarP(
|
||||
&config.CLIParams.Verbose,
|
||||
"verbose", "v", false, "启用详细日志输出")
|
||||
|
||||
cmd.PersistentFlags().BoolVar(
|
||||
&config.CLIParams.NoColor,
|
||||
"no-color", false, "禁用彩色输出")
|
||||
|
||||
// 如果指定了 --config 参数,优先使用该配置文件
|
||||
if config.CLIParams.Config != "" {
|
||||
viper.SetConfigFile(config.CLIParams.Config)
|
||||
}
|
||||
|
||||
cmd.AddCommand(initcmd.NewInitCmd())
|
||||
return cmd
|
||||
}
|
||||
|
||||
func Execute() error {
|
||||
return NewRootCmd().Execute()
|
||||
}
|
||||
41
internal/cli/soft/install.go
Normal file
41
internal/cli/soft/install.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package soft
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sunhpc/pkg/logger"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func NewSoftInstallCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "install [software]",
|
||||
Short: "安装软件",
|
||||
Long: "在集群节点上安装指定软件",
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
software := args[0]
|
||||
|
||||
logger.Info("开始安装软件", zap.String("software", software))
|
||||
|
||||
// TODO: 实现软件安装逻辑
|
||||
// 1. 检查软件包
|
||||
// 2. 分发到节点
|
||||
// 3. 执行安装
|
||||
|
||||
fmt.Printf("✓ 软件 %s 安装完成\n", software)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// 添加安装命令的标志
|
||||
cmd.Flags().StringSlice("nodes", []string{}, "目标节点列表")
|
||||
cmd.Flags().String("version", "", "软件版本")
|
||||
cmd.Flags().Bool("force", false, "强制安装")
|
||||
|
||||
return cmd
|
||||
}
|
||||
18
internal/cli/soft/soft.go
Normal file
18
internal/cli/soft/soft.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package soft
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewSoftCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "soft",
|
||||
Short: "软件管理命令",
|
||||
Long: "管理集群软件安装、更新、卸载等操作",
|
||||
}
|
||||
|
||||
// 添加 soft 的子命令
|
||||
cmd.AddCommand(NewSoftInstallCmd())
|
||||
|
||||
return cmd
|
||||
}
|
||||
58
internal/cli/tmpl/dump.go
Normal file
58
internal/cli/tmpl/dump.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package tmpl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
log "sunhpc/pkg/logger"
|
||||
"sunhpc/pkg/templating"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newDumpCmd() *cobra.Command {
|
||||
var output string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "dump <template-name>",
|
||||
Short: "导出内置模板到文件",
|
||||
Long: `
|
||||
将内置的 YAML 模板导出为可编辑的文件。
|
||||
|
||||
示例:
|
||||
sunhpc tmpl dump autofs --output ./my-autofs.yaml`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
|
||||
// 检查模板是否存在
|
||||
available, _ := templating.ListEmbeddedTemplates()
|
||||
found := false
|
||||
for _, n := range available {
|
||||
if n == name {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return fmt.Errorf("内置模板 '%s' 不存在。可用模板: %v", name, available)
|
||||
}
|
||||
|
||||
outPath := output
|
||||
if outPath == "" {
|
||||
outPath = name + ".yaml"
|
||||
}
|
||||
|
||||
if err := templating.DumpEmbeddedTemplateToFile(name, outPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("内置模板 '%s' 已导出到: %s", name, outPath)
|
||||
log.Infof("你可以编辑此文件,然后用以下命令使用它:")
|
||||
log.Infof(" sunhpc tmpl render %s -f %s [flags]", name, outPath)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&output, "output", "o", "", "输出文件路径(默认: <name>.yaml)")
|
||||
return cmd
|
||||
}
|
||||
17
internal/cli/tmpl/init.go
Normal file
17
internal/cli/tmpl/init.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// cmd/tmpl/init.go
|
||||
package tmpl
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
// Cmd 是 sunhpc tmpl 的根命令
|
||||
func NewTmplCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "tmpl",
|
||||
Short: "管理配置模板",
|
||||
Long: "从 YAML 模板生成配置文件或脚本,支持变量替换和多阶段执行",
|
||||
}
|
||||
|
||||
cmd.AddCommand(newRenderCmd())
|
||||
cmd.AddCommand(newDumpCmd())
|
||||
return cmd
|
||||
}
|
||||
96
internal/cli/tmpl/render.go
Normal file
96
internal/cli/tmpl/render.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package tmpl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
log "sunhpc/pkg/logger"
|
||||
templating "sunhpc/pkg/templating"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
tmplFile string
|
||||
hostname string
|
||||
domain string
|
||||
oldHostname string
|
||||
ip string
|
||||
clusterName string
|
||||
outputRoot string
|
||||
)
|
||||
|
||||
func newRenderCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "render <template-name>",
|
||||
Short: "渲染配置模板",
|
||||
Long: "根据 YAML 模板和上下文变量生成配置文件或脚本",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
tmplName := args[0]
|
||||
var template *templating.Template
|
||||
var err error
|
||||
|
||||
// 优先使用 -f 指定的外部模版文件
|
||||
if tmplFile != "" {
|
||||
template, err = templating.LoadTemplate(tmplFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载外部模板失败: %w", err)
|
||||
}
|
||||
log.Infof("✅ 外部模板 '%s' 已加载\n", tmplFile)
|
||||
} else {
|
||||
// 否则从内置模板加载
|
||||
template, err = templating.LoadEmbeddedTemplate(tmplName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("✅ 内置模板 '%s' 已加载\n", tmplName)
|
||||
}
|
||||
|
||||
ctx := templating.Context{
|
||||
Node: templating.NodeInfo{
|
||||
Hostname: hostname,
|
||||
OldHostname: oldHostname,
|
||||
Domain: domain,
|
||||
IP: ip,
|
||||
},
|
||||
Cluster: templating.ClusterInfo{
|
||||
Name: clusterName,
|
||||
},
|
||||
}
|
||||
|
||||
rendered, err := template.Render(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("模板渲染失败: %w", err)
|
||||
}
|
||||
|
||||
// 处理 post 阶段
|
||||
if steps, ok := rendered["post"]; ok {
|
||||
fmt.Println(">>> 执行 post 阶段")
|
||||
if err := templating.WriteFiles(steps, outputRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
templating.PrintScripts(steps)
|
||||
}
|
||||
|
||||
// 处理 configure 阶段
|
||||
if steps, ok := rendered["configure"]; ok {
|
||||
fmt.Println(">>> 执行 configure 阶段")
|
||||
templating.PrintScripts(steps)
|
||||
}
|
||||
|
||||
fmt.Println("✅ 模板渲染完成")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&tmplFile, "file", "f", "", "指定模板文件路径(覆盖默认查找)")
|
||||
cmd.Flags().StringVar(&hostname, "hostname", "", "节点主机名")
|
||||
cmd.Flags().StringVar(&domain, "domain", "cluster.local", "DNS 域名")
|
||||
cmd.Flags().StringVar(&oldHostname, "old-hostname", "", "旧主机名(用于迁移)")
|
||||
cmd.Flags().StringVar(&ip, "ip", "", "节点 IP 地址")
|
||||
cmd.Flags().StringVar(&clusterName, "cluster", "default", "集群名称")
|
||||
cmd.Flags().StringVarP(&outputRoot, "output", "o", "/", "文件输出根目录")
|
||||
|
||||
_ = cmd.MarkFlagRequired("hostname")
|
||||
return cmd
|
||||
}
|
||||
Reference in New Issue
Block a user