admin_backend/util/ssh.go
2026-02-06 15:31:37 +08:00

79 lines
1.7 KiB
Go

package util
import (
"backend/Type"
"fmt"
"os"
"golang.org/x/crypto/ssh"
)
type SshClient struct {
client *ssh.Client
}
func (ssh *SshClient) Close() {
ssh.client.Close()
}
func NewSshClient(config *Type.Node) (*SshClient, error) {
var authMethods []ssh.AuthMethod
// 支持证书连接
// 从文件读取私钥
if config.PrivateKeyPath != "" {
keyBytes, err := os.ReadFile(config.PrivateKeyPath)
if err != nil {
return nil, fmt.Errorf("read private key file failed: %w", err)
}
key, err := ssh.ParsePrivateKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("parse private key failed: %w", err)
}
authMethods = append(authMethods, ssh.PublicKeys(key))
}
// 支持密码连接
if config.Password != "" {
SP, err := Decrypt(config.Password)
if err != nil {
return nil, fmt.Errorf("decrypt password failed: %w", err)
}
authMethods = append(authMethods, ssh.Password(SP))
}
if len(authMethods) == 0 {
return nil, fmt.Errorf("no authentication method provided")
}
sshconfig := &ssh.ClientConfig{
User: "root",
Auth: authMethods,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
addr := fmt.Sprintf("%s:22", config.Host)
client, err := ssh.Dial("tcp", addr, sshconfig)
if err != nil {
return nil, err
}
return &SshClient{client: client}, nil
}
func (s *SshClient) RunCommand(cmd string) (string, error) {
session, err := s.client.NewSession()
if err != nil {
return "", err
}
defer session.Close()
output, err := session.CombinedOutput(cmd)
// 即使命令失败也返回输出,这样可以看到错误信息
if err != nil {
return string(output), err
}
return string(output), nil
}