feat(rdp): 新增 RDP 远程桌面/SMB/账单同步能力 + 清理编译产物
主要变更: - RDP 远程桌面:新增 backend/pkg/rdp(RDP 引擎 + credssp/display/rle/trace)、 backend/controller/rdp*(连接/凭证/文件/会话/实时)、frontend RDP 组件与 API - Windows SMB 文件传输:backend/pkg/winsmb - 云账单同步:backend/pkg/billingsync + billing_sync/aliyun_billing,前端账单详情 - Agent CLI Kubernetes 工具:kubernetes_action/get、pod_execute/logs - 服务器导入助手:server_import_helpers、ImportCredentialSettings - 国际化与组件重构(cloud/deploy/monitor/server/system 等多模块) - 清理编译产物二进制:移除 backend/server、backend/agent/bin/aiops-agent-* - .gitignore:新增 backend/agent/ 与 .cache/(避免 334MB go-build 缓存误入库) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
777d9e4e71
commit
76ec9387f0
202 files changed
+16555
-2543
No files matched your search
@@ -0,0 +1,133 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type agentStaticPaths struct {
|
||||
binDir string
|
||||
deployDir string
|
||||
}
|
||||
|
||||
var agentBinaryFiles = map[string]string{
|
||||
"linux-amd64": "aiops-agent-linux-amd64",
|
||||
"linux-arm64": "aiops-agent-linux-arm64",
|
||||
"darwin-arm64": "aiops-agent-darwin-arm64",
|
||||
}
|
||||
|
||||
// registerAgentDownloads 注册 Agent 安装脚本和二进制下载路由,避免维护 backend/agent 重复目录。 // Logan.Li
|
||||
func registerAgentDownloads(r *gin.Engine, log *zap.Logger) {
|
||||
paths := resolveAgentStaticPaths(log)
|
||||
|
||||
r.GET("/agent/arch", func(c *gin.Context) {
|
||||
base := requestBaseURL(c)
|
||||
downloads := availableAgentDownloads(paths.binDir)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"version": "1.0.0",
|
||||
"downloads": downloads,
|
||||
"install": fmt.Sprintf("curl -fsSL %s/agent/install.sh | sudo bash -s -- --server %s --token <token>", base, base),
|
||||
})
|
||||
})
|
||||
|
||||
r.GET("/agent/install.sh", func(c *gin.Context) {
|
||||
serveAgentStaticFile(c, paths.deployDir, "install.sh")
|
||||
})
|
||||
for _, fileName := range agentBinaryFiles {
|
||||
name := fileName
|
||||
r.GET("/agent/"+name, func(c *gin.Context) {
|
||||
serveAgentStaticFile(c, paths.binDir, name)
|
||||
})
|
||||
}
|
||||
r.GET("/agent/bin/:file", func(c *gin.Context) {
|
||||
serveAgentStaticFile(c, paths.binDir, c.Param("file"))
|
||||
})
|
||||
r.GET("/api/agent/bin/:file", func(c *gin.Context) {
|
||||
serveAgentStaticFile(c, paths.binDir, c.Param("file"))
|
||||
})
|
||||
}
|
||||
|
||||
// resolveAgentStaticPaths 按部署形态寻找唯一 Agent 资源目录:容器优先,其次项目根目录。 // Logan.Li
|
||||
func resolveAgentStaticPaths(log *zap.Logger) agentStaticPaths {
|
||||
paths := agentStaticPaths{
|
||||
binDir: firstExistingDir([]string{
|
||||
"/app/agent/bin",
|
||||
"./agent/bin",
|
||||
"../agent/bin",
|
||||
}),
|
||||
deployDir: firstExistingDir([]string{
|
||||
"/app/agent/deploy",
|
||||
"./agent/deploy",
|
||||
"../agent/deploy",
|
||||
}),
|
||||
}
|
||||
if log != nil {
|
||||
log.Info("Agent 静态资源目录已解析",
|
||||
zap.String("bin_dir", paths.binDir),
|
||||
zap.String("deploy_dir", paths.deployDir),
|
||||
)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
func firstExistingDir(candidates []string) string {
|
||||
for _, candidate := range candidates {
|
||||
info, err := os.Stat(candidate)
|
||||
if err == nil && info.IsDir() {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func availableAgentDownloads(binDir string) gin.H {
|
||||
downloads := gin.H{}
|
||||
for platform, fileName := range agentBinaryFiles {
|
||||
if binDir == "" {
|
||||
continue
|
||||
}
|
||||
fullPath := filepath.Join(binDir, fileName)
|
||||
if info, err := os.Stat(fullPath); err == nil && !info.IsDir() {
|
||||
downloads[platform] = "/agent/" + fileName
|
||||
}
|
||||
}
|
||||
return downloads
|
||||
}
|
||||
|
||||
func requestBaseURL(c *gin.Context) string {
|
||||
scheme := "http"
|
||||
if c.Request.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
if proto := c.GetHeader("X-Forwarded-Proto"); proto != "" {
|
||||
scheme = proto
|
||||
}
|
||||
host := c.Request.Host
|
||||
if host == "" {
|
||||
host = "localhost:8080"
|
||||
}
|
||||
return fmt.Sprintf("%s://%s", scheme, host)
|
||||
}
|
||||
|
||||
func serveAgentStaticFile(c *gin.Context, dir string, fileName string) {
|
||||
if dir == "" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "agent static directory not found"})
|
||||
return
|
||||
}
|
||||
if strings.Contains(fileName, "/") || strings.Contains(fileName, "\\") || fileName == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid agent file"})
|
||||
return
|
||||
}
|
||||
fullPath := filepath.Join(dir, fileName)
|
||||
if info, err := os.Stat(fullPath); err != nil || info.IsDir() {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "agent file not found"})
|
||||
return
|
||||
}
|
||||
c.File(fullPath)
|
||||
}
|
||||
Reference in new issue
Block a user