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:
LoganandClaude committed 2026-07-04 01:50:36 +08:00
1 parent 777d9e4e71
commit 76ec9387f0
202 files changed
+16555 -2543

No files matched your search

+146 -7
View File
@@ -9,9 +9,9 @@ import (
"ezops/dto"
"ezops/model"
"ezops/repository"
"ezops/pkg/crypto"
ezredis "ezops/pkg/redis"
"ezops/repository"
"gorm.io/gorm"
)
@@ -60,6 +60,9 @@ func (s *ServerService) CreateServer(req *dto.CreateServerRequest) (*model.Serve
Port: req.Port,
Username: req.Username,
AuthType: req.AuthType,
OSType: req.OSType,
Protocol: req.Protocol,
RDPPort: req.RDPPort,
OS: req.OS,
OSVersion: req.OSVersion,
Arch: req.Arch,
@@ -80,6 +83,18 @@ func (s *ServerService) CreateServer(req *dto.CreateServerRequest) (*model.Serve
if req.AuthType == "" {
srv.AuthType = "password"
}
if srv.OSType == "" {
srv.OSType = "linux"
}
if srv.Protocol == "" {
srv.Protocol = "ssh"
}
if srv.Protocol == "rdp" {
srv.OSType = "windows"
if srv.RDPPort == 0 {
srv.RDPPort = 3389
}
}
// 加密密码和 SSH 密钥
if req.Password != "" {
@@ -96,6 +111,11 @@ func (s *ServerService) CreateServer(req *dto.CreateServerRequest) (*model.Serve
}
srv.SSHKey = enc
}
if req.CredentialID != nil && *req.CredentialID > 0 {
if err := s.applyCredentialToServer(*req.CredentialID, srv); err != nil {
return nil, err
}
}
if err := s.repo.Create(srv); err != nil {
return nil, err
@@ -125,6 +145,15 @@ func (s *ServerService) UpdateServer(id uint, req *dto.UpdateServerRequest) erro
if req.AuthType != nil {
updates["auth_type"] = *req.AuthType
}
if req.OSType != nil {
updates["os_type"] = *req.OSType
}
if req.Protocol != nil {
updates["protocol"] = *req.Protocol
}
if req.RDPPort != nil {
updates["rdp_port"] = *req.RDPPort
}
if req.OS != nil {
updates["os"] = *req.OS
}
@@ -174,6 +203,23 @@ func (s *ServerService) UpdateServer(id uint, req *dto.UpdateServerRequest) erro
}
updates["ssh_key"] = enc
}
if req.CredentialID != nil && *req.CredentialID > 0 {
srv, err := s.repo.GetByID(id)
if err != nil {
return err
}
if err := s.applyCredentialToServer(*req.CredentialID, srv); err != nil {
return err
}
updates["username"] = srv.Username
updates["password"] = srv.Password
updates["ssh_key"] = srv.SSHKey
updates["auth_type"] = srv.AuthType
updates["port"] = srv.Port
updates["rdp_port"] = srv.RDPPort
updates["protocol"] = srv.Protocol
updates["os_type"] = srv.OSType
}
if len(updates) == 0 {
return nil
@@ -181,6 +227,67 @@ func (s *ServerService) UpdateServer(id uint, req *dto.UpdateServerRequest) erro
return s.repo.UpdateFields(id, updates)
}
func (s *ServerService) applyCredentialToServer(credentialID uint, srv *model.Server) error {
cred, err := s.credentialByID(credentialID)
if err != nil {
return err
}
plain, err := s.crypt.Decrypt(cred.Content)
if err != nil {
return fmt.Errorf("凭据解密失败: %w", err)
}
switch cred.SecretType {
case "ssh":
var sshc model.SSHSecretContent
if json.Unmarshal([]byte(plain), &sshc) == nil {
if sshc.SSHUser != "" {
srv.Username = sshc.SSHUser
}
if sshc.SSHPort > 0 {
srv.Port = sshc.SSHPort
}
if sshc.PrivateKey != "" {
srv.SSHKey = sshc.PrivateKey
srv.Password = ""
srv.AuthType = "key"
} else if sshc.Password != "" {
srv.Password = sshc.Password
srv.SSHKey = ""
srv.AuthType = "password"
}
}
srv.Protocol = "ssh"
if srv.OSType == "" {
srv.OSType = "linux"
}
case "rdp":
var rdpc model.RDPSecretContent
if err := json.Unmarshal([]byte(plain), &rdpc); err != nil {
return fmt.Errorf("RDP 凭据格式错误: %w", err)
}
srv.Username = rdpc.Username
srv.Password = plain
srv.SSHKey = ""
srv.AuthType = "password"
srv.Protocol = "rdp"
srv.OSType = "windows"
if srv.RDPPort == 0 {
srv.RDPPort = 3389
}
default:
return fmt.Errorf("服务器仅支持关联 ssh/rdp 凭据")
}
return nil
}
func (s *ServerService) credentialByID(id uint) (*model.Credential, error) {
var cred model.Credential
if err := s.repo.DB().First(&cred, id).Error; err != nil {
return nil, err
}
return &cred, nil
}
// DeleteServer 删除服务器
func (s *ServerService) DeleteServer(id uint) error {
return s.repo.Delete(id)
@@ -237,6 +344,19 @@ func (s *CredentialService) buildCredentialContent(req *dto.CreateCredentialRequ
}
b, _ := json.Marshal(data)
return string(b), fmt.Sprintf("SSH %s@%d", req.SSHUser, req.SSHPort), nil
case "rdp":
security := req.RDPSecurity
if security == "" {
security = "nla"
}
data := map[string]string{
"username": req.RDPUsername,
"password": req.RDPPassword,
"domain": req.RDPDomain,
"security": security,
}
b, _ := json.Marshal(data)
return string(b), fmt.Sprintf("RDP %s", req.RDPUsername), nil
case "docker":
data := map[string]string{
"server": req.DockerServer,
@@ -309,6 +429,25 @@ func (s *CredentialService) buildUpdateContent(req *dto.UpdateCredentialRequest,
}
b, _ := json.Marshal(data)
return string(b), "", nil
case "rdp":
data := map[string]string{}
if req.RDPUsername != nil {
data["username"] = *req.RDPUsername
}
if req.RDPPassword != nil {
data["password"] = *req.RDPPassword
}
if req.RDPDomain != nil {
data["domain"] = *req.RDPDomain
}
if req.RDPSecurity != nil {
data["security"] = *req.RDPSecurity
}
if len(data) == 0 {
return "", "", nil
}
b, _ := json.Marshal(data)
return string(b), "", nil
case "docker":
data := map[string]string{}
if req.DockerServer != nil {
@@ -523,9 +662,9 @@ func toJSONString(v interface{}) string {
// ━━━ Config Helper — 管理所有 Service 的依赖注入 ━━━━
type Services struct {
Server *ServerService
Credential *CredentialService
AlertContact *AlertContactService
Server *ServerService
Credential *CredentialService
AlertContact *AlertContactService
AlertContactGroup *AlertContactGroupService
}
@@ -534,9 +673,9 @@ func NewServices(db *gorm.DB, cache ezredis.Cache, masterKey string) *Services {
crypt := crypto.NewSecretBox(masterKey)
return &Services{
Server: NewServerService(repository.NewServerRepository(db), cache, crypt),
Credential: NewCredentialService(repository.NewCredentialRepository(db), crypt),
AlertContact: NewAlertContactService(repository.NewAlertContactRepository(db)),
Server: NewServerService(repository.NewServerRepository(db), cache, crypt),
Credential: NewCredentialService(repository.NewCredentialRepository(db), crypt),
AlertContact: NewAlertContactService(repository.NewAlertContactRepository(db)),
AlertContactGroup: NewAlertContactGroupService(repository.NewAlertContactGroupRepository(db)),
}
}