From 1d12fbf5e9356615d0659e43f2046565211d27fb Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Thu, 1 Aug 2024 17:10:15 +0200 Subject: [PATCH] core: add -failing filter to health command (#13989) --- core/cmd/app.go | 4 ++ core/cmd/shell_remote.go | 6 ++- core/web/health_controller.go | 4 ++ core/web/health_controller_test.go | 12 ++++++ core/web/testdata/body/health-failing.html | 47 ++++++++++++++++++++++ core/web/testdata/body/health-failing.json | 1 + core/web/testdata/body/health-failing.txt | 2 + testdata/scripts/health/help.txtar | 3 +- testdata/scripts/health/multi-chain.txtar | 26 ++++++++++++ 9 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 core/web/testdata/body/health-failing.html create mode 100644 core/web/testdata/body/health-failing.json create mode 100644 core/web/testdata/body/health-failing.txt diff --git a/core/cmd/app.go b/core/cmd/app.go index 1ccb3da9a01..53c96980de4 100644 --- a/core/cmd/app.go +++ b/core/cmd/app.go @@ -168,6 +168,10 @@ func NewApp(s *Shell) *cli.App { Usage: "Prints a health report", Action: s.Health, Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "failing, f", + Usage: "filter for failing services", + }, cli.BoolFlag{ Name: "json, j", Usage: "json output", diff --git a/core/cmd/shell_remote.go b/core/cmd/shell_remote.go index aab4a94da6f..0aa3f3837dc 100644 --- a/core/cmd/shell_remote.go +++ b/core/cmd/shell_remote.go @@ -517,7 +517,11 @@ func (s *Shell) Health(c *cli.Context) error { if c.Bool("json") { mime = gin.MIMEJSON } - resp, err := s.HTTP.Get(s.ctx(), "/health", map[string]string{"Accept": mime}) + u := "/health" + if c.Bool("failing") { + u += "?failing" + } + resp, err := s.HTTP.Get(s.ctx(), u, map[string]string{"Accept": mime}) if err != nil { return s.errorOut(err) } diff --git a/core/web/health_controller.go b/core/web/health_controller.go index bd775671d73..ee08c39fcf1 100644 --- a/core/web/health_controller.go +++ b/core/web/health_controller.go @@ -69,6 +69,8 @@ func (hc *HealthController) Readyz(c *gin.Context) { } func (hc *HealthController) Health(c *gin.Context) { + _, failing := c.GetQuery("failing") + status := http.StatusOK checker := hc.App.GetHealthChecker() @@ -89,6 +91,8 @@ func (hc *HealthController) Health(c *gin.Context) { if err != nil { status = HealthStatusFailing output = err.Error() + } else if failing { + continue // omit from returned data } checks = append(checks, presenters.Check{ diff --git a/core/web/health_controller_test.go b/core/web/health_controller_test.go index 21da1fb2e44..14367b1e4bb 100644 --- a/core/web/health_controller_test.go +++ b/core/web/health_controller_test.go @@ -97,6 +97,12 @@ var ( bodyHTML string //go:embed testdata/body/health.txt bodyTXT string + //go:embed testdata/body/health-failing.json + bodyJSONFailing string + //go:embed testdata/body/health-failing.html + bodyHTMLFailing string + //go:embed testdata/body/health-failing.txt + bodyTXTFailing string ) func TestHealthController_Health_body(t *testing.T) { @@ -111,6 +117,12 @@ func TestHealthController_Health_body(t *testing.T) { {"html", "/health", map[string]string{"Accept": gin.MIMEHTML}, bodyHTML}, {"text", "/health", map[string]string{"Accept": gin.MIMEPlain}, bodyTXT}, {".txt", "/health.txt", nil, bodyTXT}, + + {"default-failing", "/health?failing", nil, bodyJSONFailing}, + {"json-failing", "/health?failing", map[string]string{"Accept": gin.MIMEJSON}, bodyJSONFailing}, + {"html-failing", "/health?failing", map[string]string{"Accept": gin.MIMEHTML}, bodyHTMLFailing}, + {"text-failing", "/health?failing", map[string]string{"Accept": gin.MIMEPlain}, bodyTXTFailing}, + {".txt-failing", "/health.txt?failing", nil, bodyTXTFailing}, } { t.Run(tc.name, func(t *testing.T) { app := cltest.NewApplicationWithKey(t) diff --git a/core/web/testdata/body/health-failing.html b/core/web/testdata/body/health-failing.html new file mode 100644 index 00000000000..6b667a3ba69 --- /dev/null +++ b/core/web/testdata/body/health-failing.html @@ -0,0 +1,47 @@ + +
+ EVM +
+ 0 +
+ HeadTracker +
+ HeadListener +
Listener is not connected
+
+
+
+
diff --git a/core/web/testdata/body/health-failing.json b/core/web/testdata/body/health-failing.json new file mode 100644 index 00000000000..185b98b8da5 --- /dev/null +++ b/core/web/testdata/body/health-failing.json @@ -0,0 +1 @@ +{"data":[{"type":"checks","id":"EVM.0.HeadTracker.HeadListener","attributes":{"name":"EVM.0.HeadTracker.HeadListener","status":"failing","output":"Listener is not connected"}}]} diff --git a/core/web/testdata/body/health-failing.txt b/core/web/testdata/body/health-failing.txt new file mode 100644 index 00000000000..c6b948c3f93 --- /dev/null +++ b/core/web/testdata/body/health-failing.txt @@ -0,0 +1,2 @@ +! EVM.0.HeadTracker.HeadListener + Listener is not connected diff --git a/testdata/scripts/health/help.txtar b/testdata/scripts/health/help.txtar index 07eb0509e73..68176f05a4e 100644 --- a/testdata/scripts/health/help.txtar +++ b/testdata/scripts/health/help.txtar @@ -9,5 +9,6 @@ USAGE: chainlink health [command options] [arguments...] OPTIONS: - --json, -j json output + --failing, -f filter for failing services + --json, -j json output diff --git a/testdata/scripts/health/multi-chain.txtar b/testdata/scripts/health/multi-chain.txtar index 8178f8e8213..7e01493b30b 100644 --- a/testdata/scripts/health/multi-chain.txtar +++ b/testdata/scripts/health/multi-chain.txtar @@ -15,6 +15,14 @@ cp stdout compact.json exec jq . compact.json cmp stdout out.json +exec chainlink --remote-node-url $NODEURL health -failing +cmp stdout out-unhealthy.txt + +exec chainlink --remote-node-url $NODEURL health -f -json +cp stdout compact.json +exec jq . compact.json +cmp stdout out-unhealthy.json + -- testdb.txt -- CL_DATABASE_URL -- testport.txt -- @@ -87,6 +95,10 @@ ok Solana.Bar ok StarkNet.Baz ok TelemetryManager +-- out-unhealthy.txt -- +! EVM.1.HeadTracker.HeadListener + Listener is not connected + -- out.json -- { "data": [ @@ -317,3 +329,17 @@ ok TelemetryManager } ] } +-- out-unhealthy.json -- +{ + "data": [ + { + "type": "checks", + "id": "EVM.1.HeadTracker.HeadListener", + "attributes": { + "name": "EVM.1.HeadTracker.HeadListener", + "status": "failing", + "output": "Listener is not connected" + } + } + ] +}