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 }