mirror of https://github.com/databricks/cli.git
Change recommended production deployment path from /Shared to /Users (#1091)
## Changes This PR changes the default and `mode: production` recommendation to target `/Users` for deployment. Previously, we used `/Shared`, but because of a lack of POSIX-like permissions in WorkspaceFS this meant that files inside would be readable and writable by other users in the workspace. Detailed change: * `default-python` no longer uses a path that starts with `/Shared` * `mode: production` no longer requires a path that starts with `/Shared` ## Related PRs Docs: https://github.com/databricks/docs/pull/14585 Examples: https://github.com/databricks/bundle-examples/pull/17 ## Tests * Manual tests * Template unit tests (with an extra check to avoid /Shared)
This commit is contained in:
parent
e80882b5af
commit
167deec8c3
|
@ -101,29 +101,25 @@ func transformDevelopmentMode(b *bundle.Bundle) error {
|
|||
}
|
||||
|
||||
func validateDevelopmentMode(b *bundle.Bundle) error {
|
||||
if path := findIncorrectPath(b, config.Development); path != "" {
|
||||
if path := findNonUserPath(b); path != "" {
|
||||
return fmt.Errorf("%s must start with '~/' or contain the current username when using 'mode: development'", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findIncorrectPath(b *bundle.Bundle, mode config.Mode) string {
|
||||
func findNonUserPath(b *bundle.Bundle) string {
|
||||
username := b.Config.Workspace.CurrentUser.UserName
|
||||
containsExpected := true
|
||||
if mode == config.Production {
|
||||
containsExpected = false
|
||||
}
|
||||
|
||||
if strings.Contains(b.Config.Workspace.RootPath, username) != containsExpected && b.Config.Workspace.RootPath != "" {
|
||||
if b.Config.Workspace.RootPath != "" && !strings.Contains(b.Config.Workspace.RootPath, username) {
|
||||
return "root_path"
|
||||
}
|
||||
if strings.Contains(b.Config.Workspace.StatePath, username) != containsExpected {
|
||||
if b.Config.Workspace.StatePath != "" && !strings.Contains(b.Config.Workspace.StatePath, username) {
|
||||
return "state_path"
|
||||
}
|
||||
if strings.Contains(b.Config.Workspace.FilePath, username) != containsExpected {
|
||||
if b.Config.Workspace.FilePath != "" && !strings.Contains(b.Config.Workspace.FilePath, username) {
|
||||
return "file_path"
|
||||
}
|
||||
if strings.Contains(b.Config.Workspace.ArtifactPath, username) != containsExpected {
|
||||
if b.Config.Workspace.ArtifactPath != "" && !strings.Contains(b.Config.Workspace.ArtifactPath, username) {
|
||||
return "artifact_path"
|
||||
}
|
||||
return ""
|
||||
|
@ -138,23 +134,12 @@ func validateProductionMode(ctx context.Context, b *bundle.Bundle, isPrincipalUs
|
|||
r := b.Config.Resources
|
||||
for i := range r.Pipelines {
|
||||
if r.Pipelines[i].Development {
|
||||
return fmt.Errorf("target with 'mode: production' cannot specify a pipeline with 'development: true'")
|
||||
return fmt.Errorf("target with 'mode: production' cannot include a pipeline with 'development: true'")
|
||||
}
|
||||
}
|
||||
|
||||
if !isPrincipalUsed {
|
||||
if path := findIncorrectPath(b, config.Production); path != "" {
|
||||
message := "%s must not contain the current username when using 'mode: production'"
|
||||
if path == "root_path" {
|
||||
return fmt.Errorf(message+"\n tip: set workspace.root_path to a shared path such as /Shared/.bundle/${bundle.name}/${bundle.target}", path)
|
||||
} else {
|
||||
return fmt.Errorf(message, path)
|
||||
}
|
||||
}
|
||||
|
||||
if !isRunAsSet(r) {
|
||||
return fmt.Errorf("'run_as' must be set for all jobs when using 'mode: production'")
|
||||
}
|
||||
if !isPrincipalUsed && !isRunAsSet(r) {
|
||||
return fmt.Errorf("'run_as' must be set for all jobs when using 'mode: production'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ func TestProcessTargetModeProduction(t *testing.T) {
|
|||
b := mockBundle(config.Production)
|
||||
|
||||
err := validateProductionMode(context.Background(), b, false)
|
||||
require.ErrorContains(t, err, "state_path")
|
||||
require.ErrorContains(t, err, "run_as")
|
||||
|
||||
b.Config.Workspace.StatePath = "/Shared/.bundle/x/y/state"
|
||||
b.Config.Workspace.ArtifactPath = "/Shared/.bundle/x/y/artifacts"
|
||||
|
|
|
@ -32,11 +32,19 @@ targets:
|
|||
mode: production
|
||||
workspace:
|
||||
host: {{workspace_host}}
|
||||
# We only have a single deployment copy for production, so we use a shared path.
|
||||
root_path: /Shared/.bundle/prod/${bundle.name}
|
||||
{{- if not is_service_principal}}
|
||||
# We always use /Users/{{user_name}} for all resources to make sure we only have a single copy.
|
||||
{{- /*
|
||||
Internal note 2023-12: CLI versions v0.211.0 and before would show an error when using `mode: production`
|
||||
with a path that doesn't say "/Shared". For now, we'll include an extra comment in the template
|
||||
to explain that customers should update if they see this.
|
||||
*/}}
|
||||
# If this path results in an error, please make sure you have a recent version of the CLI installed.
|
||||
root_path: /Users/{{user_name}}/.bundle/${bundle.name}/${bundle.target}
|
||||
run_as:
|
||||
# This runs as {{user_name}} in production. We could also use a service principal here
|
||||
# using service_principal_name (see https://docs.databricks.com/dev-tools/bundles/permissions.html).
|
||||
{{- if is_service_principal}}
|
||||
service_principal_name: {{user_name}}
|
||||
{{- else}}
|
||||
# This runs as {{user_name}} in production. We could also use a service principal here,
|
||||
# see https://docs.databricks.com/dev-tools/bundles/permissions.html.
|
||||
user_name: {{user_name}}
|
||||
{{end -}}
|
||||
{{- end}}
|
||||
|
|
Loading…
Reference in New Issue