From bda52ed9926f26f1fb8295fcdb07c6b2c6718cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Fri, 20 May 2022 14:55:55 +0200 Subject: [PATCH] Add endpoint for primary DAL connection --- app/boot_levels.go | 57 +++++++++++++++++++----------- system/rest.yaml | 4 +++ system/rest/connection.go | 4 +++ system/rest/handlers/connection.go | 31 ++++++++++++---- system/rest/request/connection.go | 19 ++++++++++ system/service/connection.go | 20 ++++++++--- system/service/service.go | 6 ++-- 7 files changed, 107 insertions(+), 34 deletions(-) diff --git a/app/boot_levels.go b/app/boot_levels.go index 9cad1dedf..6e6e43b17 100644 --- a/app/boot_levels.go +++ b/app/boot_levels.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "fmt" "os" + "time" authService "github.com/cortezaproject/corteza-server/auth" authHandlers "github.com/cortezaproject/corteza-server/auth/handlers" @@ -272,26 +273,6 @@ func (app *CortezaApp) InitServices(ctx context.Context) (err error) { return nil } - { - // Init DAL and prepare default connection - if _, err = dal.InitGlobalService( - ctx, - app.Log.Named("DAL"), - app.Opt.Environment.IsDevelopment(), - - // DB_DSN is the default connection with full capabilities - app.Opt.DB.DSN, - dal.ConnectionDefaults{ - ModelIdent: defaultComposeRecordTable, - AttributeIdent: defaultComposeRecordValueCol, - - PartitionFormat: defaultPartitionFormat, - }, - capabilities.FullCapabilities()...); err != nil { - return err - } - } - if err := app.Provision(ctx); err != nil { return err } @@ -300,6 +281,40 @@ func (app *CortezaApp) InitServices(ctx context.Context) (err error) { return } + var primaryDALConnection = types.Connection{ + // Using id.Next since we dropped "special" ids a while ago. + // If needed, use the handle + ID: id.Next(), + Handle: "primary_connection", + DSN: app.Opt.DB.DSN, + Location: "@todo", + Ownership: "@todo", + // @todo + Sensitive: true, + Config: types.ConnectionConfig{ + DefaultModelIdent: defaultComposeRecordTable, + DefaultAttributeIdent: defaultComposeRecordValueCol, + DefaultPartitionFormat: defaultPartitionFormat, + }, + Capabilities: types.ConnectionCapabilities{ + Supported: capabilities.FullCapabilities(), + }, + CreatedAt: time.Now(), + CreatedBy: auth.ServiceUser().ID, + } + // Init DAL and prepare default connection + if _, err = dal.InitGlobalService( + ctx, + app.Log.Named("DAL"), + app.Opt.Environment.IsDevelopment(), + + // DB_DSN is the default connection with full capabilities + primaryDALConnection.DSN, + primaryDALConnection.ConnectionDefaults(), + primaryDALConnection.ActiveCapabilities()...); err != nil { + return err + } + if app.Opt.Auth.DefaultClient != "" { // default client will help streamline authorization with default clients app.DefaultAuthClient, err = store.LookupAuthClientByHandle(ctx, app.Store, app.Opt.Auth.DefaultClient) @@ -420,7 +435,7 @@ func (app *CortezaApp) InitServices(ctx context.Context) (err error) { // // Note: this is a legacy approach, all services from all 3 apps // will most likely be merged in the future - err = sysService.Initialize(ctx, app.Log, app.Store, app.WsServer, sysService.Config{ + err = sysService.Initialize(ctx, app.Log, app.Store, primaryDALConnection, app.WsServer, sysService.Config{ ActionLog: app.Opt.ActionLog, Discovery: app.Opt.Discovery, Storage: app.Opt.ObjStore, diff --git a/system/rest.yaml b/system/rest.yaml index 96763bf2a..563bbf373 100644 --- a/system/rest.yaml +++ b/system/rest.yaml @@ -835,6 +835,10 @@ endpoints: name: labels title: Labels parser: label.ParseStrings + - name: readPrimary + method: GET + title: Read primary connection details + path: "/primary" - name: read method: GET title: Read connection details diff --git a/system/rest/connection.go b/system/rest/connection.go index 2112b5a56..4198b9f15 100644 --- a/system/rest/connection.go +++ b/system/rest/connection.go @@ -118,6 +118,10 @@ func (ctrl Connection) Update(ctx context.Context, r *request.ConnectionUpdate) return ctrl.svc.Update(ctx, connection) } +func (ctrl Connection) ReadPrimary(ctx context.Context, r *request.ConnectionReadPrimary) (interface{}, error) { + return ctrl.svc.FindByID(ctx, 0) +} + func (ctrl Connection) Read(ctx context.Context, r *request.ConnectionRead) (interface{}, error) { return ctrl.svc.FindByID(ctx, r.ConnectionID) } diff --git a/system/rest/handlers/connection.go b/system/rest/handlers/connection.go index 02e9de96b..6359415ce 100644 --- a/system/rest/handlers/connection.go +++ b/system/rest/handlers/connection.go @@ -22,6 +22,7 @@ type ( List(context.Context, *request.ConnectionList) (interface{}, error) Create(context.Context, *request.ConnectionCreate) (interface{}, error) Update(context.Context, *request.ConnectionUpdate) (interface{}, error) + ReadPrimary(context.Context, *request.ConnectionReadPrimary) (interface{}, error) Read(context.Context, *request.ConnectionRead) (interface{}, error) Delete(context.Context, *request.ConnectionDelete) (interface{}, error) Undelete(context.Context, *request.ConnectionUndelete) (interface{}, error) @@ -29,12 +30,13 @@ type ( // HTTP API interface Connection struct { - List func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) - Update func(http.ResponseWriter, *http.Request) - Read func(http.ResponseWriter, *http.Request) - Delete func(http.ResponseWriter, *http.Request) - Undelete func(http.ResponseWriter, *http.Request) + List func(http.ResponseWriter, *http.Request) + Create func(http.ResponseWriter, *http.Request) + Update func(http.ResponseWriter, *http.Request) + ReadPrimary func(http.ResponseWriter, *http.Request) + Read func(http.ResponseWriter, *http.Request) + Delete func(http.ResponseWriter, *http.Request) + Undelete func(http.ResponseWriter, *http.Request) } ) @@ -88,6 +90,22 @@ func NewConnection(h ConnectionAPI) *Connection { api.Send(w, r, value) }, + ReadPrimary: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewConnectionReadPrimary() + if err := params.Fill(r); err != nil { + api.Send(w, r, err) + return + } + + value, err := h.ReadPrimary(r.Context(), params) + if err != nil { + api.Send(w, r, err) + return + } + + api.Send(w, r, value) + }, Read: func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() params := request.NewConnectionRead() @@ -145,6 +163,7 @@ func (h Connection) MountRoutes(r chi.Router, middlewares ...func(http.Handler) r.Get("/connections/", h.List) r.Post("/connections/", h.Create) r.Put("/connections/{connectionID}", h.Update) + r.Get("/connections/primary", h.ReadPrimary) r.Get("/connections/{connectionID}", h.Read) r.Delete("/connections/{connectionID}", h.Delete) r.Post("/connections/{connectionID}/undelete", h.Undelete) diff --git a/system/rest/request/connection.go b/system/rest/request/connection.go index 0a18db5e2..5ebbac880 100644 --- a/system/rest/request/connection.go +++ b/system/rest/request/connection.go @@ -171,6 +171,9 @@ type ( Labels map[string]string } + ConnectionReadPrimary struct { + } + ConnectionRead struct { // ConnectionID PATH parameter // @@ -822,6 +825,22 @@ func (r *ConnectionUpdate) Fill(req *http.Request) (err error) { return err } +// NewConnectionReadPrimary request +func NewConnectionReadPrimary() *ConnectionReadPrimary { + return &ConnectionReadPrimary{} +} + +// Auditable returns all auditable/loggable parameters +func (r ConnectionReadPrimary) Auditable() map[string]interface{} { + return map[string]interface{}{} +} + +// Fill processes request and fills internal variables +func (r *ConnectionReadPrimary) Fill(req *http.Request) (err error) { + + return err +} + // NewConnectionRead request func NewConnectionRead() *ConnectionRead { return &ConnectionRead{} diff --git a/system/service/connection.go b/system/service/connection.go index 34246f717..6a3d70ee9 100644 --- a/system/service/connection.go +++ b/system/service/connection.go @@ -18,6 +18,8 @@ type ( store store.Storer ac connectionAccessController dal dalConnections + + primaryConnection types.Connection } connectionAccessController interface { @@ -37,12 +39,13 @@ type ( } ) -func Connection(ctx context.Context, dal dalConnections) (*connection, error) { +func Connection(ctx context.Context, pcOpts types.Connection, dal dalConnections) (*connection, error) { out := &connection{ - ac: DefaultAccessControl, - actionlog: DefaultActionlog, - store: DefaultStore, - dal: dal, + ac: DefaultAccessControl, + actionlog: DefaultActionlog, + store: DefaultStore, + dal: dal, + primaryConnection: pcOpts, } return out, out.reloadConnections(ctx) @@ -54,6 +57,13 @@ func (svc *connection) FindByID(ctx context.Context, ID uint64) (q *types.Connec ) err = func() error { + if ID == 0 { + // primary; construct it since it doesn't actually exist + aux := svc.primaryConnection + q = &aux + return nil + } + if ID == 0 { return ConnectionErrInvalidID() } diff --git a/system/service/service.go b/system/service/service.go index c69d8d743..a6e1752a8 100644 --- a/system/service/service.go +++ b/system/service/service.go @@ -86,6 +86,7 @@ var ( DefaultApigwFilter *apigwFilter DefaultApigwProfiler *apigwProfiler DefaultReport *report + primaryConnectionConfig types.Connection DefaultStatistics *statistics @@ -101,7 +102,7 @@ var ( } ) -func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websocketSender, c Config) (err error) { +func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, primaryConn types.Connection, ws websocketSender, c Config) (err error) { var ( hcd = healthcheck.Defaults() ) @@ -147,7 +148,8 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock DefaultSettings = Settings(ctx, DefaultStore, DefaultLogger, DefaultAccessControl, CurrentSettings) - DefaultConnection, err = Connection(ctx, dal.Service()) + primaryConnectionConfig = primaryConn + DefaultConnection, err = Connection(ctx, primaryConnectionConfig, dal.Service()) if err != nil { return }