Skip to content

Commit b5e3b8c

Browse files
committed
initial commit;2C
0 parents  commit b5e3b8c

File tree

2 files changed

+255
-0
lines changed

2 files changed

+255
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# distributed-command-runner

dcr.go

+254
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io/ioutil"
8+
"log"
9+
"os"
10+
"os/exec"
11+
"strconv"
12+
"strings"
13+
"syscall"
14+
15+
"github.com/aybabtme/rgbterm"
16+
"github.com/urfave/cli"
17+
)
18+
19+
type Server struct {
20+
Name string `json:"name"`
21+
Environment string `json:"environment"`
22+
Tags Tags `json:"tags"`
23+
}
24+
25+
type Servers []Server
26+
27+
type Tags []string
28+
29+
func getServers(configFile string) Servers {
30+
raw, err := ioutil.ReadFile(configFile)
31+
if err != nil {
32+
fmt.Println(err.Error())
33+
os.Exit(1)
34+
}
35+
var servers []Server
36+
json.Unmarshal(raw, &servers)
37+
return servers
38+
}
39+
40+
func filterByEnvironment(servers Servers, environment string) Servers {
41+
filtered := servers[:0]
42+
for _, server := range servers {
43+
if server.Environment == environment {
44+
filtered = append(filtered, server)
45+
}
46+
}
47+
return filtered
48+
}
49+
50+
func contains(tags []string, expectedTag string) bool {
51+
for _, tag := range tags {
52+
if tag == expectedTag {
53+
return true
54+
}
55+
}
56+
57+
return false
58+
}
59+
60+
func filterByTag(servers Servers, tag string) Servers {
61+
filtered := servers[:0]
62+
for _, server := range servers {
63+
if strings.HasPrefix(tag, "!") {
64+
if !contains(server.Tags, strings.TrimPrefix(tag, "!")) {
65+
filtered = append(filtered, server)
66+
}
67+
} else {
68+
if contains(server.Tags, tag) {
69+
filtered = append(filtered, server)
70+
}
71+
}
72+
}
73+
return filtered
74+
}
75+
76+
func listNamesOutput(servers Servers) {
77+
var buffer bytes.Buffer
78+
for index, server := range servers {
79+
buffer.WriteString(server.Name)
80+
if index < (len(servers) - 1) {
81+
buffer.WriteString(",")
82+
}
83+
}
84+
fmt.Println(buffer.String())
85+
}
86+
87+
func printJSONOutput(servers Servers) {
88+
serversJSON, err := json.MarshalIndent(servers, "", " ")
89+
if err != nil {
90+
fmt.Println(err)
91+
return
92+
}
93+
fmt.Println(string(serversJSON))
94+
}
95+
96+
func columnarOutput(servers Servers) {
97+
for _, server := range servers {
98+
fmt.Printf("%s %s %s\n", server.Environment, server.Name, server.Tags)
99+
}
100+
}
101+
102+
func formatList(servers Servers, format string) {
103+
if format == "names" {
104+
listNamesOutput(servers)
105+
} else if format == "json" {
106+
printJSONOutput(servers)
107+
} else {
108+
columnarOutput(servers)
109+
}
110+
}
111+
112+
func filterServers(servers Servers, environment string, tags []string) Servers {
113+
if environment != "" {
114+
servers = filterByEnvironment(servers, environment)
115+
}
116+
if tags != nil && len(tags) != 0 {
117+
for _, tag := range tags {
118+
for _, splitTag := range strings.Split(tag, ",") {
119+
servers = filterByTag(servers, splitTag)
120+
}
121+
}
122+
}
123+
return servers
124+
}
125+
126+
func execCommand(server Server, user string, command string) (exitCode int, stdout string, stderr string) {
127+
var stdoutBuf bytes.Buffer
128+
var stderrBuf bytes.Buffer
129+
130+
exit := 0
131+
132+
cmd := exec.Command("pmrun", "-h", server.Name, user, command)
133+
//cmd := exec.Command("echo", "Hello "+user)
134+
//cmd := exec.Command("ls", "Hello "+command)
135+
136+
//fmt.Println(cmd)
137+
cmd.Stdout = &stdoutBuf
138+
cmd.Stderr = &stderrBuf
139+
startErr := cmd.Start()
140+
if startErr != nil {
141+
log.Fatalf("cmd.Start: %v", startErr)
142+
}
143+
er := cmd.Wait()
144+
if er != nil {
145+
if exiterr, ok := er.(*exec.ExitError); ok {
146+
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
147+
exit = status.ExitStatus()
148+
}
149+
}
150+
}
151+
152+
return exit, stdoutBuf.String(), stderrBuf.String()
153+
}
154+
155+
func red() (r uint8, g uint8, b uint8) {
156+
return 255, 0, 0
157+
}
158+
159+
func green() (r uint8, g uint8, b uint8) {
160+
return 0, 255, 0
161+
}
162+
163+
func white() (r uint8, g uint8, b uint8) {
164+
return 255, 255, 255
165+
}
166+
167+
func colorizeExitCode(exitCode int) string {
168+
fr, fg, fb := white()
169+
br, bg, bb := green()
170+
if exitCode != 0 {
171+
br, bg, bb = red()
172+
}
173+
return rgbterm.String(strconv.Itoa(exitCode), fr, fg, fb, br, bg, bb)
174+
}
175+
176+
func main() {
177+
var configFile string
178+
var environment string
179+
var tags []string
180+
var format string
181+
var user string
182+
183+
app := cli.NewApp()
184+
app.Usage = "List and filter servers"
185+
app.Flags = []cli.Flag{
186+
cli.StringFlag{
187+
Name: "config, c",
188+
Value: os.Getenv("HOME") + "/.dcr/servers.json",
189+
Usage: "Load configuration from `FILE`",
190+
Destination: &configFile,
191+
},
192+
cli.StringFlag{
193+
Name: "env, e",
194+
Usage: "Filter by environment",
195+
Destination: &environment,
196+
},
197+
cli.StringSliceFlag{
198+
Name: "tags, t",
199+
Usage: "Filter by tags",
200+
},
201+
}
202+
203+
app.Commands = []cli.Command{
204+
{
205+
Name: "list",
206+
Aliases: []string{"l", "ls"},
207+
Usage: "List servers",
208+
Flags: []cli.Flag{
209+
cli.StringFlag{
210+
Name: "format, f",
211+
Usage: "Output format",
212+
Destination: &format,
213+
},
214+
},
215+
Action: func(c *cli.Context) error {
216+
tags = c.StringSlice("tags")
217+
servers := getServers(configFile)
218+
servers = filterServers(servers, environment, tags)
219+
formatList(servers, format)
220+
fmt.Println("")
221+
return nil
222+
},
223+
},
224+
{
225+
Name: "exec",
226+
Aliases: []string{"x", "run"},
227+
Usage: "Execute command",
228+
Flags: []cli.Flag{
229+
cli.StringFlag{
230+
Name: "user, u",
231+
Usage: "User to run as",
232+
Destination: &user,
233+
},
234+
},
235+
Action: func(c *cli.Context) error {
236+
tags = c.StringSlice("tags")
237+
cmd := c.Args().Get(0)
238+
servers := getServers(configFile)
239+
servers = filterServers(servers, environment, tags)
240+
for _, server := range servers {
241+
exitCode, stdout, stderr := execCommand(server, user, cmd)
242+
fmt.Printf("\n%2s[%10s] STDOUT: %10s\n", colorizeExitCode(exitCode), server.Name, strings.Trim(stdout, "\n"))
243+
if stderr != "" {
244+
fmt.Printf("STDERR: %s\n", strings.Trim(stderr, "\n"))
245+
}
246+
}
247+
fmt.Println("")
248+
return nil
249+
},
250+
},
251+
}
252+
253+
app.Run(os.Args)
254+
}

0 commit comments

Comments
 (0)