From dd7f2a772dcd2075a69eb49fcbb3853cccfaaad2 Mon Sep 17 00:00:00 2001 From: okJiang Date: Mon, 27 May 2024 11:22:19 +0800 Subject: [PATCH] ctl: replace doRequest with HTTP client to get health status (#8212) ref tikv/pd#7300 Signed-off-by: okJiang <819421878@qq.com> --- client/http/api.go | 1 + client/http/interface.go | 15 +++++++++++++++ client/http/request_info.go | 1 + client/http/types.go | 9 +++++++++ .../uiserver/embedded_assets_rewriter.go | 1 + tests/integrations/client/http_client_test.go | 19 +++++++++++++++++++ tools/pd-ctl/pdctl/command/health_command.go | 17 ++++++----------- tools/pd-ctl/tests/global_test.go | 10 ---------- 8 files changed, 52 insertions(+), 21 deletions(-) diff --git a/client/http/api.go b/client/http/api.go index a1ca96b38f1..3376a48770d 100644 --- a/client/http/api.go +++ b/client/http/api.go @@ -41,6 +41,7 @@ const ( membersPrefix = "/pd/api/v1/members" leaderPrefix = "/pd/api/v1/leader" transferLeader = "/pd/api/v1/leader/transfer" + health = "/pd/api/v1/health" // Config Config = "/pd/api/v1/config" ClusterVersion = "/pd/api/v1/config/cluster-version" diff --git a/client/http/interface.go b/client/http/interface.go index 7b15291d9e7..11c24beaefd 100644 --- a/client/http/interface.go +++ b/client/http/interface.go @@ -50,6 +50,7 @@ type Client interface { GetStores(context.Context) (*StoresInfo, error) GetStore(context.Context, uint64) (*StoreInfo, error) SetStoreLabels(context.Context, int64, map[string]string) error + GetHealthStatus(context.Context) ([]Health, error) /* Config-related interfaces */ GetConfig(context.Context) (map[string]any, error) SetConfig(context.Context, map[string]any, ...float64) error @@ -337,6 +338,20 @@ func (c *client) SetStoreLabels(ctx context.Context, storeID int64, storeLabels WithBody(jsonInput)) } +// GetHealthStatus gets the health status of the cluster. +func (c *client) GetHealthStatus(ctx context.Context) ([]Health, error) { + var healths []Health + err := c.request(ctx, newRequestInfo(). + WithName(getHealthStatusName). + WithURI(health). + WithMethod(http.MethodGet). + WithResp(&healths)) + if err != nil { + return nil, err + } + return healths, nil +} + // GetConfig gets the configurations. func (c *client) GetConfig(ctx context.Context) (map[string]any, error) { var config map[string]any diff --git a/client/http/request_info.go b/client/http/request_info.go index 0ce7072d1ba..202eab1150f 100644 --- a/client/http/request_info.go +++ b/client/http/request_info.go @@ -39,6 +39,7 @@ const ( getStoresName = "GetStores" getStoreName = "GetStore" setStoreLabelsName = "SetStoreLabels" + getHealthStatusName = "GetHealthStatus" getConfigName = "GetConfig" setConfigName = "SetConfig" getScheduleConfigName = "GetScheduleConfig" diff --git a/client/http/types.go b/client/http/types.go index 31b2bfdaea7..f7273068b8c 100644 --- a/client/http/types.go +++ b/client/http/types.go @@ -661,3 +661,12 @@ func stringToKeyspaceState(str string) (keyspacepb.KeyspaceState, error) { return keyspacepb.KeyspaceState(0), fmt.Errorf("invalid KeyspaceState string: %s", str) } } + +// Health reflects the cluster's health. +// NOTE: This type is moved from `server/api/health.go`, maybe move them to the same place later. +type Health struct { + Name string `json:"name"` + MemberID uint64 `json:"member_id"` + ClientUrls []string `json:"client_urls"` + Health bool `json:"health"` +} diff --git a/pkg/dashboard/uiserver/embedded_assets_rewriter.go b/pkg/dashboard/uiserver/embedded_assets_rewriter.go index 2a5b4a5b3b6..d19db01936f 100644 --- a/pkg/dashboard/uiserver/embedded_assets_rewriter.go +++ b/pkg/dashboard/uiserver/embedded_assets_rewriter.go @@ -28,6 +28,7 @@ import ( var once sync.Once // Assets returns the Assets FileSystem of the dashboard UI +// NOTE: if you see "undefined: assets" error, please run `make dashboard-ui` in the root directory of the repository. func Assets(cfg *config.Config) http.FileSystem { once.Do(func() { resPath := distroutil.MustGetResPath() diff --git a/tests/integrations/client/http_client_test.go b/tests/integrations/client/http_client_test.go index d35b7f00584..9e712b808f3 100644 --- a/tests/integrations/client/http_client_test.go +++ b/tests/integrations/client/http_client_test.go @@ -811,3 +811,22 @@ func (suite *httpClientTestSuite) checkUpdateKeyspaceGCManagementType(mode mode, re.True(ok) re.Equal(expectGCManagementType, val) } + +func (suite *httpClientTestSuite) TestGetHealthStatus() { + suite.RunTestInTwoModes(suite.checkGetHealthStatus) +} + +func (suite *httpClientTestSuite) checkGetHealthStatus(mode mode, client pd.Client) { + re := suite.Require() + env := suite.env[mode] + + healths, err := client.GetHealthStatus(env.ctx) + re.NoError(err) + re.Len(healths, 2) + sort.Slice(healths, func(i, j int) bool { + return healths[i].Name < healths[j].Name + }) + re.Equal("pd1", healths[0].Name) + re.Equal("pd2", healths[1].Name) + re.True(healths[0].Health && healths[1].Health) +} diff --git a/tools/pd-ctl/pdctl/command/health_command.go b/tools/pd-ctl/pdctl/command/health_command.go index 50ac7763d28..a10ee118397 100644 --- a/tools/pd-ctl/pdctl/command/health_command.go +++ b/tools/pd-ctl/pdctl/command/health_command.go @@ -15,30 +15,25 @@ package command import ( - "net/http" - "github.com/spf13/cobra" ) -var ( - healthPrefix = "pd/api/v1/health" -) - // NewHealthCommand return a health subcommand of rootCmd func NewHealthCommand() *cobra.Command { m := &cobra.Command{ - Use: "health", - Short: "show all node's health information of the pd cluster", - Run: showHealthCommandFunc, + Use: "health", + Short: "show all node's health information of the PD cluster", + PersistentPreRunE: requirePDClient, + Run: showHealthCommandFunc, } return m } func showHealthCommandFunc(cmd *cobra.Command, _ []string) { - r, err := doRequest(cmd, healthPrefix, http.MethodGet, http.Header{}) + health, err := PDCli.GetHealthStatus(cmd.Context()) if err != nil { cmd.Println(err) return } - cmd.Println(r) + jsonPrint(cmd, health) } diff --git a/tools/pd-ctl/tests/global_test.go b/tools/pd-ctl/tests/global_test.go index 6987267ea54..766e357088e 100644 --- a/tools/pd-ctl/tests/global_test.go +++ b/tools/pd-ctl/tests/global_test.go @@ -46,11 +46,6 @@ func TestSendAndGetComponent(t *testing.T) { }) // check http client api // TODO: remove this comment after replacing dialClient with the PD HTTP client completely. - mux.HandleFunc("/pd/api/v1/health", func(w http.ResponseWriter, r *http.Request) { - callerID := apiutil.GetCallerIDOnHTTP(r) - re.Equal(command.PDControlCallerID, callerID) - fmt.Fprint(w, callerID) - }) mux.HandleFunc("/pd/api/v1/stores", func(w http.ResponseWriter, r *http.Request) { callerID := apiutil.GetCallerIDOnHTTP(r) re.Equal(command.PDControlCallerID, callerID) @@ -82,11 +77,6 @@ func TestSendAndGetComponent(t *testing.T) { "id": 1 }`), string(output)) - args = []string{"-u", pdAddr, "health"} - output, err = ExecuteCommand(cmd, args...) - re.NoError(err) - re.Equal(fmt.Sprintf("%s\n", command.PDControlCallerID), string(output)) - args = []string{"-u", pdAddr, "store"} output, err = ExecuteCommand(cmd, args...) re.NoError(err)