golang 实现 ssh批量执行命令

golang ssh

最近学习go编程,想做个ssh小工具,用来执行批量命令的,后面用来替换ansible的程序。不多说了直接贴代码:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main

import (
	"bufio"
	"fmt"
	"github.com/mitchellh/go-homedir"
	"golang.org/x/crypto/ssh"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"time"
)

func HandleText(textfile string) ([]string, error) {

	HostUserPasswdPort := []string{}

	file, err := os.Open(textfile)
	if err != nil {
		log.Printf("Cannot open text file: %s, err: [%v]", textfile, err)
		return nil, err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text() // or
		//line := scanner.Bytes()
		HostUserPasswdPort = append(HostUserPasswdPort, line)

	}

	if err := scanner.Err(); err != nil {
		log.Printf("Cannot scanner text file: %s, err: [%v]", textfile, err)
		return nil, err
	}

	return HostUserPasswdPort, nil
}

func GetHostUserPasswdPort() {


	var con []string
	con, _ = HandleText("C:/hostname.txt")
	for _, cons := range con {
		if len(cons) != 0 {
			SshHost := strings.Fields(strings.TrimSpace(cons))[0]
			SshUser := strings.Fields(strings.TrimSpace(cons))[1]
			SshPassword := strings.Fields(strings.TrimSpace(cons))[2]
			SshType := strings.Fields(strings.TrimSpace(cons))[3]
			SshKeyPath := strings.Fields(strings.TrimSpace(cons))[4]
			SshPort,_:= strconv.Atoi(strings.Fields(strings.TrimSpace(cons))[5])
			sshsendcmd(SshHost, SshUser, SshPassword, SshType, SshKeyPath, SshPort)

		} else {
			fmt.Println("cons is empty!")
		}

	}

}

func main() {
	GetHostUserPasswdPort()
}

func sshsendcmd(SshHost, SshUser, SshPassword, SshType, SshKeyPath string, SshPort int) {

	//创建sshp登陆配置
	config := &ssh.ClientConfig{
		Timeout:         time.Second, //ssh 连接time out 时间一秒钟, 如果ssh验证错误 会在一秒内返回
		User:            SshUser,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(), //这个可以, 但是不够安全
		//HostKeyCallback: hostKeyCallBackFunc(h.Host),
	}
	if SshType == "password" {
		config.Auth = []ssh.AuthMethod{ssh.Password(SshPassword)}
		//fmt.Println("if:", SshType)
	} else {
		config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(SshKeyPath)}
		//fmt.Println(SshPassword)
	}

	//dial 获取ssh client
	addr := fmt.Sprintf("%s:%d", SshHost, SshPort)
	sshClient, err := ssh.Dial("tcp", addr, config)
	if err != nil {
		log.Fatal("创建ssh client 失败", err)
	}
	defer sshClient.Close()

	//创建ssh-session
	session, err := sshClient.NewSession()
	if err != nil {
		log.Fatal("创建ssh session 失败", err)
	}
	defer session.Close()
	//执行远程命令
	combo, err := session.CombinedOutput("whoami; cd /; ls -al; echo https://zhuchance.github.io/; touch ~/gosshcmd")
	if err != nil {
		log.Fatal("远程执行cmd 失败", err)
	}
	log.Println("命令输出:", string(combo))

}

func publicKeyAuthFunc(kPath string) ssh.AuthMethod {

	keyPath, err := homedir.Expand(kPath)
	if err != nil {
		log.Fatal("find key's home dir failed", err)
	}
	key, err := ioutil.ReadFile(keyPath)
	if err != nil {
		log.Fatal("ssh key file read failed", err)
	}
	// Create the Signer for this private key.
	signer, err := ssh.ParsePrivateKey(key)
	if err != nil {
		log.Fatal("ssh key signer failed", err)
	}
	return ssh.PublicKeys(signer)
}