From ee8fa152789f5e63dbe8ac590c52add760473e16 Mon Sep 17 00:00:00 2001 From: istae <14264581+istae@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:41:50 +0300 Subject: [PATCH] fix(pin_integrity): changed route and added openapi (#4616) --- openapi/Swarm.yaml | 24 ++++++++++++ openapi/SwarmCommon.yaml | 17 ++++++++- openapi/SwarmDebug.yaml | 2 +- pkg/api/integritycheck.go | 62 ------------------------------- pkg/api/integritycheck_test.go | 67 ---------------------------------- pkg/api/pin.go | 52 ++++++++++++++++++++++++++ pkg/api/pin_test.go | 54 +++++++++++++++++++++++++++ pkg/api/router.go | 12 +++--- 8 files changed, 152 insertions(+), 138 deletions(-) delete mode 100644 pkg/api/integritycheck.go delete mode 100644 pkg/api/integritycheck_test.go diff --git a/openapi/Swarm.yaml b/openapi/Swarm.yaml index b4e4a18c918..72e41ec5665 100644 --- a/openapi/Swarm.yaml +++ b/openapi/Swarm.yaml @@ -638,6 +638,30 @@ paths: default: description: Default response + "/pins/check": + get: + summary: Validate pinned chunks integerity + tags: + - Pinning + parameters: + - in: query + name: ref + schema: + $ref: "SwarmCommon.yaml#/components/schemas/SwarmOnlyReference" + required: false + description: The number of items to skip before starting to collect the result set. + responses: + "200": + description: List of checked root hash references + content: + application/json: + schema: + $ref: "SwarmCommon.yaml#/components/schemas/PinCheckResponse" + "500": + $ref: "SwarmCommon.yaml#/components/responses/500" + default: + description: Default response + "/pss/send/{topic}/{targets}": post: summary: Send to recipient or target with Postal Service for Swarm diff --git a/openapi/SwarmCommon.yaml b/openapi/SwarmCommon.yaml index eccb03e9946..21ede2e5400 100644 --- a/openapi/SwarmCommon.yaml +++ b/openapi/SwarmCommon.yaml @@ -1,6 +1,6 @@ openapi: 3.0.3 info: - version: 3.2.6 + version: 3.2.7 title: Common Data Types description: | \*****bzzz***** @@ -602,15 +602,28 @@ components: - $ref: "#/components/schemas/SwarmAddress" - $ref: "#/components/schemas/SwarmEncryptedReference" + PinCheckResponse: + type: object + properties: + reference: + $ref: "#/components/schemas/SwarmOnlyReference" + total: + type: integer + missing: + type: integer + invalid: + type: integer + SwarmOnlyReferencesList: type: object properties: - references: + reference: type: array nullable: false items: $ref: "#/components/schemas/SwarmOnlyReference" + SwarmReference: oneOf: - $ref: "#/components/schemas/SwarmAddress" diff --git a/openapi/SwarmDebug.yaml b/openapi/SwarmDebug.yaml index 355d938c3ec..516fba3399d 100644 --- a/openapi/SwarmDebug.yaml +++ b/openapi/SwarmDebug.yaml @@ -1,6 +1,6 @@ openapi: 3.0.3 info: - version: 4.1.0 + version: 4.1.1 title: Bee Debug API description: "A list of the currently provided debug interfaces to interact with the bee node" diff --git a/pkg/api/integritycheck.go b/pkg/api/integritycheck.go deleted file mode 100644 index 7609c2b1674..00000000000 --- a/pkg/api/integritycheck.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2023 The Swarm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -package api - -import ( - "encoding/json" - "net/http" - - storer "github.com/ethersphere/bee/v2/pkg/storer" - "github.com/ethersphere/bee/v2/pkg/swarm" -) - -type PinIntegrityResponse struct { - Ref swarm.Address `json:"ref"` - Total int `json:"total"` - Missing int `json:"missing"` - Invalid int `json:"invalid"` -} - -func (s *Service) pinIntegrityHandler(w http.ResponseWriter, r *http.Request) { - logger := s.logger.WithName("get_pin_integrity").Build() - - querie := struct { - Ref swarm.Address `map:"ref"` - }{} - - if response := s.mapStructure(r.URL.Query(), &querie); response != nil { - response("invalid query params", logger, w) - return - } - - out := make(chan storer.PinStat) - - go s.pinIntegrity.Check(r.Context(), logger, querie.Ref.String(), out) - - flusher, ok := w.(http.Flusher) - if !ok { - http.NotFound(w, r) - return - } - - w.Header().Set("Transfer-Encoding", "chunked") - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(http.StatusOK) - flusher.Flush() - - enc := json.NewEncoder(w) - - for v := range out { - resp := PinIntegrityResponse{ - Ref: v.Ref, - Total: v.Total, - Missing: v.Missing, - Invalid: v.Invalid, - } - if err := enc.Encode(resp); err != nil { - break - } - flusher.Flush() - } -} diff --git a/pkg/api/integritycheck_test.go b/pkg/api/integritycheck_test.go deleted file mode 100644 index d9d18502d72..00000000000 --- a/pkg/api/integritycheck_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2022 The Swarm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package api_test - -import ( - "context" - "net/http" - "testing" - - "github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest" - "github.com/ethersphere/bee/v2/pkg/log" - storage "github.com/ethersphere/bee/v2/pkg/storage" - "github.com/ethersphere/bee/v2/pkg/storage/inmemstore" - storer "github.com/ethersphere/bee/v2/pkg/storer" -) - -const pinRef = "620fcd78c7ce54da2d1b7cc2274a02e190cbe8fecbc3bd244690ab6517ce8f39" - -func TestIntegrityHandler(t *testing.T) { - t.Parallel() - - t.Run("ok", func(t *testing.T) { - t.Parallel() - testServer, _, _, _ := newTestServer(t, testServerOptions{ - DebugAPI: true, - PinIntegrity: &mockPinIntegrity{ - Store: inmemstore.New(), - tester: t, - }, - }) - - endp := "/check/pin?ref=" + pinRef - - // When probe is not set health endpoint should indicate that node is not healthy - jsonhttptest.Request(t, testServer, http.MethodGet, endp, http.StatusOK, jsonhttptest.WithExpectedResponse(nil)) - }) - - t.Run("wrong hash format", func(t *testing.T) { - t.Parallel() - testServer, _, _, _ := newTestServer(t, testServerOptions{ - DebugAPI: true, - PinIntegrity: &mockPinIntegrity{ - Store: inmemstore.New(), - tester: t, - }, - }) - - endp := "/check/pin?ref=0xbadhash" - - // When probe is not set health endpoint should indicate that node is not healthy - jsonhttptest.Request(t, testServer, http.MethodGet, endp, http.StatusBadRequest, jsonhttptest.WithExpectedResponse(nil)) - }) -} - -type mockPinIntegrity struct { - tester *testing.T - Store storage.Store -} - -func (p *mockPinIntegrity) Check(ctx context.Context, logger log.Logger, pin string, out chan storer.PinStat) { - if pin != pinRef { - p.tester.Fatal("bad pin", pin) - } - close(out) -} diff --git a/pkg/api/pin.go b/pkg/api/pin.go index 21b01a626e8..6fc115fd1b1 100644 --- a/pkg/api/pin.go +++ b/pkg/api/pin.go @@ -5,12 +5,14 @@ package api import ( + "encoding/json" "errors" "net/http" "sync" "github.com/ethersphere/bee/v2/pkg/jsonhttp" "github.com/ethersphere/bee/v2/pkg/storage" + storer "github.com/ethersphere/bee/v2/pkg/storer" "github.com/ethersphere/bee/v2/pkg/swarm" "github.com/ethersphere/bee/v2/pkg/traversal" "github.com/gorilla/mux" @@ -199,3 +201,53 @@ func (s *Service) listPinnedRootHashes(w http.ResponseWriter, r *http.Request) { References: pinned, }) } + +type PinIntegrityResponse struct { + Reference swarm.Address `json:"reference"` + Total int `json:"total"` + Missing int `json:"missing"` + Invalid int `json:"invalid"` +} + +func (s *Service) pinIntegrityHandler(w http.ResponseWriter, r *http.Request) { + logger := s.logger.WithName("get_pin_integrity").Build() + + querie := struct { + Ref swarm.Address `map:"ref"` + }{} + + if response := s.mapStructure(r.URL.Query(), &querie); response != nil { + response("invalid query params", logger, w) + return + } + + out := make(chan storer.PinStat) + + go s.pinIntegrity.Check(r.Context(), logger, querie.Ref.String(), out) + + flusher, ok := w.(http.Flusher) + if !ok { + http.NotFound(w, r) + return + } + + w.Header().Set("Transfer-Encoding", "chunked") + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusOK) + flusher.Flush() + + enc := json.NewEncoder(w) + + for v := range out { + resp := PinIntegrityResponse{ + Reference: v.Ref, + Total: v.Total, + Missing: v.Missing, + Invalid: v.Invalid, + } + if err := enc.Encode(resp); err != nil { + break + } + flusher.Flush() + } +} diff --git a/pkg/api/pin_test.go b/pkg/api/pin_test.go index 1ff60b7e4d2..a85c34a9594 100644 --- a/pkg/api/pin_test.go +++ b/pkg/api/pin_test.go @@ -5,6 +5,7 @@ package api_test import ( + "context" "net/http" "strings" "testing" @@ -12,7 +13,11 @@ import ( "github.com/ethersphere/bee/v2/pkg/api" "github.com/ethersphere/bee/v2/pkg/jsonhttp" "github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest" + "github.com/ethersphere/bee/v2/pkg/log" mockpost "github.com/ethersphere/bee/v2/pkg/postage/mock" + storage "github.com/ethersphere/bee/v2/pkg/storage" + "github.com/ethersphere/bee/v2/pkg/storage/inmemstore" + storer "github.com/ethersphere/bee/v2/pkg/storer" mockstorer "github.com/ethersphere/bee/v2/pkg/storer/mock" "github.com/ethersphere/bee/v2/pkg/swarm" ) @@ -185,3 +190,52 @@ func TestPinHandlersInvalidInputs(t *testing.T) { } } } + +const pinRef = "620fcd78c7ce54da2d1b7cc2274a02e190cbe8fecbc3bd244690ab6517ce8f39" + +func TestIntegrityHandler(t *testing.T) { + + t.Parallel() + + t.Run("ok", func(t *testing.T) { + t.Parallel() + testServer, _, _, _ := newTestServer(t, testServerOptions{ + PinIntegrity: &mockPinIntegrity{ + Store: inmemstore.New(), + tester: t, + }, + }) + + endp := "/pins/check?ref=" + pinRef + + // When probe is not set health endpoint should indicate that node is not healthy + jsonhttptest.Request(t, testServer, http.MethodGet, endp, http.StatusOK, jsonhttptest.WithExpectedResponse(nil)) + }) + + t.Run("wrong hash format", func(t *testing.T) { + t.Parallel() + testServer, _, _, _ := newTestServer(t, testServerOptions{ + PinIntegrity: &mockPinIntegrity{ + Store: inmemstore.New(), + tester: t, + }, + }) + + endp := "/pins/check?ref=0xbadhash" + + // When probe is not set health endpoint should indicate that node is not healthy + jsonhttptest.Request(t, testServer, http.MethodGet, endp, http.StatusBadRequest, jsonhttptest.WithExpectedResponse(nil)) + }) +} + +type mockPinIntegrity struct { + tester *testing.T + Store storage.Store +} + +func (p *mockPinIntegrity) Check(ctx context.Context, logger log.Logger, pin string, out chan storer.PinStat) { + if pin != pinRef { + p.tester.Fatal("bad pin", pin) + } + close(out) +} diff --git a/pkg/api/router.go b/pkg/api/router.go index 872304e85c7..18c2bfb9a46 100644 --- a/pkg/api/router.go +++ b/pkg/api/router.go @@ -315,6 +315,12 @@ func (s *Service) mountAPI() { })), ) + handle("/pins/check", web.ChainHandlers( + web.FinalHandler(jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.pinIntegrityHandler), + }), + )) + handle("/pins/{reference}", web.ChainHandlers( web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.getPinnedRootHash), @@ -608,10 +614,4 @@ func (s *Service) mountBusinessDebug(restricted bool) { "GET": http.HandlerFunc(s.rchash), }), )) - - handle("/check/pin", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.pinIntegrityHandler), - }), - )) }