v2_admin.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. if err := s.setClusterConfig(c); err != nil {
  43. return err
  44. }
  45. default:
  46. return allow(w, "GET", "PUT")
  47. }
  48. w.Header().Set("Content-Type", "application/json")
  49. json.NewEncoder(w).Encode(s.ClusterConfig())
  50. return nil
  51. }
  52. func (s *Server) serveAdminMachines(w http.ResponseWriter, r *http.Request) error {
  53. name := strings.TrimPrefix(r.URL.Path, v2adminMachinesPrefix)
  54. switch r.Method {
  55. case "GET":
  56. var info interface{}
  57. var err error
  58. if name != "" {
  59. info, err = s.someMachineMessage(name)
  60. } else {
  61. info, err = s.allMachineMessages()
  62. }
  63. if err != nil {
  64. return err
  65. }
  66. w.Header().Set("Content-Type", "application/json")
  67. json.NewEncoder(w).Encode(info)
  68. case "PUT":
  69. if !s.node.IsLeader() {
  70. return s.redirect(w, r, s.node.Leader())
  71. }
  72. id, err := strconv.ParseInt(name, 0, 64)
  73. if err != nil {
  74. return err
  75. }
  76. info := &context{}
  77. if err := json.NewDecoder(r.Body).Decode(info); err != nil {
  78. return err
  79. }
  80. return s.Add(id, info.PeerURL, info.ClientURL)
  81. case "DELETE":
  82. if !s.node.IsLeader() {
  83. return s.redirect(w, r, s.node.Leader())
  84. }
  85. id, err := strconv.ParseInt(name, 0, 64)
  86. if err != nil {
  87. return err
  88. }
  89. return s.Remove(id)
  90. default:
  91. return allow(w, "GET", "PUT", "DELETE")
  92. }
  93. return nil
  94. }
  95. // someMachineMessage return machine message of specified name.
  96. func (s *Server) someMachineMessage(name string) (*machineMessage, error) {
  97. p := filepath.Join(v2machineKVPrefix, name)
  98. e, err := s.Get(p, false, false)
  99. if err != nil {
  100. return nil, err
  101. }
  102. lead := fmt.Sprint(s.node.Leader())
  103. return newMachineMessage(e.Node, lead), nil
  104. }
  105. func (s *Server) allMachineMessages() ([]*machineMessage, error) {
  106. e, err := s.Get(v2machineKVPrefix, false, false)
  107. if err != nil {
  108. return nil, err
  109. }
  110. lead := fmt.Sprint(s.node.Leader())
  111. ms := make([]*machineMessage, len(e.Node.Nodes))
  112. for i, n := range e.Node.Nodes {
  113. ms[i] = newMachineMessage(n, lead)
  114. }
  115. return ms, nil
  116. }
  117. func newMachineMessage(n *store.NodeExtern, lead string) *machineMessage {
  118. _, name := filepath.Split(n.Key)
  119. q, err := url.ParseQuery(*n.Value)
  120. if err != nil {
  121. panic("fail to parse the info for machine " + name)
  122. }
  123. m := &machineMessage{
  124. Name: name,
  125. State: stateFollower,
  126. ClientURL: q["etcd"][0],
  127. PeerURL: q["raft"][0],
  128. }
  129. if name == lead {
  130. m.State = stateLeader
  131. }
  132. return m
  133. }