github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/steampipeconfig/workspace_profile_loader.go (about) 1 package steampipeconfig 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "os" 8 "path/filepath" 9 10 "github.com/spf13/viper" 11 "github.com/turbot/steampipe-plugin-sdk/v5/sperr" 12 "github.com/turbot/steampipe/pkg/constants" 13 "github.com/turbot/steampipe/pkg/steampipeconfig/modconfig" 14 "github.com/turbot/steampipe/pkg/steampipeconfig/parse" 15 "github.com/turbot/steampipe/pkg/utils" 16 ) 17 18 var GlobalWorkspaceProfile *modconfig.WorkspaceProfile 19 var defaultWorkspaceSampleFileName = "workspaces.spc.sample" 20 21 type WorkspaceProfileLoader struct { 22 workspaceProfiles map[string]*modconfig.WorkspaceProfile 23 workspaceProfilePath string 24 DefaultProfile *modconfig.WorkspaceProfile 25 ConfiguredProfile *modconfig.WorkspaceProfile 26 } 27 28 func ensureDefaultWorkspaceFile(configFolder string) error { 29 // always write the workspaces.spc.sample file 30 err := os.MkdirAll(configFolder, 0755) 31 if err != nil { 32 return err 33 } 34 defaultWorkspaceSampleFile := filepath.Join(configFolder, defaultWorkspaceSampleFileName) 35 err = os.WriteFile(defaultWorkspaceSampleFile, []byte(constants.DefaultWorkspaceContent), 0755) 36 if err != nil { 37 return err 38 } 39 return nil 40 } 41 42 func NewWorkspaceProfileLoader(ctx context.Context, workspaceProfilePath string) (*WorkspaceProfileLoader, error) { 43 // write the workspaces.spc.sample file 44 if err := ensureDefaultWorkspaceFile(workspaceProfilePath); err != nil { 45 return nil, 46 sperr.WrapWithMessage( 47 err, 48 "could not create sample workspace", 49 ) 50 } 51 loader := &WorkspaceProfileLoader{workspaceProfilePath: workspaceProfilePath} 52 workspaceProfiles, err := loader.load(ctx) 53 if err != nil { 54 return nil, err 55 } 56 loader.workspaceProfiles = workspaceProfiles 57 58 defaultProfile, err := loader.get("default") 59 if err != nil { 60 // there must always be a default - this should have been added by parse.LoadWorkspaceProfiles 61 return nil, err 62 } 63 loader.DefaultProfile = defaultProfile 64 65 if viper.IsSet(constants.ArgWorkspaceProfile) { 66 configuredProfile, err := loader.get(viper.GetString(constants.ArgWorkspaceProfile)) 67 if err != nil { 68 // could not find configured profile 69 return nil, err 70 } 71 loader.ConfiguredProfile = configuredProfile 72 } 73 74 return loader, nil 75 } 76 77 func (l *WorkspaceProfileLoader) GetActiveWorkspaceProfile() *modconfig.WorkspaceProfile { 78 if l.ConfiguredProfile != nil { 79 return l.ConfiguredProfile 80 } 81 return l.DefaultProfile 82 } 83 84 func (l *WorkspaceProfileLoader) get(name string) (*modconfig.WorkspaceProfile, error) { 85 if workspaceProfile, ok := l.workspaceProfiles[name]; ok { 86 return workspaceProfile, nil 87 } 88 89 if implicitWorkspace := l.getImplicitWorkspace(name); implicitWorkspace != nil { 90 return implicitWorkspace, nil 91 } 92 93 return nil, fmt.Errorf("workspace profile %s does not exist", name) 94 } 95 96 func (l *WorkspaceProfileLoader) load(ctx context.Context) (map[string]*modconfig.WorkspaceProfile, error) { 97 // get all the config files in the directory 98 return parse.LoadWorkspaceProfiles(ctx, l.workspaceProfilePath) 99 } 100 101 /* 102 Named workspaces follow normal standards for hcl identities, thus they cannot contain the slash (/) character. 103 104 If you pass a value to --workspace or STEAMPIPE_WORKSPACE in the form of {identity_handle}/{workspace_handle}, 105 it will be interpreted as an implicit workspace. 106 107 Implicit workspaces, as the name suggests, do not need to be specified in the workspaces.spc file. 108 109 Instead they will be assumed to refer to a Turbot Pipes workspace, 110 which will be used as both the database and snapshot location. 111 112 Essentially, --workspace acme/dev is equivalent to: 113 114 workspace "acme/dev" { 115 workspace_database = "acme/dev" 116 snapshot_location = "acme/dev" 117 } 118 */ 119 func (l *WorkspaceProfileLoader) getImplicitWorkspace(name string) *modconfig.WorkspaceProfile { 120 if IsCloudWorkspaceIdentifier(name) { 121 log.Printf("[TRACE] getImplicitWorkspace - %s is implicit workspace: SnapshotLocation=%s, WorkspaceDatabase=%s", name, name, name) 122 return &modconfig.WorkspaceProfile{ 123 SnapshotLocation: utils.ToStringPointer(name), 124 WorkspaceDatabase: utils.ToStringPointer(name), 125 } 126 } 127 return nil 128 }