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
+146
-7
@@ -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)),
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user