-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9e410ea
Showing
6 changed files
with
545 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.txt | ||
*.json | ||
*.exe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
## multissh | ||
|
||
一个简单的并行 SSH 工具,可以批量的对主机通过 SSH 执行命令组合。 | ||
|
||
#### 编译 | ||
``` | ||
go get ./... | ||
go build | ||
``` | ||
|
||
|
||
#### 命令体系 | ||
``` | ||
./multissh -h | ||
-cmd string | ||
cmds // 需要执行的命令组合,多条命令以 ; 分割 | ||
-cmdfile string | ||
cmdfile path //需要执行的命令组合文件,文件内命令按行分割 | ||
-hostfile string | ||
hostfile path // 需要执行的主机列表文件,主机列表在文件内按行分割 | ||
-hosts string | ||
host address list //需要执行的主机列表,多个主机以 ; 分割 | ||
-ipfile string | ||
hostfile path //需要执行的主机(IP)列表文件,IP可以以地址段的方式逐行写在文本内 | ||
-p string | ||
password // 主机的 SSH 密码 | ||
-port int | ||
ssh port (default 22) //主机的 SSH 端口,默认 22 | ||
-u string | ||
username //主机的 SSH 用户名 | ||
``` | ||
**cmdfile 示例** | ||
``` | ||
show clock | ||
exit | ||
``` | ||
**hostfile 示例** | ||
``` | ||
10.10.15.101 | ||
10.10.15.102 | ||
``` | ||
**ipfile 示例** | ||
``` | ||
10.10.15.101-10.10.15.102 | ||
``` | ||
|
||
## 用法 | ||
#### cmd string & host string | ||
``` | ||
./multissh -cmd "show clock;exit" -hosts "10.10.15.101;10.10.15.102" -u admin -p admin | ||
10.10.15.101 ssh start | ||
sw-1#show clock | ||
05:26:40.649 UTC Tue Jun 6 2017 | ||
sw-1#exit | ||
10.10.15.101 ssh end | ||
10.10.15.102 ssh start | ||
sw-2#show clock | ||
05:24:38.708 UTC Tue Jun 6 2017 | ||
sw-2#exit | ||
10.10.15.102 ssh end | ||
``` | ||
|
||
#### cmdfile & hostfile | ||
``` | ||
./multissh -cmdfile cmd.txt -hostfile host.txt -u admin -p admin | ||
10.10.15.101 ssh start | ||
sw-1#show clock | ||
05:29:43.269 UTC Tue Jun 6 2017 | ||
sw-1#exit | ||
10.10.15.101 ssh end | ||
10.10.15.102 ssh start | ||
sw-2#show clock | ||
05:27:41.332 UTC Tue Jun 6 2017 | ||
sw-2#exit | ||
10.10.15.102 ssh end | ||
``` | ||
|
||
#### ipfile | ||
``` | ||
./multissh -cmdfile cmd.txt -ipfile ip.txt -u admin -p admin | ||
10.10.15.101 ssh start | ||
sw-1#show clock | ||
05:29:43.269 UTC Tue Jun 6 2017 | ||
sw-1#exit | ||
10.10.15.101 ssh end | ||
10.10.15.102 ssh start | ||
sw-2#show clock | ||
05:27:41.332 UTC Tue Jun 6 2017 | ||
sw-2#exit | ||
10.10.15.102 ssh end | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/binary" | ||
"io/ioutil" | ||
"log" | ||
"net" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
func GetfileAll(filePath string) ([]byte, error) { | ||
result, err := ioutil.ReadFile(filePath) | ||
if err != nil { | ||
log.Println("read file ", filePath, err) | ||
return result, err | ||
} | ||
return result, nil | ||
} | ||
|
||
func Getfile(filePath string) ([]string, error) { | ||
result := []string{} | ||
b, err := ioutil.ReadFile(filePath) | ||
if err != nil { | ||
log.Println("read file ", filePath, err) | ||
return result, err | ||
} | ||
s := string(b) | ||
for _, lineStr := range strings.Split(s, "\n") { | ||
lineStr = strings.TrimSpace(lineStr) | ||
if lineStr == "" { | ||
continue | ||
} | ||
result = append(result, lineStr) | ||
} | ||
return result, nil | ||
} | ||
|
||
func GetIpList(filePath string) ([]string, error) { | ||
res, err := Getfile(filePath) | ||
if err != nil { | ||
return nil, nil | ||
} | ||
var allIp []string | ||
if len(res) > 0 { | ||
for _, sip := range res { | ||
aip := ParseIp(sip) | ||
for _, ip := range aip { | ||
allIp = append(allIp, ip) | ||
} | ||
} | ||
} | ||
return allIp, nil | ||
} | ||
|
||
func ParseIp(ip string) []string { | ||
var availableIPs []string | ||
// if ip is "1.1.1.1/",trim / | ||
ip = strings.TrimRight(ip, "/") | ||
if strings.Contains(ip, "/") == true { | ||
if strings.Contains(ip, "/32") == true { | ||
aip := strings.Replace(ip, "/32", "", -1) | ||
availableIPs = append(availableIPs, aip) | ||
} else { | ||
availableIPs = GetAvailableIP(ip) | ||
} | ||
} else if strings.Contains(ip, "-") == true { | ||
ipRange := strings.SplitN(ip, "-", 2) | ||
availableIPs = GetAvailableIPRange(ipRange[0], ipRange[1]) | ||
} else { | ||
availableIPs = append(availableIPs, ip) | ||
} | ||
return availableIPs | ||
} | ||
|
||
func GetAvailableIPRange(ipStart, ipEnd string) []string { | ||
var availableIPs []string | ||
|
||
firstIP := net.ParseIP(ipStart) | ||
endIP := net.ParseIP(ipEnd) | ||
if firstIP.To4() == nil || endIP.To4() == nil { | ||
return availableIPs | ||
} | ||
firstIPNum := ipToInt(firstIP.To4()) | ||
EndIPNum := ipToInt(endIP.To4()) | ||
pos := int32(1) | ||
|
||
newNum := firstIPNum | ||
|
||
for newNum <= EndIPNum { | ||
availableIPs = append(availableIPs, intToIP(newNum).String()) | ||
newNum = newNum + pos | ||
} | ||
return availableIPs | ||
} | ||
|
||
func GetAvailableIP(ipAndMask string) []string { | ||
var availableIPs []string | ||
|
||
ipAndMask = strings.TrimSpace(ipAndMask) | ||
ipAndMask = IPAddressToCIDR(ipAndMask) | ||
_, ipnet, _ := net.ParseCIDR(ipAndMask) | ||
|
||
firstIP, _ := networkRange(ipnet) | ||
ipNum := ipToInt(firstIP) | ||
size := networkSize(ipnet.Mask) | ||
pos := int32(1) | ||
max := size - 2 // -1 for the broadcast address, -1 for the gateway address | ||
|
||
var newNum int32 | ||
for attempt := int32(0); attempt < max; attempt++ { | ||
newNum = ipNum + pos | ||
pos = pos%max + 1 | ||
availableIPs = append(availableIPs, intToIP(newNum).String()) | ||
} | ||
return availableIPs | ||
} | ||
|
||
func IPAddressToCIDR(ipAdress string) string { | ||
if strings.Contains(ipAdress, "/") == true { | ||
ipAndMask := strings.Split(ipAdress, "/") | ||
ip := ipAndMask[0] | ||
mask := ipAndMask[1] | ||
if strings.Contains(mask, ".") == true { | ||
mask = IPMaskStringToCIDR(mask) | ||
} | ||
return ip + "/" + mask | ||
} else { | ||
return ipAdress | ||
} | ||
} | ||
|
||
func IPMaskStringToCIDR(netmask string) string { | ||
netmaskList := strings.Split(netmask, ".") | ||
var mint []int | ||
for _, v := range netmaskList { | ||
strv, _ := strconv.Atoi(v) | ||
mint = append(mint, strv) | ||
} | ||
myIPMask := net.IPv4Mask(byte(mint[0]), byte(mint[1]), byte(mint[2]), byte(mint[3])) | ||
ones, _ := myIPMask.Size() | ||
return strconv.Itoa(ones) | ||
} | ||
|
||
func IPMaskCIDRToString(one string) string { | ||
oneInt, _ := strconv.Atoi(one) | ||
mIPmask := net.CIDRMask(oneInt, 32) | ||
var maskstring []string | ||
for _, v := range mIPmask { | ||
maskstring = append(maskstring, strconv.Itoa(int(v))) | ||
} | ||
return strings.Join(maskstring, ".") | ||
} | ||
|
||
// Calculates the first and last IP addresses in an IPNet | ||
func networkRange(network *net.IPNet) (net.IP, net.IP) { | ||
netIP := network.IP.To4() | ||
firstIP := netIP.Mask(network.Mask) | ||
lastIP := net.IPv4(0, 0, 0, 0).To4() | ||
for i := 0; i < len(lastIP); i++ { | ||
lastIP[i] = netIP[i] | ^network.Mask[i] | ||
} | ||
return firstIP, lastIP | ||
} | ||
|
||
// Given a netmask, calculates the number of available hosts | ||
func networkSize(mask net.IPMask) int32 { | ||
m := net.IPv4Mask(0, 0, 0, 0) | ||
for i := 0; i < net.IPv4len; i++ { | ||
m[i] = ^mask[i] | ||
} | ||
return int32(binary.BigEndian.Uint32(m)) + 1 | ||
} | ||
|
||
// Converts a 4 bytes IP into a 32 bit integer | ||
func ipToInt(ip net.IP) int32 { | ||
return int32(binary.BigEndian.Uint32(ip.To4())) | ||
} | ||
|
||
// Converts 32 bit integer into a 4 bytes IP address | ||
func intToIP(n int32) net.IP { | ||
b := make([]byte, 4) | ||
binary.BigEndian.PutUint32(b, uint32(n)) | ||
return net.IP(b) | ||
} |
Oops, something went wrong.