From ef23442cabfac8670a159f128c90951a24a087cc Mon Sep 17 00:00:00 2001 From: arthurgavazza Date: Thu, 20 Apr 2023 08:18:38 -0300 Subject: [PATCH 1/6] feat: add health endpoint --- api/common/api.go | 7 ++++++- api/pinsvcapi/pinsvcapi.go | 8 +++++++- api/pinsvcapi/pinsvcapi_test.go | 16 ++++++++++++++++ api/rest/client/client.go | 3 +++ api/rest/client/methods.go | 7 +++++++ api/rest/restapi.go | 6 ++++++ api/rest/restapi_test.go | 17 +++++++++++++++++ 7 files changed, 62 insertions(+), 2 deletions(-) diff --git a/api/common/api.go b/api/common/api.go index 9990b199..05f744fe 100644 --- a/api/common/api.go +++ b/api/common/api.go @@ -302,7 +302,7 @@ func (api *API) authHandler(h http.Handler, lggr *logging.ZapEventLogger) http.H wrap := func(w http.ResponseWriter, r *http.Request) { // We let CORS preflight requests pass through the next // handler. - if r.Method == http.MethodOptions { + if r.Method == http.MethodOptions || r.URL.Path == "/health" { h.ServeHTTP(w, r) return } @@ -853,3 +853,8 @@ func (api *API) Headers() map[string][]string { func (api *API) SetKeepAlivesEnabled(b bool) { api.server.SetKeepAlivesEnabled(b) } + + +func (api *API) HealthHandler(w http.ResponseWriter, r *http.Request){ + api.SendResponse(w,http.StatusNoContent,nil,nil) +} \ No newline at end of file diff --git a/api/pinsvcapi/pinsvcapi.go b/api/pinsvcapi/pinsvcapi.go index 127d1672..23a98961 100644 --- a/api/pinsvcapi/pinsvcapi.go +++ b/api/pinsvcapi/pinsvcapi.go @@ -22,9 +22,9 @@ import ( "go.uber.org/multierr" logging "github.com/ipfs/go-log/v2" + rpc "github.com/libp2p/go-libp2p-gorpc" "github.com/libp2p/go-libp2p/core/host" peer "github.com/libp2p/go-libp2p/core/peer" - rpc "github.com/libp2p/go-libp2p-gorpc" ) var ( @@ -178,6 +178,12 @@ func (api *API) routes(c *rpc.Client) []common.Route { Pattern: "/token", HandlerFunc: api.GenerateTokenHandler, }, + { + Name: "Health", + Method: "GET", + Pattern: "/health", + HandlerFunc: api.HealthHandler, + }, } } diff --git a/api/pinsvcapi/pinsvcapi_test.go b/api/pinsvcapi/pinsvcapi_test.go index 545c4e7c..dc787fd1 100644 --- a/api/pinsvcapi/pinsvcapi_test.go +++ b/api/pinsvcapi/pinsvcapi_test.go @@ -251,3 +251,19 @@ func TestAPIRemovePinEndpoint(t *testing.T) { test.BothEndpoints(t, tf) } + +func TestHealthEndpoint(t *testing.T) { + ctx := context.Background() + svcapi := testAPI(t) + defer svcapi.Shutdown(ctx) + + tf := func(t *testing.T, url test.URLFunc) { + errResp := api.Error{} + test.MakeGet(t, svcapi, url(svcapi)+"/health", &errResp) + if errResp.Code != 0 || errResp.Message != "" { + t.Error("expected no errors") + } + } + + test.BothEndpoints(t, tf) +} \ No newline at end of file diff --git a/api/rest/client/client.go b/api/rest/client/client.go index d9780c3c..c9a74290 100644 --- a/api/rest/client/client.go +++ b/api/rest/client/client.go @@ -122,6 +122,9 @@ type Client interface { // returns collected CIDs. If local is true, it would garbage collect // only on contacted peer, otherwise on all peers' IPFS daemons. RepoGC(ctx context.Context, local bool) (api.GlobalRepoGC, error) + + // Health returns no content when everything is ok, and an error otherwise + Health(ctx context.Context) (error) } // Config allows to configure the parameters to connect diff --git a/api/rest/client/methods.go b/api/rest/client/methods.go index 3fd51c25..28b2247b 100644 --- a/api/rest/client/methods.go +++ b/api/rest/client/methods.go @@ -697,3 +697,10 @@ func (c *defaultClient) AddMultiFile( ) return err } + +func (c *defaultClient) Health(ctx context.Context) (error) { + ctx, span := trace.StartSpan(ctx, "client/Health") + defer span.End() + err := c.do(ctx, "GET", "/health", nil, nil, nil) + return err +} diff --git a/api/rest/restapi.go b/api/rest/restapi.go index 14afc2e9..e6adeb44 100644 --- a/api/rest/restapi.go +++ b/api/rest/restapi.go @@ -204,6 +204,12 @@ func (api *API) routes(c *rpc.Client) []common.Route { Pattern: "/token", HandlerFunc: api.GenerateTokenHandler, }, + { + Name: "Health", + Method: "GET", + Pattern: "/health", + HandlerFunc: api.HealthHandler, + }, } } diff --git a/api/rest/restapi_test.go b/api/rest/restapi_test.go index d338d042..cad5f367 100644 --- a/api/rest/restapi_test.go +++ b/api/rest/restapi_test.go @@ -844,3 +844,20 @@ func TestAPIIPFSGCEndpoint(t *testing.T) { test.BothEndpoints(t, tf) } + + +func TestHealthEndpoint(t *testing.T) { + ctx := context.Background() + rest := testAPI(t) + defer rest.Shutdown(ctx) + + tf := func(t *testing.T, url test.URLFunc) { + errResp := api.Error{} + test.MakeGet(t, rest, url(rest)+"/health", &errResp) + if errResp.Code != 0 || errResp.Message != "" { + t.Error("expected no errors") + } + } + + test.BothEndpoints(t, tf) +} \ No newline at end of file From a15b4171d4eded0bb84a17cf6f10461b4aa1f95a Mon Sep 17 00:00:00 2001 From: arthurgavazza Date: Thu, 20 Apr 2023 08:37:41 -0300 Subject: [PATCH 2/6] test: add client health method tests --- api/rest/client/methods_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/api/rest/client/methods_test.go b/api/rest/client/methods_test.go index 27badf2e..0773db9d 100644 --- a/api/rest/client/methods_test.go +++ b/api/rest/client/methods_test.go @@ -903,3 +903,19 @@ func TestRepoGC(t *testing.T) { testClients(t, api, testF) } + +func TestHealth(t *testing.T) { + ctx := context.Background() + api := testAPI(t) + defer shutdown(api) + + testF := func(t *testing.T, c Client) { + err := c.Health(ctx) + if err != nil { + t.Log(err) + t.Error("expected no errors") + } + } + + testClients(t, api, testF) +} \ No newline at end of file From d4340a339f3251e7e1eaed2a6589d483b8781f14 Mon Sep 17 00:00:00 2001 From: arthurgavazza Date: Thu, 20 Apr 2023 08:45:09 -0300 Subject: [PATCH 3/6] fix: make lbclient implement client interface correctly --- api/rest/client/lbclient.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/api/rest/client/lbclient.go b/api/rest/client/lbclient.go index 1de307e4..8b2be3da 100644 --- a/api/rest/client/lbclient.go +++ b/api/rest/client/lbclient.go @@ -4,9 +4,9 @@ import ( "context" "sync/atomic" + "github.com/ipfs-cluster/ipfs-cluster/api" shell "github.com/ipfs/go-ipfs-api" files "github.com/ipfs/go-libipfs/files" - "github.com/ipfs-cluster/ipfs-cluster/api" peer "github.com/libp2p/go-libp2p/core/peer" ) @@ -553,3 +553,12 @@ func (lc *loadBalancingClient) IPFS(ctx context.Context) *shell.Shell { return s } + +func (lc *loadBalancingClient) Health(ctx context.Context) (error) { + call := func(c Client) error { + err := c.Health(ctx) + return err + } + err := lc.retry(0, call) + return err +} \ No newline at end of file From 9cb2219636c0c32f5e07ce67a90a9c5cac3190ba Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Thu, 11 May 2023 12:10:50 +0200 Subject: [PATCH 4/6] Add end of line to api.go --- api/common/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/common/api.go b/api/common/api.go index 66036070..9906d048 100644 --- a/api/common/api.go +++ b/api/common/api.go @@ -857,4 +857,4 @@ func (api *API) SetKeepAlivesEnabled(b bool) { func (api *API) HealthHandler(w http.ResponseWriter, r *http.Request){ api.SendResponse(w,http.StatusNoContent,nil,nil) -} \ No newline at end of file +} From 287f285d79315677244c6bbe3cb05833d9bd97b9 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Thu, 11 May 2023 12:11:21 +0200 Subject: [PATCH 5/6] api.go: only pass through GET requests to /health --- api/common/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/common/api.go b/api/common/api.go index 9906d048..7b9509d2 100644 --- a/api/common/api.go +++ b/api/common/api.go @@ -302,7 +302,7 @@ func (api *API) authHandler(h http.Handler, lggr *logging.ZapEventLogger) http.H wrap := func(w http.ResponseWriter, r *http.Request) { // We let CORS preflight requests pass through the next // handler. - if r.Method == http.MethodOptions || r.URL.Path == "/health" { + if r.Method == http.MethodOptions || (r.Method == http.MethodGet && r.URL.Path == "/health") { h.ServeHTTP(w, r) return } From 50015947da28460c58f697edf876029ab28e114c Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Thu, 11 May 2023 12:11:57 +0200 Subject: [PATCH 6/6] api.go: update comment on auth pass-through --- api/common/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/common/api.go b/api/common/api.go index 7b9509d2..a543fc88 100644 --- a/api/common/api.go +++ b/api/common/api.go @@ -300,8 +300,8 @@ func (api *API) authHandler(h http.Handler, lggr *logging.ZapEventLogger) http.H } wrap := func(w http.ResponseWriter, r *http.Request) { - // We let CORS preflight requests pass through the next - // handler. + // We let CORS preflight and Health requests pass through to + // the next handler. if r.Method == http.MethodOptions || (r.Method == http.MethodGet && r.URL.Path == "/health") { h.ServeHTTP(w, r) return