You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by zh...@apache.org on 2021/12/14 11:26:42 UTC

[apisix-ingress-controller] branch master updated: feat: implement apisix healthz check (#770)

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 <ma...@yahoo.co.jp>
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")