This is an automated email from the ASF dual-hosted git repository.

miaoliyao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/shardingsphere-on-cloud.git


The following commit(s) were added to refs/heads/main by this push:
     new 110fd9c  chore(pitr): agent add health check api, cli check duplicate 
agent ip.
     new 7a88262  Merge pull request #331 from Xu-Wentao/pitr
110fd9c is described below

commit 110fd9cc4e62203564c66f4784b24d1e12d6f040
Author: xuwentao <[email protected]>
AuthorDate: Thu Apr 27 16:48:16 2023 +0800

    chore(pitr): agent add health check api, cli check duplicate agent ip.
---
 pitr/agent/internal/handler/handler_suite_test.go  |   1 +
 .../{handler_suite_test.go => healthcheck.go}      |  50 +++-----
 .../{handler_suite_test.go => healthcheck_test.go} |  46 +++----
 pitr/agent/internal/handler/view/healthcheck.go    |  25 ++++
 pitr/agent/main.go                                 |   2 +
 pitr/agent/pkg/gsutil/conn.go                      |   2 +-
 pitr/cli/internal/cmd/backup.go                    |  11 +-
 pitr/cli/internal/cmd/backup_test.go               |  11 +-
 pitr/cli/internal/cmd/restore_test.go              |   2 +-
 pitr/cli/internal/cmd/root.go                      |  25 +++-
 pitr/cli/internal/pkg/agent-server.go              | 142 ++++++---------------
 pitr/cli/internal/pkg/agent-server_test.go         |  17 ++-
 pitr/cli/internal/pkg/mocks/agent-server.go        |   8 +-
 pitr/cli/internal/pkg/model/as_healthcheck.go      |  25 ++++
 pitr/cli/internal/pkg/xerr/err.go                  |   6 +
 pitr/cli/pkg/httputils/mocks/req.go                |  26 +---
 pitr/cli/pkg/httputils/req.go                      |  32 +++--
 .../pkg/kubernetes/deployment/deployment_test.go   |   2 +-
 18 files changed, 213 insertions(+), 220 deletions(-)

diff --git a/pitr/agent/internal/handler/handler_suite_test.go 
b/pitr/agent/internal/handler/handler_suite_test.go
index 816ef69..30dbb4b 100644
--- a/pitr/agent/internal/handler/handler_suite_test.go
+++ b/pitr/agent/internal/handler/handler_suite_test.go
@@ -56,5 +56,6 @@ var _ = BeforeSuite(func() {
        app.Route("/api", func(r fiber.Router) {
                r.Post("/diskspace", handler.DiskSpace)
                r.Delete("/backup", handler.DeleteBackup)
+               r.Post("/healthz", handler.HealthCheck)
        })
 })
diff --git a/pitr/agent/internal/handler/handler_suite_test.go 
b/pitr/agent/internal/handler/healthcheck.go
similarity index 56%
copy from pitr/agent/internal/handler/handler_suite_test.go
copy to pitr/agent/internal/handler/healthcheck.go
index 816ef69..877adc0 100644
--- a/pitr/agent/internal/handler/handler_suite_test.go
+++ b/pitr/agent/internal/handler/healthcheck.go
@@ -15,46 +15,28 @@
  * limitations under the License.
  */
 
-package handler_test
+package handler
 
 import (
-       "os"
-       "testing"
+       "fmt"
 
-       "github.com/apache/shardingsphere-on-cloud/pitr/agent/internal/handler"
-       "github.com/apache/shardingsphere-on-cloud/pitr/agent/pkg/logging"
+       "github.com/apache/shardingsphere-on-cloud/pitr/agent/internal/cons"
+       
"github.com/apache/shardingsphere-on-cloud/pitr/agent/internal/handler/view"
+       "github.com/apache/shardingsphere-on-cloud/pitr/agent/internal/pkg"
        "github.com/apache/shardingsphere-on-cloud/pitr/agent/pkg/responder"
        "github.com/gofiber/fiber/v2"
-       "github.com/golang/mock/gomock"
-       . "github.com/onsi/ginkgo/v2"
-       . "github.com/onsi/gomega"
-       "go.uber.org/zap"
 )
 
