mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00

etcdhttp will check the cluster version and update its capability version periodically. Any new handler's after 2.0 needs to wrap by capability handler to ensure it is not accessable until rolling upgrade finished.
83 lines
1.9 KiB
Go
83 lines
1.9 KiB
Go
package etcdhttp
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
|
|
"github.com/coreos/etcd/etcdserver"
|
|
"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
|
|
)
|
|
|
|
type capability string
|
|
|
|
const (
|
|
securityCapability capability = "security"
|
|
)
|
|
|
|
var (
|
|
// capabilityMap is a static map of version to capability map.
|
|
// the base capabilities is the set of capability 2.0 supports.
|
|
capabilityMaps = map[string]map[capability]bool{
|
|
"2.1.0": {securityCapability: true},
|
|
}
|
|
|
|
enableMapMu sync.Mutex
|
|
// enabled points to a map in cpapbilityMaps
|
|
enabledMap map[capability]bool
|
|
)
|
|
|
|
// capabilityLoop checks the cluster version every 500ms and updates
|
|
// the enabledCapability when the cluster version increased.
|
|
// capabilityLoop MUST be ran in a goroutine before checking capability
|
|
// or using capabilityHandler.
|
|
func capabilityLoop(s *etcdserver.EtcdServer) {
|
|
stopped := s.StopNotify()
|
|
|
|
var pv *semver.Version
|
|
for {
|
|
if v := s.ClusterVersion(); v != pv {
|
|
if pv == nil {
|
|
pv = v
|
|
} else if v != nil && pv.LessThan(*v) {
|
|
pv = v
|
|
}
|
|
enableMapMu.Lock()
|
|
enabledMap = capabilityMaps[pv.String()]
|
|
enableMapMu.Unlock()
|
|
}
|
|
|
|
select {
|
|
case <-stopped:
|
|
return
|
|
case <-time.After(500 * time.Millisecond):
|
|
}
|
|
}
|
|
}
|
|
|
|
func isCapabilityEnabled(c capability) bool {
|
|
enableMapMu.Lock()
|
|
defer enableMapMu.Unlock()
|
|
if enabledMap == nil {
|
|
return false
|
|
}
|
|
return enabledMap[c]
|
|
}
|
|
|
|
func capabilityHandler(c capability, fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if !isCapabilityEnabled(c) {
|
|
notCapable(w, c)
|
|
return
|
|
}
|
|
fn(w, r)
|
|
}
|
|
}
|
|
|
|
func notCapable(w http.ResponseWriter, c capability) {
|
|
herr := httptypes.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Not capable of accessing %s feature during rolling upgrades.", c))
|
|
herr.WriteTo(w)
|
|
}
|