79 lines
1.7 KiB
Go
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
|
|
}
|