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

zhangjintao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 6110bf5  feat: implement apisix healthz check (#770)
6110bf5 is described below

commit 6110bf54e3185e137fc68cb24771c3170c5c6ce5
Author: Mayo Cream <[email protected]>
AuthorDate: Tue Dec 14 19:26:34 2021 +0800

    feat: implement apisix healthz check (#770)
---
 pkg/api/router/{router.go => apisix_healthz.go} | 40 ++++++++++---------------
 pkg/api/router/router.go                        |  1 -
 pkg/api/router/router_test.go                   | 16 ++++++++++
 pkg/api/router/{router.go => types.go}          | 35 ++++------------------
 pkg/api/server.go                               |  4 +++
 pkg/ingress/controller.go                       |  4 +++
 6 files changed, 45 insertions(+), 55 deletions(-)

diff --git a/pkg/api/router/router.go b/pkg/api/router/apisix_healthz.go
similarity index 60%
copy from pkg/api/router/router.go
copy to pkg/api/router/apisix_healthz.go
index 88063fd..63b871d 100644
--- a/pkg/api/router/router.go
+++ b/pkg/api/router/apisix_healthz.go
@@ -19,32 +19,24 @@ import (
        "net/http"
 
        "github.com/gin-gonic/gin"
-       "github.com/prometheus/client_golang/prometheus/promhttp"
 )
 
-type healthzResponse struct {
-       Status string `json:"status"`
+// MountWebhooks mounts apisix healthz route.
+func MountApisixHealthz(r *gin.Engine, state *HealthState) {
+       r.GET("/apisix/healthz", apisixHealthz(state))
 }
 
-func mountHealthz(r *gin.Engine) {
-       r.GET("/healthz", healthz)
-       r.GET("/apisix/healthz", healthz)
-}
-
-func healthz(c *gin.Context) {
-       c.AbortWithStatusJSON(http.StatusOK, healthzResponse{Status: "ok"})
-}
-
-func mountMetrics(r *gin.Engine) {
-       r.GET("/metrics", metrics)
-}
-
-func metrics(c *gin.Context) {
-       promhttp.Handler().ServeHTTP(c.Writer, c.Request)
-}
-
-// Mount mounts all api routers.
-func Mount(r *gin.Engine) {
-       mountHealthz(r)
-       mountMetrics(r)
+func apisixHealthz(state *HealthState) gin.HandlerFunc {
+       return func(c *gin.Context) {
+               state.RLock()
+               err := state.Err
+               state.RUnlock()
+
+               if err != nil {
+                       c.AbortWithStatusJSON(http.StatusInternalServerError,
+                               healthzResponse{Status: err.Error()})
+                       return
+               }
+               c.AbortWithStatusJSON(http.StatusOK, healthzResponse{Status: 
"ok"})
+       }
 }
diff --git a/pkg/api/router/router.go b/pkg/api/router/router.go
index 88063fd..ea8cd88 100644
--- a/pkg/api/router/router.go
+++ b/pkg/api/router/router.go
@@ -28,7 +28,6 @@ type healthzResponse struct {
 
 func mountHealthz(r *gin.Engine) {
        r.GET("/healthz", healthz)
-       r.GET("/apisix/healthz", healthz)
 }
 
 func healthz(c *gin.Context) {
diff --git a/pkg/api/router/router_test.go b/pkg/api/router/router_test.go
index 0063276..28c73ac 100644
--- a/pkg/api/router/router_test.go
+++ b/pkg/api/router/router_test.go
@@ -41,6 +41,22 @@ func TestHealthz(t *testing.T) {
        assert.Equal(t, healthzResponse{Status: "ok"}, resp)
 }
 
+func TestApisixHealthz(t *testing.T) {
+       w := httptest.NewRecorder()
+       c, r := gin.CreateTestContext(w)
+       var state HealthState
+       MountApisixHealthz(r, &state)
+       apisixHealthz(&state)(c)
+
+       assert.Equal(t, w.Code, http.StatusOK)
+
+       var resp healthzResponse
+       dec := json.NewDecoder(w.Body)
+       assert.Nil(t, dec.Decode(&resp))
+
+       assert.Equal(t, resp, healthzResponse{Status: "ok"})
+}
+
 func TestMetrics(t *testing.T) {
        w := httptest.NewRecorder()
        c, r := gin.CreateTestContext(w)
diff --git a/pkg/api/router/router.go b/pkg/api/router/types.go
similarity index 56%
copy from pkg/api/router/router.go
copy to pkg/api/router/types.go
index 88063fd..21cbbfe 100644
--- a/pkg/api/router/router.go
+++ b/pkg/api/router/types.go
@@ -15,36 +15,11 @@
 
 package router
 
-import (
-       "net/http"
+import "sync"
 
-       "github.com/gin-gonic/gin"
-       "github.com/prometheus/client_golang/prometheus/promhttp"
-)
+// HealthState stores healthcheck err of APISIX
+type HealthState struct {
+       sync.RWMutex
 
-type healthzResponse struct {
-       Status string `json:"status"`
-}
-
-func mountHealthz(r *gin.Engine) {
-       r.GET("/healthz", healthz)
-       r.GET("/apisix/healthz", healthz)
-}
-
-func healthz(c *gin.Context) {
-       c.AbortWithStatusJSON(http.StatusOK, healthzResponse{Status: "ok"})
-}
-
-func mountMetrics(r *gin.Engine) {
-       r.GET("/metrics", metrics)
-}
-
-func metrics(c *gin.Context) {
-       promhttp.Handler().ServeHTTP(c.Writer, c.Request)
-}
-
-// Mount mounts all api routers.
-func Mount(r *gin.Engine) {
-       mountHealthz(r)
-       mountMetrics(r)
+       Err error
 }
diff --git a/pkg/api/server.go b/pkg/api/server.go
index 87f1b0b..6474d46 100644
--- a/pkg/api/server.go
+++ b/pkg/api/server.go
@@ -35,6 +35,7 @@ import (
 
 // Server represents the API Server in ingress-apisix-controller.
 type Server struct {
+       HealthState     *apirouter.HealthState
        httpServer      *gin.Engine
        admissionServer *http.Server
        httpListener    net.Listener
@@ -53,9 +54,12 @@ func NewServer(cfg *config.Config) (*Server, error) {
        apirouter.Mount(httpServer)
 
        srv := &Server{
+               HealthState:  new(apirouter.HealthState),
                httpServer:   httpServer,
                httpListener: httpListener,
        }
+       apirouter.MountApisixHealthz(httpServer, srv.HealthState)
+
        if cfg.EnableProfiling {
                srv.pprofMu = new(http.ServeMux)
                srv.pprofMu.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
diff --git a/pkg/ingress/controller.go b/pkg/ingress/controller.go
index 917fd61..8f80bcb 100644
--- a/pkg/ingress/controller.go
+++ b/pkg/ingress/controller.go
@@ -650,6 +650,10 @@ func (c *Controller) checkClusterHealth(ctx 
context.Context, cancelFunc context.
                if err != nil {
                        // Finally failed health check, then give up leader.
                        log.Warnf("failed to check health for default cluster: 
%s, give up leader", err)
+                       c.apiServer.HealthState.Lock()
+                       defer c.apiServer.HealthState.Unlock()
+
+                       c.apiServer.HealthState.Err = err
                        return
                }
                log.Debugf("success check health for default cluster")

Reply via email to