You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
6.2 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/codegangsta/cli"
  5. "io/ioutil"
  6. "net/url"
  7. "os"
  8. "regexp"
  9. "strings"
  10. "sync"
  11. acm "github.com/tendermint/tendermint/account"
  12. "github.com/tendermint/tendermint/binary"
  13. btypes "github.com/tendermint/tendermint/cmd/barak/types"
  14. . "github.com/tendermint/tendermint/common"
  15. )
  16. func remoteNick(remote string) string {
  17. u, err := url.Parse(remote)
  18. if err != nil {
  19. return regexp.MustCompile(`[[:^alnum:]]`).ReplaceAllString(remote, "_")
  20. } else {
  21. return regexp.MustCompile(`[[:^alnum:]]`).ReplaceAllString(u.Host, "_")
  22. }
  23. }
  24. var Config = struct {
  25. Remotes []string
  26. PrivKey acm.PrivKey
  27. }{}
  28. func main() {
  29. fmt.Printf("New Debora Process (PID: %d)\n", os.Getpid())
  30. rootDir := os.Getenv("DEBROOT")
  31. if rootDir == "" {
  32. rootDir = os.Getenv("HOME") + "/.debora"
  33. }
  34. var (
  35. groupFlag = cli.StringFlag{
  36. Name: "group",
  37. Value: "default",
  38. Usage: "uses ~/.debora/<group>.cfg",
  39. }
  40. labelFlag = cli.StringFlag{
  41. Name: "label",
  42. Value: "_",
  43. Usage: "label of the process, or _ by default",
  44. }
  45. bgFlag = cli.BoolFlag{
  46. Name: "bg",
  47. Usage: "if set, runs as a background daemon",
  48. }
  49. inputFlag = cli.StringFlag{
  50. Name: "input",
  51. Value: "",
  52. Usage: "input to the program (e.g. stdin)",
  53. }
  54. )
  55. app := cli.NewApp()
  56. app.Name = "debora"
  57. app.Usage = "summons commands to barak"
  58. app.Version = "0.0.1"
  59. app.Email = "ethan@erisindustries.com,jae@tendermint.com"
  60. app.Flags = []cli.Flag{
  61. groupFlag,
  62. }
  63. app.Before = func(c *cli.Context) error {
  64. configFile := rootDir + "/" + c.String("group") + ".cfg"
  65. fmt.Printf("Using configuration from %v\n", configFile)
  66. ReadConfig(configFile)
  67. return nil
  68. }
  69. app.Commands = []cli.Command{
  70. cli.Command{
  71. Name: "status",
  72. Usage: "shows remote status",
  73. Action: cliGetStatus,
  74. },
  75. cli.Command{
  76. Name: "run",
  77. Usage: "run process",
  78. Action: cliRunProcess,
  79. Flags: []cli.Flag{
  80. labelFlag,
  81. bgFlag,
  82. inputFlag,
  83. },
  84. },
  85. cli.Command{
  86. Name: "stop",
  87. Usage: "stop process",
  88. Action: cliStopProcess,
  89. },
  90. cli.Command{
  91. Name: "list",
  92. Usage: "list processes",
  93. Action: cliListProcesses,
  94. },
  95. cli.Command{
  96. Name: "download",
  97. Usage: "download file <remote-path> <local-path-prefix>",
  98. Action: cliDownloadFile,
  99. },
  100. }
  101. app.Run(os.Args)
  102. }
  103. func ReadConfig(configFilePath string) {
  104. configJSONBytes, err := ioutil.ReadFile(configFilePath)
  105. if err != nil {
  106. Exit(Fmt("Failed to read config file %v. %v\n", configFilePath, err))
  107. }
  108. binary.ReadJSON(&Config, configJSONBytes, &err)
  109. if err != nil {
  110. Exit(Fmt("Failed to parse config. %v", err))
  111. }
  112. }
  113. func cliGetStatus(c *cli.Context) {
  114. args := c.Args()
  115. if len(args) != 0 {
  116. fmt.Println("BTW, status takes no arguments.")
  117. }
  118. wg := sync.WaitGroup{}
  119. for _, remote := range Config.Remotes {
  120. wg.Add(1)
  121. go func(remote string) {
  122. defer wg.Done()
  123. response, err := GetStatus(remote)
  124. if err != nil {
  125. fmt.Printf("%v failure. %v\n", remote, err)
  126. } else {
  127. fmt.Printf("%v success. %v\n", remote, response)
  128. }
  129. }(remote)
  130. }
  131. wg.Wait()
  132. }
  133. func cliRunProcess(c *cli.Context) {
  134. args := c.Args()
  135. if len(args) < 1 {
  136. Exit("Must specify <execPath> <args...>")
  137. }
  138. execPath := args[0]
  139. args = args[1:]
  140. command := btypes.CommandRunProcess{
  141. Wait: !c.Bool("bg"),
  142. Label: c.String("label"),
  143. ExecPath: execPath,
  144. Args: args,
  145. Input: c.String("input"),
  146. }
  147. wg := sync.WaitGroup{}
  148. for _, remote := range Config.Remotes {
  149. wg.Add(1)
  150. go func(remote string) {
  151. defer wg.Done()
  152. response, err := RunProcess(Config.PrivKey, remote, command)
  153. if err != nil {
  154. fmt.Printf("%v failure. %v\n", remote, err)
  155. } else {
  156. fmt.Printf("%v success.\n", remote)
  157. if response.Output != "" {
  158. fmt.Println("--------------------------------------------------------------------------------")
  159. fmt.Println(response.Output)
  160. fmt.Println("--------------------------------------------------------------------------------")
  161. } else {
  162. fmt.Println("(no output)")
  163. }
  164. }
  165. }(remote)
  166. }
  167. wg.Wait()
  168. }
  169. func cliStopProcess(c *cli.Context) {
  170. args := c.Args()
  171. if len(args) == 0 {
  172. Exit("Must specify label to stop")
  173. }
  174. label := args[0]
  175. command := btypes.CommandStopProcess{
  176. Label: label,
  177. Kill: true,
  178. }
  179. wg := sync.WaitGroup{}
  180. for _, remote := range Config.Remotes {
  181. wg.Add(1)
  182. go func(remote string) {
  183. defer wg.Done()
  184. response, err := StopProcess(Config.PrivKey, remote, command)
  185. if err != nil {
  186. fmt.Printf("%v failure. %v\n", remote, err)
  187. } else {
  188. fmt.Printf("%v success. %v\n", remote, response)
  189. }
  190. }(remote)
  191. }
  192. wg.Wait()
  193. }
  194. func cliListProcesses(c *cli.Context) {
  195. /*
  196. args := c.Args()
  197. if len(args) == 0 {
  198. log.Fatal("Must specify application name")
  199. }
  200. app := args[0]
  201. */
  202. command := btypes.CommandListProcesses{}
  203. wg := sync.WaitGroup{}
  204. for _, remote := range Config.Remotes {
  205. wg.Add(1)
  206. go func(remote string) {
  207. defer wg.Done()
  208. response, err := ListProcesses(Config.PrivKey, remote, command)
  209. if err != nil {
  210. fmt.Printf("%v failure. %v\n", Blue(remote), Red(err))
  211. } else {
  212. fmt.Printf("%v processes:\n", Blue(remote))
  213. for _, proc := range response.Processes {
  214. fmt.Printf(" \"%v\" => `%v %v` (%v)\n", Yellow(proc.Label), proc.ExecPath, strings.Join(proc.Args, ","), proc.Pid)
  215. fmt.Printf(" started at %v", proc.StartTime.String())
  216. if proc.EndTime.IsZero() {
  217. fmt.Printf(", running still\n")
  218. } else {
  219. endTimeStr := proc.EndTime.String()
  220. fmt.Printf(", stopped at %v\n", Yellow(endTimeStr))
  221. }
  222. fmt.Printf(" stdout/stderr goes to %v\n", proc.OutputPath)
  223. }
  224. }
  225. }(remote)
  226. }
  227. wg.Wait()
  228. }
  229. func cliDownloadFile(c *cli.Context) {
  230. args := c.Args()
  231. if len(args) != 2 {
  232. Exit("Must specify <remote-path> <local-path-prefix>")
  233. }
  234. remotePath := args[0]
  235. localPathPrefix := args[1]
  236. command := btypes.CommandServeFile{
  237. Path: remotePath,
  238. }
  239. wg := sync.WaitGroup{}
  240. for _, remote := range Config.Remotes {
  241. wg.Add(1)
  242. go func(remote string, localPath string) {
  243. defer wg.Done()
  244. n, err := DownloadFile(Config.PrivKey, remote, command, localPath)
  245. if err != nil {
  246. fmt.Printf("%v failure. %v\n", remote, err)
  247. } else {
  248. fmt.Printf("%v success. Wrote %v bytes to %v\n", remote, n, localPath)
  249. }
  250. }(remote, Fmt("%v_%v", localPathPrefix, remoteNick(remote)))
  251. }
  252. wg.Wait()
  253. }