From f9a4a6120db69e5ead542cb130533b0c20e2cd66 Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Wed, 29 May 2024 12:56:17 +0200 Subject: [PATCH] [feature] Debug admin endpoint to clear caches (#2940) * [feature] Debug admin endpoint to clear caches * go fmt --- cmd/gotosocial/action/server/server.go | 2 +- cmd/gotosocial/action/testrig/testrig.go | 2 +- docs/api/swagger.yaml | 25 ++++++++++++++++++ internal/api/client.go | 7 +++--- internal/api/client/admin/admin.go | 7 +++++- internal/api/client/admin/admin_test.go | 2 +- internal/api/client/admin/debug_off.go | 32 ++++++++++++++++++++++++ internal/api/client/admin/debug_on.go | 24 ++++++++++++++++++ 8 files changed, 94 insertions(+), 7 deletions(-) diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go index 22d8b3920..87184f5b1 100644 --- a/cmd/gotosocial/action/server/server.go +++ b/cmd/gotosocial/action/server/server.go @@ -316,7 +316,7 @@ var Start action.GTSAction = func(ctx context.Context) error { var ( authModule = api.NewAuth(dbService, processor, idp, routerSession, sessionName) // auth/oauth paths - clientModule = api.NewClient(dbService, processor) // api client endpoints + clientModule = api.NewClient(&state, processor) // api client endpoints metricsModule = api.NewMetrics() // Metrics endpoints healthModule = api.NewHealth(dbService.Ready) // Health check endpoints fileserverModule = api.NewFileserver(processor) // fileserver endpoints diff --git a/cmd/gotosocial/action/testrig/testrig.go b/cmd/gotosocial/action/testrig/testrig.go index 24d41721a..0c1341d4c 100644 --- a/cmd/gotosocial/action/testrig/testrig.go +++ b/cmd/gotosocial/action/testrig/testrig.go @@ -223,7 +223,7 @@ var Start action.GTSAction = func(ctx context.Context) error { var ( authModule = api.NewAuth(state.DB, processor, idp, routerSession, sessionName) // auth/oauth paths - clientModule = api.NewClient(state.DB, processor) // api client endpoints + clientModule = api.NewClient(&state, processor) // api client endpoints metricsModule = api.NewMetrics() // Metrics endpoints healthModule = api.NewHealth(state.DB.Ready) // Health check endpoints fileserverModule = api.NewFileserver(processor) // fileserver endpoints diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml index b069eaf55..b86d4b9eb 100644 --- a/docs/api/swagger.yaml +++ b/docs/api/swagger.yaml @@ -4494,6 +4494,31 @@ paths: summary: Perform a GET to the specified ActivityPub URL and return detailed debugging information. tags: - debug + /api/v1/admin/debug/caches/clear: + post: + description: Only enabled / exposed if GoToSocial was built and is running with flag DEBUG=1. + operationId: debugClearCaches + produces: + - application/json + responses: + "200": + description: All good baby! + "400": + description: bad request + "401": + description: unauthorized + "404": + description: not found + "406": + description: not acceptable + "500": + description: internal server error + security: + - OAuth2 Bearer: + - admin + summary: Sweep/clear all in-memory caches. + tags: + - debug /api/v1/admin/domain_allows: get: operationId: domainAllowsGet diff --git a/internal/api/client.go b/internal/api/client.go index d30f82e7b..ce95e3dfc 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -50,6 +50,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/middleware" "github.com/superseriousbusiness/gotosocial/internal/processing" "github.com/superseriousbusiness/gotosocial/internal/router" + "github.com/superseriousbusiness/gotosocial/internal/state" ) type Client struct { @@ -127,13 +128,13 @@ func (c *Client) Route(r *router.Router, m ...gin.HandlerFunc) { c.user.Route(h) } -func NewClient(db db.DB, p *processing.Processor) *Client { +func NewClient(state *state.State, p *processing.Processor) *Client { return &Client{ processor: p, - db: db, + db: state.DB, accounts: accounts.New(p), - admin: admin.New(p), + admin: admin.New(state, p), apps: apps.New(p), blocks: blocks.New(p), bookmarks: bookmarks.New(p), diff --git a/internal/api/client/admin/admin.go b/internal/api/client/admin/admin.go index e898bca46..ef54f0b50 100644 --- a/internal/api/client/admin/admin.go +++ b/internal/api/client/admin/admin.go @@ -23,6 +23,7 @@ import ( "codeberg.org/gruf/go-debug" "github.com/gin-gonic/gin" "github.com/superseriousbusiness/gotosocial/internal/processing" + "github.com/superseriousbusiness/gotosocial/internal/state" ) const ( @@ -56,6 +57,7 @@ const ( InstanceRulesPathWithID = InstanceRulesPath + "/:" + IDKey DebugPath = BasePath + "/debug" DebugAPUrlPath = DebugPath + "/apurl" + DebugClearCachesPath = DebugPath + "/caches/clear" IDKey = "id" FilterQueryKey = "filter" @@ -73,11 +75,13 @@ const ( type Module struct { processor *processing.Processor + state *state.State } -func New(processor *processing.Processor) *Module { +func New(state *state.State, processor *processing.Processor) *Module { return &Module{ processor: processor, + state: state, } } @@ -145,5 +149,6 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H // debug stuff if debug.DEBUG { attachHandler(http.MethodGet, DebugAPUrlPath, m.DebugAPUrlHandler) + attachHandler(http.MethodPost, DebugClearCachesPath, m.DebugClearCachesHandler) } } diff --git a/internal/api/client/admin/admin_test.go b/internal/api/client/admin/admin_test.go index 4a429e57a..962ec3872 100644 --- a/internal/api/client/admin/admin_test.go +++ b/internal/api/client/admin/admin_test.go @@ -105,7 +105,7 @@ func (suite *AdminStandardTestSuite) SetupTest() { suite.sentEmails = make(map[string]string) suite.emailSender = testrig.NewEmailSender("../../../../web/template/", suite.sentEmails) suite.processor = testrig.NewTestProcessor(&suite.state, suite.federator, suite.emailSender, suite.mediaManager) - suite.adminModule = admin.New(suite.processor) + suite.adminModule = admin.New(&suite.state, suite.processor) testrig.StandardDBSetup(suite.db, nil) testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media") } diff --git a/internal/api/client/admin/debug_off.go b/internal/api/client/admin/debug_off.go index bc6e4001c..a43326f02 100644 --- a/internal/api/client/admin/debug_off.go +++ b/internal/api/client/admin/debug_off.go @@ -73,3 +73,35 @@ import ( // '500': // description: internal server error func (m *Module) DebugAPUrlHandler(c *gin.Context) {} + +// DebugClearCachesHandler swagger:operation POST /api/v1/admin/debug/caches/clear debugClearCaches +// +// Sweep/clear all in-memory caches. +// +// Only enabled / exposed if GoToSocial was built and is running with flag DEBUG=1. +// +// --- +// tags: +// - debug +// +// produces: +// - application/json +// +// security: +// - OAuth2 Bearer: +// - admin +// +// responses: +// '200': +// description: All good baby! +// '400': +// description: bad request +// '401': +// description: unauthorized +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) DebugClearCachesHandler(c *gin.Context) {} diff --git a/internal/api/client/admin/debug_on.go b/internal/api/client/admin/debug_on.go index c6dfa11ff..ea42206f8 100644 --- a/internal/api/client/admin/debug_on.go +++ b/internal/api/client/admin/debug_on.go @@ -56,3 +56,27 @@ func (m *Module) DebugAPUrlHandler(c *gin.Context) { c.JSON(http.StatusOK, resp) } + +func (m *Module) DebugClearCachesHandler(c *gin.Context) { + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if !*authed.User.Admin { + err := fmt.Errorf("user %s not an admin", authed.User.ID) + apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1) + return + } + + // Sweep all caches down to 0 (empty). + m.state.Caches.Sweep(0) + + c.JSON(http.StatusOK, gin.H{"status": "OK"}) +}