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.

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