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")