Skip to content

Commit

Permalink
mcs: support rules http interface in scheduling server (tikv#7199)
Browse files Browse the repository at this point in the history
ref tikv#5839

Signed-off-by: lhy1024 <admin@liudos.us>

Co-authored-by: ti-chi-bot[bot] <108142056+ti-chi-bot[bot]@users.noreply.github.com>
  • Loading branch information
2 people authored and rleungx committed Dec 1, 2023
1 parent a3f40a3 commit 0f4f4f5
Show file tree
Hide file tree
Showing 11 changed files with 932 additions and 280 deletions.
20 changes: 20 additions & 0 deletions errors.toml
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,11 @@ error = '''
build rule list failed, %s
'''

["PD:placement:ErrKeyFormat"]
error = '''
key should be in hex format, %s
'''

["PD:placement:ErrLoadRule"]
error = '''
load rule failed
Expand All @@ -556,11 +561,21 @@ error = '''
load rule group failed
'''

["PD:placement:ErrPlacementDisabled"]
error = '''
placement rules feature is disabled
'''

["PD:placement:ErrRuleContent"]
error = '''
invalid rule content, %s
'''

["PD:placement:ErrRuleNotFound"]
error = '''
rule not found
'''

["PD:plugin:ErrLoadPlugin"]
error = '''
failed to load plugin
Expand Down Expand Up @@ -611,6 +626,11 @@ error = '''
region %v has abnormal peer
'''

["PD:region:ErrRegionInvalidID"]
error = '''
invalid region id
'''

["PD:region:ErrRegionNotAdjacent"]
error = '''
two regions are not adjacent
Expand Down
13 changes: 9 additions & 4 deletions pkg/errs/errno.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ var (

// region errors
var (
// ErrRegionInvalidID is error info for region id invalid.
ErrRegionInvalidID = errors.Normalize("invalid region id", errors.RFCCodeText("PD:region:ErrRegionInvalidID"))
// ErrRegionNotAdjacent is error info for region not adjacent.
ErrRegionNotAdjacent = errors.Normalize("two regions are not adjacent", errors.RFCCodeText("PD:region:ErrRegionNotAdjacent"))
// ErrRegionNotFound is error info for region not found.
Expand Down Expand Up @@ -152,10 +154,13 @@ var (

// placement errors
var (
ErrRuleContent = errors.Normalize("invalid rule content, %s", errors.RFCCodeText("PD:placement:ErrRuleContent"))
ErrLoadRule = errors.Normalize("load rule failed", errors.RFCCodeText("PD:placement:ErrLoadRule"))
ErrLoadRuleGroup = errors.Normalize("load rule group failed", errors.RFCCodeText("PD:placement:ErrLoadRuleGroup"))
ErrBuildRuleList = errors.Normalize("build rule list failed, %s", errors.RFCCodeText("PD:placement:ErrBuildRuleList"))
ErrRuleContent = errors.Normalize("invalid rule content, %s", errors.RFCCodeText("PD:placement:ErrRuleContent"))
ErrLoadRule = errors.Normalize("load rule failed", errors.RFCCodeText("PD:placement:ErrLoadRule"))
ErrLoadRuleGroup = errors.Normalize("load rule group failed", errors.RFCCodeText("PD:placement:ErrLoadRuleGroup"))
ErrBuildRuleList = errors.Normalize("build rule list failed, %s", errors.RFCCodeText("PD:placement:ErrBuildRuleList"))
ErrPlacementDisabled = errors.Normalize("placement rules feature is disabled", errors.RFCCodeText("PD:placement:ErrPlacementDisabled"))
ErrKeyFormat = errors.Normalize("key should be in hex format, %s", errors.RFCCodeText("PD:placement:ErrKeyFormat"))
ErrRuleNotFound = errors.Normalize("rule not found", errors.RFCCodeText("PD:placement:ErrRuleNotFound"))
)

// region label errors
Expand Down
296 changes: 290 additions & 6 deletions pkg/mcs/scheduling/server/apis/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package apis

import (
"encoding/hex"
"net/http"
"strconv"
"sync"
Expand Down Expand Up @@ -127,12 +128,6 @@ func (s *Service) RegisterAdminRouter() {
router.DELETE("cache/regions/:id", deleteRegionCacheByID)
}

// RegisterConfigRouter registers the router of the config handler.
func (s *Service) RegisterConfigRouter() {
router := s.root.Group("config")
router.GET("", getConfig)
}

// RegisterSchedulersRouter registers the router of the schedulers handler.
func (s *Service) RegisterSchedulersRouter() {
router := s.root.Group("schedulers")
Expand Down Expand Up @@ -172,6 +167,32 @@ func (s *Service) RegisterOperatorsRouter() {
router.GET("/records", getOperatorRecords)
}

// RegisterConfigRouter registers the router of the config handler.
func (s *Service) RegisterConfigRouter() {
router := s.root.Group("config")
router.GET("", getConfig)

rules := router.Group("rules")
rules.GET("", getAllRules)
rules.GET("/group/:group", getRuleByGroup)
rules.GET("/region/:region", getRulesByRegion)
rules.GET("/region/:region/detail", checkRegionPlacementRule)
rules.GET("/key/:key", getRulesByKey)

// We cannot merge `/rule` and `/rules`, because we allow `group_id` to be "group",
// which is the same as the prefix of `/rules/group/:group`.
rule := router.Group("rule")
rule.GET("/:group/:id", getRuleByGroupAndID)

groups := router.Group("rule_groups")
groups.GET("", getAllGroupConfigs)
groups.GET("/:id", getRuleGroupConfig)

placementRule := router.Group("placement-rule")
placementRule.GET("", getPlacementRules)
placementRule.GET("/:group", getPlacementRuleByGroup)
}

// @Tags admin
// @Summary Change the log level.
// @Produce json
Expand Down Expand Up @@ -671,3 +692,266 @@ func getHistoryHotRegions(c *gin.Context) {
var res storage.HistoryHotRegions
c.IndentedJSON(http.StatusOK, res)
}

// @Tags rule
// @Summary List all rules of cluster.
// @Produce json
// @Success 200 {array} placement.Rule
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/rules [get]
func getAllRules(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
rules := manager.GetAllRules()
c.IndentedJSON(http.StatusOK, rules)
}

// @Tags rule
// @Summary List all rules of cluster by group.
// @Param group path string true "The name of group"
// @Produce json
// @Success 200 {array} placement.Rule
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/rules/group/{group} [get]
func getRuleByGroup(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
group := c.Param("group")
rules := manager.GetRulesByGroup(group)
c.IndentedJSON(http.StatusOK, rules)
}

// @Tags rule
// @Summary List all rules of cluster by region.
// @Param id path integer true "Region Id"
// @Produce json
// @Success 200 {array} placement.Rule
// @Failure 400 {string} string "The input is invalid."
// @Failure 404 {string} string "The region does not exist."
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/rules/region/{region} [get]
func getRulesByRegion(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
regionStr := c.Param("region")
region, code, err := handler.PreCheckForRegion(regionStr)
if err != nil {
c.String(code, err.Error())
return
}
rules := manager.GetRulesForApplyRegion(region)
c.IndentedJSON(http.StatusOK, rules)
}

// @Tags rule
// @Summary List rules and matched peers related to the given region.
// @Param id path integer true "Region Id"
// @Produce json
// @Success 200 {object} placement.RegionFit
// @Failure 400 {string} string "The input is invalid."
// @Failure 404 {string} string "The region does not exist."
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/rules/region/{region}/detail [get]
func checkRegionPlacementRule(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
regionStr := c.Param("region")
region, code, err := handler.PreCheckForRegion(regionStr)
if err != nil {
c.String(code, err.Error())
return
}
regionFit, err := handler.CheckRegionPlacementRule(region)
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
c.IndentedJSON(http.StatusOK, regionFit)
}

// @Tags rule
// @Summary List all rules of cluster by key.
// @Param key path string true "The name of key"
// @Produce json
// @Success 200 {array} placement.Rule
// @Failure 400 {string} string "The input is invalid."
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/rules/key/{key} [get]
func getRulesByKey(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
keyHex := c.Param("key")
key, err := hex.DecodeString(keyHex)
if err != nil {
c.String(http.StatusBadRequest, errs.ErrKeyFormat.Error())
return
}
rules := manager.GetRulesByKey(key)
c.IndentedJSON(http.StatusOK, rules)
}

// @Tags rule
// @Summary Get rule of cluster by group and id.
// @Param group path string true "The name of group"
// @Param id path string true "Rule Id"
// @Produce json
// @Success 200 {object} placement.Rule
// @Failure 404 {string} string "The rule does not exist."
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Router /config/rule/{group}/{id} [get]
func getRuleByGroupAndID(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
group, id := c.Param("group"), c.Param("id")
rule := manager.GetRule(group, id)
if rule == nil {
c.String(http.StatusNotFound, errs.ErrRuleNotFound.Error())
return
}
c.IndentedJSON(http.StatusOK, rule)
}

// @Tags rule
// @Summary List all rule group configs.
// @Produce json
// @Success 200 {array} placement.RuleGroup
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/rule_groups [get]
func getAllGroupConfigs(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
ruleGroups := manager.GetRuleGroups()
c.IndentedJSON(http.StatusOK, ruleGroups)
}

// @Tags rule
// @Summary Get rule group config by group id.
// @Param id path string true "Group Id"
// @Produce json
// @Success 200 {object} placement.RuleGroup
// @Failure 404 {string} string "The RuleGroup does not exist."
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/rule_groups/{id} [get]
func getRuleGroupConfig(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
id := c.Param("id")
group := manager.GetRuleGroup(id)
if group == nil {
c.String(http.StatusNotFound, errs.ErrRuleNotFound.Error())
return
}
c.IndentedJSON(http.StatusOK, group)
}

// @Tags rule
// @Summary List all rules and groups configuration.
// @Produce json
// @Success 200 {array} placement.GroupBundle
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/placement-rules [get]
func getPlacementRules(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
bundles := manager.GetAllGroupBundles()
c.IndentedJSON(http.StatusOK, bundles)
}

// @Tags rule
// @Summary Get group config and all rules belong to the group.
// @Param group path string true "The name of group"
// @Produce json
// @Success 200 {object} placement.GroupBundle
// @Failure 412 {string} string "Placement rules feature is disabled."
// @Failure 500 {string} string "PD server failed to proceed the request."
// @Router /config/placement-rules/{group} [get]
func getPlacementRuleByGroup(c *gin.Context) {
handler := c.MustGet(handlerKey).(*handler.Handler)
manager, err := handler.GetRuleManager()
if err == errs.ErrPlacementDisabled {
c.String(http.StatusPreconditionFailed, err.Error())
return
}
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
g := c.Param("group")
group := manager.GetGroupBundle(g)
c.IndentedJSON(http.StatusOK, group)
}
Loading

0 comments on commit 0f4f4f5

Please sign in to comment.