v2_admin.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package etcd
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "path/filepath"
  8. "strconv"
  9. "strings"
  10. "github.com/coreos/etcd/store"
  11. )
  12. const (
  13. stateFollower = "follower"
  14. stateCandidate = "candidate"
  15. stateLeader = "leader"
  16. )
  17. // machineMessage represents information about a peer or standby in the registry.
  18. type machineMessage struct {
  19. Name string `json:"name"`
  20. State string `json:"state"`
  21. ClientURL string `json:"clientURL"`
  22. PeerURL string `json:"peerURL"`
  23. }
  24. type context struct {
  25. MinVersion int `json:"minVersion"`
  26. MaxVersion int `json:"maxVersion"`
  27. ClientURL string `json:"clientURL"`
  28. PeerURL string `json:"peerURL"`
  29. }
  30. func (s *Server) serveAdminConfig(w http.ResponseWriter, r *http.Request) error {
  31. switch r.Method {
  32. case "GET":
  33. case "PUT":
  34. if !s.node.IsLeader() {
  35. return s.redirect(w, r, s.node.Leader())
  36. }
  37. c := s.ClusterConfig()
  38. if err := json.NewDecoder(r.Body).Decode(c); err != nil {
  39. return err
  40. }
  41. c.Sanitize()
  42. b, err := json.Marshal(c)
  43. if err != nil {
  44. return err
  45. }
  46. if _, err := s.Set(v2configKVPrefix, false, string(b), store.Permanent); err != nil {
  47. return err
  48. }
  49. default:
  50. return allow(w, "GET", "PUT")
  51. }
  52. w.Header().Set("Content-Type", "application/json")
  53. json.NewEncoder(w).Encode(s.ClusterConfig())
  54. return nil
  55. }
  56. func (s *Server) serveAdminMachines(w http.ResponseWriter, r *http.Request) error {
  57. name := strings.TrimPrefix(r.URL.Path, v2adminMachinesPrefix)
  58. switch r.Method {
  59. case "GET":
  60. var info interface{}
  61. var err error
  62. if name != "" {
  63. info, err = s.someMachineMessage(name)
  64. } else {
  65. info, err = s.allMachineMessages()
  66. }
  67. if err != nil {
  68. return err
  69. }
  70. w.Header().Set("Content-Type", "application/json")
  71. json.NewEncoder(w).Encode(info)
  72. case "PUT":
  73. if !s.node.IsLeader() {
  74. return s.redirect(w, r, s.node.Leader())
  75. }
  76. id, err := strconv.ParseInt(name, 0, 64)
  77. if err != nil {
  78. return err
  79. }
  80. info := &context{}
  81. if err := json.NewDecoder(r.Body).Decode(info); err != nil {
  82. return err
  83. }
  84. return s.Add(id, info.PeerURL, info.ClientURL)
  85. case "DELETE":
  86. if !s.node.IsLeader() {
  87. return s.redirect(w, r, s.node.Leader())
  88. }
  89. id, err := strconv.ParseInt(name, 0, 64)
  90. if err != nil {
  91. return err
  92. }
  93. return s.Remove(id)
  94. default:
  95. return allow(w, "GET", "PUT", "DELETE")
  96. }
  97. return nil
  98. }
  99. // someMachineMessage return machine message of specified name.
  100. func (s *Server) someMachineMessage(name string) (*machineMessage, error) {
  101. p := filepath.Join(v2machineKVPrefix, name)
  102. e, err := s.Get(p, false, false)
  103. if err != nil {
  104. return nil, err
  105. }
  106. lead := fmt.Sprint(s.node.Leader())
  107. return newMachineMessage(e.Node, lead), nil
  108. }
  109. func (s *Server) allMachineMessages() ([]*machineMessage, error) {
  110. e, err := s.Get(v2machineKVPrefix, false, false)
  111. if err != nil {
  112. return nil, err
  113. }
  114. lead := fmt.Sprint(s.node.Leader())
  115. ms := make([]*machineMessage, len(e.Node.Nodes))
  116. for i, n := range e.Node.Nodes {
  117. ms[i] = newMachineMessage(n, lead)
  118. }
  119. return ms, nil
  120. }
  121. func newMachineMessage(n *store.NodeExtern, lead string) *machineMessage {
  122. _, name := filepath.Split(n.Key)
  123. q, err := url.ParseQuery(*n.Value)
  124. if err != nil {
  125. panic("fail to parse the info for machine " + name)
  126. }
  127. m := &machineMessage{
  128. Name: name,
  129. State: stateFollower,
  130. ClientURL: q["etcd"][0],
  131. PeerURL: q["raft"][0],
  132. }
  133. if name == lead {
  134. m.State = stateLeader
  135. }
  136. return m
  137. }