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 {
|
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 fmt.Errorf("%s must start with '~/' or contain the current username when using 'mode: development'", path)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findIncorrectPath(b *bundle.Bundle, mode config.Mode) string {
|
func findNonUserPath(b *bundle.Bundle) string {
|
||||||
username := b.Config.Workspace.CurrentUser.UserName
|
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"
|
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"
|
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"
|
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 "artifact_path"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
|
@ -138,24 +134,13 @@ func validateProductionMode(ctx context.Context, b *bundle.Bundle, isPrincipalUs
|
||||||
r := b.Config.Resources
|
r := b.Config.Resources
|
||||||
for i := range r.Pipelines {
|
for i := range r.Pipelines {
|
||||||
if r.Pipelines[i].Development {
|
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 !isPrincipalUsed && !isRunAsSet(r) {
|
||||||
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'")
|
return fmt.Errorf("'run_as' must be set for all jobs when using 'mode: production'")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@ func TestProcessTargetModeProduction(t *testing.T) {
|
||||||
b := mockBundle(config.Production)
|
b := mockBundle(config.Production)
|
||||||
|
|
||||||
err := validateProductionMode(context.Background(), b, false)
|
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.StatePath = "/Shared/.bundle/x/y/state"
|
||||||
b.Config.Workspace.ArtifactPath = "/Shared/.bundle/x/y/artifacts"
|
b.Config.Workspace.ArtifactPath = "/Shared/.bundle/x/y/artifacts"
|
||||||
|
|
|
@ -32,11 +32,19 @@ targets:
|
||||||
mode: production
|
mode: production
|
||||||
workspace:
|
workspace:
|
||||||
host: {{workspace_host}}
|
host: {{workspace_host}}
|
||||||
# We only have a single deployment copy for production, so we use a shared path.
|
# We always use /Users/{{user_name}} for all resources to make sure we only have a single copy.
|
||||||
root_path: /Shared/.bundle/prod/${bundle.name}
|
{{- /*
|
||||||
{{- if not is_service_principal}}
|
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:
|
run_as:
|
||||||
# This runs as {{user_name}} in production. We could also use a service principal here
|
{{- if is_service_principal}}
|
||||||
# using service_principal_name (see https://docs.databricks.com/dev-tools/bundles/permissions.html).
|
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}}
|
user_name: {{user_name}}
|
||||||
{{end -}}
|
{{- end}}
|
||||||
|
|
Loading…
Reference in New Issue