Skip to content

Commit

Permalink
Ensure GetDefaultDatabaseConfig is only called once
Browse files Browse the repository at this point in the history
Update GetDefaultDatabaseConfig to accept mod
remove DefaultDatabase global
dashboardServer and dashboardExecutor store defaultDatabase and defaultSearchPathConfig
tidy determineBackendSupport
v1.2.1
  • Loading branch information
kaidaguerre committed Jan 31, 2025
1 parent 931eb5a commit 25996e8
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 129 deletions.
6 changes: 3 additions & 3 deletions internal/cmd/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func runModInstallCmd(cmd *cobra.Command, args []string) {

// if any mod names were passed as args, convert into formed mod names
installOpts := modinstaller.NewInstallOpts(workspaceMod, args...)
installOpts.PluginVersions = getPluginVersions(ctx)
installOpts.PluginVersions = getPluginVersions(ctx, workspaceMod)

installData, err := modinstaller.InstallWorkspaceDependencies(ctx, installOpts)
if err != nil {
Expand All @@ -162,8 +162,8 @@ func validateModArgs() error {
return localcmdconfig.ValidateDatabaseArg()
}

func getPluginVersions(ctx context.Context) *plugin.PluginVersionMap {
defaultDatabase, _, err := db_client.GetDefaultDatabaseConfig()
func getPluginVersions(ctx context.Context, workspaceMod *modconfig.Mod) *plugin.PluginVersionMap {
defaultDatabase, _, err := db_client.GetDefaultDatabaseConfig(workspaceMod)
if err != nil {
if !viper.GetBool(constants.ArgForce) {
error_helpers.ShowWarning("Could not connect to database - plugin validation will not be performed")
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func runServerCmd(cmd *cobra.Command, _ []string) {
// setup a new webSocket service
webSocket := melody.New()
// create the dashboardServer
dashboardServer, err := dashboardserver.NewServer(ctx, modInitData.Workspace, webSocket)
dashboardServer, err := dashboardserver.NewServer(ctx, modInitData, webSocket)
error_helpers.FailOnError(err)

// send it over to the powerpipe API Server
Expand Down
11 changes: 3 additions & 8 deletions internal/dashboardexecute/dashboard_execution_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ type DashboardExecutionTree struct {
DateTimeRange utils.TimeRange
}

func newDashboardExecutionTree(rootResource modconfig.ModTreeItem, sessionId string, workspace *workspace.PowerpipeWorkspace, inputs *InputValues, defaultClientMap *db_client.ClientMap, opts ...backend.BackendOption) (*DashboardExecutionTree, error) {
func (e *DashboardExecutor) newDashboardExecutionTree(rootResource modconfig.ModTreeItem, sessionId string, workspace *workspace.PowerpipeWorkspace, inputs *InputValues, opts ...backend.BackendOption) (*DashboardExecutionTree, error) {
// now populate the DashboardExecutionTree
executionTree := &DashboardExecutionTree{
dashboardName: rootResource.Name(),
sessionId: sessionId,
defaultClientMap: defaultClientMap,
defaultClientMap: e.defaultClient,
clientMap: db_client.NewClientMap(),
runs: make(map[string]dashboardtypes.DashboardTreeRun),
workspace: workspace,
Expand All @@ -63,12 +63,7 @@ func newDashboardExecutionTree(rootResource modconfig.ModTreeItem, sessionId str
}
executionTree.id = fmt.Sprintf("%p", executionTree)

// set the dashboard database and search patch config
defaultDatabase, defaultSearchPathConfig, err := db_client.GetDefaultDatabaseConfig(opts...)
if err != nil {
return nil, err
}
database, searchPathConfig, err := db_client.GetDatabaseConfigForResource(rootResource, workspace.Mod, defaultDatabase, defaultSearchPathConfig)
database, searchPathConfig, err := db_client.GetDatabaseConfigForResource(rootResource, workspace.Mod, e.defaultDatabase, e.defaultSearchPathConfig)
if err != nil {
return nil, err
}
Expand Down
15 changes: 10 additions & 5 deletions internal/dashboardexecute/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

filehelpers "github.com/turbot/go-kit/files"
"github.com/turbot/pipe-fittings/v2/backend"
"github.com/turbot/pipe-fittings/v2/connection"
"github.com/turbot/pipe-fittings/v2/modconfig"
"github.com/turbot/pipe-fittings/v2/utils"
"github.com/turbot/powerpipe/internal/dashboardevents"
Expand All @@ -29,15 +30,19 @@ type DashboardExecutor struct {
interactive bool
// store the default client which is created during initData creation
// - this is to avoid creating a new client for each dashboard execution if the database/search path is NOT overridden
defaultClient *db_client.ClientMap
defaultClient *db_client.ClientMap
defaultDatabase connection.ConnectionStringProvider
defaultSearchPathConfig backend.SearchPathConfig
}

func NewDashboardExecutor(defaultClient *db_client.ClientMap) *DashboardExecutor {
func NewDashboardExecutor(defaultClient *db_client.ClientMap, defaultDatabase connection.ConnectionStringProvider, defaultSearchPathConfig backend.SearchPathConfig) *DashboardExecutor {
return &DashboardExecutor{
executions: make(map[string]*DashboardExecutionTree),
// default to interactive execution
interactive: true,
defaultClient: defaultClient,
interactive: true,
defaultClient: defaultClient,
defaultDatabase: defaultDatabase,
defaultSearchPathConfig: defaultSearchPathConfig,
}
}

Expand Down Expand Up @@ -68,7 +73,7 @@ func (e *DashboardExecutor) ExecuteDashboard(ctx context.Context, sessionId stri
e.CancelExecutionForSession(ctx, sessionId)

// now create a new execution
executionTree, err = newDashboardExecutionTree(rootResource, sessionId, workspace, inputs, e.defaultClient, opts...)
executionTree, err = e.newDashboardExecutionTree(rootResource, sessionId, workspace, inputs, opts...)
if err != nil {
return err
}
Expand Down
90 changes: 90 additions & 0 deletions internal/dashboardserver/backend_support.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package dashboardserver

import (
"github.com/turbot/pipe-fittings/v2/connection"
"github.com/turbot/pipe-fittings/v2/modconfig"
"log/slog"
)

type backendSupport struct {
supportsSearchPath bool
supportsTimeRange bool
}

// setFromDb sets the backend support based on the database type
func (bs *backendSupport) setFromDb(db connection.ConnectionStringProvider) {
if db != nil {
switch db.(type) {
case *connection.SteampipePgConnection, *connection.PostgresConnection:
bs.supportsSearchPath = true
case *connection.TailpipeConnection:
bs.supportsTimeRange = true
}
}
}

func newBackendSupport(database connection.ConnectionStringProvider) *backendSupport {
bs := &backendSupport{}
bs.setFromDb(database)
return bs
}

// determineBackendSupport determines the backend support for a dashboard
// if no resource has a specified database, use the default database to set the backend support
func determineBackendSupport(dashboard modconfig.ModTreeItem, defaultDatabase connection.ConnectionStringProvider) backendSupport {
bs := determineBackendSupportForResource(dashboard)
if bs == nil {
slog.Info("determineBackendSupport - no resource in the tree specifies a database, using default database")
bs = newBackendSupport(defaultDatabase)
}

slog.Info("determineBackendSupport", "supportsSearchPath", bs.supportsSearchPath, "supportsTimeRange", bs.supportsTimeRange)
return *bs
}

func determineBackendSupportForResource(item modconfig.ModTreeItem) *backendSupport {
var bs *backendSupport

// NOT: just check the database on this resource - GetDatabase also checks the parents
// - there is no need to do that here as we are traversing down the tree
if db := item.GetModTreeItemImpl().Database; db != nil {
bs = &backendSupport{}
bs.setFromDb(db)
slog.Info("determineBackendSupportForResource - resource has database", "resource", item.Name(), "backendSupport", bs)
}

// if we have now set both flags, we can stop - no need to traverse further
if backendSupportsAll(bs) {
return bs
}

for _, child := range item.GetChildren() {
childBs := determineBackendSupportForResource(child)
// merge this with out ba
bs = mergeBackendSupport(bs, childBs)

// if we have now set both flags, we can stop - no need to traverse further
if backendSupportsAll(bs) {
return bs
}
}
return bs
}

func backendSupportsAll(bs *backendSupport) bool {
return bs != nil && bs.supportsSearchPath && bs.supportsTimeRange
}

// merge 2 backend support objects
func mergeBackendSupport(bs1, bs2 *backendSupport) *backendSupport {
if bs1 == nil {
return bs2
}
if bs2 == nil {
return bs1
}
return &backendSupport{
supportsSearchPath: bs1.supportsSearchPath || bs2.supportsSearchPath,
supportsTimeRange: bs1.supportsTimeRange || bs2.supportsTimeRange,
}
}
74 changes: 7 additions & 67 deletions internal/dashboardserver/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/spf13/viper"
"log/slog"

"github.com/spf13/viper"
typeHelpers "github.com/turbot/go-kit/types"
"github.com/turbot/pipe-fittings/v2/app_specific"
"github.com/turbot/pipe-fittings/v2/backend"
"github.com/turbot/pipe-fittings/v2/connection"
"github.com/turbot/pipe-fittings/v2/constants"
"github.com/turbot/pipe-fittings/v2/modconfig"
"github.com/turbot/pipe-fittings/v2/steampipeconfig"
Expand All @@ -23,7 +22,7 @@ import (
"github.com/turbot/steampipe-plugin-sdk/v5/sperr"
)

func buildServerMetadataPayload(rm modconfig.ModResources, pipesMetadata *steampipeconfig.PipesMetadata) ([]byte, error) {
func (s *Server) buildServerMetadataPayload(rm modconfig.ModResources, pipesMetadata *steampipeconfig.PipesMetadata) ([]byte, error) {
workspaceResources := rm.(*resources.PowerpipeModResources)
installedMods := make(map[string]*ModMetadata)
for _, mod := range workspaceResources.Mods {
Expand Down Expand Up @@ -52,14 +51,8 @@ func buildServerMetadataPayload(rm modconfig.ModResources, pipesMetadata *steamp
cliVersion = versionFile.Version
}

defaultDatabase, defaultSearchPathConfig, err := db_client.GetDefaultDatabaseConfig()
if err != nil {
return nil, err
}

// populate the backend support flags (supportsSearchPath, supportsTimeRange) from the default database
var bs backendSupport
bs.setFromDb(defaultDatabase)
bs := newBackendSupport(s.defaultDatabase)

payload := ServerMetadataPayload{
Action: "server_metadata",
Expand All @@ -74,11 +67,11 @@ func buildServerMetadataPayload(rm modconfig.ModResources, pipesMetadata *steamp
},
}

connectionString, err := defaultDatabase.GetConnectionString()
connectionString, err := s.defaultDatabase.GetConnectionString()
if err != nil {
return nil, err
}
searchPath, err := getSearchPathMetadata(context.Background(), connectionString, defaultSearchPathConfig)
searchPath, err := getSearchPathMetadata(context.Background(), connectionString, s.defaultSearchPathConfig)
if err != nil {
return nil, err
}
Expand All @@ -99,18 +92,12 @@ func buildServerMetadataPayload(rm modconfig.ModResources, pipesMetadata *steamp
return json.Marshal(payload)
}

func buildDashboardMetadataPayload(dashboard modconfig.ModTreeItem) ([]byte, error) {
func (s *Server) buildDashboardMetadataPayload(dashboard modconfig.ModTreeItem) ([]byte, error) {
slog.Debug("calling buildDashboardMetadataPayload")

defaultDatabase, _, err := db_client.GetDefaultDatabaseConfig()
if err != nil {
slog.Warn("error getting database config for resource", "error", err)
return nil, err
}

// walk the tree of resources and determine whether any of them are using a tailpipe/steampipe/postrgres
// and set the SupportsSearchPath and SupportsTimeRange flags accordingly
backendSupport := determineBackendSupport(dashboard, defaultDatabase)
backendSupport := determineBackendSupport(dashboard, s.defaultDatabase)

payload := DashboardMetadataPayload{
Action: "dashboard_metadata",
Expand All @@ -128,53 +115,6 @@ func buildDashboardMetadataPayload(dashboard modconfig.ModTreeItem) ([]byte, err
return res, nil
}

type backendSupport struct {
supportsSearchPath bool
supportsTimeRange bool
}

func (bs *backendSupport) setFromDb(db connection.ConnectionStringProvider) {
if db != nil {
switch db.(type) {
case *connection.SteampipePgConnection, *connection.PostgresConnection:
bs.supportsSearchPath = true
case *connection.TailpipeConnection:
bs.supportsTimeRange = true
}
}
}
func determineBackendSupport(dashboard modconfig.ModTreeItem, defaultDatabase connection.ConnectionStringProvider) backendSupport {
var res backendSupport

usingDefaultDb := determineBackendSupportForResource(dashboard, &res)
if usingDefaultDb {
res.setFromDb(defaultDatabase)
}
return res
}

func determineBackendSupportForResource(item modconfig.ModTreeItem, bs *backendSupport) bool {
var usingDefaultDb bool
db := item.GetDatabase()
if db == nil {
usingDefaultDb = true
} else {
bs.setFromDb(db)
}

// if we have now found both, we can stop
if bs.supportsSearchPath && bs.supportsTimeRange {
return false
}
for _, child := range item.GetChildren() {
childUsingDefaultDb := determineBackendSupportForResource(child, bs)
if childUsingDefaultDb {
usingDefaultDb = true
}
}
return usingDefaultDb
}

func getSearchPathMetadata(ctx context.Context, database string, searchPathConfig backend.SearchPathConfig) (*SearchPathMetadata, error) {
// if backend supports search path, get it
client, err := db_client.NewClientMap().GetOrCreate(ctx, database, searchPathConfig)
Expand Down
Loading

0 comments on commit 25996e8

Please sign in to comment.