v2_admin.go 2.7 KB

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