2022-09-05 18:25:54 +00:00
|
|
|
package configure
|
|
|
|
|
|
|
|
import (
|
2023-06-15 12:50:19 +00:00
|
|
|
"context"
|
2022-09-05 18:25:54 +00:00
|
|
|
"fmt"
|
2023-06-15 12:50:19 +00:00
|
|
|
"net/url"
|
2022-09-05 18:25:54 +00:00
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
"github.com/databricks/cli/libs/cmdio"
|
|
|
|
"github.com/databricks/cli/libs/databrickscfg"
|
|
|
|
"github.com/databricks/databricks-sdk-go/config"
|
2022-09-05 18:25:54 +00:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
func validateHost(s string) error {
|
|
|
|
u, err := url.Parse(s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if u.Host == "" || u.Scheme != "https" {
|
|
|
|
return fmt.Errorf("must start with https://")
|
|
|
|
}
|
|
|
|
if u.Path != "" && u.Path != "/" {
|
|
|
|
return fmt.Errorf("must use empty path")
|
|
|
|
}
|
|
|
|
return nil
|
2022-09-05 18:25:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
func configureFromFlags(cmd *cobra.Command, ctx context.Context, cfg *config.Config) error {
|
|
|
|
// Configure profile name if set.
|
|
|
|
profile, err := cmd.Flags().GetString("profile")
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("read --profile flag: %w", err)
|
|
|
|
}
|
|
|
|
if profile != "" {
|
|
|
|
cfg.Profile = profile
|
|
|
|
}
|
2022-09-05 18:25:54 +00:00
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
// Configure host if set.
|
2022-09-06 14:37:58 +00:00
|
|
|
host, err := cmd.Flags().GetString("host")
|
2023-06-15 12:50:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("read --host flag: %w", err)
|
|
|
|
}
|
|
|
|
if host != "" {
|
|
|
|
cfg.Host = host
|
2022-09-06 14:37:58 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
// Validate host if set.
|
|
|
|
if cfg.Host != "" {
|
|
|
|
err = validateHost(cfg.Host)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-09-06 14:37:58 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func configureInteractive(cmd *cobra.Command, ctx context.Context, cfg *config.Config) error {
|
|
|
|
err := configureFromFlags(cmd, ctx, cfg)
|
2022-09-05 18:25:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
// Ask user to specify the host if not already set.
|
|
|
|
if cfg.Host == "" {
|
|
|
|
prompt := cmdio.Prompt(ctx)
|
|
|
|
prompt.Label = "Databricks Host"
|
|
|
|
prompt.Default = "https://"
|
|
|
|
prompt.AllowEdit = true
|
|
|
|
prompt.Validate = validateHost
|
|
|
|
out, err := prompt.Run()
|
2022-09-06 14:37:58 +00:00
|
|
|
if err != nil {
|
2023-06-15 12:50:19 +00:00
|
|
|
return err
|
2022-09-06 14:37:58 +00:00
|
|
|
}
|
2023-06-15 12:50:19 +00:00
|
|
|
cfg.Host = out
|
|
|
|
}
|
2022-09-06 14:37:58 +00:00
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
// Ask user to specify the token is not already set.
|
|
|
|
if cfg.Token == "" {
|
|
|
|
prompt := cmdio.Prompt(ctx)
|
|
|
|
prompt.Label = "Personal Access Token"
|
|
|
|
prompt.Mask = '*'
|
|
|
|
out, err := prompt.Run()
|
2022-09-05 18:25:54 +00:00
|
|
|
if err != nil {
|
2023-06-15 12:50:19 +00:00
|
|
|
return err
|
2022-09-05 18:25:54 +00:00
|
|
|
}
|
2023-06-15 12:50:19 +00:00
|
|
|
cfg.Token = out
|
|
|
|
}
|
2022-09-05 18:25:54 +00:00
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-09-05 18:25:54 +00:00
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
func configureNonInteractive(cmd *cobra.Command, ctx context.Context, cfg *config.Config) error {
|
|
|
|
err := configureFromFlags(cmd, ctx, cfg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg.Host == "" {
|
|
|
|
return fmt.Errorf("host must be set in non-interactive mode")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read token from stdin if not already set.
|
|
|
|
if cfg.Token == "" {
|
|
|
|
_, err := fmt.Fscanf(cmd.InOrStdin(), "%s\n", &cfg.Token)
|
2022-09-05 18:25:54 +00:00
|
|
|
if err != nil {
|
2023-06-15 12:50:19 +00:00
|
|
|
return err
|
2022-09-05 18:25:54 +00:00
|
|
|
}
|
2023-06-15 12:50:19 +00:00
|
|
|
}
|
2022-09-05 18:25:54 +00:00
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
func newConfigureCommand() *cobra.Command {
|
|
|
|
cmd := &cobra.Command{
|
|
|
|
Use: "configure",
|
|
|
|
Short: "Configure authentication",
|
|
|
|
Long: `Configure authentication.
|
2023-06-15 12:50:19 +00:00
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
This command adds a profile to your ~/.databrickscfg file.
|
|
|
|
You can write to a different file by setting the DATABRICKS_CONFIG_FILE environment variable.
|
2023-06-15 12:50:19 +00:00
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
If this command is invoked in non-interactive mode, it will read the token from stdin.
|
|
|
|
The host must be specified with the --host flag.
|
|
|
|
`,
|
|
|
|
Hidden: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.Flags().String("host", "", "Databricks workspace host.")
|
|
|
|
cmd.Flags().String("profile", "DEFAULT", "Name for the connection profile to configure.")
|
|
|
|
|
|
|
|
// Include token flag for compatibility with the legacy CLI.
|
|
|
|
// It doesn't actually do anything because we always use PATs.
|
2023-08-17 15:22:32 +00:00
|
|
|
cmd.Flags().Bool("token", true, "Configure using Databricks Personal Access Token")
|
2023-07-27 10:03:08 +00:00
|
|
|
cmd.Flags().MarkHidden("token")
|
|
|
|
|
|
|
|
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
2023-06-15 12:50:19 +00:00
|
|
|
var cfg config.Config
|
|
|
|
|
|
|
|
// Load environment variables, possibly the DEFAULT profile.
|
|
|
|
err := config.ConfigAttributes.Configure(&cfg)
|
2022-09-05 18:25:54 +00:00
|
|
|
if err != nil {
|
2023-06-15 12:50:19 +00:00
|
|
|
return fmt.Errorf("unable to instantiate configuration from environment variables: %w", err)
|
2022-09-05 18:25:54 +00:00
|
|
|
}
|
2022-09-06 14:37:58 +00:00
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
ctx := cmd.Context()
|
|
|
|
interactive := cmdio.IsInTTY(ctx) && cmdio.IsOutTTY(ctx)
|
|
|
|
var fn func(*cobra.Command, context.Context, *config.Config) error
|
|
|
|
if interactive {
|
|
|
|
fn = configureInteractive
|
|
|
|
} else {
|
|
|
|
fn = configureNonInteractive
|
2022-09-05 18:25:54 +00:00
|
|
|
}
|
2023-06-15 12:50:19 +00:00
|
|
|
err = fn(cmd, ctx, &cfg)
|
2022-09-05 18:25:54 +00:00
|
|
|
if err != nil {
|
2023-06-15 12:50:19 +00:00
|
|
|
return err
|
2022-09-05 18:25:54 +00:00
|
|
|
}
|
|
|
|
|
2023-06-15 12:50:19 +00:00
|
|
|
// Clear the Databricks CLI path in token mode.
|
|
|
|
// This is relevant for OAuth only.
|
|
|
|
cfg.DatabricksCliPath = ""
|
|
|
|
|
|
|
|
// Save profile to config file.
|
|
|
|
return databrickscfg.SaveToProfile(ctx, &cfg)
|
2023-07-27 10:03:08 +00:00
|
|
|
}
|
2022-09-05 18:25:54 +00:00
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
return cmd
|
|
|
|
}
|
2023-06-15 12:50:19 +00:00
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
func New() *cobra.Command {
|
|
|
|
return newConfigureCommand()
|
2022-09-05 18:25:54 +00:00
|
|
|
}
|