capability.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package etcdhttp
  2. import (
  3. "fmt"
  4. "net/http"
  5. "sync"
  6. "time"
  7. "github.com/coreos/etcd/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
  8. "github.com/coreos/etcd/etcdserver"
  9. "github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
  10. )
  11. type capability string
  12. const (
  13. authCapability capability = "auth"
  14. )
  15. var (
  16. // capabilityMap is a static map of version to capability map.
  17. // the base capabilities is the set of capability 2.0 supports.
  18. capabilityMaps = map[string]map[capability]bool{
  19. "2.1.0": {authCapability: true},
  20. "2.2.0": {authCapability: true},
  21. }
  22. enableMapMu sync.Mutex
  23. // enabled points to a map in cpapbilityMaps
  24. enabledMap map[capability]bool
  25. )
  26. // capabilityLoop checks the cluster version every 500ms and updates
  27. // the enabledCapability when the cluster version increased.
  28. // capabilityLoop MUST be ran in a goroutine before checking capability
  29. // or using capabilityHandler.
  30. func capabilityLoop(s *etcdserver.EtcdServer) {
  31. stopped := s.StopNotify()
  32. var pv *semver.Version
  33. for {
  34. if v := s.ClusterVersion(); v != pv {
  35. if pv == nil {
  36. pv = v
  37. } else if v != nil && pv.LessThan(*v) {
  38. pv = v
  39. }
  40. enableMapMu.Lock()
  41. enabledMap = capabilityMaps[pv.String()]
  42. enableMapMu.Unlock()
  43. }
  44. select {
  45. case <-stopped:
  46. return
  47. case <-time.After(500 * time.Millisecond):
  48. }
  49. }
  50. }
  51. func isCapabilityEnabled(c capability) bool {
  52. enableMapMu.Lock()
  53. defer enableMapMu.Unlock()
  54. if enabledMap == nil {
  55. return false
  56. }
  57. return enabledMap[c]
  58. }
  59. func capabilityHandler(c capability, fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
  60. return func(w http.ResponseWriter, r *http.Request) {
  61. if !isCapabilityEnabled(c) {
  62. notCapable(w, c)
  63. return
  64. }
  65. fn(w, r)
  66. }
  67. }
  68. func notCapable(w http.ResponseWriter, c capability) {
  69. herr := httptypes.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Not capable of accessing %s feature during rolling upgrades.", c))
  70. herr.WriteTo(w)
  71. }