• Go语言远程执行ssh命令简单封装(支持带交互命令)


    使用包:golang.org/x/crypto/ssh

    以下封装一个发送命令的Cli结构体

    package utils
    
    import (
    	"fmt"
    	"golang.org/x/crypto/ssh"
    	"golang.org/x/crypto/ssh/terminal"
    	"io"
    	"net"
    	"os"
    	"time"
    )
    
    type Cli struct {
    	IP         string      //IP地址
    	Username   string      //用户名
    	Password   string      //密码
    	Port       int         //端口号
    	client     *ssh.Client //ssh客户端
    	LastResult string      //最近一次Run的结果
    }
    
    //创建命令行对象
    //@param ip IP地址
    //@param username 用户名
    //@param password 密码
    //@param port 端口号,默认22
    func New(ip string, username string, password string, port ...int) *Cli {
    	cli := new(Cli)
    	cli.IP = ip
    	cli.Username = username
    	cli.Password = password
    	if len(port) <= 0 {
    		cli.Port = 22
    	} else {
    		cli.Port = port[0]
    	}
    	return cli
    }
    
    //执行shell
    //@param shell shell脚本命令
    func (c Cli) Run(shell string) (string, error) {
    	if c.client == nil {
    		if err := c.connect(); err != nil {
    			return "", err
    		}
    	}
    	session, err := c.client.NewSession()
    	if err != nil {
    		return "", err
    	}
    	defer session.Close()
    	buf, err := session.CombinedOutput(shell)
    
    	c.LastResult = string(buf)
    	return c.LastResult, err
    }
    //连接
    func (c *Cli) connect() error {
    	config := ssh.ClientConfig{
    		User: c.Username,
    		Auth: []ssh.AuthMethod{ssh.Password(c.Password)},
    		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
    			return nil
    		},
    		Timeout: 10 * time.Second,
    	}
    	addr := fmt.Sprintf("%s:%d", c.IP, c.Port)
    	sshClient, err := ssh.Dial("tcp", addr, &config)
    	if err != nil {
    		return err
    	}
    	c.client = sshClient
    	return nil
    }

    测试执行shell代码

        cli := New("IP", "用户名", "密码", 端口号)
        output, err := cli.Run("free -h")
        fmt.Printf("%v
    %v", output, err)

    还有类似top或者vim的命令是需要交互的,可以利用包golang.org/x/crypto/ssh/terminal实现

    再封装一个方法RunTerminal

    //执行带交互的命令
    func (c *Cli) RunTerminal(shell string, stdout, stderr io.Writer) error {
        if c.client == nil {
            if err := c.connect(); err != nil {
                return err
            }
        }
        session, err := c.client.NewSession()
        if err != nil {
            return err
        }
        defer session.Close()
    
        fd := int(os.Stdin.Fd())
        oldState, err := terminal.MakeRaw(fd)
        if err != nil {
            panic(err)
        }
        defer terminal.Restore(fd, oldState)
    
        session.Stdout = stdout
        session.Stderr = stderr
        session.Stdin = os.Stdin
    
        termWidth, termHeight, err := terminal.GetSize(fd)
        if err != nil {
            panic(err)
        }
        // Set up terminal modes
        modes := ssh.TerminalModes{
            ssh.ECHO:          1,     // enable echoing
            ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
            ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
        }
    
        // Request pseudo terminal
        if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
            return err
        }
    
        session.Run(shell)
        return nil
    }

    测试RunTerminal方法

        cli := New("IP", "用户名", "密码", 端口号)
        cli.RunTerminal("top", os.Stdout, os.Stdin)
  • 相关阅读:
    未能加载文件或程序集“System.EnterpriseServices, Version=4.0.0.0或2.0.0.0
    解决本地调用office组件成功,但是发布到IIS中出现的错误(检索COM类工厂中CLSID为{00024500-0000-0000-C000-000000000046}的组件时失败)
    未能找到类型或命名空间名称“Coco”(是否缺少 using 指令或程序集引用)
    SQL截取字段字符串的方法
    C# 128位AES 加密解密 (转)
    检索 COM 类工厂中 CLSID 为 {13C28AD0-F195-4319-B7D7-A1BDAA329FB8} 的组件时失败,原因是出现以下错误: 80040154
    js 获取时间比较全,留备用(zhuan)
    windows之如何把iso文件转换为VHD文件
    python之三行代码发送邮件
    RobotFramework第二篇之web自动化
  • 原文地址:https://www.cnblogs.com/chenqionghe/p/8267326.html
Copyright © 2020-2023  润新知