2022-11-18 09:57:31 +00:00
|
|
|
package config
|
|
|
|
|
2022-11-23 14:20:03 +00:00
|
|
|
import (
|
2023-03-08 15:14:24 +00:00
|
|
|
"os"
|
2023-04-03 14:23:53 +00:00
|
|
|
"path/filepath"
|
2023-03-08 15:14:24 +00:00
|
|
|
|
2023-05-16 16:35:39 +00:00
|
|
|
"github.com/databricks/cli/libs/databrickscfg"
|
2022-11-24 20:41:57 +00:00
|
|
|
"github.com/databricks/databricks-sdk-go"
|
2023-03-29 18:44:19 +00:00
|
|
|
"github.com/databricks/databricks-sdk-go/config"
|
2023-10-16 06:56:06 +00:00
|
|
|
"github.com/databricks/databricks-sdk-go/marshal"
|
2023-04-21 08:30:20 +00:00
|
|
|
"github.com/databricks/databricks-sdk-go/service/iam"
|
2022-11-23 14:20:03 +00:00
|
|
|
)
|
|
|
|
|
2022-11-18 09:57:31 +00:00
|
|
|
// Workspace defines configurables at the workspace level.
|
|
|
|
type Workspace struct {
|
2022-11-23 14:20:03 +00:00
|
|
|
// Unified authentication attributes.
|
|
|
|
//
|
|
|
|
// We omit sensitive attributes as they should never be hardcoded.
|
|
|
|
// They must be specified through environment variables instead.
|
|
|
|
//
|
|
|
|
// For example: token, password, Google credentials, Azure client secret, etc.
|
|
|
|
//
|
|
|
|
|
|
|
|
// Generic attributes.
|
2023-07-19 12:06:58 +00:00
|
|
|
Host string `json:"host,omitempty"`
|
|
|
|
Profile string `json:"profile,omitempty"`
|
|
|
|
AuthType string `json:"auth_type,omitempty"`
|
2023-08-10 10:03:52 +00:00
|
|
|
MetadataServiceURL string `json:"metadata_service_url,omitempty" bundle:"internal"`
|
2023-07-19 12:06:58 +00:00
|
|
|
|
|
|
|
// OAuth specific attributes.
|
|
|
|
ClientID string `json:"client_id,omitempty"`
|
2022-11-23 14:20:03 +00:00
|
|
|
|
|
|
|
// Google specific attributes.
|
|
|
|
GoogleServiceAccount string `json:"google_service_account,omitempty"`
|
|
|
|
|
|
|
|
// Azure specific attributes.
|
|
|
|
AzureResourceID string `json:"azure_workspace_resource_id,omitempty"`
|
|
|
|
AzureUseMSI bool `json:"azure_use_msi,omitempty"`
|
|
|
|
AzureClientID string `json:"azure_client_id,omitempty"`
|
|
|
|
AzureTenantID string `json:"azure_tenant_id,omitempty"`
|
|
|
|
AzureEnvironment string `json:"azure_environment,omitempty"`
|
|
|
|
AzureLoginAppID string `json:"azure_login_app_id,omitempty"`
|
2022-11-30 13:15:22 +00:00
|
|
|
|
2022-12-01 10:17:29 +00:00
|
|
|
// CurrentUser holds the current user.
|
|
|
|
// This is set after configuration initialization.
|
2023-07-30 07:19:49 +00:00
|
|
|
CurrentUser *User `json:"current_user,omitempty" bundle:"readonly"`
|
2022-12-01 10:17:29 +00:00
|
|
|
|
2023-04-12 14:54:36 +00:00
|
|
|
// Remote workspace base path for deployment state, for artifacts, as synchronization target.
|
2023-08-17 15:22:32 +00:00
|
|
|
// This defaults to "~/.bundle/${bundle.name}/${bundle.target}" where "~" expands to
|
2023-01-26 18:55:38 +00:00
|
|
|
// the current user's home directory in the workspace (e.g. `/Users/jane@doe.com`).
|
2023-04-12 14:54:36 +00:00
|
|
|
RootPath string `json:"root_path,omitempty"`
|
2023-01-26 18:55:38 +00:00
|
|
|
|
2023-04-12 14:54:36 +00:00
|
|
|
// Remote workspace path to synchronize local files to.
|
2023-01-26 18:55:38 +00:00
|
|
|
// This defaults to "${workspace.root}/files".
|
2023-11-15 13:37:26 +00:00
|
|
|
FilePath string `json:"file_path,omitempty"`
|
2023-01-26 18:55:38 +00:00
|
|
|
|
2023-04-12 14:54:36 +00:00
|
|
|
// Remote workspace path for build artifacts.
|
2023-01-26 18:55:38 +00:00
|
|
|
// This defaults to "${workspace.root}/artifacts".
|
2023-11-15 13:37:26 +00:00
|
|
|
ArtifactPath string `json:"artifact_path,omitempty"`
|
2023-01-26 18:55:38 +00:00
|
|
|
|
2023-04-12 14:54:36 +00:00
|
|
|
// Remote workspace path for deployment state.
|
2023-01-26 18:55:38 +00:00
|
|
|
// This defaults to "${workspace.root}/state".
|
2023-04-12 14:54:36 +00:00
|
|
|
StatePath string `json:"state_path,omitempty"`
|
2022-11-23 14:20:03 +00:00
|
|
|
}
|
|
|
|
|
2023-07-30 07:19:49 +00:00
|
|
|
type User struct {
|
|
|
|
// A short name for the user, based on the user's UserName.
|
|
|
|
ShortName string `json:"short_name,omitempty" bundle:"readonly"`
|
|
|
|
|
|
|
|
*iam.User
|
|
|
|
}
|
|
|
|
|
2023-10-16 06:56:06 +00:00
|
|
|
func (s *User) UnmarshalJSON(b []byte) error {
|
|
|
|
return marshal.Unmarshal(b, s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s User) MarshalJSON() ([]byte, error) {
|
|
|
|
return marshal.Marshal(s)
|
|
|
|
}
|
|
|
|
|
2024-04-03 08:14:04 +00:00
|
|
|
func (w *Workspace) Config() *config.Config {
|
|
|
|
cfg := &config.Config{
|
2022-11-23 14:20:03 +00:00
|
|
|
// Generic
|
2023-07-19 12:06:58 +00:00
|
|
|
Host: w.Host,
|
|
|
|
Profile: w.Profile,
|
|
|
|
AuthType: w.AuthType,
|
|
|
|
MetadataServiceURL: w.MetadataServiceURL,
|
|
|
|
|
|
|
|
// OAuth
|
|
|
|
ClientID: w.ClientID,
|
2022-11-23 14:20:03 +00:00
|
|
|
|
|
|
|
// Google
|
|
|
|
GoogleServiceAccount: w.GoogleServiceAccount,
|
|
|
|
|
|
|
|
// Azure
|
|
|
|
AzureResourceID: w.AzureResourceID,
|
|
|
|
AzureUseMSI: w.AzureUseMSI,
|
|
|
|
AzureClientID: w.AzureClientID,
|
|
|
|
AzureTenantID: w.AzureTenantID,
|
|
|
|
AzureEnvironment: w.AzureEnvironment,
|
|
|
|
AzureLoginAppID: w.AzureLoginAppID,
|
|
|
|
}
|
|
|
|
|
2024-04-03 08:14:04 +00:00
|
|
|
for k := range config.ConfigAttributes {
|
|
|
|
attr := &config.ConfigAttributes[k]
|
|
|
|
if !attr.IsZero(cfg) {
|
|
|
|
cfg.SetAttrSource(attr, config.Source{Type: config.SourceType("bundle")})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *Workspace) Client() (*databricks.WorkspaceClient, error) {
|
|
|
|
cfg := w.Config()
|
|
|
|
|
2023-03-29 18:44:19 +00:00
|
|
|
// If only the host is configured, we try and unambiguously match it to
|
|
|
|
// a profile in the user's databrickscfg file. Override the default loaders.
|
2023-07-12 12:09:25 +00:00
|
|
|
if w.Host != "" && w.Profile == "" {
|
2023-04-05 16:12:11 +00:00
|
|
|
cfg.Loaders = []config.Loader{
|
|
|
|
// Load auth creds from env vars
|
|
|
|
config.ConfigAttributes,
|
|
|
|
|
|
|
|
// Our loader that resolves a profile from the host alone.
|
|
|
|
// This only kicks in if the above loaders don't configure auth.
|
|
|
|
databrickscfg.ResolveProfileFromHost,
|
|
|
|
}
|
2023-03-29 18:44:19 +00:00
|
|
|
}
|
|
|
|
|
2023-10-20 13:10:31 +00:00
|
|
|
// Resolve the configuration. This is done by [databricks.NewWorkspaceClient] as well, but here
|
|
|
|
// we need to verify that a profile, if loaded, matches the host configured in the bundle.
|
|
|
|
err := cfg.EnsureResolved()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that the configuration is resolved, we can verify that the host in the bundle configuration
|
|
|
|
// is identical to the host associated with the selected profile.
|
|
|
|
if w.Host != "" && w.Profile != "" {
|
2024-04-03 08:14:04 +00:00
|
|
|
err := databrickscfg.ValidateConfigAndProfileHost(cfg, w.Profile)
|
2023-07-12 12:09:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-03 08:14:04 +00:00
|
|
|
return databricks.NewWorkspaceClient((*databricks.Config)(cfg))
|
2022-11-18 09:57:31 +00:00
|
|
|
}
|
2023-03-08 15:14:24 +00:00
|
|
|
|
|
|
|
func init() {
|
2023-04-03 14:23:53 +00:00
|
|
|
arg0 := os.Args[0]
|
|
|
|
|
2023-05-22 14:40:50 +00:00
|
|
|
// Configure DATABRICKS_CLI_PATH only if our caller intends to use this specific version of this binary.
|
2023-04-03 14:23:53 +00:00
|
|
|
// Otherwise, if it is equal to its basename, processes can find it in $PATH.
|
|
|
|
if arg0 != filepath.Base(arg0) {
|
2023-05-22 14:40:50 +00:00
|
|
|
os.Setenv("DATABRICKS_CLI_PATH", arg0)
|
2023-04-03 14:23:53 +00:00
|
|
|
}
|
2023-03-08 15:14:24 +00:00
|
|
|
}
|