Skip to main content
Glama
migrate.go13.2 kB
package models import ( "fmt" "strings" "github.com/weibaohui/k8m/internal/dao" "github.com/weibaohui/k8m/pkg/constants" "github.com/weibaohui/k8m/pkg/flag" "gorm.io/gorm" "k8s.io/klog/v2" ) func init() { err := AutoMigrate() if err != nil { klog.Errorf("数据库迁移失败: %v", err.Error()) } klog.V(4).Info("数据库自动迁移完成") _ = FixClusterName() _ = AddInnerMCPServer() _ = FixRoleName() _ = InitConfigTable() _ = InitConditionTable() _ = FixClusterAuthorizationTypeName() _ = AddInnerAdminUserGroup() _ = AddInnerAdminUser() _ = MigrateAIModel() _ = AddBuiltinLuaScripts() _ = InitBuiltinAIPrompts() } func AutoMigrate() error { var errs []error // 添加需要迁移的所有模型 if err := dao.DB().AutoMigrate(&CustomTemplate{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&KubeConfig{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&User{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&ClusterUserRole{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&OperationLog{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&ShellLog{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&HelmRepository{}); err != nil { errs = append(errs, err) } // MYSQL 下需要单独处理 content字段为LONGTEXT,pg、sqlite不需要处理,这个字段删掉了,不用了 // if dao.DB().Migrator().HasTable(&HelmRepository{}) && dao.DB().Dialector.Name() == "mysql" { // dao.DB().Exec("ALTER TABLE helm_repositories MODIFY COLUMN content LONGTEXT") // } if err := dao.DB().AutoMigrate(&HelmChart{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&HelmRelease{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&UserGroup{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&MCPServerConfig{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&MCPTool{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&Config{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&ApiKey{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&ConditionReverse{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&MCPToolLog{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&McpKey{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&SSOConfig{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&LDAPConfig{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&AIModelConfig{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&InspectionCheckEvent{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&InspectionRecord{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&InspectionSchedule{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&InspectionScriptResult{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&InspectionLuaScript{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&InspectionLuaScriptBuiltinVersion{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&WebhookReceiver{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&WebhookLogRecord{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&Menu{}); err != nil { errs = append(errs, err) } if err := dao.DB().AutoMigrate(&AIPrompt{}); err != nil { errs = append(errs, err) } // 事件处理器配置表 if err := dao.DB().AutoMigrate(&K8sEventConfig{}); err != nil { errs = append(errs, err) } // 事件处理器:K8s事件存储表 if err := dao.DB().AutoMigrate(&K8sEvent{}); err != nil { errs = append(errs, err) } // 删除 user 表 name 字段,已弃用 if dao.DB().Migrator().HasColumn(&User{}, "Role") { if err := dao.DB().Migrator().DropColumn(&User{}, "Role"); err != nil { // 判断是不是check that column/key exists // 不存在,不用删除,那么不用报错误 if !strings.Contains(err.Error(), "check that column/key exists") { errs = append(errs, err) } } } // 打印所有非nil的错误 for _, err := range errs { if err != nil { klog.Errorf("数据库迁移报错: %v", err.Error()) } } return nil } func AddBuiltinLuaScripts() error { // 检查数据库中记录的内置脚本版本 db := dao.DB() version, err := GetBuiltinLuaScriptsVersion(db) if err == nil { // 有记录,判断是否需要更新 if version == BuiltinLuaScriptsVersion { // 版本一致,无需更新 return nil } } // 版本不一致或无记录,先删除所有内置脚本 if err := db.Where("script_type = ?", constants.LuaScriptTypeBuiltin).Delete(&InspectionLuaScript{}).Error; err != nil { klog.Errorf("删除旧内置巡检脚本失败: %v", err) return err } // 插入最新内置脚本 if err := db.CreateInBatches(BuiltinLuaScripts, 100).Error; err != nil { klog.Errorf("插入内置巡检脚本失败: %v", err) return err } // 更新版本号 if err := SetBuiltinLuaScriptsVersion(db, BuiltinLuaScriptsVersion); err != nil { klog.Errorf("更新内置脚本版本号失败: %v", err) return err } return nil } func FixRoleName() error { // 将用户组表中角色进行统一,除了平台管理员以外,都更新为普通用户guest err := dao.DB().Model(&UserGroup{}).Where("role != ?", "platform_admin").Update("role", "guest").Error if err != nil { klog.Errorf("更新用户组表中角色失败: %v", err) return err } return nil } func FixClusterAuthorizationTypeName() error { // 将用户组表中角色进行统一,除了平台管理员以外,都更新为普通用户guest err := dao.DB().Model(&ClusterUserRole{}).Where("authorization_type = '' or authorization_type is null").Update("authorization_type", "user").Error if err != nil { klog.Errorf("更新用户组表中角色失败: %v", err) return err } return nil } func FixClusterName() error { // 将display_name为空的记录更新为cluster字段 result := dao.DB().Model(&KubeConfig{}).Where("display_name = ?", "").Update("display_name", gorm.Expr("cluster")) if result.Error != nil { klog.Errorf("更新cluster_name失败: %v", result.Error) return result.Error } return nil } // AddInnerMCPServer 检查并初始化名为 "k8m" 的内部 MCP 服务器配置,不存在则创建,已存在则更新其 URL。 func AddInnerMCPServer() error { // 检查是否存在名为k8m的记录 var count int64 if err := dao.DB().Model(&MCPServerConfig{}).Where("name = ?", "k8m").Count(&count).Error; err != nil { klog.Errorf("查询MCP服务器配置失败: %v", err) return err } cfg := flag.Init() // 如果不存在,添加默认的内部MCP服务器配置 if count == 0 { config := &MCPServerConfig{ Name: "k8m", URL: fmt.Sprintf("http://localhost:%d/mcp/k8m/sse", cfg.Port), Enabled: false, } if err := dao.DB().Create(config).Error; err != nil { klog.Errorf("添加内部MCP服务器配置失败: %v", err) return err } klog.V(4).Info("成功添加内部MCP服务器配置") } else { klog.V(4).Info("内部MCP服务器配置已存在") dao.DB().Model(&MCPServerConfig{}).Select("url"). Where("name =?", "k8m"). Update("url", fmt.Sprintf("http://localhost:%d/mcp/k8m/sse", cfg.Port)) } return nil } func InitConfigTable() error { var count int64 if err := dao.DB().Model(&Config{}).Count(&count).Error; err != nil { klog.Errorf("查询配置表: %v", err) return err } if count == 0 { config := &Config{ PrintConfig: false, EnableAI: true, AnySelect: true, LoginType: "password", } if err := dao.DB().Create(config).Error; err != nil { klog.Errorf("初始化配置表失败: %v", err) return err } klog.V(4).Info("成功初始化配置表") } return nil } func InitConditionTable() error { var count int64 if err := dao.DB().Model(&ConditionReverse{}).Count(&count).Error; err != nil { klog.Errorf("查询翻转指标配置表: %v", err) return err } if count == 0 { // 初始化需要翻转的指标 conditions := []ConditionReverse{ {Name: "Pressure", Enabled: true}, {Name: "Unavailable", Enabled: true}, {Name: "Problem", Enabled: true}, {Name: "Error", Enabled: true}, {Name: "Slow", Enabled: true}, } if err := dao.DB().Create(&conditions).Error; err != nil { klog.Errorf("初始化翻转指标配置失败: %v", err) return err } klog.V(4).Info("成功初始化翻转指标配置表") } return nil } // AddInnerAdminUser 添加内置管理员账户 func AddInnerAdminUser() error { // 检查是否存在名为k8m的记录 var count int64 if err := dao.DB().Model(&User{}).Count(&count).Error; err != nil { klog.Errorf("统计用户数错误: %v", err) return err } if count > 0 { klog.V(4).Info("已存在用户,不再添加默认管理员用户") return nil } if err := dao.DB().Model(&User{}).Where("username = ?", "k8m").Count(&count).Error; err != nil { klog.Errorf("查看k8m默认用户是否存在,发生错误: %v", err) return err } // 如果不存在,添加默认的一个默认的平台管理员账户 // 用户名为: k8m // 密码为: k8m if count == 0 { config := &User{ Username: "k8m", Salt: "grfi92rq", Password: "8RGCXWw6IzgKDPyeFKt6Kw==", GroupNames: "平台管理员组", } if err := dao.DB().Create(config).Error; err != nil { klog.Errorf("添加默认平台管理员账户失败: %v", err) return err } klog.V(4).Info("成功添加默认平台管理员账户") } else { klog.V(4).Info("默认平台管理员k8m账户已存在") } return nil } // AddInnerAdminUserGroup 添加内置管理员账户组 func AddInnerAdminUserGroup() error { // 检查是否存在名为 平台管理员组 的内置管理员账户组的记录 var count int64 if err := dao.DB().Model(&UserGroup{}).Where("group_name = ?", "平台管理员组").Count(&count).Error; err != nil { klog.Errorf("已存在内置 平台管理员组 角色: %v", err) return err } // 如果不存在,添加默认的内部MCP服务器配置 if count == 0 { config := &UserGroup{ GroupName: "平台管理员组", Role: "platform_admin", } if err := dao.DB().Create(config).Error; err != nil { klog.Errorf("添加默认平台管理员组失败: %v", err) return err } klog.V(4).Info("成功添加默认平台管理员组") } else { klog.V(4).Info("默认平台管理员组已存在") } return nil } func MigrateAIModel() error { // 将旧表 config 中的 AI 配置字段批量搬迁到新表 ai_model_configs // 先看AIModelConfigs是否有数据,如果有数据,则停止迁移 model := &AIModelConfig{} _, count, err := model.List(nil) if err != nil { klog.Errorf("查询新表 ai_model_configs 失败: %v", err) } if count > 0 { klog.V(4).Info("新表 ai_model_configs 已有数据,不再进行迁移") // 不需要进行迁移 return nil } if !dao.DB().Migrator().HasColumn(&Config{}, "api_key") { // 不需要进行迁移 klog.Infof("参数表config 无老版本API_KEY相关配置,无需进行迁移") return nil } row := dao.DB().Raw("select api_key,api_model,api_url,temperature,top_p from configs limit 1").Row() err = row.Scan(&model.ApiKey, &model.ApiModel, &model.ApiURL, &model.Temperature, &model.TopP) if err != nil { // 不需要进行迁移 klog.Infof("查询旧表 config 失败: %v,不再进行迁移", err) return nil } // 检查这几个 字段是否为空,如果为空,则不进行迁移 if model.ApiKey == "" && model.ApiModel == "" && model.ApiURL == "" { klog.V(4).Info("旧表 config 中的 AI 配置字段为空,不再进行迁移") // 不需要进行迁移 return nil } err = model.Save(nil) if err != nil { klog.Errorf("保存新表 ai_model_configs 失败: %v", err) return err } // 更新config表,记录ModelID dao.DB().Model(&Config{}).Update("model_id", model.ID) return nil } // InitBuiltinAIPrompts 初始化内置AI提示词 func InitBuiltinAIPrompts() error { // 检查是否已经存在内置提示词 var count int64 dao.DB().Model(&AIPrompt{}).Where("is_builtin = ?", true).Count(&count) if count > 0 { return nil // 已经初始化过了 } // 使用已定义的内置提示词 for _, prompt := range BuiltinAIPrompts { // 检查是否已存在相同的提示词名称和类型 var existing AIPrompt err := dao.DB().Where("name = ? AND prompt_type = ?", prompt.Name, prompt.PromptType).First(&existing).Error if err == nil { continue // 已存在,跳过 } // 创建新的提示词 if err := dao.DB().Create(&prompt).Error; err != nil { return err } } return nil }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/weibaohui/k8m'

If you have feedback or need assistance with the MCP directory API, please join our Discord server