capability.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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. }
  21. enableMapMu sync.Mutex
  22. // enabled points to a map in cpapbilityMaps
  23. enabledMap map[capability]bool
  24. )
  25. // capabilityLoop checks the cluster version every 500ms and updates
  26. // the enabledCapability when the cluster version increased.
  27. // capabilityLoop MUST be ran in a goroutine before checking capability
  28. // or using capabilityHandler.
  29. func capabilityLoop(s *etcdserver.EtcdServer) {
  30. stopped := s.StopNotify()
  31. var pv *semver.Version
  32. for {
  33. if v := s.ClusterVersion(); v != pv {
  34. if pv == nil {
  35. pv = v
  36. } else if v != nil && pv.LessThan(*v) {
  37. pv = v
  38. }
  39. enableMapMu.Lock()
  40. enabledMap = capabilityMaps[pv.String()]
  41. enableMapMu.Unlock()
  42. }
  43. select {
  44. case <-stopped:
  45. return
  46. case <-time.After(500 * time.Millisecond):
  47. }
  48. }
  49. }
  50. func isCapabilityEnabled(c capability) bool {
  51. enableMapMu.Lock()
  52. defer enableMapMu.Unlock()
  53. if enabledMap == nil {
  54. return false
  55. }
  56. return enabledMap[c]
  57. }
  58. func capabilityHandler(c capability, fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
  59. return func(w http.ResponseWriter, r *http.Request) {
  60. if !isCapabilityEnabled(c) {
  61. notCapable(w, c)
  62. return
  63. }
  64. fn(w, r)
  65. }
  66. }
  67. func notCapable(w http.ResponseWriter, c capability) {
  68. herr := httptypes.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Not capable of accessing %s feature during rolling upgrades.", c))
  69. herr.WriteTo(w)
  70. }