-var (
-       app  *fiber.App
-       ctrl *gomock.Controller
-)
-
-func TestHandler(t *testing.T) {
-       RegisterFailHandler(Fail)
-       RunSpecs(t, "Handler Suite")
-}
+func HealthCheck(ctx *fiber.Ctx) error {
+       in := &view.HealthCheckIn{}
+       if err := ctx.BodyParser(in); err != nil {
+               return fmt.Errorf("body parse err=%s,wrap=%w", err, 
cons.BodyParseFailed)
+       }
 
-var _ = BeforeSuite(func() {
-       // init log
-       logging.Init(zap.DebugLevel)
+       if err := pkg.OG.Auth(in.Username, in.Password, in.DBName, in.DBPort); 
err != nil {
+               efmt := "pkg.OG.Auth failure[un=%s,pw.len=%d,db=%s],err=%w"
+               return fmt.Errorf(efmt, in.Username, len(in.Password), 
in.DBName, err)
+       }
 
-       Expect(os.Setenv("SHELL", "/bin/bash")).To(Succeed())
-
-       // init app
-       app = fiber.New()
-       app.Get("/ping", func(ctx *fiber.Ctx) error {
-               return responder.Success(ctx, "pong")
-       })
-
-       app.Route("/api", func(r fiber.Router) {
-               r.Post("/diskspace", handler.DiskSpace)
-               r.Delete("/backup", handler.DeleteBackup)
-       })
-})
+       return responder.Success(ctx, "")
+}
diff --git a/pitr/agent/internal/handler/handler_suite_test.go 
b/pitr/agent/internal/handler/healthcheck_test.go
similarity index 52%
copy from pitr/agent/internal/handler/handler_suite_test.go
copy to pitr/agent/internal/handler/healthcheck_test.go
index 816ef69..185ee18 100644
--- a/pitr/agent/internal/handler/handler_suite_test.go
+++ b/pitr/agent/internal/handler/healthcheck_test.go
@@ -18,43 +18,27 @@
 package handler_test
 
 import (
-       "os"
-       "testing"
+       "net/http"
+       "net/http/httptest"
+       "strings"
 
-       "github.com/apache/shardingsphere-on-cloud/pitr/agent/internal/handler"
-       "github.com/apache/shardingsphere-on-cloud/pitr/agent/pkg/logging"
-       "github.com/apache/shardingsphere-on-cloud/pitr/agent/pkg/responder"
-       "github.com/gofiber/fiber/v2"
-       "github.com/golang/mock/gomock"
        . "github.com/onsi/ginkgo/v2"
        . "github.com/onsi/gomega"
-       "go.uber.org/zap"
 )
 
