From 541b431d5cd5e69af0bfa71703c5e662b34e70a8 Mon Sep 17 00:00:00 2001 From: lhy1024 Date: Wed, 13 Sep 2023 16:43:28 +0800 Subject: [PATCH] temp Signed-off-by: lhy1024 --- pkg/errs/error.go | 42 ++ pkg/mcs/scheduling/server/apis/v1/api.go | 79 +--- .../scheduling/server/apis/v1/operators.go | 376 ++++++++++++++++++ pkg/schedule/operator/kind.go | 3 + pkg/utils/apiutil/apiutil.go | 13 + server/api/hot_status.go | 5 +- server/api/label.go | 3 +- server/api/operator.go | 20 +- server/api/region.go | 3 +- server/api/rule.go | 2 +- server/api/store.go | 6 +- server/api/trend.go | 12 +- server/handler.go | 77 ++-- 13 files changed, 497 insertions(+), 144 deletions(-) create mode 100644 pkg/errs/error.go create mode 100644 pkg/mcs/scheduling/server/apis/v1/operators.go diff --git a/pkg/errs/error.go b/pkg/errs/error.go new file mode 100644 index 000000000000..b42ddf1d5f1b --- /dev/null +++ b/pkg/errs/error.go @@ -0,0 +1,42 @@ +// Copyright 2023 TiKV Project Authors. +// +// 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 errs + +import "github.com/pingcap/errors" + +var ( + // ErrOperatorNotFound is error info for operator not found. + ErrOperatorNotFound = errors.New("operator not found") + // ErrAddOperator is error info for already have an operator when adding operator. + ErrAddOperator = errors.New("failed to add operator, maybe already have one") + // ErrRegionNotAdjacent is error info for region not adjacent. + ErrRegionNotAdjacent = errors.New("two regions are not adjacent") + // ErrRegionNotFound is error info for region not found. + ErrRegionNotFound = func(regionID uint64) error { + return errors.Errorf("region %v not found", regionID) + } + // ErrRegionAbnormalPeer is error info for region has abnormal peer. + ErrRegionAbnormalPeer = func(regionID uint64) error { + return errors.Errorf("region %v has abnormal peer", regionID) + } + // ErrStoreNotFoundByID is error info for store not found. + ErrStoreNotFoundByID = func(storeID uint64) error { + return errors.Errorf("store %v not found", storeID) + } + // ErrPluginNotFound is error info for plugin not found. + ErrPluginNotFound = func(pluginPath string) error { + return errors.Errorf("plugin is not found: %s", pluginPath) + } +) diff --git a/pkg/mcs/scheduling/server/apis/v1/api.go b/pkg/mcs/scheduling/server/apis/v1/api.go index 3d1c3921470a..148ce7cfec8f 100644 --- a/pkg/mcs/scheduling/server/apis/v1/api.go +++ b/pkg/mcs/scheduling/server/apis/v1/api.go @@ -16,7 +16,6 @@ package apis import ( "net/http" - "strconv" "sync" "time" @@ -27,7 +26,6 @@ import ( "github.com/joho/godotenv" scheserver "github.com/tikv/pd/pkg/mcs/scheduling/server" "github.com/tikv/pd/pkg/mcs/utils" - "github.com/tikv/pd/pkg/schedule/operator" "github.com/tikv/pd/pkg/utils/apiutil" "github.com/tikv/pd/pkg/utils/apiutil/multiservicesapi" "github.com/unrolled/render" @@ -115,76 +113,13 @@ func (s *Service) RegisterCheckersRouter() { func (s *Service) RegisterOperatorsRouter() { router := s.root.Group("operators") router.GET("", getOperators) - router.GET("/:id", getOperatorByID) -} - -// @Tags operators -// @Summary Get an operator by ID. -// @Param region_id path int true "A Region's Id" -// @Produce json -// @Success 200 {object} operator.OpWithStatus -// @Failure 400 {string} string "The input is invalid." -// @Failure 500 {string} string "PD server failed to proceed the request." -// @Router /operators/{id} [GET] -func getOperatorByID(c *gin.Context) { - svr := c.MustGet(multiservicesapi.ServiceContextKey).(*scheserver.Server) - id := c.Param("id") - - regionID, err := strconv.ParseUint(id, 10, 64) - if err != nil { - c.String(http.StatusBadRequest, err.Error()) - return - } - - opController := svr.GetCoordinator().GetOperatorController() - if opController == nil { - c.String(http.StatusInternalServerError, err.Error()) - return - } - - c.IndentedJSON(http.StatusOK, opController.GetOperatorStatus(regionID)) -} - -// @Tags operators -// @Summary List operators. -// @Param kind query string false "Specify the operator kind." Enums(admin, leader, region, waiting) -// @Produce json -// @Success 200 {array} operator.Operator -// @Failure 500 {string} string "PD server failed to proceed the request." -// @Router /operators [GET] -func getOperators(c *gin.Context) { - svr := c.MustGet(multiservicesapi.ServiceContextKey).(*scheserver.Server) - var ( - results []*operator.Operator - ops []*operator.Operator - err error - ) - - opController := svr.GetCoordinator().GetOperatorController() - if opController == nil { - c.String(http.StatusInternalServerError, err.Error()) - return - } - kinds := c.QueryArray("kind") - if len(kinds) == 0 { - results = opController.GetOperators() - } else { - for _, kind := range kinds { - switch kind { - case "admin": - ops = opController.GetOperatorsOfKind(operator.OpAdmin) - case "leader": - ops = opController.GetOperatorsOfKind(operator.OpLeader) - case "region": - ops = opController.GetOperatorsOfKind(operator.OpRegion) - case "waiting": - ops = opController.GetWaitingOperators() - } - results = append(results, ops...) - } - } - - c.IndentedJSON(http.StatusOK, results) + router.POST("", createOperator) + router.GET("/:id", getOperatorByRegion) + router.DELETE("/:id", deleteOperatorByRegion) + router.GET("/records", getOperatorRecords) + // todo: add more operators api [post] + // todo: add test for pd-ctl + // todo: add test for api } // @Tags checkers diff --git a/pkg/mcs/scheduling/server/apis/v1/operators.go b/pkg/mcs/scheduling/server/apis/v1/operators.go new file mode 100644 index 000000000000..22a509c5ae34 --- /dev/null +++ b/pkg/mcs/scheduling/server/apis/v1/operators.go @@ -0,0 +1,376 @@ +// Copyright 2023 TiKV Project Authors. +// +// 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 apis + +import ( + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/tikv/pd/pkg/errs" + scheserver "github.com/tikv/pd/pkg/mcs/scheduling/server" + "github.com/tikv/pd/pkg/schedule/operator" + "github.com/tikv/pd/pkg/utils/apiutil" + "github.com/tikv/pd/pkg/utils/apiutil/multiservicesapi" + "github.com/tikv/pd/pkg/utils/typeutil" +) + +// @Tags operators +// @Summary Get an operator by ID. +// @Param region_id path int true "A Region's Id" +// @Produce json +// @Success 200 {object} operator.OpWithStatus +// @Failure 400 {string} string "The input is invalid." +// @Failure 500 {string} string "PD server failed to proceed the request." +// @Router /operators/{id} [GET] +func getOperatorByRegion(c *gin.Context) { + opController, err := getOpController(c) + if err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + + id := c.Param("id") + regionID, err := strconv.ParseUint(id, 10, 64) + if err != nil { + c.String(http.StatusBadRequest, err.Error()) + return + } + + c.IndentedJSON(http.StatusOK, opController.GetOperatorStatus(regionID)) +} + +// @Tags operators +// @Summary List operators. +// @Param kind query string false "Specify the operator kind." Enums(admin, leader, region, waiting) +// @Produce json +// @Success 200 {array} operator.Operator +// @Failure 500 {string} string "PD server failed to proceed the request." +// @Router /operators [GET] +func getOperators(c *gin.Context) { + opController, err := getOpController(c) + if err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + + var ( + results []*operator.Operator + ops []*operator.Operator + ) + + kinds := c.QueryArray("kind") + if len(kinds) == 0 { + results = opController.GetOperators() + } else { + for _, kind := range kinds { + switch kind { + case operator.OpAdmin.String(): + ops = opController.GetOperatorsOfKind(operator.OpAdmin) + case operator.OpLeader.String(): + ops = opController.GetOperatorsOfKind(operator.OpLeader) + case operator.OpRegion.String(): + ops = opController.GetOperatorsOfKind(operator.OpRegion) + case operator.OpWaiting: + ops = opController.GetWaitingOperators() + } + results = append(results, ops...) + } + } + + c.IndentedJSON(http.StatusOK, results) +} + +// @Tags operator +// @Summary Cancel a Region's pending operator. +// @Param region_id path int true "A Region's Id" +// @Produce json +// @Success 200 {string} string "The pending operator is canceled." +// @Failure 400 {string} string "The input is invalid." +// @Failure 500 {string} string "PD server failed to proceed the request." +// @Router /operators/{region_id} [delete] +func deleteOperatorByRegion(c *gin.Context) { + opController, err := getOpController(c) + if err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + + id := c.Param("id") + regionID, err := strconv.ParseUint(id, 10, 64) + if err != nil { + c.String(http.StatusBadRequest, err.Error()) + return + } + + op := opController.GetOperator(regionID) + if op == nil { + c.String(http.StatusBadRequest, errs.ErrOperatorNotFound.Error()) + return + } + + opController.RemoveOperator(op, operator.AdminStop) + c.String(http.StatusOK, "The pending operator is canceled.") +} + +// @Tags operator +// @Summary lists the finished operators since the given timestamp in second. +// @Param from query integer false "From Unix timestamp" +// @Produce json +// @Success 200 {object} []operator.OpRecord +// @Failure 400 {string} string "The request is invalid." +// @Failure 500 {string} string "PD server failed to proceed the request." +// @Router /operators/records [get] +func getOperatorRecords(c *gin.Context) { + opController, err := getOpController(c) + if err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + + from, err := apiutil.ParseTime(c.Query("from")) + if err != nil { + c.String(http.StatusBadRequest, err.Error()) + return + } + + records := opController.GetRecords(from) + if len(records) == 0 { + c.String(http.StatusBadRequest, errs.ErrOperatorNotFound.Error()) + return + } + c.IndentedJSON(http.StatusOK, records) +} + +// FIXME: details of input json body params +// @Tags operator +// @Summary Create an operator. +// @Accept json +// @Param body body object true "json params" +// @Produce json +// @Success 200 {string} string "The operator is created." +// @Failure 400 {string} string "The input is invalid." +// @Failure 500 {string} string "PD server failed to proceed the request." +// @Router /operators [post] +func createOperator(c *gin.Context) { + var input map[string]interface{} + if err := c.BindJSON(input); err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, errs.ErrBindJSON.Wrap(err).GenWithStackByCause()) + return + } + + name, ok := input["name"].(string) + if !ok { + c.String(http.StatusBadRequest, "missing operator name") + return + } + + switch name { + case "transfer-leader": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + storeID, ok := input["to_store_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing store id to transfer leader to") + return + } + if err := h.AddTransferLeaderOperator(uint64(regionID), uint64(storeID)); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "transfer-region": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + storeIDs, ok := parseStoreIDsAndPeerRole(input["to_store_ids"], input["peer_roles"]) + if !ok { + c.String(http.StatusBadRequest, "invalid store ids to transfer region to") + return + } + if len(storeIDs) == 0 { + c.String(http.StatusBadRequest, "missing store ids to transfer region to") + return + } + if err := h.AddTransferRegionOperator(uint64(regionID), storeIDs); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "transfer-peer": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + fromID, ok := input["from_store_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "invalid store id to transfer peer from") + return + } + toID, ok := input["to_store_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "invalid store id to transfer peer to") + return + } + if err := h.AddTransferPeerOperator(uint64(regionID), uint64(fromID), uint64(toID)); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "add-peer": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + storeID, ok := input["store_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "invalid store id to transfer peer to") + return + } + if err := h.AddAddPeerOperator(uint64(regionID), uint64(storeID)); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "add-learner": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + storeID, ok := input["store_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "invalid store id to transfer peer to") + return + } + if err := h.AddAddLearnerOperator(uint64(regionID), uint64(storeID)); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "remove-peer": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + storeID, ok := input["store_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "invalid store id to transfer peer to") + return + } + if err := h.AddRemovePeerOperator(uint64(regionID), uint64(storeID)); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "merge-region": + regionID, ok := input["source_region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + targetID, ok := input["target_region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "invalid target region id to merge to") + return + } + if err := h.AddMergeRegionOperator(uint64(regionID), uint64(targetID)); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "split-region": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + policy, ok := input["policy"].(string) + if !ok { + c.String(http.StatusBadRequest, "missing split policy") + return + } + var keys []string + if ks, ok := input["keys"]; ok { + for _, k := range ks.([]interface{}) { + key, ok := k.(string) + if !ok { + c.String(http.StatusBadRequest, "bad format keys") + return + } + keys = append(keys, key) + } + } + if err := h.AddSplitRegionOperator(uint64(regionID), policy, keys); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "scatter-region": + regionID, ok := input["region_id"].(float64) + if !ok { + c.String(http.StatusBadRequest, "missing region id") + return + } + group, _ := input["group"].(string) + if err := h.AddScatterRegionOperator(uint64(regionID), group); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + case "scatter-regions": + // support both receiving key ranges or regionIDs + startKey, _ := input["start_key"].(string) + endKey, _ := input["end_key"].(string) + ids, ok := typeutil.JSONToUint64Slice(input["region_ids"]) + if !ok { + c.String(http.StatusBadRequest, "region_ids is invalid") + return + } + group, _ := input["group"].(string) + // retry 5 times if retryLimit not defined + retryLimit := 5 + if rl, ok := input["retry_limit"].(float64); ok { + retryLimit = int(rl) + } + processedPercentage, err := h.AddScatterRegionsOperators(ids, startKey, endKey, group, retryLimit) + errorMessage := "" + if err != nil { + errorMessage = err.Error() + } + s := struct { + ProcessedPercentage int `json:"processed-percentage"` + Error string `json:"error"` + }{ + ProcessedPercentage: processedPercentage, + Error: errorMessage, + } + c.IndentedJSON(http.StatusOK, s) + return + default: + c.String(http.StatusBadRequest, "unknown operator") + return + } + c.String(http.StatusOK, "The operator is created.") +} + +func getOpController(c *gin.Context) (*operator.Controller, error) { + svr := c.MustGet(multiservicesapi.ServiceContextKey).(*scheserver.Server) + + opController := svr.GetCoordinator().GetOperatorController() + if opController == nil { + return nil, errs.ErrNotBootstrapped.GenWithStackByArgs() + } + return opController, nil +} diff --git a/pkg/schedule/operator/kind.go b/pkg/schedule/operator/kind.go index 265eea5ade65..0187a64c5683 100644 --- a/pkg/schedule/operator/kind.go +++ b/pkg/schedule/operator/kind.go @@ -20,6 +20,9 @@ import ( "github.com/pingcap/errors" ) +// OpWaiting is the status of a waiting operators. +const OpWaiting = "waiting" + // OpKind is a bit field to identify operator types. type OpKind uint32 diff --git a/pkg/utils/apiutil/apiutil.go b/pkg/utils/apiutil/apiutil.go index bcab7c8e9e71..c1ddfa54f6c9 100644 --- a/pkg/utils/apiutil/apiutil.go +++ b/pkg/utils/apiutil/apiutil.go @@ -27,6 +27,7 @@ import ( "path" "strconv" "strings" + "time" "github.com/gorilla/mux" "github.com/pingcap/errcode" @@ -480,3 +481,15 @@ func copyHeader(dst, src http.Header) { } } } + +// ParseTime parses a time string with the format "1694580288" +func ParseTime(t string) (time.Time, error) { + if len(t) == 0 { + return time.Time{}, nil + } + i, err := strconv.ParseInt(t, 10, 64) + if err != nil { + return time.Time{}, err + } + return time.Unix(i, 0), nil +} diff --git a/server/api/hot_status.go b/server/api/hot_status.go index 4f64f1bebc50..a3be72a56ac3 100644 --- a/server/api/hot_status.go +++ b/server/api/hot_status.go @@ -22,6 +22,7 @@ import ( "strconv" "github.com/tikv/pd/pkg/core" + "github.com/tikv/pd/pkg/errs" "github.com/tikv/pd/pkg/statistics/buckets" "github.com/tikv/pd/pkg/statistics/utils" "github.com/tikv/pd/pkg/storage" @@ -117,7 +118,7 @@ func (h *hotStatusHandler) GetHotWriteRegions(w http.ResponseWriter, r *http.Req } store := rc.GetStore(id) if store == nil { - h.rd.JSON(w, http.StatusNotFound, server.ErrStoreNotFound(id).Error()) + h.rd.JSON(w, http.StatusNotFound, errs.ErrStoreNotFoundByID(id).Error()) return } ids = append(ids, id) @@ -153,7 +154,7 @@ func (h *hotStatusHandler) GetHotReadRegions(w http.ResponseWriter, r *http.Requ } store := rc.GetStore(id) if store == nil { - h.rd.JSON(w, http.StatusNotFound, server.ErrStoreNotFound(id).Error()) + h.rd.JSON(w, http.StatusNotFound, errs.ErrStoreNotFoundByID(id).Error()) return } ids = append(ids, id) diff --git a/server/api/label.go b/server/api/label.go index abaad02a4e34..115d93dfdd24 100644 --- a/server/api/label.go +++ b/server/api/label.go @@ -21,6 +21,7 @@ import ( "github.com/pingcap/errors" "github.com/pingcap/kvproto/pkg/metapb" + "github.com/tikv/pd/pkg/errs" "github.com/tikv/pd/server" "github.com/unrolled/render" ) @@ -87,7 +88,7 @@ func (h *labelsHandler) GetStoresByLabel(w http.ResponseWriter, r *http.Request) storeID := s.GetId() store := rc.GetStore(storeID) if store == nil { - h.rd.JSON(w, http.StatusInternalServerError, server.ErrStoreNotFound(storeID).Error()) + h.rd.JSON(w, http.StatusInternalServerError, errs.ErrStoreNotFoundByID(storeID).Error()) return } diff --git a/server/api/operator.go b/server/api/operator.go index 6645a601fb0d..cfdbe00c82d4 100644 --- a/server/api/operator.go +++ b/server/api/operator.go @@ -90,13 +90,13 @@ func (h *operatorHandler) GetOperators(w http.ResponseWriter, r *http.Request) { } else { for _, kind := range kinds { switch kind { - case "admin": + case operator.OpAdmin.String(): ops, err = h.GetAdminOperators() - case "leader": + case operator.OpLeader.String(): ops, err = h.GetLeaderOperators() - case "region": + case operator.OpRegion.String(): ops, err = h.GetRegionOperators() - case "waiting": + case operator.OpWaiting: ops, err = h.GetWaitingOperators() } if err != nil { @@ -354,18 +354,20 @@ func (h *operatorHandler) DeleteOperatorByRegion(w http.ResponseWriter, r *http. // @Failure 500 {string} string "PD server failed to proceed the request." // @Router /operators/records [get] func (h *operatorHandler) GetOperatorRecords(w http.ResponseWriter, r *http.Request) { - var from time.Time - if fromStr := r.URL.Query()["from"]; len(fromStr) > 0 { - fromInt, err := strconv.ParseInt(fromStr[0], 10, 64) + var ( + from time.Time + err error + ) + if froms := r.URL.Query()["from"]; len(froms) > 0 { + from, err = apiutil.ParseTime(froms[0]) if err != nil { h.r.JSON(w, http.StatusBadRequest, err.Error()) return } - from = time.Unix(fromInt, 0) } records, err := h.GetRecords(from) if err != nil { - h.r.JSON(w, http.StatusInternalServerError, err.Error()) + h.r.JSON(w, http.StatusBadRequest, err.Error()) return } h.r.JSON(w, http.StatusOK, records) diff --git a/server/api/region.go b/server/api/region.go index 1c21af53296f..95134a1c29dd 100644 --- a/server/api/region.go +++ b/server/api/region.go @@ -33,6 +33,7 @@ import ( "github.com/pingcap/kvproto/pkg/replication_modepb" "github.com/pingcap/log" "github.com/tikv/pd/pkg/core" + "github.com/tikv/pd/pkg/errs" "github.com/tikv/pd/pkg/keyspace" "github.com/tikv/pd/pkg/schedule/filter" "github.com/tikv/pd/pkg/statistics" @@ -763,7 +764,7 @@ func (h *regionsHandler) GetRegionSiblings(w http.ResponseWriter, r *http.Reques } region := rc.GetRegion(uint64(id)) if region == nil { - h.rd.JSON(w, http.StatusNotFound, server.ErrRegionNotFound(uint64(id)).Error()) + h.rd.JSON(w, http.StatusNotFound, errs.ErrRegionNotFound(uint64(id)).Error()) return } diff --git a/server/api/rule.go b/server/api/rule.go index 33c63a8faa2c..585a0669b0d2 100644 --- a/server/api/rule.go +++ b/server/api/rule.go @@ -167,7 +167,7 @@ func (h *ruleHandler) preCheckForRegionAndRule(w http.ResponseWriter, r *http.Re } region := cluster.GetRegion(regionID) if region == nil { - h.rd.JSON(w, http.StatusNotFound, server.ErrRegionNotFound(regionID).Error()) + h.rd.JSON(w, http.StatusNotFound, errs.ErrRegionNotFound(regionID).Error()) return cluster, nil } return cluster, region diff --git a/server/api/store.go b/server/api/store.go index a3e8c4518a2c..65e67c1eff37 100644 --- a/server/api/store.go +++ b/server/api/store.go @@ -191,7 +191,7 @@ func (h *storeHandler) GetStore(w http.ResponseWriter, r *http.Request) { store := rc.GetStore(storeID) if store == nil { - h.rd.JSON(w, http.StatusNotFound, server.ErrStoreNotFound(storeID).Error()) + h.rd.JSON(w, http.StatusNotFound, errs.ErrStoreNotFoundByID(storeID).Error()) return } @@ -437,7 +437,7 @@ func (h *storeHandler) SetStoreLimit(w http.ResponseWriter, r *http.Request) { store := rc.GetStore(storeID) if store == nil { - h.rd.JSON(w, http.StatusInternalServerError, server.ErrStoreNotFound(storeID).Error()) + h.rd.JSON(w, http.StatusInternalServerError, errs.ErrStoreNotFoundByID(storeID).Error()) return } @@ -758,7 +758,7 @@ func (h *storesHandler) GetAllStores(w http.ResponseWriter, r *http.Request) { storeID := s.GetId() store := rc.GetStore(storeID) if store == nil { - h.rd.JSON(w, http.StatusInternalServerError, server.ErrStoreNotFound(storeID).Error()) + h.rd.JSON(w, http.StatusInternalServerError, errs.ErrStoreNotFoundByID(storeID).Error()) return } diff --git a/server/api/trend.go b/server/api/trend.go index 79c43f3c5fbf..5dd82e79ec71 100644 --- a/server/api/trend.go +++ b/server/api/trend.go @@ -16,10 +16,10 @@ package api import ( "net/http" - "strconv" "time" "github.com/tikv/pd/pkg/statistics" + "github.com/tikv/pd/pkg/utils/apiutil" "github.com/tikv/pd/pkg/utils/typeutil" "github.com/tikv/pd/server" "github.com/unrolled/render" @@ -89,14 +89,16 @@ func newTrendHandler(s *server.Server, rd *render.Render) *trendHandler { // @Failure 500 {string} string "PD server failed to proceed the request." // @Router /trend [get] func (h *trendHandler) GetTrend(w http.ResponseWriter, r *http.Request) { - var from time.Time - if fromStr := r.URL.Query()["from"]; len(fromStr) > 0 { - fromInt, err := strconv.ParseInt(fromStr[0], 10, 64) + var ( + from time.Time + err error + ) + if froms := r.URL.Query()["from"]; len(froms) > 0 { + from, err = apiutil.ParseTime(froms[0]) if err != nil { h.rd.JSON(w, http.StatusBadRequest, err.Error()) return } - from = time.Unix(fromInt, 0) } stores, err := h.getTrendStores() diff --git a/server/handler.go b/server/handler.go index adc1e8ecd318..5bb52db38687 100644 --- a/server/handler.go +++ b/server/handler.go @@ -53,29 +53,6 @@ import ( var ( // SchedulerConfigHandlerPath is the api router path of the schedule config handler. SchedulerConfigHandlerPath = "/api/v1/scheduler-config" - - // ErrOperatorNotFound is error info for operator not found. - ErrOperatorNotFound = errors.New("operator not found") - // ErrAddOperator is error info for already have an operator when adding operator. - ErrAddOperator = errors.New("failed to add operator, maybe already have one") - // ErrRegionNotAdjacent is error info for region not adjacent. - ErrRegionNotAdjacent = errors.New("two regions are not adjacent") - // ErrRegionNotFound is error info for region not found. - ErrRegionNotFound = func(regionID uint64) error { - return errors.Errorf("region %v not found", regionID) - } - // ErrRegionAbnormalPeer is error info for region has abnormal peer. - ErrRegionAbnormalPeer = func(regionID uint64) error { - return errors.Errorf("region %v has abnormal peer", regionID) - } - // ErrStoreNotFound is error info for store not found. - ErrStoreNotFound = func(storeID uint64) error { - return errors.Errorf("store %v not found", storeID) - } - // ErrPluginNotFound is error info for plugin not found. - ErrPluginNotFound = func(pluginPath string) error { - return errors.Errorf("plugin is not found: %s", pluginPath) - } ) // Handler is a helper to export methods to handle API/RPC requests. @@ -170,7 +147,7 @@ func (h *Handler) GetStores() ([]*core.StoreInfo, error) { storeID := s.GetId() store := rc.GetStore(storeID) if store == nil { - return nil, ErrStoreNotFound(storeID) + return nil, errs.ErrStoreNotFoundByID(storeID) } stores = append(stores, store) } @@ -416,7 +393,7 @@ func (h *Handler) GetOperator(regionID uint64) (*operator.Operator, error) { op := c.GetOperator(regionID) if op == nil { - return nil, ErrOperatorNotFound + return nil, errs.ErrOperatorNotFound } return op, nil @@ -431,7 +408,7 @@ func (h *Handler) GetOperatorStatus(regionID uint64) (*operator.OpWithStatus, er op := c.GetOperatorStatus(regionID) if op == nil { - return nil, ErrOperatorNotFound + return nil, errs.ErrOperatorNotFound } return op, nil @@ -446,7 +423,7 @@ func (h *Handler) RemoveOperator(regionID uint64) error { op := c.GetOperator(regionID) if op == nil { - return ErrOperatorNotFound + return errs.ErrOperatorNotFound } _ = c.RemoveOperator(op, operator.AdminStop) @@ -515,7 +492,7 @@ func (h *Handler) GetRecords(from time.Time) ([]*operator.OpRecord, error) { } records := c.GetRecords(from) if len(records) == 0 { - return nil, ErrOperatorNotFound + return nil, errs.ErrOperatorNotFound } return records, nil } @@ -585,7 +562,7 @@ func (h *Handler) AddTransferLeaderOperator(regionID uint64, storeID uint64) err region := c.GetRegion(regionID) if region == nil { - return ErrRegionNotFound(regionID) + return errs.ErrRegionNotFound(regionID) } newLeader := region.GetStoreVoter(storeID) @@ -599,7 +576,7 @@ func (h *Handler) AddTransferLeaderOperator(regionID uint64, storeID uint64) err return err } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -613,7 +590,7 @@ func (h *Handler) AddTransferRegionOperator(regionID uint64, storeIDs map[uint64 region := c.GetRegion(regionID) if region == nil { - return ErrRegionNotFound(regionID) + return errs.ErrRegionNotFound(regionID) } if c.GetOpts().IsPlacementRulesEnabled() { @@ -643,7 +620,7 @@ func (h *Handler) AddTransferRegionOperator(regionID uint64, storeIDs map[uint64 return err } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -657,7 +634,7 @@ func (h *Handler) AddTransferPeerOperator(regionID uint64, fromStoreID, toStoreI region := c.GetRegion(regionID) if region == nil { - return ErrRegionNotFound(regionID) + return errs.ErrRegionNotFound(regionID) } oldPeer := region.GetStorePeer(fromStoreID) @@ -676,7 +653,7 @@ func (h *Handler) AddTransferPeerOperator(regionID uint64, fromStoreID, toStoreI return err } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -690,7 +667,7 @@ func (h *Handler) checkAdminAddPeerOperator(regionID uint64, toStoreID uint64) ( region := c.GetRegion(regionID) if region == nil { - return nil, nil, ErrRegionNotFound(regionID) + return nil, nil, errs.ErrRegionNotFound(regionID) } if region.GetStorePeer(toStoreID) != nil { @@ -718,7 +695,7 @@ func (h *Handler) AddAddPeerOperator(regionID uint64, toStoreID uint64) error { return err } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -741,7 +718,7 @@ func (h *Handler) AddAddLearnerOperator(regionID uint64, toStoreID uint64) error return err } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -755,7 +732,7 @@ func (h *Handler) AddRemovePeerOperator(regionID uint64, fromStoreID uint64) err region := c.GetRegion(regionID) if region == nil { - return ErrRegionNotFound(regionID) + return errs.ErrRegionNotFound(regionID) } if region.GetStorePeer(fromStoreID) == nil { @@ -768,7 +745,7 @@ func (h *Handler) AddRemovePeerOperator(regionID uint64, fromStoreID uint64) err return err } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -782,26 +759,26 @@ func (h *Handler) AddMergeRegionOperator(regionID uint64, targetID uint64) error region := c.GetRegion(regionID) if region == nil { - return ErrRegionNotFound(regionID) + return errs.ErrRegionNotFound(regionID) } target := c.GetRegion(targetID) if target == nil { - return ErrRegionNotFound(targetID) + return errs.ErrRegionNotFound(targetID) } if !filter.IsRegionHealthy(region) || !filter.IsRegionReplicated(c, region) { - return ErrRegionAbnormalPeer(regionID) + return errs.ErrRegionAbnormalPeer(regionID) } if !filter.IsRegionHealthy(target) || !filter.IsRegionReplicated(c, target) { - return ErrRegionAbnormalPeer(targetID) + return errs.ErrRegionAbnormalPeer(targetID) } // for the case first region (start key is nil) with the last region (end key is nil) but not adjacent if (!bytes.Equal(region.GetStartKey(), target.GetEndKey()) || len(region.GetStartKey()) == 0) && (!bytes.Equal(region.GetEndKey(), target.GetStartKey()) || len(region.GetEndKey()) == 0) { - return ErrRegionNotAdjacent + return errs.ErrRegionNotAdjacent } ops, err := operator.CreateMergeRegionOperator("admin-merge-region", c, region, target, operator.OpAdmin) @@ -810,7 +787,7 @@ func (h *Handler) AddMergeRegionOperator(regionID uint64, targetID uint64) error return err } if ok := c.GetOperatorController().AddOperator(ops...); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -824,7 +801,7 @@ func (h *Handler) AddSplitRegionOperator(regionID uint64, policyStr string, keys region := c.GetRegion(regionID) if region == nil { - return ErrRegionNotFound(regionID) + return errs.ErrRegionNotFound(regionID) } policy, ok := pdpb.CheckPolicy_value[strings.ToUpper(policyStr)] @@ -849,7 +826,7 @@ func (h *Handler) AddSplitRegionOperator(regionID uint64, policyStr string, keys } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -863,7 +840,7 @@ func (h *Handler) AddScatterRegionOperator(regionID uint64, group string) error region := c.GetRegion(regionID) if region == nil { - return ErrRegionNotFound(regionID) + return errs.ErrRegionNotFound(regionID) } if c.IsRegionHot(region) { @@ -879,7 +856,7 @@ func (h *Handler) AddScatterRegionOperator(regionID uint64, group string) error return nil } if ok := c.GetOperatorController().AddOperator(op); !ok { - return errors.WithStack(ErrAddOperator) + return errors.WithStack(errs.ErrAddOperator) } return nil } @@ -1010,7 +987,7 @@ func (h *Handler) PluginUnload(pluginPath string) error { ch <- schedule.PluginUnload return nil } - return ErrPluginNotFound(pluginPath) + return errs.ErrPluginNotFound(pluginPath) } // GetAddr returns the server urls for clients.