中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用golang封裝ssh用于在遠程主機上執行命令

發布時間:2021-02-12 10:16:01 來源:億速云 閱讀:1212 作者:小新 欄目:編程語言

這篇文章主要介紹了如何使用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用于在遠程主機上執行命令”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

黑水县| 望都县| 台北市| 花垣县| 南阳市| 永泰县| 霍州市| 靖西县| 大田县| 定西市| 抚顺市| 平乐县| 岐山县| 霍林郭勒市| 井陉县| 宜黄县| 平果县| 康定县| 亚东县| 本溪| 苏尼特左旗| 渭南市| 霍城县| 景德镇市| 沁阳市| 罗城| 靖远县| 昌都县| 阳曲县| 莎车县| 琼中| 佛山市| 长白| 巴彦县| 营山县| 客服| 荥经县| 同德县| 苍南县| 小金县| 靖远县|