使用GO语言灵活批量ssh登录服务器执行操作

在工作中时常需要登录服务器做一系列操作,每次输入ssh xxx总是很麻烦。这时候为什么不考虑写一个通用的小脚本呢?

go语言是一门新兴语言,能够在很多地方发挥总用。初学go语言,做了这么一个小工具,也算是练练手了。

这个小程序实现的功能是从用户指定的文件中读取相关配置,然后根据用户指令执行相关操作。

代码如下:

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
129
130
131
package main
import (
"fmt"
"golang.org/x/crypto/ssh"
"os"
"io"
"bufio"
"encoding/csv"
"strings"
"container/list"
)
var (
num int
)
func main() {
if len(os.Args) == 1{
fmt.Println("请输入文件名参数")
return
}
list := listNode(os.Args[1])
fmt.Println("请选择执行的语句")
fmt.Scanln(&num)
if num <= list.Len(){
fmt.Println("您选择的是 ", num)
ssh_to_do(list,num)
}else {
fmt.Println("您输入有误! num:",num)
}
}
func ssh_to_do(list *list.List, num int) {
if num != 0 {
i := 1
for node := list.Front(); node != nil; node = node.Next() {
if i == num {
switch value := node.Value.(type) {
case BatchNode:
SSH_do(value.User, value.Password, value.Ip_port, value.Cmd)
}
}
i++
}
} else {
for node := list.Front(); node != nil; node = node.Next() {
switch value := node.Value.(type) {
case BatchNode:
SSH_do(value.User, value.Password, value.Ip_port, value.Cmd)
}
}
}
}
func listNode(fileName string) *list.List {
list := readNode(fileName)
fmt.Printf("共计 %d 条数据\n", list.Len())
i := 1
for node := list.Front(); node != nil; node = node.Next() {
switch value := node.Value.(type) {
case BatchNode:
fmt.Println(i, " ", value.String())
}
i++
}
return list
}
func SSH_do(user, password, ip_port string, cmd string) {
PassWd := []ssh.AuthMethod{ssh.Password(password)}
Conf := ssh.ClientConfig{User: user, Auth: PassWd}
Client, _ := ssh.Dial("tcp", ip_port, &Conf)
defer Client.Close()
for {
command := cmd
if session, err := Client.NewSession(); err == nil {
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Run(command)
break
}
}
}
type BatchNode struct {
User string
Password string
Ip_port string
Cmd string
}
func (batchNode *BatchNode) String() string {
return "ssh " + batchNode.User + "@" + batchNode.Ip_port + " with password: " + batchNode.Password + " and run: " + batchNode.Cmd
}
func readNode(fileName string) *list.List {
inputFile, err := os.Open(fileName)
if err != nil {
fmt.Printf("在打开文件的时候出现错误\n文件存在吗?\n有权限吗?\n")
return list.New()
}
defer inputFile.Close()
batchNodeList := list.New()
inputReader := bufio.NewReader(inputFile)
for {
inputString, err := inputReader.ReadString('\n')
r := csv.NewReader(strings.NewReader(string(inputString)))
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
fmt.Println("error !!! ", err)
continue
}
batchNode := BatchNode{record[0], record[1], record[2], record[3]}
batchNodeList.PushBack(batchNode)
}
if err == io.EOF {
break
}
}
return batchNodeList
}

我的文件内容是:

1
2
3
4
gavin,xxxx,192.168.1.128:22,echo ok1 >>a.data
gavin,xxxx,192.168.1.128:22,echo ok2 >>a.data
gavin,xxxx,192.168.1.128:22,echo ok3 >>a.data
gavin,xxxx,192.168.1.128:22,echo ok4 >>a.data

小程序限制使用csv格式的文件内容,这种格式也方便被excel处理

运行的结果如下:

1
2
3
4
5
6
7
8
共计 4 条数据
1 ssh gavin@192.168.1.128:22 with password: root and run: echo ok1 >>a.data
2 ssh gavin@192.168.1.128:22 with password: root and run: echo ok2 >>a.data
3 ssh gavin@192.168.1.128:22 with password: root and run: echo ok3 >>a.data
4 ssh gavin@192.168.1.128:22 with password: root and run: echo ok4 >>a.data
请选择执行的语句
1
您选择的是 1

去线上查看:

upload successful

如果输入的是0,则执行所有配置项。也就是说如果有固定执行的任务,可以很方便地批量去操控了。