-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssh.go
144 lines (118 loc) · 2.68 KB
/
ssh.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
132
133
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"log"
"net"
"os/exec"
"syscall"
"github.com/tucnak/climax"
)
var sshCommand = climax.Command{
Name: "ssh",
Brief: "runs ssh to a given machine's internal IP",
Usage: `[flags] <selector>`,
Flags: []climax.Flag{
{
Name: "identity",
Short: "i",
Usage: `-i <key>`,
Help: `specifies the ssh key that should be used to connect`,
Variable: true,
},
{
Name: "user",
Short: "u",
Usage: `-u <user>`,
Help: `specifies the username to login with`,
Variable: true,
},
},
Examples: []climax.Example{
{
Usecase: `"minion.*"`,
Description: `Will SSH to a minion if one matches the selector.`,
},
},
Handle: truckSSH,
}
func isLocalAddress(ip string) bool {
addr := net.ParseIP(ip)
networks := []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"}
for _, network := range networks {
_, cidrnet, err := net.ParseCIDR(network)
if err != nil {
panic(err)
}
if cidrnet.Contains(addr) {
return true
}
}
return false
}
// Returns either the first local address, or the first address.
func getBestAddress(ips []string) string {
for _, ip := range ips {
if isLocalAddress(ip) {
return ip
}
}
return ips[0]
}
func selectMinion(minions map[string][]string) []string {
if len(minions) == 0 {
return []string{}
} else if len(minions) == 1 {
for _, minion := range minions {
return minion
}
}
options := []string{}
for id := range minions {
options = append(options, id)
}
menu := ListMenu{Title: "Select Minion", Options: options}
option := menu.Show()
return minions[option]
}
func truckSSH(ctx climax.Context) int {
sshopts := []string{"ssh"}
minions := map[string][]string{}
if len(ctx.Args) == 0 {
log.Println("no selector specified")
return 1
}
err := salt(&minions, ctx.Args[0], "network.ip_addrs")
if err != nil {
log.Println("couldn't get IPs:", err.Error())
return 1
}
if len(minions) == 0 {
log.Println("no minions matched")
return 0
}
// Figure out what IP address to use.
minion := selectMinion(minions)
ip := getBestAddress(minion)
// Identity option.
if identity, ok := ctx.Get("identity"); ok {
sshopts = append(sshopts, "-i", identity)
}
// Form hostname.
hostname := ip
if user, ok := ctx.Get("user"); ok {
hostname = user + "@" + ip
}
sshopts = append(sshopts, hostname)
// Add arguments from our invocation.
sshopts = append(sshopts, ctx.Args[1:]...)
// Find the SSH command.
sshPath, err := exec.LookPath("ssh")
if err != nil {
log.Println("couldn't find ssh path:", err)
}
// Go!
err = syscall.Exec(sshPath, sshopts, []string{})
if err != nil {
log.Println("couldn't fork to ssh:", err)
}
return 0
}