连接工具
package Tools
import (
"errors"
"fmt"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"io"
"log"
"os"
"time"
)
type ClientConfig struct {
Host string
Port int
Username string
Password string
SshClient *ssh.Client
Session *ssh.Session
Stdin io.WriteCloser
Stdout io.Reader
Stderr io.Reader
sftpClient *sftp.Client
LastResult string
}
func (cliConf *ClientConfig) CreateClient(host string, port int, username, password string) error {
var (
sshClient *ssh.Client
err error
)
cliConf.Host = host
cliConf.Port = port
cliConf.Username = username
cliConf.Password = password
config := ssh.ClientConfig{
User: cliConf.Username,
Auth: []ssh.AuthMethod{ssh.Password(password)},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: 10 * time.Second,
}
addr := fmt.Sprintf("%s:%d", cliConf.Host, cliConf.Port)
if sshClient, err = ssh.Dial("tcp", addr, &config); err != nil {
return err
}
cliConf.SshClient = sshClient
return err
}
func (cliConf *ClientConfig) RunTerminal() error {
session, err := cliConf.SshClient.NewSession()
if err != nil {
return err
}
stdin, err := session.StdinPipe()
if err != nil {
return err
}
stdout, err := session.StdoutPipe()
if err != nil {
return err
}
stderr, err := session.StderrPipe()
if err != nil {
return err
}
if err := session.Shell(); err != nil {
return err
}
cliConf.Stdin = stdin
cliConf.Stdout = stdout
cliConf.Stderr = stderr
cliConf.Session = session
go func() {
if err := session.Wait(); err != nil {
log.Fatalf("Failed to wait for session: %s", err)
}
}()
return nil
}
func (cliConf *ClientConfig) RunCommand(cmd string) error {
_, errExecute := fmt.Fprintf(cliConf.Stdin, "%s\n", cmd)
if errExecute != nil {
return errExecute
}
return nil
}
func (cliConf *ClientConfig) RunShell(shell string) (string, error) {
var (
session *ssh.Session
err error
)
if session, err = cliConf.SshClient.NewSession(); err != nil {
log.Fatalln("error occurred:", err)
return "", err
}
if output, err := session.CombinedOutput(shell); err != nil {
fmt.Println(shell)
log.Fatalln("error occurred:", err)
return "", err
} else {
cliConf.LastResult = string(output)
}
return cliConf.LastResult, nil
}
func (cliConf *ClientConfig) Upload(srcPath, dstPath string) error {
if cliConf.sftpClient == nil {
return errors.New("no Create sftpClient")
}
srcFile, _ := os.Open(srcPath)
dstFile, _ := cliConf.sftpClient.Create(dstPath)
defer func() {
_ = srcFile.Close()
_ = dstFile.Close()
}()
buf := make([]byte, 1024)
for {
n, err := srcFile.Read(buf)
if err != nil {
if err != io.EOF {
log.Fatalln("error occurred:", err)
return err
} else {
break
}
}
_, _ = dstFile.Write(buf[:n])
}
fmt.Println(cliConf.RunShell(fmt.Sprintf("ls %s", dstPath)))
return nil
}
func (cliConf *ClientConfig) Download(srcPath, dstPath string) error {
if cliConf.sftpClient == nil {
return errors.New("no Create sftpClient")
}
srcFile, err := cliConf.sftpClient.Open(srcPath)
fmt.Println(srcFile)
if err != nil {
fmt.Println(err.Error())
return err
}
dstFile, _ := os.Create(dstPath)
defer func() {
_ = srcFile.Close()
_ = dstFile.Close()
}()
if _, err := srcFile.WriteTo(dstFile); err != nil {
log.Fatalln("error occurred", err)
return err
}
fmt.Println("文件下载完毕")
return nil
}
使用样例
测试连接与执行
type SelfObject struct {
cliConf *Tools.ClientConfig
}
func (s *SelfObject) TestDBConnect(ip string, port int, user string, password string) error {
cliConf := new(Tools.ClientConfig)
err := cliConf.CreateClient(ip, port, user, password)
if err != nil {
if strings.Contains(err.Error(), "unable to authenticate") {
return errors.New("SSH连接的用户名密码错误,请重新确认")
} else if strings.Contains(err.Error(), " i/o timeout") {
return errors.New("SSH连接超时,请确认网络是否正常")
}
return err
}
res, err := cliConf.RunShell("pwd")
if err != nil {
return err
}
fmt.Println(res)
return nil
}
交互式窗口连续执行
type SelfObject struct {
cliConf *Tools.ClientConfig
}
func (s *SelfObject) RunTerminal(ip string, port int, user string, password string) error {
cliConf := new(Tools.ClientConfig)
err := cliConf.CreateClient(ip, port, user, password)
if err != nil {
if strings.Contains(err.Error(), "unable to authenticate") {
return errors.New("SSH连接的用户名密码错误,请重新确认")
} else if strings.Contains(err.Error(), " i/o timeout") {
return errors.New("SSH连接超时,请确认网络是否正常")
}
return err
}
err = cliConf.RunTerminal()
if err != nil {
fmt.Println("Open Terminal Error:", err)
return err
}
defer cliConf.Session.Close()
readErrFlag := false
go func() {
scanerr := bufio.NewScanner(cliConf.Stderr)
for scanerr.Scan() {
err := errors.New(scanerr.Text())
defer func() {
if r := recover(); r != nil {
panic(err)
}
}()
cliConf.Stdin.Close()
}
}()
go func() {
defer func() {
err := recover()
if err != nil {
fmt.Println("解析输出协程异常:", err)
}
}()
scanner := bufio.NewScanner(cliConf.Stdout)
for scanner.Scan() {
line := scanner.Text()
fmt.Println(line)
}
}()
cliConf.RunCommand("pwd")
cliConf.RunCommand("mkdir test")
cliConf.RunCommand("cd mkdir;echo hello")
cliConf.Stdin.Close()
if err := cliConf.Session.Wait(); err != nil {
log.Fatalf("Failed to wait for session: %s", err)
}
}