controller/handlers/membership.go (153 lines of code) (raw):

// Copyright (c) 2017-2018 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package handlers import ( "fmt" apiCom "github.com/uber/aresdb/api/common" "github.com/uber/aresdb/utils" "net/http" "github.com/gorilla/mux" "github.com/uber-go/tally" mutatorCom "github.com/uber/aresdb/controller/mutators/common" metaCom "github.com/uber/aresdb/metastore/common" "go.uber.org/fx" "go.uber.org/zap" ) // MembershipHandlerParams defineds parameters needed to initialize schema handler type MembershipHandlerParams struct { fx.In MembershipMutator mutatorCom.MembershipMutator Logger *zap.SugaredLogger Scope tally.Scope } // MembershipHandler serves schema requests type MembershipHandler struct { membershipMutator mutatorCom.MembershipMutator logger *zap.SugaredLogger scope tally.Scope } // NewMembershipHandler creates a new schema handler func NewMembershipHandler(p MembershipHandlerParams) MembershipHandler { return MembershipHandler{ membershipMutator: p.MembershipMutator, logger: p.Logger, scope: p.Scope, } } // Register adds paths to router func (h MembershipHandler) Register(router *mux.Router, wrappers ...utils.HTTPHandlerWrapper) { router.HandleFunc("/{namespace}/instances", utils.ApplyHTTPWrappers(h.Join, wrappers...)).Methods(http.MethodPost) router.HandleFunc("/{namespace}/instances/{instance}", utils.ApplyHTTPWrappers(h.GetInstance, wrappers...)).Methods(http.MethodGet) router.HandleFunc("/{namespace}/instances", utils.ApplyHTTPWrappers(h.GetInstances, wrappers...)).Methods(http.MethodGet) router.HandleFunc("/{namespace}/instances/{instance}", utils.ApplyHTTPWrappers(h.Leave, wrappers...)).Methods(http.MethodDelete) router.HandleFunc("/{namespace}/hash", utils.ApplyHTTPWrappers(h.GetHash, wrappers...)).Methods(http.MethodGet) } // Join adds a instance func (h MembershipHandler) Join(w *utils.ResponseWriter, r *http.Request) { if h.membershipMutator == nil { w.WriteError(ErrNotImplemented) return } var req JoinRequest err := apiCom.ReadRequest(r, &req, w.SetRequest) if err != nil { w.WriteErrorWithCode(http.StatusBadRequest, err) return } err = h.membershipMutator.Join(req.Namespace, req.Body) if err != nil { statusCode := http.StatusInternalServerError if err == mutatorCom.ErrNamespaceDoesNotExist || err == mutatorCom.ErrInstanceAlreadyExist { statusCode = http.StatusBadRequest } w.WriteErrorWithCode(statusCode, err) return } w.WriteObject(nil) } // GetInstance swagger:route GET /membership/{namespace}/instances/{instance} getInstance // returns an instance func (h MembershipHandler) GetInstance(w *utils.ResponseWriter, r *http.Request) { if h.membershipMutator == nil { w.WriteError(ErrNotImplemented) return } var req GetInstanceRequest err := apiCom.ReadRequest(r, &req, w.SetRequest) if err != nil { w.WriteErrorWithCode(http.StatusBadRequest, err) return } instance, err := h.membershipMutator.GetInstance(req.Namespace, req.InstanceName) if err != nil { statusCode := http.StatusInternalServerError if mutatorCom.IsNonExist(err) { statusCode = http.StatusBadRequest err = metaCom.ErrTableDoesNotExist } w.WriteErrorWithCode(statusCode, err) return } resp := GetInstanceResponse{Instance{fmt.Sprintf("%s:%d", instance.Host, instance.Port)}} w.WriteObject(resp) } // GetInstances swagger:route GET /membership/{namespace}/instances getInstances // returns all instances func (h MembershipHandler) GetInstances(w *utils.ResponseWriter, r *http.Request) { if h.membershipMutator == nil { w.WriteError(ErrNotImplemented) return } var req GetInstancesRequest err := apiCom.ReadRequest(r, &req, w.SetRequest) if err != nil { w.WriteErrorWithCode(http.StatusBadRequest, err) return } instances, err := h.membershipMutator.GetInstances(req.Namespace) if err != nil { statusCode := http.StatusInternalServerError w.WriteErrorWithCode(statusCode, err) return } instancesMap := make(map[string]Instance) for _, instance := range instances { instancesMap[instance.Name] = Instance{fmt.Sprintf("%s:%d", instance.Host, instance.Port)} } resp := GetInstancesResponse{instancesMap} w.WriteObject(resp) } // Leave deletes an existing instance func (h MembershipHandler) Leave(w *utils.ResponseWriter, r *http.Request) { if h.membershipMutator == nil { w.WriteError(ErrNotImplemented) return } var req LeaveRequest err := apiCom.ReadRequest(r, &req, w.SetRequest) if err != nil { w.WriteErrorWithCode(http.StatusBadRequest, err) return } err = h.membershipMutator.Leave(req.Namespace, req.InstanceName) if err != nil { statusCode := http.StatusInternalServerError if err == mutatorCom.ErrInstanceDoesNotExist { statusCode = http.StatusBadRequest } w.WriteErrorWithCode(statusCode, err) return } w.WriteObject(nil) } // GetHash swagger:route GET /membership/{namespace}/hash getMembershipHash // returns hash of all instances in a namespace func (h MembershipHandler) GetHash(w *utils.ResponseWriter, r *http.Request) { if h.membershipMutator == nil { w.WriteError(ErrNotImplemented) return } var req GetHashRequest err := apiCom.ReadRequest(r, &req, w.SetRequest) if err != nil { w.WriteErrorWithCode(http.StatusBadRequest, err) return } hash, err := h.membershipMutator.GetHash(req.Namespace) if err != nil { statusCode := http.StatusInternalServerError if mutatorCom.IsNonExist(err) { statusCode = http.StatusBadRequest err = metaCom.ErrTableDoesNotExist } w.WriteErrorWithCode(statusCode, err) return } w.WriteJSONBytesWithCode(http.StatusOK, []byte(hash), nil) }