Add usescases to handle test plugins
This commit is contained in:
parent
a777420809
commit
8704952d6f
9 changed files with 213 additions and 14 deletions
78
internal/api-admin/controller/plugin_test_controller.go
Normal file
78
internal/api-admin/controller/plugin_test_controller.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2020-2025 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// This program is offered under a commercial and under the AGPL license.
|
||||
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||
//
|
||||
// For AGPL licensing:
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"git.happydns.org/happyDomain/internal/api/middleware"
|
||||
"git.happydns.org/happyDomain/model"
|
||||
)
|
||||
|
||||
type TestPluginController struct {
|
||||
testPluginService happydns.TestPluginUsecase
|
||||
}
|
||||
|
||||
func NewTestPluginController(testPluginService happydns.TestPluginUsecase) *TestPluginController {
|
||||
return &TestPluginController{
|
||||
testPluginService,
|
||||
}
|
||||
}
|
||||
|
||||
func (uc *TestPluginController) TestPluginHandler(c *gin.Context) {
|
||||
pname := c.Param("pname")
|
||||
|
||||
plugin, err := uc.testPluginService.GetTestPlugin(pname)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusNotFound, happydns.ErrorResponse{Message: "Plugin not found"})
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("plugin", plugin)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
||||
func (uc *TestPluginController) ListTestPlugins(c *gin.Context) {
|
||||
plugins, err := uc.testPluginService.ListTestPlugins()
|
||||
if err != nil {
|
||||
middleware.ErrorResponse(c, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
ret := map[string]happydns.PluginVersionInfo{}
|
||||
|
||||
for _, p := range plugins {
|
||||
pnames := p.PluginEnvName()
|
||||
ret[pnames[0]] = p.Version()
|
||||
}
|
||||
|
||||
happydns.ApiResponse(c, ret, nil)
|
||||
}
|
||||
|
||||
func (uc *TestPluginController) GetTestPluginStatus(c *gin.Context) {
|
||||
plugin := c.MustGet("plugin").(happydns.TestPlugin)
|
||||
|
||||
c.JSON(http.StatusOK, plugin.Version())
|
||||
}
|
||||
52
internal/api-admin/route/plugin.go
Normal file
52
internal/api-admin/route/plugin.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2020-2025 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// This program is offered under a commercial and under the AGPL license.
|
||||
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||
//
|
||||
// For AGPL licensing:
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"git.happydns.org/happyDomain/internal/api-admin/controller"
|
||||
"git.happydns.org/happyDomain/internal/storage"
|
||||
"git.happydns.org/happyDomain/model"
|
||||
)
|
||||
|
||||
func declarePluginsRoutes(router *gin.RouterGroup, dependancies happydns.UsecaseDependancies, store storage.Storage) {
|
||||
apiPluginsRoutes := router.Group("/plugins")
|
||||
declareTestPluginsRoutes(apiPluginsRoutes, dependancies)
|
||||
}
|
||||
|
||||
func declareTestPluginsRoutes(router *gin.RouterGroup, dependancies happydns.UsecaseDependancies) {
|
||||
tpc := controller.NewTestPluginController(dependancies.TestPluginUsecase())
|
||||
|
||||
apiTestPluginsRoutes := router.Group("/tests")
|
||||
|
||||
apiTestPluginsRoutes.GET("", tpc.ListTestPlugins)
|
||||
|
||||
apiTestPluginRoutes := apiTestPluginsRoutes.Group("/:pname")
|
||||
apiTestPluginRoutes.Use(tpc.TestPluginHandler)
|
||||
|
||||
apiTestPluginRoutes.GET("", tpc.GetTestPluginStatus)
|
||||
//apiTestPluginRoutes.POST("", tpc.ChangeTestPluginStatus)
|
||||
|
||||
//apiTestPluginRoutes.GET("/options", tpc.ListTestPluginOptions)
|
||||
//apiTestPluginRoutes.PUT("/options", tpc.ChangeTestPluginOptions)
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ func DeclareRoutes(cfg *happydns.Options, router *gin.Engine, s storage.Storage,
|
|||
|
||||
declareBackupRoutes(cfg, apiRoutes, s)
|
||||
declareDomainRoutes(apiRoutes, dependancies, s)
|
||||
declarePluginsRoutes(apiRoutes, dependancies, s)
|
||||
declareProviderRoutes(apiRoutes, dependancies, s)
|
||||
declareSessionsRoutes(cfg, apiRoutes, s)
|
||||
declareUserAuthsRoutes(apiRoutes, dependancies, s)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import (
|
|||
domainUC "git.happydns.org/happyDomain/internal/usecase/domain"
|
||||
domainlogUC "git.happydns.org/happyDomain/internal/usecase/domain_log"
|
||||
"git.happydns.org/happyDomain/internal/usecase/orchestrator"
|
||||
pluginUC "git.happydns.org/happyDomain/internal/usecase/plugin"
|
||||
providerUC "git.happydns.org/happyDomain/internal/usecase/provider"
|
||||
serviceUC "git.happydns.org/happyDomain/internal/usecase/service"
|
||||
sessionUC "git.happydns.org/happyDomain/internal/usecase/session"
|
||||
|
|
@ -63,6 +64,7 @@ type Usecases struct {
|
|||
session happydns.SessionUsecase
|
||||
service happydns.ServiceUsecase
|
||||
serviceSpecs happydns.ServiceSpecsUsecase
|
||||
testPlugin happydns.TestPluginUsecase
|
||||
user happydns.UserUsecase
|
||||
zone happydns.ZoneUsecase
|
||||
zoneService happydns.ZoneServiceUsecase
|
||||
|
|
@ -77,7 +79,7 @@ type App struct {
|
|||
router *gin.Engine
|
||||
srv *http.Server
|
||||
insights *insightsCollector
|
||||
plugins happydns.PluginManger
|
||||
plugins happydns.PluginManager
|
||||
store storage.Storage
|
||||
usecases Usecases
|
||||
}
|
||||
|
|
@ -138,6 +140,10 @@ func (a *App) SessionUsecase() happydns.SessionUsecase {
|
|||
return a.usecases.session
|
||||
}
|
||||
|
||||
func (a *App) TestPluginUsecase() happydns.TestPluginUsecase {
|
||||
return a.usecases.testPlugin
|
||||
}
|
||||
|
||||
func (a *App) UserUsecase() happydns.UserUsecase {
|
||||
return a.usecases.user
|
||||
}
|
||||
|
|
@ -167,9 +173,9 @@ func NewApp(cfg *happydns.Options) *App {
|
|||
app.initStorageEngine()
|
||||
app.initNewsletter()
|
||||
app.initInsights()
|
||||
app.initPlugins()
|
||||
app.initUsecases()
|
||||
app.setupRouter()
|
||||
app.initPlugins()
|
||||
|
||||
return app
|
||||
}
|
||||
|
|
@ -182,9 +188,9 @@ func NewAppWithStorage(cfg *happydns.Options, store storage.Storage) *App {
|
|||
|
||||
app.initMailer()
|
||||
app.initNewsletter()
|
||||
app.initPlugins()
|
||||
app.initUsecases()
|
||||
app.setupRouter()
|
||||
app.initPlugins()
|
||||
|
||||
return app
|
||||
}
|
||||
|
|
@ -273,6 +279,7 @@ func (app *App) initUsecases() {
|
|||
app.usecases.authUser = authUserService
|
||||
app.usecases.resolver = usecase.NewResolverUsecase(app.cfg)
|
||||
app.usecases.session = sessionService
|
||||
app.usecases.testPlugin = pluginUC.NewTestPluginUsecase(app.cfg, app.plugins)
|
||||
|
||||
app.usecases.orchestrator = orchestrator.NewOrchestrator(
|
||||
domainLogService,
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@ import (
|
|||
)
|
||||
|
||||
func (a *App) initPlugins() error {
|
||||
a.plugins = PluginManger{
|
||||
manager := PluginManger{
|
||||
testsIdx: map[string]happydns.TestPlugin{},
|
||||
}
|
||||
a.plugins = &manager
|
||||
|
||||
var ret error
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ func (a *App) initPlugins() error {
|
|||
|
||||
fname := path.Join(directory, file.Name())
|
||||
|
||||
err = a.plugins.loadPlugin(fname)
|
||||
err = manager.loadPlugin(fname)
|
||||
if err != nil {
|
||||
ret = errors.Join(ret, fmt.Errorf("unable to load plugin %q: %w", fname, err))
|
||||
}
|
||||
|
|
@ -84,27 +85,27 @@ func (m *PluginManger) loadPlugin(fname string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
m.plugins = append(m.plugins, myplugin)
|
||||
m.tests = append(m.tests, myplugin)
|
||||
|
||||
// Index the plugin by its names
|
||||
pluginNames := myplugin.PluginEnvName()
|
||||
for _, name := range pluginNames {
|
||||
if p, exists := m.pluginsIdx[name]; exists {
|
||||
if p, exists := m.testsIdx[name]; exists {
|
||||
log.Printf("Plugin name conflict: the plugin at %q tries to register the name %q but it's already registered by %q", fname, name, p.Version().Name)
|
||||
continue
|
||||
}
|
||||
|
||||
m.pluginsIdx[name] = myplugin
|
||||
m.testsIdx[name] = myplugin
|
||||
}
|
||||
|
||||
log.Printf("Plugin %s loaded (version %s)", myplugin.Version().Name, myplugin.Version().Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *PluginManger) GetTestPlugins() ([]happydns.TestPlugin, error) {
|
||||
func (m *PluginManger) GetTestPlugins() []happydns.TestPlugin {
|
||||
return m.tests
|
||||
}
|
||||
|
||||
func (m *PluginManger) GetTestPluginsIndex() (map[string]happydns.TestPlugin, error) {
|
||||
func (m *PluginManger) GetTestPluginsIndex() map[string]happydns.TestPlugin {
|
||||
return m.testsIdx
|
||||
}
|
||||
|
|
|
|||
52
internal/usecase/plugin/plugin_test_usecase.go
Normal file
52
internal/usecase/plugin/plugin_test_usecase.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2020-2025 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// This program is offered under a commercial and under the AGPL license.
|
||||
// For commercial licensing, contact us at <contact@happydomain.org>.
|
||||
//
|
||||
// For AGPL licensing:
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.happydns.org/happyDomain/model"
|
||||
)
|
||||
|
||||
type testPluginUsecase struct {
|
||||
config *happydns.Options
|
||||
manager happydns.PluginManager
|
||||
}
|
||||
|
||||
func NewTestPluginUsecase(cfg *happydns.Options, manager happydns.PluginManager) happydns.TestPluginUsecase {
|
||||
return &testPluginUsecase{
|
||||
config: cfg,
|
||||
manager: manager,
|
||||
}
|
||||
}
|
||||
|
||||
func (tu *testPluginUsecase) GetTestPlugin(pname string) (happydns.TestPlugin, error) {
|
||||
if plugin, ok := tu.manager.GetTestPluginsIndex()[pname]; !ok {
|
||||
return nil, fmt.Errorf("unable to find plugin named %q", pname)
|
||||
} else {
|
||||
return plugin, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (tu *testPluginUsecase) ListTestPlugins() ([]happydns.TestPlugin, error) {
|
||||
return tu.manager.GetTestPlugins(), nil
|
||||
}
|
||||
|
|
@ -30,11 +30,13 @@ const (
|
|||
|
||||
type PluginResultStatus int
|
||||
|
||||
type PluginOptions map[string]interface{}
|
||||
|
||||
type TestPlugin interface {
|
||||
PluginEnvName() []string
|
||||
Version() PluginVersionInfo
|
||||
|
||||
RunTest(options map[string]interface{}, meta map[string]string) (*PluginResult, error)
|
||||
RunTest(options PluginOptions, meta map[string]string) (*PluginResult, error)
|
||||
}
|
||||
|
||||
type PluginVersionInfo struct {
|
||||
|
|
@ -57,6 +59,11 @@ type PluginResult struct {
|
|||
}
|
||||
|
||||
type PluginManager interface {
|
||||
GetTestPlugins() ([]TestPlugin, error)
|
||||
GetTestPluginsIndex() (map[string]TestPlugin, error)
|
||||
GetTestPlugins() []TestPlugin
|
||||
GetTestPluginsIndex() map[string]TestPlugin
|
||||
}
|
||||
|
||||
type TestPluginUsecase interface {
|
||||
GetTestPlugin(string) (TestPlugin, error)
|
||||
ListTestPlugins() ([]TestPlugin, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ type UsecaseDependancies interface {
|
|||
ServiceUsecase() ServiceUsecase
|
||||
ServiceSpecsUsecase() ServiceSpecsUsecase
|
||||
SessionUsecase() SessionUsecase
|
||||
TestPluginUsecase() TestPluginUsecase
|
||||
UserUsecase() UserUsecase
|
||||
ZoneCorrectionApplierUsecase() ZoneCorrectionApplierUsecase
|
||||
ZoneImporterUsecase() ZoneImporterUsecase
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ type FederationTesterResponse struct {
|
|||
FederationOK bool `json:"FederationOK"`
|
||||
}
|
||||
|
||||
func (p *MatrixTester) RunTest(options map[string]interface{}, meta map[string]string) (*happydns.PluginResult, error) {
|
||||
func (p *MatrixTester) RunTest(options happydns.PluginOptions, meta map[string]string) (*happydns.PluginResult, error) {
|
||||
var domain string
|
||||
|
||||
if dn, ok := options["domain"]; ok {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue