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,137 @@
|
||||
// pod_execute.go - 在目标 Pod 容器内执行 shell 命令 // Logan.Li
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
k8sclient "ezops/pkg/kubernetesclient"
|
||||
)
|
||||
|
||||
// PodExecuteTool 在 Pod 容器内执行命令(K8s exec WebSocket 协议) // Logan.Li
|
||||
type PodExecuteTool struct {
|
||||
client *k8sclient.Client
|
||||
namespace string
|
||||
podName string
|
||||
container string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// NewPodExecuteTool 创建 Pod 执行工具 // Logan.Li
|
||||
func NewPodExecuteTool(client *k8sclient.Client, namespace, podName, container string, timeout time.Duration) *PodExecuteTool {
|
||||
if timeout <= 0 {
|
||||
timeout = 60 * time.Second
|
||||
}
|
||||
return &PodExecuteTool{
|
||||
client: client, namespace: namespace, podName: podName,
|
||||
container: container, timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// Name 工具名 // Logan.Li
|
||||
func (t *PodExecuteTool) Name() string { return "pod_execute" }
|
||||
|
||||
// Description 给 LLM 的工具说明 // Logan.Li
|
||||
func (t *PodExecuteTool) Description() string {
|
||||
return "在已选定的 Kubernetes Pod 容器内执行 shell 命令并返回 stdout+stderr。" +
|
||||
"用于容器内排障(查看进程/配置/连通性)、应用调试。" +
|
||||
"注意:容器内可能没有 systemctl 或宿主机路径;多容器 Pod 可通过 container 参数指定。" +
|
||||
"高危命令需用户确认。"
|
||||
}
|
||||
|
||||
// Parameters JSON Schema // Logan.Li
|
||||
func (t *PodExecuteTool) Parameters() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"command": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "要执行的 shell 命令,例如 ps aux、cat /etc/nginx/nginx.conf、curl -s localhost:8080/health",
|
||||
},
|
||||
"container": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "可选,多容器 Pod 时指定容器名;默认使用会话绑定的容器",
|
||||
},
|
||||
"timeout": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"description": "命令超时秒数(默认 60)",
|
||||
},
|
||||
},
|
||||
"required": []string{"command"},
|
||||
}
|
||||
}
|
||||
|
||||
// RiskLevel 静态风险 // Logan.Li
|
||||
func (t *PodExecuteTool) RiskLevel() RiskLevel { return RiskHigh }
|
||||
|
||||
// RiskLevelForArgs 依据命令动态评估风险 // Logan.Li
|
||||
func (t *PodExecuteTool) RiskLevelForArgs(args map[string]interface{}) RiskLevel {
|
||||
return AssessBashRisk(StringParam(args, "command"))
|
||||
}
|
||||
|
||||
// Execute 在 Pod 内执行命令 // Logan.Li
|
||||
func (t *PodExecuteTool) Execute(ctx context.Context, args map[string]interface{}) (*Result, error) {
|
||||
command := strings.TrimSpace(StringParam(args, "command"))
|
||||
if command == "" {
|
||||
return &Result{Success: false, Error: "参数 command 不能为空"}, nil
|
||||
}
|
||||
if t.podName == "" {
|
||||
return &Result{Success: false, Error: "未绑定目标 Pod,请在前端选择 Pod 或在命令前先 kubernetes_get 确认"}, nil
|
||||
}
|
||||
|
||||
container := strings.TrimSpace(StringParam(args, "container"))
|
||||
if container == "" {
|
||||
container = t.container
|
||||
}
|
||||
|
||||
timeout := t.timeout
|
||||
if sec := IntParam(args, "timeout"); sec > 0 {
|
||||
timeout = time.Duration(sec) * time.Second
|
||||
}
|
||||
|
||||
execCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
// 用 sh -c 保持 shell 语义,并嵌入 exit_code 与 ssh_execute 对齐 // Logan.Li
|
||||
wrapped := command + "; echo [exit_code=$?]"
|
||||
done := make(chan struct {
|
||||
res *k8sclient.ExecResult
|
||||
err error
|
||||
}, 1)
|
||||
go func() {
|
||||
r, err := t.client.ExecInPod(t.namespace, t.podName, container, []string{"sh", "-c", wrapped})
|
||||
done <- struct {
|
||||
res *k8sclient.ExecResult
|
||||
err error
|
||||
}{r, err}
|
||||
}()
|
||||
|
||||
var result *k8sclient.ExecResult
|
||||
var err error
|
||||
select {
|
||||
case <-execCtx.Done():
|
||||
return &Result{Success: false, Error: "命令执行超时"}, nil
|
||||
case out := <-done:
|
||||
result, err = out.res, out.err
|
||||
}
|
||||
if err != nil {
|
||||
return &Result{Success: false, Error: fmt.Sprintf("Pod exec 失败: %v", err)}, nil
|
||||
}
|
||||
|
||||
output := strings.TrimSpace(result.Stdout)
|
||||
if result.Stderr != "" {
|
||||
if output != "" {
|
||||
output += "\n"
|
||||
}
|
||||
output += strings.TrimSpace(result.Stderr)
|
||||
}
|
||||
success := strings.Contains(output, "[exit_code=0]")
|
||||
if !success && !strings.Contains(output, "[exit_code=") {
|
||||
// 无 exit_code 标记时,无 stderr 视为成功 // Logan.Li
|
||||
success = strings.TrimSpace(result.Stderr) == ""
|
||||
}
|
||||
|
||||
return &Result{Success: success, Output: output}, nil
|
||||
}
|
||||
Reference in new issue
Block a user