/
app.go
181 lines (154 loc) · 4.29 KB
/
app.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package elfgate
import (
"os"
"fmt"
"runtime"
"strings"
"io/ioutil"
"gopkg.in/yaml.v2"
"github.com/codegangsta/cli"
)
var (
Username string
Password string
PublicKeyPath string
Cmd string
Timeout int
Hosts []string
SSHAgents *AgentPool
SSHOput *SSHOut
OutputChan chan *CmdOutput
)
// Init app details.
func AppInit() *cli.App {
cmdFlag := []cli.Flag{
cli.StringFlag{
Name : "config, c",
Value : "",
Usage : "elfgate config file path",
},
cli.StringFlag{
Name : "group, g",
Value : "default",
Usage : "hosts group name",
},
cli.IntFlag{
Name : "timeout, t",
Value : 0,
Usage : "cmd execute timeout",
},
}
var err error
app := cli.NewApp()
app.Name = APP_NAME
app.Usage = "execute commands on group servers"
app.Version = APP_VERSION
app.Flags = cmdFlag
app.Before = func(c *cli.Context) error { // Parse cmds & params
return parseParams(c)
}
app.After = func(c *cli.Context) error { // If has exec errors, return
return err
}
app.Action = func(c *cli.Context) { // Run apps
err = appRun()
}
return app
}
// Main running commands.
func appRun() error {
runtime.GOMAXPROCS(1)
go NewSignal().Run() // listen ^C & kill
if Cmd == "list" {
for _, host := range Hosts {
piece := strings.Split(host, ":")
fmt.Println(piece[0])
}
return nil
}
if PublicKeyPath == "" && Password == "" {
Password = getPasswd()
} else if PublicKeyPath != "" && Password == "" { // If sudo cmd, needs password
if CmdType(Cmd) == "sudo" {
Password = getPasswd()
}
}
SSHAgents = NewAgentPool(Username, Password, Hosts, OutputChan)
if SSHAgents.Active() == false {
return fmt.Errorf("can not connect any clients")
}
if err := SSHAgents.Exec(Cmd, Timeout); err != nil {
return err
}
outputs := SSHOput.GetOutput(SSHAgents.Len())
StdOutput(outputs)
SSHAgents.Close()
return nil
}
// Parse command line params.
func parseParams(context *cli.Context) error {
var cfgFile = context.String("config")
var group = context.String("group")
var timeout = context.Int("timeout")
defaultCfgPath := [...]string{"/etc/elfgate.yml", "./elfgate.yml"}
if cfgFile == "" {
for _, cfgPath := range defaultCfgPath {
if err := FileExist(cfgPath); err == nil {
cfgFile = cfgPath
break
}
}
}
if cfgFile == "" {
return fmt.Errorf("config file not found in any /etc/elfgate.yml or ./elfgate.yml")
}
config := ConfigStruct{}
if c, err := ioutil.ReadFile(cfgFile); err != nil {
return err
} else {
if err = yaml.Unmarshal(c, &config); err != nil {
return err
}
}
Timeout = timeout
Cmd = ""
if len(context.Args()) > 0 {
Cmd = strings.TrimSpace(strings.Join(context.Args(), " "))
}
if Cmd == "" {
return fmt.Errorf("no command")
}
Username = config.Username
Password = config.Password
PublicKeyPath = config.PublicKey
if _, ok := config.Groups[group]; !ok { // Support multi groups
return fmt.Errorf("group: %s not exist", group)
}
for name, s := range config.Groups { // Parse & valid hosts
if name == group {
var err error
if Hosts, err = ParseHosts(s); err != nil {
return err
}
break
}
}
if len(Hosts) == 0 {
return fmt.Errorf("group: %s no valid hosts", group)
}
OutputChan = make(chan *CmdOutput, 10240)
SSHOput = NewSSHOut(OutputChan)
return nil
}
// Get password from stdin
func getPasswd() string {
fmt.Printf("password for %s: ", Username)
passwd, err := GetPasswd(false)
if err != nil {
fmt.Println()
fmt.Println(err.Error())
os.Exit(1)
}
return passwd
}
/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */