关于用golang封装ssh用于在远程主机上执行命令,上传或下载文件

藏色散人
发布: 2021-02-07 11:50:31
转载
3370 人浏览过

下面由golang教程栏目给大家介绍用golang封装ssh用于在远程主机上执行命令,上传或下载文件,希望对需要的朋友有所帮助!

关于用golang封装ssh用于在远程主机上执行命令,上传或下载文件

python中可以paramiko实现在远程主机上执行命令,上传和下载文件,用go也可以封装一个,在go中用ssh就sftp包可以实现,实现了下面的功能

  • 在远程主机执行命令返回结果、返回值
  • 上传和下载文件远程主机上,以及传输了多少个字节

认证方式

  • 如果指定了密码,那么采用用户+密码的方式认证,否则采用用户+秘钥的方式
    • 如果没有指定用户,则默认使用当前的用户
  • 如果没有指定密码,将采用用户+秘钥方式,默认取~/.ssh/id_rsa文件私钥文件获取秘钥
    和paramik类似

直接上代码

package mainimport ( "errors" "fmt" "github.com/pkg/sftp" "golang.org/x/crypto/ssh" "io" "io/ioutil" "log" "os" "os/user" "time")var ( DefaultSShTcpTimeout = 15 * time.Second // 与ssh建立连接的默认时间,自己设置一个就行)// 错误定义var ( InvalidHostName = errors.New("invalid parameters: hostname is empty") InvalidPort = errors.New("invalid parameters: port must be range 0 ~ 65535"))// 返回当前用户名func getCurrentUser() string { user, _ := user.Current() return user.Username}// 存放上传或下载的信息type TransferInfo struct { Kind string // upload或download Local string // 本地路径 Dst string // 目标路径 TransferByte int64 // 传输的字节数(byte)}func (t *TransferInfo) String() string { return fmt.Sprintf(`TransforInfo(Kind:"%s", Local: "%s", Dst: "%s", TransferByte: %d)`, t.Kind, t.Local, t.Dst, t.TransferByte)}// 存放执行结果的结构体信息type ExecInfo struct { Cmd string Output []byte ExitCode int}func (e *ExecInfo) OutputString() string { return string(e.Output)}func (e *ExecInfo) String() string { return fmt.Sprintf(`ExecInfo(cmd: "%s", exitcode: %d)`, e.Cmd, e.ExitCode)}type AuthConfig struct { *ssh.ClientConfig User string Password string KeyFile string Timeout time.Duration}func (a *AuthConfig) setDefault() { if a.User == "" { a.User = getCurrentUser() } if a.KeyFile == "" { userHome, _ := os.UserHomeDir() a.KeyFile = fmt.Sprintf("%s/.ssh/id_rsa", userHome) } if a.Timeout == 0 { a.Timeout = DefaultSShTcpTimeout }}func (a *AuthConfig) SetAuthMethod() (ssh.AuthMethod, error) { a.setDefault() if a.Password != "" { return ssh.Password(a.Password), nil } data, err := ioutil.ReadFile(a.KeyFile) if err != nil { return nil, err } singer, err := ssh.ParsePrivateKey(data) if err != nil { return nil, err } return ssh.PublicKeys(singer), nil}func (a *AuthConfig) ApplyConfig() error { authMethod, err := a.SetAuthMethod() if err != nil { return err } a.ClientConfig = &ssh.ClientConfig{ User: a.User, Auth: []ssh.AuthMethod{authMethod}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: a.Timeout, } return nil}// 存放连接的结构体type conn struct { client *ssh.Client sftpClient *sftp.Client}func (c *conn) Close() { if c.sftpClient != nil { c.sftpClient.Close() c.sftpClient = nil } if c.client != nil { c.client.Close() c.client = nil }}// SSHClient结构体type SSHClient struct { conn HostName string Port int AuthConfig AuthConfig}// 设置默认端口信息func (s *SSHClient) setDefaultValue() { if s.Port == 0 { s.Port = 22 }}// 与远程主机连接func (s *SSHClient) Connect() error { if s.client != nil { log.Println("Already Login") return nil } if err := s.AuthConfig.ApplyConfig(); err != nil { return err } s.setDefaultValue() addr := fmt.Sprintf("%s:%d", s.HostName, s.Port) var err error s.client, err = ssh.Dial("tcp", addr, s.AuthConfig.ClientConfig) if err != nil { return err } return nil}// 一个session只能执行一次命令,也就是说不能在同一个session执行多次s.session.CombinedOutput// 如果想执行多次,需要每条为每个命令创建一个session(这里是这样做)func (s *SSHClient) Exec(cmd string) (*ExecInfo, error) { session, err := s.client.NewSession() if err != nil { return nil, err } defer session.Close() output, err := session.CombinedOutput(cmd) var exitcode int if err != nil { // 断言转成具体实现类型,获取返回值 exitcode = err.(*ssh.ExitError).ExitStatus() } return &ExecInfo{ Cmd: cmd, Output: output, ExitCode: exitcode, }, nil}// 将本地文件上传到远程主机上func (s *SSHClient) Upload(localPath string, dstPath string) (*TransferInfo, error) { transferInfo := &TransferInfo{Kind: "upload", Local: localPath, Dst: dstPath, TransferByte: 0} var err error // 如果sftp客户端没有打开,就打开,为了复用 if s.sftpClient == nil { if s.sftpClient, err = sftp.NewClient(s.client); err != nil { return transferInfo, err } } localFileObj, err := os.Open(localPath) if err != nil { return transferInfo, err } defer localFileObj.Close() dstFileObj, err := s.sftpClient.Create(dstPath) if err != nil { return transferInfo, err } defer dstFileObj.Close() written, err := io.Copy(dstFileObj, localFileObj) if err != nil { return transferInfo, err } transferInfo.TransferByte = written return transferInfo, nil}// 从远程主机上下载文件到本地func (s *SSHClient) Download(dstPath string, localPath string) (*TransferInfo, error) { transferInfo := &TransferInfo{Kind: "download", Local: localPath, Dst: dstPath, TransferByte: 0} var err error if s.sftpClient == nil { if s.sftpClient, err = sftp.NewClient(s.client); err != nil { return transferInfo, err } } //defer s.sftpClient.Close() localFileObj, err := os.Create(localPath) if err != nil { return transferInfo, err } defer localFileObj.Close() dstFileObj, err := s.sftpClient.Open(dstPath) if err != nil { return transferInfo, err } defer dstFileObj.Close() written, err := io.Copy(localFileObj, dstFileObj) if err != nil { return transferInfo, err } transferInfo.TransferByte = written return transferInfo, nil}// SSHclient的构造方法func NewSSHClient(hostname string, port int, authConfig AuthConfig) (*SSHClient, error) { switch { case hostname == "": return nil, InvalidHostName case port > 65535 || port < 0: return nil, InvalidPort } sshClient := &SSHClient{HostName: hostname, Port: port, AuthConfig: authConfig} err := sshClient.Connect() if err != nil { return nil, err } return sshClient, nil}func main() {// 测试 sshClient, err := NewSSHClient("172.16.0.178", 22, AuthConfig{User: "root"}) if err != nil { fmt.Println(err) return } defer sshClient.Close() //第一次 执行命令 execinfo, err := sshClient.Exec("ls -l") fmt.Println(execinfo.OutputString(), err) //第二次执行命令 out1, exitcode2 := sshClient.Exec("ifconfig -a") fmt.Println(string(out1), exitcode2) // 上传文件 transInfoUpload, err := sshClient.Upload("/tmp/passwd", "/tmp/password_upload") fmt.Println(transInfoUpload, err) // 下载文件 transInfoDownload, err := sshClient.Download("/etc/passwd", "/tmp/passwd_download") fmt.Println(transInfoDownload, err)}
登录后复制

以上是关于用golang封装ssh用于在远程主机上执行命令,上传或下载文件的详细内容。更多信息请关注PHP中文网其他相关文章!

相关标签:
来源:learnku.com
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!