From 0b64097b7e1e7aee1ec6121bd9ed559ba7522f7d Mon Sep 17 00:00:00 2001 From: eryajf Date: Sun, 4 Jan 2026 18:10:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=98=BF=E9=87=8C?= =?UTF-8?q?=E4=BA=91=E8=85=BE=E8=AE=AF=E4=BA=91=E6=9C=AA=E4=BC=98=E5=85=88?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=95=B0=E6=8D=AE=E5=BA=93=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 7 +- config.example.yaml | 6 +- internal/imcp/handlers_aliyun_oss.go | 44 ++------- internal/imcp/handlers_tencent_cos.go | 44 ++------- internal/imcp/helpers.go | 128 ++++++++++++++++++++++++-- internal/server/http.go | 101 ++++++++++++++++++++ zenops-web | 2 +- 7 files changed, 251 insertions(+), 81 deletions(-) diff --git a/Dockerfile b/Dockerfile index e8a9d44..3cbef58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,14 @@ ENV GIN_MODE=release RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories \ && apk upgrade \ - && apk add bash curl wget alpine-conf busybox-extras tzdata \ + && apk add --no-cache bash curl wget alpine-conf busybox-extras tzdata \ + && apk add --no-cache nodejs npm python3 py3-pip uv \ && apk del alpine-conf && rm -rf /var/cache/* +ENV YARN_REGISTRY=https://registry.npmmirror.com +ENV NPM_CONFIG_REGISTRY=https://registry.npmmirror.com +ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/ + ARG TARGETOS ARG TARGETARCH diff --git a/config.example.yaml b/config.example.yaml index 17cf358..4197572 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -3,7 +3,7 @@ providers: # 阿里云账号配置(支持多账号) aliyun: - name: "default" - enabled: true + enabled: false ak: "YOUR_ACCESS_KEY_ID" sk: "YOUR_ACCESS_KEY_SECRET" regions: @@ -20,7 +20,7 @@ providers: # 腾讯云账号配置(支持多账号) tencent: - name: "default" - enabled: true + enabled: false ak: "YOUR_SECRET_ID" sk: "YOUR_SECRET_KEY" regions: @@ -31,7 +31,7 @@ providers: cicd: # Jenkins 配置 jenkins: - enabled: true + enabled: false url: "https://jenkins.example.com" username: "admin" token: "YOUR_JENKINS_TOKEN" diff --git a/internal/imcp/handlers_aliyun_oss.go b/internal/imcp/handlers_aliyun_oss.go index 0515e27..7bd1cde 100644 --- a/internal/imcp/handlers_aliyun_oss.go +++ b/internal/imcp/handlers_aliyun_oss.go @@ -138,42 +138,18 @@ func formatOSSBuckets(buckets []*model.OSSBucket, accountName string) string { // getAliyunConfigByName 获取指定名称的阿里云账号配置(辅助方法) func (s *MCPServer) getAliyunConfigByName(accountName string) (*AliyunAccountConfig, error) { - if len(s.config.Providers.Aliyun) == 0 { - return nil, fmt.Errorf("no aliyun account configured") - } - - if accountName == "" { - for _, acc := range s.config.Providers.Aliyun { - if acc.Enabled { - return &AliyunAccountConfig{ - Name: acc.Name, - AK: acc.AK, - SK: acc.SK, - Regions: acc.Regions, - }, nil - } - } - acc := s.config.Providers.Aliyun[0] - return &AliyunAccountConfig{ - Name: acc.Name, - AK: acc.AK, - SK: acc.SK, - Regions: acc.Regions, - }, nil - } - - for _, acc := range s.config.Providers.Aliyun { - if acc.Name == accountName { - return &AliyunAccountConfig{ - Name: acc.Name, - AK: acc.AK, - SK: acc.SK, - Regions: acc.Regions, - }, nil - } + // 使用 helpers.go 中的方法从数据库或配置获取 + cfg, err := s.getAliyunConfigByNameFromDB(accountName) + if err != nil { + return nil, err } - return nil, fmt.Errorf("aliyun account '%s' not found", accountName) + return &AliyunAccountConfig{ + Name: cfg.Name, + AK: cfg.AK, + SK: cfg.SK, + Regions: cfg.Regions, + }, nil } // AliyunAccountConfig 阿里云账号配置 diff --git a/internal/imcp/handlers_tencent_cos.go b/internal/imcp/handlers_tencent_cos.go index 73e74bc..f960070 100644 --- a/internal/imcp/handlers_tencent_cos.go +++ b/internal/imcp/handlers_tencent_cos.go @@ -141,42 +141,18 @@ func formatCOSBuckets(buckets []*model.OSSBucket, accountName string) string { // getTencentConfigByName 获取指定名称的腾讯云账号配置(辅助方法) func (s *MCPServer) getTencentConfigByName(accountName string) (*TencentAccountConfig, error) { - if len(s.config.Providers.Tencent) == 0 { - return nil, fmt.Errorf("no tencent account configured") - } - - if accountName == "" { - for _, acc := range s.config.Providers.Tencent { - if acc.Enabled { - return &TencentAccountConfig{ - Name: acc.Name, - AK: acc.AK, - SK: acc.SK, - Regions: acc.Regions, - }, nil - } - } - acc := s.config.Providers.Tencent[0] - return &TencentAccountConfig{ - Name: acc.Name, - AK: acc.AK, - SK: acc.SK, - Regions: acc.Regions, - }, nil - } - - for _, acc := range s.config.Providers.Tencent { - if acc.Name == accountName { - return &TencentAccountConfig{ - Name: acc.Name, - AK: acc.AK, - SK: acc.SK, - Regions: acc.Regions, - }, nil - } + // 使用 helpers.go 中的方法从数据库或配置获取 + cfg, err := s.getTencentConfigByNameFromDB(accountName) + if err != nil { + return nil, err } - return nil, fmt.Errorf("tencent account '%s' not found", accountName) + return &TencentAccountConfig{ + Name: cfg.Name, + AK: cfg.AK, + SK: cfg.SK, + Regions: cfg.Regions, + }, nil } // TencentAccountConfig 腾讯云账号配置 diff --git a/internal/imcp/helpers.go b/internal/imcp/helpers.go index 98a3d20..9580dce 100644 --- a/internal/imcp/helpers.go +++ b/internal/imcp/helpers.go @@ -4,18 +4,20 @@ import ( "fmt" "strings" + "cnb.cool/zhiqiangwang/pkg/logx" "github.com/eryajf/zenops/internal/config" "github.com/eryajf/zenops/internal/model" "github.com/eryajf/zenops/internal/provider" "github.com/eryajf/zenops/internal/provider/aliyun" + "github.com/eryajf/zenops/internal/service" ) // ==================== Provider 辅助函数 ==================== // getAliyunProvider 获取阿里云 Provider func (s *MCPServer) getAliyunProvider(accountName string) (provider.Provider, *config.ProviderConfig, error) { - // 获取账号配置 - aliyunConfig, err := getAliyunConfigByName(s.config, accountName) + // 从数据库或配置获取账号配置 + aliyunConfig, err := s.getAliyunConfigByNameFromDB(accountName) if err != nil { return nil, nil, err } @@ -42,8 +44,8 @@ func (s *MCPServer) getAliyunProvider(accountName string) (provider.Provider, *c // getAliyunClient 直接获取阿里云客户端(用于高级查询) func (s *MCPServer) getAliyunClient(accountName string, region string) (*aliyun.Client, *config.ProviderConfig, error) { - // 获取账号配置 - aliyunConfig, err := getAliyunConfigByName(s.config, accountName) + // 从数据库或配置获取账号配置 + aliyunConfig, err := s.getAliyunConfigByNameFromDB(accountName) if err != nil { return nil, nil, err } @@ -64,8 +66,8 @@ func (s *MCPServer) getAliyunClient(accountName string, region string) (*aliyun. // getTencentProvider 获取腾讯云 Provider func (s *MCPServer) getTencentProvider(accountName string) (provider.Provider, *config.ProviderConfig, error) { - // 获取账号配置 - tencentConfig, err := getTencentConfigByName(s.config, accountName) + // 从数据库或配置获取账号配置 + tencentConfig, err := s.getTencentConfigByNameFromDB(accountName) if err != nil { return nil, nil, err } @@ -112,7 +114,62 @@ func (s *MCPServer) getJenkinsProvider() (provider.CICDProvider, error) { return p, nil } -// getAliyunConfigByName 根据名称获取阿里云账号配置 +// getAliyunConfigByNameFromDB 从数据库或配置获取阿里云账号配置 +func (s *MCPServer) getAliyunConfigByNameFromDB(accountName string) (*config.ProviderConfig, error) { + // 先尝试从数据库加载 + configService := service.NewConfigService() + accounts, err := configService.ListProviderAccounts("aliyun") + if err == nil && len(accounts) > 0 { + logx.Debug("Loading aliyun config from database, account count %d", len(accounts)) + + // 如果没有指定账号名,返回第一个启用的账号 + if accountName == "" { + for _, acc := range accounts { + if acc.Enabled { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + // 如果没有启用的,返回第一个 + if len(accounts) > 0 { + acc := accounts[0] + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + // 根据名称查找 + for _, acc := range accounts { + if acc.Name == accountName { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + return nil, fmt.Errorf("aliyun account '%s' not found in database", accountName) + } + + // 如果数据库没有配置,回退到 YAML 配置 + logx.Debug("No aliyun config in database, falling back to YAML config") + return getAliyunConfigByName(s.config, accountName) +} + +// getAliyunConfigByName 根据名称获取阿里云账号配置(从YAML) func getAliyunConfigByName(cfg *config.Config, accountName string) (*config.ProviderConfig, error) { if len(cfg.Providers.Aliyun) == 0 { return nil, fmt.Errorf("no aliyun account configured") @@ -136,7 +193,62 @@ func getAliyunConfigByName(cfg *config.Config, accountName string) (*config.Prov return nil, fmt.Errorf("aliyun account '%s' not found", accountName) } -// getTencentConfigByName 根据名称获取腾讯云账号配置 +// getTencentConfigByNameFromDB 从数据库或配置获取腾讯云账号配置 +func (s *MCPServer) getTencentConfigByNameFromDB(accountName string) (*config.ProviderConfig, error) { + // 先尝试从数据库加载 + configService := service.NewConfigService() + accounts, err := configService.ListProviderAccounts("tencent") + if err == nil && len(accounts) > 0 { + logx.Debug("Loading tencent config from database, account count %d", len(accounts)) + + // 如果没有指定账号名,返回第一个启用的账号 + if accountName == "" { + for _, acc := range accounts { + if acc.Enabled { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + // 如果没有启用的,返回第一个 + if len(accounts) > 0 { + acc := accounts[0] + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + // 根据名称查找 + for _, acc := range accounts { + if acc.Name == accountName { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + return nil, fmt.Errorf("tencent account '%s' not found in database", accountName) + } + + // 如果数据库没有配置,回退到 YAML 配置 + logx.Debug("No tencent config in database, falling back to YAML config") + return getTencentConfigByName(s.config, accountName) +} + +// getTencentConfigByName 根据名称获取腾讯云账号配置(从YAML) func getTencentConfigByName(cfg *config.Config, accountName string) (*config.ProviderConfig, error) { if len(cfg.Providers.Tencent) == 0 { return nil, fmt.Errorf("no tencent account configured") diff --git a/internal/server/http.go b/internal/server/http.go index e6721b8..523336d 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -16,6 +16,7 @@ import ( "github.com/eryajf/zenops/internal/model" "github.com/eryajf/zenops/internal/provider" aliyunprovider "github.com/eryajf/zenops/internal/provider/aliyun" + "github.com/eryajf/zenops/internal/service" "github.com/eryajf/zenops/internal/wecom" "github.com/eryajf/zenops/web" "github.com/gin-gonic/gin" @@ -1432,6 +1433,56 @@ func (s *HTTPGinServer) handleJenkinsBuildList(c *gin.Context) { // getAliyunConfigByName 根据名称获取阿里云账号配置 func getAliyunConfigByName(cfg *config.Config, accountName string) (*config.ProviderConfig, error) { + // 先尝试从数据库加载 + configService := service.NewConfigService() + accounts, err := configService.ListProviderAccounts("aliyun") + if err == nil && len(accounts) > 0 { + logx.Debug("Loading aliyun config from database for HTTP API, account count %d", len(accounts)) + + // 如果没有指定账号名,返回第一个启用的账号 + if accountName == "" { + for _, acc := range accounts { + if acc.Enabled { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + // 如果没有启用的,返回第一个 + if len(accounts) > 0 { + acc := accounts[0] + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + // 根据名称查找 + for _, acc := range accounts { + if acc.Name == accountName { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + return nil, fmt.Errorf("aliyun account '%s' not found in database", accountName) + } + + // 如果数据库没有配置,回退到 YAML 配置 + logx.Debug("No aliyun config in database for HTTP API, falling back to YAML config") if len(cfg.Providers.Aliyun) == 0 { return nil, fmt.Errorf("no aliyun account configured") } @@ -1456,6 +1507,56 @@ func getAliyunConfigByName(cfg *config.Config, accountName string) (*config.Prov // getTencentConfigByName 根据名称获取腾讯云账号配置 func getTencentConfigByName(cfg *config.Config, accountName string) (*config.ProviderConfig, error) { + // 先尝试从数据库加载 + configService := service.NewConfigService() + accounts, err := configService.ListProviderAccounts("tencent") + if err == nil && len(accounts) > 0 { + logx.Debug("Loading tencent config from database for HTTP API, account count %d", len(accounts)) + + // 如果没有指定账号名,返回第一个启用的账号 + if accountName == "" { + for _, acc := range accounts { + if acc.Enabled { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + // 如果没有启用的,返回第一个 + if len(accounts) > 0 { + acc := accounts[0] + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + // 根据名称查找 + for _, acc := range accounts { + if acc.Name == accountName { + return &config.ProviderConfig{ + Name: acc.Name, + Enabled: acc.Enabled, + AK: acc.AccessKey, + SK: acc.SecretKey, + Regions: acc.Regions, + }, nil + } + } + + return nil, fmt.Errorf("tencent account '%s' not found in database", accountName) + } + + // 如果数据库没有配置,回退到 YAML 配置 + logx.Debug("No tencent config in database for HTTP API, falling back to YAML config") if len(cfg.Providers.Tencent) == 0 { return nil, fmt.Errorf("no tencent account configured") } diff --git a/zenops-web b/zenops-web index 3cc55e2..cde4266 160000 --- a/zenops-web +++ b/zenops-web @@ -1 +1 @@ -Subproject commit 3cc55e24994e702eaf83049b0f276d70c2b647b7 +Subproject commit cde426629f16104a771d0405803f1dcc7f56dab9