ccm.go 3.1 KB

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