added endpoint protection for cluster resize

This commit is contained in:
Todd Gruben 2017-10-31 11:32:08 -05:00
parent 3bdcc16dbc
commit 9b7adde692
3 changed files with 84 additions and 11 deletions

View file

@ -167,6 +167,7 @@ type Cluster struct {
// Close management
wg sync.WaitGroup
closing chan struct{}
prefect SecurityManager
// The writer for any logging.
LogOutput io.Writer
@ -185,6 +186,7 @@ func NewCluster() *Cluster {
closing: make(chan struct{}),
LogOutput: os.Stderr,
prefect: &DefaultSecurityManager{},
}
}
@ -226,6 +228,20 @@ func (c *Cluster) NodeSet() []URI {
}
func (c *Cluster) setState(state string) {
if c.State != state { //only on new state, perform routing change
switch state {
case ClusterStateResizing:
c.prefect.SetRestricted()
case ClusterStateNormal:
c.prefect.SetNormal()
// Don't change routing for these new states
// ClusterStateStarting
// ResizeJobStateRunning
// ResizeJobStateDone
// ResizeJobStateAborted
}
}
c.State = state
}

View file

@ -60,7 +60,9 @@ type Handler struct {
Cluster *Cluster
ClientOptions *ClientOptions
Router *mux.Router
Router *mux.Router
NormalRouter *mux.Router
RestrictedRouter *mux.Router
// The execution engine for running queries.
Executor interface {
@ -89,14 +91,49 @@ func NewHandler() *Handler {
handler := &Handler{
LogOutput: os.Stderr,
}
handler.Router = NewRouter(handler)
BuildRouters(handler)
return handler
}
// NewRouter creates a Gorilla Mux http router.
func NewRouter(handler *Handler) *mux.Router {
// BuildRouters creates a Gorilla Mux http routers for both normal and restricted enpoints.
func BuildRouters(handler *Handler) {
router := mux.NewRouter()
router.HandleFunc("/", handler.handleWebUI).Methods("GET")
loadCommon(router, handler)
loadNormal(router, handler)
handler.NormalRouter = router
router = mux.NewRouter()
loadCommon(router, handler)
loadRestricted(router, handler)
handler.RestrictedRouter = router
handler.SetNormal()
}
// SetNormal a method of the SecurityManager interface which provides normal URI routing
func (h *Handler) SetNormal() {
h.Router = h.NormalRouter
}
// SetRestricted a method of the SecurityManager interface which provides restricted URI routing
func (h *Handler) SetRestricted() {
h.Router = h.RestrictedRouter
}
func loadCommon(router *mux.Router, handler *Handler) {
router.HandleFunc("/schema", handler.handleGetSchema).Methods("GET")
router.HandleFunc("/status", handler.handleGetStatus).Methods("GET")
router.HandleFunc("/version", handler.handleGetVersion).Methods("GET")
router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux).Methods("GET")
router.HandleFunc("/debug/vars", handler.handleExpvar).Methods("GET")
router.HandleFunc("/slices/max", handler.handleGetSlicesMax).Methods("GET") // TODO: deprecate, but it's being used by the client (for backups)
router.HandleFunc("/hosts", handler.handleGetHosts).Methods("GET")
}
func loadRestricted(router *mux.Router, handler *Handler) {
router.HandleFunc("/cluster/resize/abort", handler.handlePostClusterResizeAbort).Methods("POST")
router.NotFoundHandler = http.HandlerFunc(handler.reportRestricted)
}
func loadNormal(router *mux.Router, handler *Handler) {
router.HandleFunc("/assets/{file}", handler.handleWebUI).Methods("GET")
router.HandleFunc("/cluster/resize/abort", handler.handlePostClusterResizeAbort).Methods("POST")
router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux).Methods("GET")
@ -131,11 +168,6 @@ func NewRouter(handler *Handler) *mux.Router {
router.HandleFunc("/index/{index}/input-definition/{input-definition}", handler.handleDeleteInputDefinition).Methods("DELETE")
router.HandleFunc("/index/{index}/query", handler.handlePostQuery).Methods("POST")
router.HandleFunc("/index/{index}/time-quantum", handler.handlePatchIndexTimeQuantum).Methods("PATCH")
router.HandleFunc("/hosts", handler.handleGetHosts).Methods("GET")
router.HandleFunc("/schema", handler.handleGetSchema).Methods("GET")
router.HandleFunc("/slices/max", handler.handleGetSlicesMax).Methods("GET") // TODO: deprecate, but it's being used by the client (for backups)
router.HandleFunc("/status", handler.handleGetStatus).Methods("GET")
router.HandleFunc("/version", handler.handleGetVersion).Methods("GET")
router.HandleFunc("/recalculate-caches", handler.handleRecalculateCaches).Methods("POST")
// TODO: Apply MethodNotAllowed statuses to all endpoints.
@ -144,7 +176,10 @@ func NewRouter(handler *Handler) *mux.Router {
// For now we just do it for the most commonly used handler, /query
router.HandleFunc("/index/{index}/query", handler.methodNotAllowedHandler).Methods("GET")
return router
}
func (h *Handler) reportRestricted(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not allowed during resize", http.StatusMethodNotAllowed)
}
func (h *Handler) methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {

22
security_manager.go Normal file
View file

@ -0,0 +1,22 @@
package pilosa
// SecurityManager provides the ability to limit access to restricted endpoints
// during cluster configuration
type SecurityManager interface {
SetRestricted()
SetNormal()
}
// DefaultSecurityManager provides a no-op implimentation of the SecurityManager interface
type DefaultSecurityManager struct {
}
// SetRestricted no-op
func (sdm *DefaultSecurityManager) SetRestricted() {
}
// SetNormal no-op
func (sdm *DefaultSecurityManager) SetNormal() {
}