Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 213
Add a foundation for built-in templates#685
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
59c1c732b67262737c6122955e846ae0279568afe037de1e7a7c69289435670cfa8a8343403569d41ccc33d8f38File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -28,3 +28,6 @@ __pycache__ | ||
| .terraform.lock.hcl | ||
| .vscode/launch.json | ||
| .vscode/tasks.json | ||
| .databricks | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Typings for Pylance in VS Code | ||
| # see https://github.com/microsoft/pyright/blob/main/docs/builtins.md | ||
| from databricks.sdk.runtime import * |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -43,7 +43,7 @@ func getTarget(cmd *cobra.Command) (value string) { | ||
| return target | ||
| } | ||
| func getProfile(cmd *cobra.Command) (value string) { | ||
| func GetProfile(cmd *cobra.Command) (value string) { | ||
lennartkats-db marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // The command line flag takes precedence. | ||
| flag := cmd.Flag("profile") | ||
| if flag != nil { | ||
| @@ -70,7 +70,7 @@ func loadBundle(cmd *cobra.Command, args []string, load func(ctx context.Context | ||
| return nil, nil | ||
| } | ||
| profile := getProfile(cmd) | ||
| profile := GetProfile(cmd) | ||
| if profile != "" { | ||
| b.Config.Workspace.Profile = profile | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package auth | ||
| import ( | ||
| "context" | ||
| "github.com/databricks/databricks-sdk-go" | ||
| ) | ||
| // Determines whether a given user id is a service principal. | ||
| // This function uses a heuristic: if no user exists with this id, we assume | ||
| // it's a service principal. Unfortunately, the standard service principal API is too | ||
| // slow for our purposes. | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should do something else. This can fail for other reasons and if it does will incorrectly assume the user is a service principal. If I look at the scim/me output (that we include in {
"active":true,
"displayName":"sdk-1693297374999987000",
"emails": [
{
"primary":true,
"type":"work",
"value":"a1e691b7-a6df-4a6b-881e-d93a03a7ce52"
}
],
"id":"6079497891687986",
"name": {
"givenName":"sdk-1693297374999987000"
},
"userName":"a1e691b7-a6df-4a6b-881e-d93a03a7ce52"
}ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that always the case though, that the username is an id like that? And will that be the case in the future? ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually — this should have error handling code. Not sure what happened to it. Let me add it back in a cleanup PR: #707. | ||
| func IsServicePrincipal(ctx context.Context, ws *databricks.WorkspaceClient, userId string) bool { | ||
| _, err := ws.Users.GetById(ctx, userId) | ||
| return err != nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,16 @@ | ||
| package template | ||
| import ( | ||
| "context" | ||
| "errors" | ||
| "fmt" | ||
| "net/url" | ||
| "regexp" | ||
| "text/template" | ||
| "github.com/databricks/cli/cmd/root" | ||
| "github.com/databricks/cli/libs/auth" | ||
| "github.com/databricks/databricks-sdk-go/service/iam" | ||
| ) | ||
| type ErrFail struct { | ||
| @@ -20,35 +26,87 @@ type pair struct { | ||
| v any | ||
| } | ||
| var helperFuncs = template.FuncMap{ | ||
| "fail": func(format string, args ...any) (any, error) { | ||
| return nil, ErrFail{fmt.Sprintf(format, args...)} | ||
| }, | ||
| // Alias for https://pkg.go.dev/net/url#Parse. Allows usage of all methods of url.URL | ||
| "url": func(rawUrl string) (*url.URL, error) { | ||
| return url.Parse(rawUrl) | ||
| }, | ||
| // Alias for https://pkg.go.dev/regexp#Compile. Allows usage of all methods of regexp.Regexp | ||
| "regexp": func(expr string) (*regexp.Regexp, error) { | ||
| return regexp.Compile(expr) | ||
| }, | ||
| // A key value pair. This is used with the map function to generate maps | ||
| // to use inside a template | ||
| "pair": func(k string, v any) pair { | ||
| return pair{k, v} | ||
| }, | ||
| // map converts a list of pairs to a map object. This is useful to pass multiple | ||
| // objects to templates defined in the library directory. Go text template | ||
| // syntax for invoking a template only allows specifying a single argument, | ||
| // this function can be used to workaround that limitation. | ||
| // | ||
| // For example: {{template "my_template" (map (pair "foo" $arg1) (pair "bar" $arg2))}} | ||
| // $arg1 and $arg2 can be referred from inside "my_template" as ".foo" and ".bar" | ||
| "map": func(pairs ...pair) map[string]any { | ||
| result := make(map[string]any, 0) | ||
| for _, p := range pairs { | ||
| result[p.k] = p.v | ||
| } | ||
| return result | ||
| }, | ||
| func loadHelpers(ctx context.Context) template.FuncMap { | ||
| var user *iam.User | ||
| var is_service_principal *bool | ||
lennartkats-db marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| w := root.WorkspaceClient(ctx) | ||
| return template.FuncMap{ | ||
| "fail": func(format string, args ...any) (any, error) { | ||
| return nil, ErrFail{fmt.Sprintf(format, args...)} | ||
| }, | ||
| // Alias for https://pkg.go.dev/net/url#Parse. Allows usage of all methods of url.URL | ||
| "url": func(rawUrl string) (*url.URL, error) { | ||
| return url.Parse(rawUrl) | ||
| }, | ||
| // Alias for https://pkg.go.dev/regexp#Compile. Allows usage of all methods of regexp.Regexp | ||
| "regexp": func(expr string) (*regexp.Regexp, error) { | ||
| return regexp.Compile(expr) | ||
| }, | ||
| // A key value pair. This is used with the map function to generate maps | ||
| // to use inside a template | ||
| "pair": func(k string, v any) pair { | ||
| return pair{k, v} | ||
| }, | ||
| // map converts a list of pairs to a map object. This is useful to pass multiple | ||
| // objects to templates defined in the library directory. Go text template | ||
| // syntax for invoking a template only allows specifying a single argument, | ||
| // this function can be used to workaround that limitation. | ||
| // | ||
| // For example: {{template "my_template" (map (pair "foo" $arg1) (pair "bar" $arg2))}} | ||
| // $arg1 and $arg2 can be referred from inside "my_template" as ".foo" and ".bar" | ||
| "map": func(pairs ...pair) map[string]any { | ||
| result := make(map[string]any, 0) | ||
| for _, p := range pairs { | ||
| result[p.k] = p.v | ||
| } | ||
| return result | ||
| }, | ||
| // Get smallest node type (follows Terraform's GetSmallestNodeType) | ||
| "smallest_node_type": func() (string, error) { | ||
| if w.Config.Host == "" { | ||
| return "", errors.New("cannot determine target workspace, please first setup a configuration profile using 'databricks auth login'") | ||
| } | ||
| if w.Config.IsAzure() { | ||
| return "Standard_D3_v2", nil | ||
| } else if w.Config.IsGcp() { | ||
| return "n1-standard-4", nil | ||
| } | ||
| return "i3.xlarge", nil | ||
| }, | ||
| "workspace_host": func() (string, error) { | ||
| if w.Config.Host == "" { | ||
| return "", errors.New("cannot determine target workspace, please first setup a configuration profile using 'databricks auth login'") | ||
| } | ||
| return w.Config.Host, nil | ||
| }, | ||
| "user_name": func() (string, error) { | ||
| if user == nil { | ||
| var err error | ||
| user, err = w.CurrentUser.Me(ctx) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| } | ||
| result := user.UserName | ||
| if result == "" { | ||
| result = user.Id | ||
| } | ||
| return result, nil | ||
| }, | ||
| "is_service_principal": func() (bool, error) { | ||
| if is_service_principal != nil { | ||
| return *is_service_principal, nil | ||
| } | ||
| if user == nil { | ||
| var err error | ||
| user, err = w.CurrentUser.Me(ctx) | ||
| if err != nil { | ||
| return false, err | ||
| } | ||
| } | ||
| result := auth.IsServicePrincipal(ctx, w, user.Id) | ||
| is_service_principal = &result | ||
| return result, nil | ||
| }, | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.