ccm.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package ccm
  2. import (
  3. "bufio"
  4. "bytes"
  5. "errors"
  6. "fmt"
  7. "os/exec"
  8. "strings"
  9. )
  10. func execCmd(args ...string) (*bytes.Buffer, error) {
  11. cmd := exec.Command("ccm", args...)
  12. stdout := &bytes.Buffer{}
  13. cmd.Stdout = stdout
  14. cmd.Stderr = &bytes.Buffer{}
  15. if err := cmd.Run(); err != nil {
  16. return nil, errors.New(cmd.Stderr.(*bytes.Buffer).String())
  17. }
  18. return stdout, nil
  19. }
  20. func AllUp() error {
  21. status, err := Status()
  22. if err != nil {
  23. return err
  24. }
  25. for _, host := range status {
  26. if !host.State.IsUp() {
  27. if err := NodeUp(host.Name); err != nil {
  28. return err
  29. }
  30. }
  31. }
  32. return nil
  33. }
  34. func NodeUp(node string) error {
  35. _, err := execCmd(node, "start", "--wait-for-binary-proto", "--wait-other-notice")
  36. return err
  37. }
  38. func NodeDown(node string) error {
  39. _, err := execCmd(node, "stop")
  40. return err
  41. }
  42. type Host struct {
  43. State NodeState
  44. Addr string
  45. Name string
  46. }
  47. type NodeState int
  48. func (n NodeState) String() string {
  49. if n == NodeStateUp {
  50. return "UP"
  51. } else if n == NodeStateDown {
  52. return "DOWN"
  53. } else {
  54. return fmt.Sprintf("UNKNOWN_STATE_%d", n)
  55. }
  56. }
  57. func (n NodeState) IsUp() bool {
  58. return n == NodeStateUp
  59. }
  60. const (
  61. NodeStateUp NodeState = iota
  62. NodeStateDown
  63. )
  64. func Status() (map[string]Host, error) {
  65. // TODO: parse into struct o maniuplate
  66. out, err := execCmd("status", "-v")
  67. if err != nil {
  68. return nil, err
  69. }
  70. const (
  71. stateCluster = iota
  72. stateCommas
  73. stateNode
  74. stateOption
  75. )
  76. nodes := make(map[string]Host)
  77. // didnt really want to write a full state machine parser
  78. state := stateCluster
  79. sc := bufio.NewScanner(out)
  80. var host Host
  81. for sc.Scan() {
  82. switch state {
  83. case stateCluster:
  84. text := sc.Text()
  85. if !strings.HasPrefix(text, "Cluster:") {
  86. return nil, fmt.Errorf("expected 'Cluster:' got %q", text)
  87. }
  88. state = stateCommas
  89. case stateCommas:
  90. text := sc.Text()
  91. if text != "----------------" {
  92. return nil, fmt.Errorf("expected '----------------' got %q", text)
  93. }
  94. state = stateNode
  95. case stateNode:
  96. // assume nodes start with node
  97. text := sc.Text()
  98. if !strings.HasPrefix(text, "node") {
  99. return nil, fmt.Errorf("expected 'node' got %q", text)
  100. }
  101. line := strings.Split(text, ":")
  102. host.Name = line[0]
  103. nodeState := strings.TrimSpace(line[1])
  104. switch nodeState {
  105. case "UP":
  106. host.State = NodeStateUp
  107. case "DOWN":
  108. host.State = NodeStateDown
  109. default:
  110. return nil, fmt.Errorf("unknown node state from ccm: %q", nodeState)
  111. }
  112. state = stateOption
  113. case stateOption:
  114. text := sc.Text()
  115. if text == "" {
  116. state = stateNode
  117. nodes[host.Name] = host
  118. host = Host{}
  119. continue
  120. }
  121. line := strings.Split(strings.TrimSpace(text), "=")
  122. k, v := line[0], line[1]
  123. if k == "binary" {
  124. // could check errors
  125. // ('127.0.0.1', 9042)
  126. v = v[2:] // (''
  127. if i := strings.IndexByte(v, '\''); i < 0 {
  128. return nil, fmt.Errorf("invalid binary v=%q", v)
  129. } else {
  130. host.Addr = v[:i]
  131. // dont need port
  132. }
  133. // v = v[i+1:]
  134. // }
  135. // v = v[2:] // ,
  136. // if i := strings.IndexByte(v, ')'); i < 0 {
  137. // return nil, fmt.Errorf("invalid binary v=%q", v)
  138. // } else {
  139. // port, err = strconv.Atoi(v[:i])
  140. // if err != nil {
  141. // return nil, err
  142. // }
  143. // }
  144. // host.Addr = fmt.Sprintf("%s:%d", addr, port)
  145. }
  146. default:
  147. return nil, fmt.Errorf("unexpected state: %q", state)
  148. }
  149. }
  150. if err := sc.Err(); err != nil {
  151. return nil, fmt.Errorf("unable to parse ccm status: %v", err)
  152. }
  153. return nodes, nil
  154. }