-var (
-       app  *fiber.App
-       ctrl *gomock.Controller
-)
-
-func TestHandler(t *testing.T) {
-       RegisterFailHandler(Fail)
-       RunSpecs(t, "Handler Suite")
-}
-
-var _ = BeforeSuite(func() {
-       // init log
-       logging.Init(zap.DebugLevel)
-
-       Expect(os.Setenv("SHELL", "/bin/bash")).To(Succeed())
-
-       // init app
-       app = fiber.New()
-       app.Get("/ping", func(ctx *fiber.Ctx) error {
-               return responder.Success(ctx, "pong")
+var _ = Describe("Test Health Check", func() {
+       It("should failed with empty body", func() {
+               req := httptest.NewRequest(http.MethodPost, "/api/healthz", nil)
+               resp, err := app.Test(req)
+               Expect(err).To(BeNil())
+               
Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError))
        })
 
-       app.Route("/api", func(r fiber.Router) {
-               r.Post("/diskspace", handler.DiskSpace)
-               r.Delete("/backup", handler.DeleteBackup)
+       It("should success", func() {
+               body := `{"username": "root", "password": "root", "db_name": 
"test", "db_port": 3306}`
+               req := httptest.NewRequest(http.MethodPost, "/api/healthz", 
strings.NewReader(body))
+               resp, err := app.Test(req)
+               Expect(err).To(BeNil())
+               
Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError))
        })
 })
diff --git a/pitr/agent/internal/handler/view/healthcheck.go 
b/pitr/agent/internal/handler/view/healthcheck.go
new file mode 100644
index 0000000..f214fa0
--- /dev/null
+++ b/pitr/agent/internal/handler/view/healthcheck.go
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 view
+
+type HealthCheckIn struct {
+       DBPort   uint16 `json:"db_port"`
+       DBName   string `json:"db_name"`
+       Username string `json:"username"`
+       Password string `json:"password"`
+}
diff --git a/pitr/agent/main.go b/pitr/agent/main.go
index 8c11df7..a2bdddd 100644
--- a/pitr/agent/main.go
+++ b/pitr/agent/main.go
@@ -149,6 +149,7 @@ func SetupApp() {
        )
 
        app.Get("/ping", func(ctx *fiber.Ctx) error {
+
                return responder.Success(ctx, "pong")
        })
 
@@ -160,6 +161,7 @@ func SetupApp() {
        app.Route("/api", func(r fiber.Router) {
                r.Use(middleware.RequestIDChecker())
 
+               r.Post("/healthz", handler.HealthCheck)
                r.Post("/backup", handler.Backup)
                r.Delete("/backup", handler.DeleteBackup)
                r.Post("/restore", handler.Restore)
diff --git a/pitr/agent/pkg/gsutil/conn.go b/pitr/agent/pkg/gsutil/conn.go
index 72a6e8a..a5bca1d 100644
--- a/pitr/agent/pkg/gsutil/conn.go
+++ b/pitr/agent/pkg/gsutil/conn.go
@@ -66,5 +66,5 @@ func (og *OpenGauss) Ping() error {
                efmt := "db ping 
fail[user=%s,pwLen=%d,dbName=%s],err=%s,wrap=%w"
                return fmt.Errorf(efmt, og.user, og.pwLen, og.dbName, err, 
cons.DBConnectionFailed)
        }
-       return nil
+       return og.db.Close()
 }
diff --git a/pitr/cli/internal/cmd/backup.go b/pitr/cli/internal/cmd/backup.go
index 9ef1b63..8537501 100644
--- a/pitr/cli/internal/cmd/backup.go
+++ b/pitr/cli/internal/cmd/backup.go
@@ -143,6 +143,7 @@ func backup() error {
        // Step3. Check agent server status
        logging.Info("Checking agent server status...")
        if available := checkAgentServerStatus(lsBackup); !available {
+               logging.Error("Cancel! One or more agent server are not 
available.")
                err = xerr.NewCliErr("One or more agent server are not 
available.")
                return err
        }
@@ -179,6 +180,10 @@ func backup() error {
        logging.Info("Starting check backup status ...")
        status := checkBackupStatus(lsBackup)
        logging.Info(fmt.Sprintf("Backup result: %s", status))
+       if status != model.SsBackupStatusCompleted && status != 
model.SsBackupStatusCanceled {
+               err = xerr.NewCliErr("Backup failed")
+               return err
+       }
 
        // Step9. finished backup and update backup file
        logging.Info("Starting update backup file ...")
@@ -437,7 +442,7 @@ func deleteBackupFiles(lsBackup *model.LsBackup) {
                sn := sn
                dn, ok := dataNodeMap[sn.IP]
                if !ok {
-                       logging.Error(fmt.Sprintf("data node %s:%d not found, 
SKIPPED!", sn.IP, sn.Port))
+                       logging.Warn(fmt.Sprintf("SKIPPED! data node %s:%d not 
found in backup info.", sn.IP, sn.Port))
                        continue
                }
                as := pkg.NewAgentServer(fmt.Sprintf("%s:%d", 
convertLocalhost(sn.IP), AgentPort))
@@ -447,8 +452,12 @@ func deleteBackupFiles(lsBackup *model.LsBackup) {
 
        time.Sleep(time.Millisecond * 100)
        for pw.IsRenderInProgress() {
+               if pw.LengthActive() == 0 {
+                       pw.Stop()
+               }
                time.Sleep(time.Millisecond * 100)
        }
+
        close(resultCh)
 
        t := table.NewWriter()
diff --git a/pitr/cli/internal/cmd/backup_test.go 
b/pitr/cli/internal/cmd/backup_test.go
index 6fbf352..bc531d6 100644
--- a/pitr/cli/internal/cmd/backup_test.go
+++ b/pitr/cli/internal/cmd/backup_test.go
@@ -383,18 +383,21 @@ var _ = Describe("test backup mock", func() {
                })
 
                It("agent server is not running", func() {
-                       mockIreq.EXPECT().Send(gomock.Any()).Return(-1, 
errors.New("error")).AnyTimes()
+                       
mockIreq.EXPECT().Send(gomock.Any()).Return(errors.New("error")).AnyTimes()
+                       mockIreq.EXPECT().Header(gomock.Any()).AnyTimes()
                        Expect(checkAgentServerStatus(ls)).To(BeFalse())
                })
 
                It("agent server are running", func() {
-                       mockIreq.EXPECT().Send(gomock.Any()).Return(200, 
nil).AnyTimes()
+                       
mockIreq.EXPECT().Send(gomock.Any()).Return(nil).AnyTimes()
+                       mockIreq.EXPECT().Header(gomock.Any()).AnyTimes()
                        Expect(checkAgentServerStatus(ls)).To(BeTrue())
                })
 
                It("one agent server is not running", func() {
-                       mockIreq.EXPECT().Send(gomock.Any()).Return(500, nil)
-                       mockIreq.EXPECT().Send(gomock.Any()).Return(200, 
nil).AnyTimes()
+                       
mockIreq.EXPECT().Send(gomock.Any()).Return(errors.New("failed"))
+                       
mockIreq.EXPECT().Send(gomock.Any()).Return(nil).AnyTimes()
+                       mockIreq.EXPECT().Header(gomock.Any()).AnyTimes()
                        Expect(checkAgentServerStatus(ls)).To(BeFalse())
                })
        })
diff --git a/pitr/cli/internal/cmd/restore_test.go 
b/pitr/cli/internal/cmd/restore_test.go
index 04a12e1..7da6dea 100644
--- a/pitr/cli/internal/cmd/restore_test.go
+++ b/pitr/cli/internal/cmd/restore_test.go
@@ -126,7 +126,7 @@ var _ = Describe("test restore", func() {
                RecordID = "backup-id"
                proxy.EXPECT().ExportMetaData().Return(&model.ClusterInfo{}, 
nil)
                proxy.EXPECT().ImportMetaData(gomock.Any()).Return(nil)
-               as.EXPECT().CheckStatus().Return(nil)
+               as.EXPECT().CheckStatus(gomock.Any()).Return(nil)
                as.EXPECT().Restore(gomock.Any()).Return(nil)
 
                Expect(restore()).To(BeNil())
diff --git a/pitr/cli/internal/cmd/root.go b/pitr/cli/internal/cmd/root.go
index 6df5fc7..33a4f40 100644
--- a/pitr/cli/internal/cmd/root.go
+++ b/pitr/cli/internal/cmd/root.go
@@ -93,10 +93,20 @@ func checkAgentServerStatus(lsBackup *model.LsBackup) bool {
        // all agent server are available
        available := true
 
+       // IMPORTANT: we don't support multiple agent server run on the same 
host
+       asMap := make(map[string]bool)
+       asDuplicate := false
+
        for _, node := range lsBackup.SsBackup.StorageNodes {
                sn := node
                as := pkg.NewAgentServer(fmt.Sprintf("%s:%d", 
convertLocalhost(sn.IP), AgentPort))
-               if err := as.CheckStatus(); err != nil {
+               in := &model.HealthCheckIn{
+                       DBPort:   sn.Port,
+                       DBName:   convertLocalhost(sn.IP),
+                       Username: sn.Username,
+                       Password: sn.Password,
+               }
+               if err := as.CheckStatus(in); err != nil {
                        statusList = append(statusList, 
&model.AgentServerStatus{IP: sn.IP, Port: sn.Port, Status: "Unavailable"})
                        available = false
                } else {
@@ -116,6 +126,19 @@ func checkAgentServerStatus(lsBackup *model.LsBackup) bool 
{
 
        t.Render()
 
+       for _, node := range lsBackup.SsBackup.StorageNodes {
+               if _, ok := asMap[node.IP]; ok {
+                       asDuplicate = true
+                       break
+               }
+               asMap[node.IP] = true
+       }
+
+       if asDuplicate {
+               logging.Error("IMPORTANT!: we don't support multiple agent 
server run on the same host.\n")
+               return false
+       }
+
        return available
 }
 
diff --git a/pitr/cli/internal/pkg/agent-server.go 
b/pitr/cli/internal/pkg/agent-server.go
index 9a35146..d6286a9 100644
--- a/pitr/cli/internal/pkg/agent-server.go
+++ b/pitr/cli/internal/pkg/agent-server.go
@@ -25,21 +25,21 @@ import (
        "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg/model"
        "github.com/apache/shardingsphere-on-cloud/pitr/cli/internal/pkg/xerr"
        "github.com/apache/shardingsphere-on-cloud/pitr/cli/pkg/httputils"
-       "github.com/google/uuid"
 )
 
 type agentServer struct {
        addr string
 
-       _apiBackup     string
-       _apiRestore    string
-       _apiShowDetail string
-       _apiShowList   string
-       _apiDiskspace  string
+       _apiBackup      string
+       _apiRestore     string
+       _apiShowDetail  string
+       _apiShowList    string
+       _apiDiskspace   string
+       _apiHealthCheck string
 }
 
 type IAgentServer interface {
-       CheckStatus() error
+       CheckStatus(in *model.HealthCheckIn) error
        Backup(in *model.BackupIn) (string, error)
        DeleteBackup(in *model.DeleteBackupIn) error
        Restore(in *model.RestoreIn) error
@@ -54,26 +54,25 @@ func NewAgentServer(addr string) IAgentServer {
        return &agentServer{
                addr: addr,
 
-               _apiBackup:     "/api/backup",
-               _apiRestore:    "/api/restore",
-               _apiShowDetail: "/api/show",
-               _apiShowList:   "/api/show/list",
-               _apiDiskspace:  "/api/diskspace",
+               _apiBackup:      "/api/backup",
+               _apiRestore:     "/api/restore",
+               _apiShowDetail:  "/api/show",
+               _apiShowList:    "/api/show/list",
+               _apiDiskspace:   "/api/diskspace",
+               _apiHealthCheck: "/api/healthz",
        }
 }
 
 // CheckStatus check agent server is alive
-func (as *agentServer) CheckStatus() error {
-       url := fmt.Sprintf("%s/%s", as.addr, "ping")
-       r := httputils.NewRequest(context.Background(), http.MethodGet, url)
-       httpCode, err := r.Send(nil)
-       if err != nil {
-               efmt := "httputils.NewRequest[url=%s] return err=%s,wrap=%w"
-               return fmt.Errorf(efmt, url, err, xerr.NewCliErr(xerr.Unknown))
-       }
-       if httpCode != http.StatusOK {
-               return fmt.Errorf("httpCode=%d", httpCode)
+func (as *agentServer) CheckStatus(in *model.HealthCheckIn) error {
+       url := fmt.Sprintf("%s%s", as.addr, as._apiHealthCheck)
+
+       r := httputils.NewRequest(context.Background(), http.MethodPost, url)
+
+       if err := r.Send(in); err != nil {
+               return xerr.NewUnknownErr(url, in, nil, err)
        }
+
        return nil
 }
 
@@ -82,25 +81,14 @@ func (as *agentServer) Backup(in *model.BackupIn) (string, 
error) {
 
        out := &model.BackupOutResp{}
        r := httputils.NewRequest(context.Background(), http.MethodPost, url)
-       r.Header(map[string]string{
-               "x-request-id": uuid.New().String(),
-               "content-type": "application/json",
-       })
        r.Body(in)
 
-       httpCode, err := r.Send(out)
-       if err != nil {
-               efmt := "httputils.NewRequest[url=%s,body=%v,out=%v] return 
err=%s,wrap=%w"
-               return "", fmt.Errorf(efmt, url, in, out, err, 
xerr.NewCliErr(xerr.Unknown))
-       }
-
-       if httpCode != http.StatusOK {
-               return "", fmt.Errorf("unknown http status[code=%d],err=%w", 
httpCode, xerr.NewCliErr(xerr.InvalidHTTPStatus))
+       if err := r.Send(out); err != nil {
+               return "", xerr.NewUnknownErr(url, in, out, err)
        }
 
        if out.Code != 0 {
-               asErr := xerr.NewAgentServerErr(out.Code, out.Msg)
-               return "", fmt.Errorf("agent server 
error[code=%d,msg=%s],err=%w", out.Code, out.Msg, asErr)
+               return "", xerr.NewAgentServerErr(out.Code, out.Msg)
        }
 
        return out.Data.ID, nil
@@ -112,24 +100,14 @@ func (as *agentServer) Restore(in *model.RestoreIn) error 
{
 
        out := &model.RestoreResp{}
        r := httputils.NewRequest(context.Background(), http.MethodPost, url)
-       r.Header(map[string]string{
-               "x-request-id": uuid.New().String(),
-               "content-type": "application/json",
-       })
        r.Body(in)
-       httpCode, err := r.Send(out)
-       if err != nil {
-               efmt := "httputils.NewRequest[url=%s,body=%v,out=%v] return 
err=%s,wrap=%w"
-               return fmt.Errorf(efmt, url, in, out, err, 
xerr.NewCliErr(xerr.Unknown))
-       }
 
-       if httpCode != http.StatusOK {
-               return fmt.Errorf("unknown http status[code=%d],err=%w", 
httpCode, xerr.NewCliErr(xerr.InvalidHTTPStatus))
+       if err := r.Send(out); err != nil {
+               return xerr.NewUnknownErr(url, in, out, err)
        }
 
        if out.Code != 0 {
-               asErr := xerr.NewAgentServerErr(out.Code, out.Msg)
-               return fmt.Errorf("agent server error[code=%d,msg=%s],err=%w", 
out.Code, out.Msg, asErr)
+               return xerr.NewAgentServerErr(out.Code, out.Msg)
        }
 
        return nil
@@ -140,24 +118,14 @@ func (as *agentServer) ShowDetail(in *model.ShowDetailIn) 
(*model.BackupInfo, er
 
        out := &model.BackupDetailResp{}
        r := httputils.NewRequest(context.Background(), http.MethodPost, url)
-       r.Header(map[string]string{
-               "x-request-id": uuid.New().String(),
-               "content-type": "application/json",
-       })
        r.Body(in)
-       httpCode, err := r.Send(out)
-       if err != nil {
-               efmt := "httputils.NewRequest[url=%s,body=%v,out=%v] return 
err=%s,wrap=%w"
-               return nil, fmt.Errorf(efmt, url, in, out, err, 
xerr.NewCliErr(xerr.Unknown))
-       }
 
-       if httpCode != http.StatusOK {
-               return nil, fmt.Errorf("unknown http status[code=%d],err=%w", 
httpCode, xerr.NewCliErr(xerr.InvalidHTTPStatus))
+       if err := r.Send(out); err != nil {
+               return nil, xerr.NewUnknownErr(url, in, out, err)
        }
 
        if out.Code != 0 {
-               asErr := xerr.NewAgentServerErr(out.Code, out.Msg)
-               return nil, fmt.Errorf("agent server 
error[code=%d,msg=%s],err=%w", out.Code, out.Msg, asErr)
+               return nil, xerr.NewAgentServerErr(out.Code, out.Msg)
        }
 
        return &out.Data, nil
@@ -168,24 +136,14 @@ func (as *agentServer) ShowList(in *model.ShowListIn) 
([]model.BackupInfo, error
 
        out := &model.BackupListResp{}
        r := httputils.NewRequest(context.Background(), http.MethodPost, url)
-       r.Header(map[string]string{
-               "x-request-id": uuid.New().String(),
-               "content-type": "application/json",
-       })
        r.Body(in)
-       httpCode, err := r.Send(out)
-       if err != nil {
-               efmt := "httputils.NewRequest[url=%s,body=%v,out=%v] return 
err=%s,wrap=%w"
-               return nil, fmt.Errorf(efmt, url, in, out, err, 
xerr.NewCliErr(xerr.Unknown))
-       }
 
-       if httpCode != http.StatusOK {
-               return nil, fmt.Errorf("unknown http status[code=%d],err=%w", 
httpCode, xerr.NewCliErr(xerr.InvalidHTTPStatus))
+       if err := r.Send(out); err != nil {
+               return nil, xerr.NewUnknownErr(url, in, out, err)
        }
 
        if out.Code != 0 {
-               asErr := xerr.NewAgentServerErr(out.Code, out.Msg)
-               return nil, fmt.Errorf("agent server 
error[code=%d,msg=%s],err=%w", out.Code, out.Msg, asErr)
+               return nil, xerr.NewAgentServerErr(out.Code, out.Msg)
        }
 
        return out.Data, nil
@@ -196,25 +154,14 @@ func (as *agentServer) ShowDiskSpace(in 
*model.DiskSpaceIn) (*model.DiskSpaceInf
 
        out := &model.DiskSpaceInfo{}
        r := httputils.NewRequest(context.Background(), http.MethodPost, url)
-       r.Header(map[string]string{
-               "x-request-id": uuid.New().String(),
-               "content-type": "application/json",
-       })
        r.Body(in)
 
-       httpCode, err := r.Send(out)
-       if err != nil {
-               efmt := "httputils.NewRequest[url=%s,body=%v,out=%v] return 
err=%s,wrap=%w"
-               return nil, fmt.Errorf(efmt, url, in, out, err, 
xerr.NewCliErr(xerr.Unknown))
-       }
-
-       if httpCode != http.StatusOK {
-               return nil, fmt.Errorf("unknown http status[code=%d],err=%w", 
httpCode, xerr.NewCliErr(xerr.InvalidHTTPStatus))
+       if err := r.Send(out); err != nil {
+               return nil, xerr.NewUnknownErr(url, in, out, err)
        }
 
        if out.Code != 0 {
-               asErr := xerr.NewAgentServerErr(out.Code, out.Msg)
-               return nil, fmt.Errorf("agent server 
error[code=%d,msg=%s],err=%w", out.Code, out.Msg, asErr)
+               return nil, xerr.NewAgentServerErr(out.Code, out.Msg)
        }
 
        return out, nil
@@ -226,25 +173,14 @@ func (as *agentServer) DeleteBackup(in 
*model.DeleteBackupIn) error {
 
        out := &model.DeleteBackupOut{}
        r := httputils.NewRequest(context.Background(), http.MethodDelete, url)
-       r.Header(map[string]string{
-               "x-request-id": uuid.New().String(),
-               "content-type": "application/json",
-       })
        r.Body(in)
 
-       httpCode, err := r.Send(out)
-       if err != nil {
-               efmt := "httputils.NewRequest[url=%s,body=%v,out=%v] return 
err=%s,wrap=%w"
-               return fmt.Errorf(efmt, url, in, out, err, 
xerr.NewCliErr(xerr.Unknown))
-       }
-
-       if httpCode != http.StatusOK {
-               return fmt.Errorf("unknown http status[code=%d],err=%w", 
httpCode, xerr.NewCliErr(xerr.InvalidHTTPStatus))
+       if err := r.Send(out); err != nil {
+               return xerr.NewUnknownErr(url, in, out, err)
        }
 
        if out.Code != 0 {
-               asErr := xerr.NewAgentServerErr(out.Code, out.Msg)
-               return fmt.Errorf("agent server error[code=%d,msg=%s],err=%w", 
out.Code, out.Msg, asErr)
+               return xerr.NewAgentServerErr(out.Code, out.Msg)
        }
 
        return nil
diff --git a/pitr/cli/internal/pkg/agent-server_test.go 
b/pitr/cli/internal/pkg/agent-server_test.go
index 1bf05f2..e76b8f3 100644
--- a/pitr/cli/internal/pkg/agent-server_test.go
+++ b/pitr/cli/internal/pkg/agent-server_test.go
@@ -132,7 +132,6 @@ var _ = Describe("AgentServer", func() {
                as = NewAgentServer("http://agent-server:18080";)
                ctrl = gomock.NewController(GinkgoT())
                req = mock_httputils.NewMockIreq(ctrl)
-               req.EXPECT().Header(gomock.Any())
                req.EXPECT().Body(gomock.Any())
                monkey.Patch(httputils.NewRequest, func(c context.Context, 
method, url string) httputils.Ireq {
                        return req
@@ -145,7 +144,7 @@ var _ = Describe("AgentServer", func() {
 
        Context("backup", func() {
                It("backup failed", func() {
-                       req.EXPECT().Send(gomock.Any()).Return(-1, 
fmt.Errorf("error"))
+                       
req.EXPECT().Send(gomock.Any()).Return(fmt.Errorf("error"))
                        _, err := as.Backup(&model.BackupIn{})
                        Expect(err).ShouldNot(BeNil())
                })
@@ -153,7 +152,7 @@ var _ = Describe("AgentServer", func() {
                It("backup success", func() {
                        req.EXPECT().Send(gomock.Any()).Do(func(i 
*model.BackupOutResp) {
                                i.Data.ID = "backup-id"
-                       }).Return(200, nil)
+                       }).Return(nil)
                        as := NewAgentServer("http://agent-server:18080";)
                        resp, err := as.Backup(&model.BackupIn{})
                        Expect(err).Should(BeNil())
@@ -163,13 +162,13 @@ var _ = Describe("AgentServer", func() {
 
        Context("restore", func() {
                It("restore failed", func() {
-                       req.EXPECT().Send(gomock.Any()).Return(-1, 
fmt.Errorf("error"))
+                       
req.EXPECT().Send(gomock.Any()).Return(fmt.Errorf("error"))
                        err := as.Restore(&model.RestoreIn{})
                        Expect(err).ShouldNot(BeNil())
                })
                // restore success
                It("restore success", func() {
-                       req.EXPECT().Send(gomock.Any()).Return(200, nil)
+                       req.EXPECT().Send(gomock.Any()).Return(nil)
                        err := as.Restore(&model.RestoreIn{})
                        Expect(err).Should(BeNil())
                })
@@ -178,7 +177,7 @@ var _ = Describe("AgentServer", func() {
 
        Context("show detail", func() {
                It("show detail failed", func() {
-                       req.EXPECT().Send(gomock.Any()).Return(-1, 
fmt.Errorf("error"))
+                       
req.EXPECT().Send(gomock.Any()).Return(fmt.Errorf("error"))
                        _, err := as.ShowDetail(&model.ShowDetailIn{})
                        Expect(err).ShouldNot(BeNil())
                })
@@ -186,7 +185,7 @@ var _ = Describe("AgentServer", func() {
                It("show detail success", func() {
                        req.EXPECT().Send(gomock.Any()).Do(func(i 
*model.BackupDetailResp) {
                                i.Data = model.BackupInfo{}
-                       }).Return(200, nil)
+                       }).Return(nil)
                        resp, err := as.ShowDetail(&model.ShowDetailIn{})
                        Expect(err).Should(BeNil())
                        Expect(resp).Should(Equal(&model.BackupInfo{}))
@@ -195,7 +194,7 @@ var _ = Describe("AgentServer", func() {
 
        Context("show list", func() {
                It("show list failed", func() {
-                       req.EXPECT().Send(gomock.Any()).Return(-1, 
fmt.Errorf("error"))
+                       
req.EXPECT().Send(gomock.Any()).Return(fmt.Errorf("error"))
                        _, err := as.ShowList(&model.ShowListIn{})
                        Expect(err).ShouldNot(BeNil())
                })
@@ -203,7 +202,7 @@ var _ = Describe("AgentServer", func() {
                It("show list success", func() {
                        req.EXPECT().Send(gomock.Any()).Do(func(i 
*model.BackupListResp) {
                                i.Data = []model.BackupInfo{}
-                       }).Return(200, nil)
+                       }).Return(nil)
                        resp, err := as.ShowList(&model.ShowListIn{})
                        Expect(err).Should(BeNil())
                        Expect(resp).Should(Equal([]model.BackupInfo{}))
diff --git a/pitr/cli/internal/pkg/mocks/agent-server.go 
b/pitr/cli/internal/pkg/mocks/agent-server.go
index e736033..c9047d8 100644
--- a/pitr/cli/internal/pkg/mocks/agent-server.go
+++ b/pitr/cli/internal/pkg/mocks/agent-server.go
@@ -50,17 +50,17 @@ func (mr *MockIAgentServerMockRecorder) Backup(in 
interface{}) *gomock.Call {
 }
 
 // CheckStatus mocks base method.
-func (m *MockIAgentServer) CheckStatus() error {
+func (m *MockIAgentServer) CheckStatus(in *model.HealthCheckIn) error {
        m.ctrl.T.Helper()
-       ret := m.ctrl.Call(m, "CheckStatus")
+       ret := m.ctrl.Call(m, "CheckStatus", in)
        ret0, _ := ret[0].(error)
        return ret0
 }
 
 // CheckStatus indicates an expected call of CheckStatus.
-func (mr *MockIAgentServerMockRecorder) CheckStatus() *gomock.Call {
+func (mr *MockIAgentServerMockRecorder) CheckStatus(in interface{}) 
*gomock.Call {
        mr.mock.ctrl.T.Helper()
-       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckStatus", 
reflect.TypeOf((*MockIAgentServer)(nil).CheckStatus))
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckStatus", 
reflect.TypeOf((*MockIAgentServer)(nil).CheckStatus), in)
 }
 
 // DeleteBackup mocks base method.
diff --git a/pitr/cli/internal/pkg/model/as_healthcheck.go 
b/pitr/cli/internal/pkg/model/as_healthcheck.go
new file mode 100644
index 0000000..4dae579
--- /dev/null
+++ b/pitr/cli/internal/pkg/model/as_healthcheck.go
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 model
+
+type HealthCheckIn struct {
+       DBPort   uint16 `json:"db_port"`
+       DBName   string `json:"db_name"`
+       Username string `json:"username"`
+       Password string `json:"password"`
+}
diff --git a/pitr/cli/internal/pkg/xerr/err.go 
b/pitr/cli/internal/pkg/xerr/err.go
index 5e363d6..66f8dd3 100644
--- a/pitr/cli/internal/pkg/xerr/err.go
+++ b/pitr/cli/internal/pkg/xerr/err.go
@@ -24,6 +24,8 @@ type err struct {
 }
 
 const (
+       postErrFmt = "httputils.NewRequest[url=%s,body=%v,out=%v] return 
err=%s,wrap=%w"
+
        Unknown           = "Unknown error"
        InvalidHTTPStatus = "Invalid http status"
        NotFound          = "Not found"
@@ -39,6 +41,10 @@ func NewCliErr(msg string) error {
        }
 }
 
+func NewUnknownErr(url string, in, out interface{}, err error) error {
+       return fmt.Errorf(postErrFmt, url, in, out, err, NewCliErr(Unknown))
+}
+
 func NewAgentServerErr(code int, msg string) error {
        return &err{
                msg: fmt.Sprintf("agent server err[code=%d,msg=%s]", code, msg),
diff --git a/pitr/cli/pkg/httputils/mocks/req.go 
b/pitr/cli/pkg/httputils/mocks/req.go
index 0cfe247..c7bc91a 100644
--- a/pitr/cli/pkg/httputils/mocks/req.go
+++ b/pitr/cli/pkg/httputils/mocks/req.go
@@ -1,22 +1,5 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You 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.
- */
-
 // Code generated by MockGen. DO NOT EDIT.
-// Source: pkg/httputils/req.go
+// Source: req.go
 
 // Package mock_httputils is a generated GoMock package.
 package mock_httputils
@@ -87,12 +70,11 @@ func (mr *MockIreqMockRecorder) Query(m interface{}) 
*gomock.Call {
 }
 
 // Send mocks base method.
-func (m *MockIreq) Send(body any) (int, error) {
+func (m *MockIreq) Send(body any) error {
        m.ctrl.T.Helper()
        ret := m.ctrl.Call(m, "Send", body)
-       ret0, _ := ret[0].(int)
-       ret1, _ := ret[1].(error)
-       return ret0, ret1
+       ret0, _ := ret[0].(error)
+       return ret0
 }
 
 // Send indicates an expected call of Send.
diff --git a/pitr/cli/pkg/httputils/req.go b/pitr/cli/pkg/httputils/req.go
index 7d99079..61ae871 100644
--- a/pitr/cli/pkg/httputils/req.go
+++ b/pitr/cli/pkg/httputils/req.go
@@ -26,6 +26,8 @@ import (
        "io"
        "net/http"
        "strings"
+
+       "github.com/google/uuid"
 )
 
 type req struct {
@@ -41,7 +43,7 @@ type Ireq interface {
        Header(h map[string]string)
        Body(b any)
        Query(m map[string]string)
-       Send(body any) (int, error)
+       Send(body any) error
 }
 
 func NewRequest(ctx context.Context, method, url string) Ireq {
@@ -68,7 +70,7 @@ func (r *req) Query(m map[string]string) {
        r.query = m
 }
 
-func (r *req) Send(body any) (int, error) {
+func (r *req) Send(body any) error {
        var (
                bs  []byte
                err error
@@ -77,19 +79,29 @@ func (r *req) Send(body any) (int, error) {
        if r.body != nil {
                bs, err = json.Marshal(r.body)
                if err != nil {
-                       return -1, fmt.Errorf("json.Marshal return err=%w", err)
+                       return fmt.Errorf("json.Marshal return err=%w", err)
                }
        }
 
        _req, err := http.NewRequestWithContext(r.ctx, r.method, r.url, 
bytes.NewReader(bs))
        if err != nil {
-               return -1, fmt.Errorf("new request failure,err=%w", err)
+               return fmt.Errorf("new request failure,err=%w", err)
        }
 
        for k, v := range r.header {
                _req.Header.Set(k, v)
        }
 
+       // set default header
+       if r.method == http.MethodPost {
+               if _req.Header.Get("Content-Type") == "" {
+                       _req.Header.Set("Content-Type", "application/json")
+               }
+               if _req.Header.Get("x-request-id") == "" {
+                       _req.Header.Set("x-request-id", uuid.New().String())
+               }
+       }
+
        for k, v := range r.query {
                values := _req.URL.Query()
                values.Add(k, v)
@@ -103,20 +115,24 @@ func (r *req) Send(body any) (int, error) {
        c := &http.Client{Transport: tr}
        resp, err := c.Do(_req)
        if err != nil {
-               return -1, fmt.Errorf("http request err=%w", err)
+               return fmt.Errorf("http request err=%w", err)
        }
 
        defer resp.Body.Close()
 
        all, err := io.ReadAll(resp.Body)
        if err != nil {
-               return -1, fmt.Errorf("invalid response,err=%w", err)
+               return fmt.Errorf("invalid response,err=%w", err)
        }
        if body != nil {
                if err = json.Unmarshal(all, body); err != nil {
-                       return -1, fmt.Errorf("json unmarshal return err=%w", 
err)
+                       return fmt.Errorf("json unmarshal return err=%w", err)
                }
        }
 
-       return resp.StatusCode, nil
+       if resp.StatusCode != http.StatusOK {
+               return fmt.Errorf("response status code is not 200, code=%d", 
resp.StatusCode)
+       }
+
+       return nil
 }
diff --git 
a/shardingsphere-operator/pkg/kubernetes/deployment/deployment_test.go 
b/shardingsphere-operator/pkg/kubernetes/deployment/deployment_test.go
index 2267ff0..d1270cd 100644
--- a/shardingsphere-operator/pkg/kubernetes/deployment/deployment_test.go
+++ b/shardingsphere-operator/pkg/kubernetes/deployment/deployment_test.go
@@ -273,7 +273,7 @@ func Test_NewDeployment(t *testing.T) {
                                                "k1": "v1",
                                        },
                                        Annotations: map[string]string{
-                                               "anno1": "value1",
+                                               
defaultAnnotationJavaAgentEnabled: "true",
                                        },
                                },
                                Spec: appsv1.DeploymentSpec{

Reply via email to