2023-07-21 08:59:02 +00:00
package template
import (
2023-08-25 09:03:42 +00:00
"context"
"errors"
2023-07-21 08:59:02 +00:00
"fmt"
2024-06-06 07:11:23 +00:00
"math/rand"
2023-07-27 09:51:31 +00:00
"net/url"
2023-10-19 07:08:36 +00:00
"os"
2023-07-25 14:42:53 +00:00
"regexp"
2023-07-21 08:59:02 +00:00
"text/template"
2023-08-25 09:03:42 +00:00
"github.com/databricks/cli/cmd/root"
"github.com/databricks/cli/libs/auth"
2024-02-19 09:15:17 +00:00
"github.com/databricks/databricks-sdk-go/apierr"
2023-08-25 09:03:42 +00:00
"github.com/databricks/databricks-sdk-go/service/iam"
2024-07-19 11:38:20 +00:00
"github.com/google/uuid"
2023-07-21 08:59:02 +00:00
)
type ErrFail struct {
msg string
}
func ( err ErrFail ) Error ( ) string {
return err . msg
}
2023-08-15 16:07:22 +00:00
type pair struct {
k string
v any
}
2023-09-06 09:52:31 +00:00
var cachedUser * iam . User
var cachedIsServicePrincipal * bool
2024-02-19 09:15:17 +00:00
var cachedCatalog * string
2023-09-06 09:52:31 +00:00
2023-08-25 09:03:42 +00:00
func loadHelpers ( ctx context . Context ) template . FuncMap {
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 )
} ,
2024-06-06 07:11:23 +00:00
// Alias for https://pkg.go.dev/math/rand#Intn. Returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n).
"random_int" : func ( n int ) int {
return rand . Intn ( n )
} ,
2024-07-19 11:38:20 +00:00
// Alias for https://pkg.go.dev/github.com/google/uuid#New. Returns, as a string, a UUID which is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC 4122.
"uuid" : func ( ) string {
return uuid . New ( ) . String ( )
} ,
2023-08-25 09:03:42 +00:00
// 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 == "" {
2023-10-19 07:08:36 +00:00
return "" , errors . New ( "cannot determine target workspace, please first setup a configuration profile using 'databricks configure'" )
2023-08-25 09:03:42 +00:00
}
if w . Config . IsAzure ( ) {
return "Standard_D3_v2" , nil
} else if w . Config . IsGcp ( ) {
return "n1-standard-4" , nil
}
return "i3.xlarge" , nil
} ,
2023-10-19 07:08:36 +00:00
"path_separator" : func ( ) string {
return string ( os . PathSeparator )
} ,
2023-08-25 09:03:42 +00:00
"workspace_host" : func ( ) ( string , error ) {
if w . Config . Host == "" {
2023-10-19 07:08:36 +00:00
return "" , errors . New ( "cannot determine target workspace, please first setup a configuration profile using 'databricks configure'" )
2023-08-25 09:03:42 +00:00
}
return w . Config . Host , nil
} ,
"user_name" : func ( ) ( string , error ) {
2023-09-06 09:52:31 +00:00
if cachedUser == nil {
2023-08-25 09:03:42 +00:00
var err error
2023-09-06 09:52:31 +00:00
cachedUser , err = w . CurrentUser . Me ( ctx )
2023-08-25 09:03:42 +00:00
if err != nil {
return "" , err
}
}
2023-09-06 09:52:31 +00:00
result := cachedUser . UserName
2023-08-25 09:03:42 +00:00
if result == "" {
2023-09-06 09:52:31 +00:00
result = cachedUser . Id
2023-08-25 09:03:42 +00:00
}
return result , nil
} ,
2024-02-01 16:46:07 +00:00
"short_name" : func ( ) ( string , error ) {
if cachedUser == nil {
var err error
cachedUser , err = w . CurrentUser . Me ( ctx )
if err != nil {
return "" , err
}
}
return auth . GetShortUserName ( cachedUser . UserName ) , nil
} ,
2024-02-19 09:15:17 +00:00
// Get the default workspace catalog. If there is no default, or if
// Unity Catalog is not enabled, return an empty string.
"default_catalog" : func ( ) ( string , error ) {
if cachedCatalog == nil {
metastore , err := w . Metastores . Current ( ctx )
if err != nil {
var aerr * apierr . APIError
if errors . As ( err , & aerr ) && aerr . ErrorCode == "METASTORE_DOES_NOT_EXIST" {
// Workspace doesn't have a metastore assigned, ignore error
empty_default := ""
cachedCatalog = & empty_default
return "" , nil
}
return "" , err
}
cachedCatalog = & metastore . DefaultCatalogName
}
return * cachedCatalog , nil
} ,
2023-08-25 09:03:42 +00:00
"is_service_principal" : func ( ) ( bool , error ) {
2023-09-06 09:52:31 +00:00
if cachedIsServicePrincipal != nil {
return * cachedIsServicePrincipal , nil
2023-08-25 09:03:42 +00:00
}
2023-09-06 09:52:31 +00:00
if cachedUser == nil {
2023-08-25 09:03:42 +00:00
var err error
2023-09-06 09:52:31 +00:00
cachedUser , err = w . CurrentUser . Me ( ctx )
2023-08-25 09:03:42 +00:00
if err != nil {
return false , err
}
}
2024-03-25 11:32:45 +00:00
result := auth . IsServicePrincipal ( cachedUser . UserName )
2023-09-06 09:52:31 +00:00
cachedIsServicePrincipal = & result
2023-08-25 09:03:42 +00:00
return result , nil
} ,
}
2023-07-21 08:59:02 +00:00
}