-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathgrape.go
118 lines (103 loc) · 2.44 KB
/
grape.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
package main
import (
"fmt"
"log"
"sync"
"github.com/mitchellh/go-homedir"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
"gopkg.in/yaml.v2"
)
type (
grape struct {
input input
ssh grapeSSH
config config
servers servers
commands commands
}
)
var wg sync.WaitGroup
func newGrape(input *input) *grape {
app := grape{}
var err error
app.input = *input
//validate input
if err = app.input.validate(); err != nil {
panic(err)
}
//set config into place
if err = app.config.set(app.input.configPath); err != nil {
panic(err)
}
// data !
if app.servers, err = app.config.getServersFromConfig(app.input.serverGroup); err != nil {
panic(err)
}
if app.commands, err = app.config.getCommandsFromConfig(app.input.commandName); err != nil {
panic(err)
}
//load private key
if err = app.ssh.setKey(app.input.keyPath); err != nil {
panic(err)
}
return &app
}
func (app *grape) run(knownHostsPath string) {
knownHostsPath, err := homedir.Expand(knownHostsPath)
if err != nil {
log.Fatal(err)
}
hostKeyCallback, err := knownhosts.New(knownHostsPath)
if err != nil {
log.Fatal(err)
}
for _, server := range app.servers {
if app.input.asyncFlag {
wg.Add(1)
go app.runOnServer(server, hostKeyCallback, &wg)
} else {
app.runOnServer(server, hostKeyCallback, nil)
}
}
if app.input.asyncFlag {
wg.Wait()
}
}
func (app *grape) runOnServer(server server, hostKeyCallback ssh.HostKeyCallback, wg *sync.WaitGroup) {
client, err := app.ssh.newClient(server, hostKeyCallback)
if err != nil {
server.Fatal = err.Error()
} else {
server.Output = client.execCommands(app.commands)
}
if wg != nil {
wg.Done()
}
server.printOutput()
}
func (s *server) printOutput() {
out, _ := yaml.Marshal(s)
fmt.Println(string(out))
}
func (app *grape) verifyAction() {
var char = "n"
fmt.Println("The following command will run on the following servers:")
fmt.Printf("command `%s` will run over `%s`.\n", app.input.commandName, app.input.serverGroup)
fmt.Println("commands:")
for k, v := range app.commands {
fmt.Printf("\t#%d - `%s` \n", k, v)
}
fmt.Println("servers:")
for k, v := range app.servers {
fmt.Printf("\t#%d - %s [%s@%s] \n", k, v.Name, v.User, v.Host)
}
if app.input.verifyFlag {
fmt.Println("-y used.forced to continue.")
return
}
fmt.Print("\n -- are your sure? [y/N] : ")
if _, err := fmt.Scanf("%s", &char); err != nil || char != "y" {
panic("type y to continue")
}
}