diff --git a/.codegen/_openapi_sha b/.codegen/_openapi_sha index 588cf9d63..9a95107e8 100644 --- a/.codegen/_openapi_sha +++ b/.codegen/_openapi_sha @@ -1 +1 @@ -0be1b914249781b5e903b7676fd02255755bc851 \ No newline at end of file +c72c58f97b950fcb924a90ef164bcb10cfcd5ece \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index ebe94ed8e..4b3715c93 100755 --- a/.gitattributes +++ b/.gitattributes @@ -1,11 +1,13 @@ cmd/account/access-control/access-control.go linguist-generated=true cmd/account/billable-usage/billable-usage.go linguist-generated=true +cmd/account/budget-policy/budget-policy.go linguist-generated=true cmd/account/budgets/budgets.go linguist-generated=true cmd/account/cmd.go linguist-generated=true cmd/account/credentials/credentials.go linguist-generated=true cmd/account/csp-enablement-account/csp-enablement-account.go linguist-generated=true cmd/account/custom-app-integration/custom-app-integration.go linguist-generated=true cmd/account/disable-legacy-features/disable-legacy-features.go linguist-generated=true +cmd/account/enable-ip-access-lists/enable-ip-access-lists.go linguist-generated=true cmd/account/encryption-keys/encryption-keys.go linguist-generated=true cmd/account/esm-enablement-account/esm-enablement-account.go linguist-generated=true cmd/account/federation-policy/federation-policy.go linguist-generated=true @@ -75,6 +77,7 @@ cmd/workspace/instance-pools/instance-pools.go linguist-generated=true cmd/workspace/instance-profiles/instance-profiles.go linguist-generated=true cmd/workspace/ip-access-lists/ip-access-lists.go linguist-generated=true cmd/workspace/jobs/jobs.go linguist-generated=true +cmd/workspace/lakeview-embedded/lakeview-embedded.go linguist-generated=true cmd/workspace/lakeview/lakeview.go linguist-generated=true cmd/workspace/libraries/libraries.go linguist-generated=true cmd/workspace/metastores/metastores.go linguist-generated=true @@ -99,11 +102,13 @@ cmd/workspace/providers/providers.go linguist-generated=true cmd/workspace/quality-monitors/quality-monitors.go linguist-generated=true cmd/workspace/queries-legacy/queries-legacy.go linguist-generated=true cmd/workspace/queries/queries.go linguist-generated=true +cmd/workspace/query-execution/query-execution.go linguist-generated=true cmd/workspace/query-history/query-history.go linguist-generated=true cmd/workspace/query-visualizations-legacy/query-visualizations-legacy.go linguist-generated=true cmd/workspace/query-visualizations/query-visualizations.go linguist-generated=true cmd/workspace/recipient-activation/recipient-activation.go linguist-generated=true cmd/workspace/recipients/recipients.go linguist-generated=true +cmd/workspace/redash-config/redash-config.go linguist-generated=true cmd/workspace/registered-models/registered-models.go linguist-generated=true cmd/workspace/repos/repos.go linguist-generated=true cmd/workspace/resource-quotas/resource-quotas.go linguist-generated=true diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 76835de7d..3c3895bc1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,2 @@ * @pietern @andrewnester @shreyas-goenka @denik +cmd/labs @alexott @nfx diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index ea9558caf..fc764fb0d 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -18,7 +18,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 with: stale-issue-message: This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled. stale-pr-message: This PR has not received an update in a while. If you want to keep this PR open, please leave a comment below or push a new commit and auto-close will be canceled. diff --git a/.github/workflows/integration-main.yml b/.github/workflows/integration-main.yml index 84dd7263a..f737c48e6 100644 --- a/.github/workflows/integration-main.yml +++ b/.github/workflows/integration-main.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1 + uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 with: app-id: ${{ secrets.DECO_WORKFLOW_TRIGGER_APP_ID }} private-key: ${{ secrets.DECO_WORKFLOW_TRIGGER_PRIVATE_KEY }} diff --git a/.github/workflows/integration-pr.yml b/.github/workflows/integration-pr.yml index 7a62113cd..bf096c863 100644 --- a/.github/workflows/integration-pr.yml +++ b/.github/workflows/integration-pr.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Generate GitHub App Token id: generate-token - uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1 + uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1.11.2 with: app-id: ${{ secrets.DECO_WORKFLOW_TRIGGER_APP_ID }} private-key: ${{ secrets.DECO_WORKFLOW_TRIGGER_PRIVATE_KEY }} diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 2a8a68862..c41afc18c 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -50,7 +50,7 @@ jobs: - name: Setup Go uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: - go-version: 1.23.4 + go-version-file: go.mod - name: Setup Python uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 @@ -82,7 +82,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: - go-version: 1.23.4 + go-version-file: go.mod # Use different schema from regular job, to avoid overwriting the same key cache-dependency-path: | go.sum @@ -95,12 +95,12 @@ jobs: # Exit with status code 1 if there are differences (i.e. unformatted files) git diff --exit-code - name: golangci-lint - uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 + uses: golangci/golangci-lint-action@ec5d18412c0aeab7936cb16880d708ba2a64e1ae # v6.2.0 with: version: v1.63.4 args: --timeout=15m - name: Run ruff - uses: astral-sh/ruff-action@31a518504640beb4897d0b9f9e50a2a9196e75ba # v3.0.1 + uses: astral-sh/ruff-action@f14634c415d3e63ffd4d550a22f037df4c734a60 # v3.1.0 with: version: "0.9.1" args: "format --check" @@ -116,7 +116,7 @@ jobs: - name: Setup Go uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: - go-version: 1.23.4 + go-version-file: go.mod # Use different schema from regular job, to avoid overwriting the same key cache-dependency-path: | go.sum diff --git a/.github/workflows/release-snapshot.yml b/.github/workflows/release-snapshot.yml index 548d93e90..8b4684eab 100644 --- a/.github/workflows/release-snapshot.yml +++ b/.github/workflows/release-snapshot.yml @@ -34,7 +34,7 @@ jobs: - name: Setup Go uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: - go-version: 1.23.4 + go-version-file: go.mod # The default cache key for this action considers only the `go.sum` file. # We include .goreleaser.yaml here to differentiate from the cache used by the push action diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5d5811b19..fe5b4170b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: - name: Setup Go uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: - go-version: 1.23.4 + go-version-file: go.mod # The default cache key for this action considers only the `go.sum` file. # We include .goreleaser.yaml here to differentiate from the cache used by the push action diff --git a/.gitignore b/.gitignore index 2060b6bac..35aef1764 100644 --- a/.gitignore +++ b/.gitignore @@ -25,11 +25,7 @@ coverage-acceptance.txt __pycache__ *.pyc -.terraform -.terraform.lock.hcl - .vscode/launch.json .vscode/tasks.json -.databricks .ruff_cache diff --git a/CHANGELOG.md b/CHANGELOG.md index 255bfb0a8..23c696ab7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,66 @@ # Version changelog +## [Release] Release v0.241.2 + +This is a bugfix release to address an issue where jobs with tasks with a +libraries section with PyPI packages could not be deployed. + +Bundles: + * Revert changes related to basename check for local libraries ([#2345](https://github.com/databricks/cli/pull/2345)). + +## [Release] Release v0.241.1 + +Bundles: + * Fix for regression deploying resources with PyPi and Maven library types ([#2341](https://github.com/databricks/cli/pull/2341)). + +## [Release] Release v0.241.0 + +Bundles: + * Added support to generate Git based jobs ([#2304](https://github.com/databricks/cli/pull/2304)). + * Added support for run_as in pipelines ([#2287](https://github.com/databricks/cli/pull/2287)). + * Raise an error when there are multiple local libraries with the same basename used ([#2297](https://github.com/databricks/cli/pull/2297)). + * Fix env variable for AzureCli local config ([#2248](https://github.com/databricks/cli/pull/2248)). + * Accept JSON files in includes section ([#2265](https://github.com/databricks/cli/pull/2265)). + * Always print warnings and errors; clean up format ([#2213](https://github.com/databricks/cli/pull/2213)) + +API Changes: + * Added `databricks account budget-policy` command group. + * Added `databricks lakeview-embedded` command group. + * Added `databricks query-execution` command group. + * Added `databricks account enable-ip-access-lists` command group. + * Added `databricks redash-config` command group. + +OpenAPI commit c72c58f97b950fcb924a90ef164bcb10cfcd5ece (2025-02-03) +Dependency updates: + * Upgrade to TF provider 1.65.1 ([#2328](https://github.com/databricks/cli/pull/2328)). + * Bump github.com/hashicorp/terraform-exec from 0.21.0 to 0.22.0 ([#2237](https://github.com/databricks/cli/pull/2237)). + * Bump github.com/spf13/pflag from 1.0.5 to 1.0.6 ([#2281](https://github.com/databricks/cli/pull/2281)). + * Bump github.com/databricks/databricks-sdk-go from 0.56.1 to 0.57.0 ([#2321](https://github.com/databricks/cli/pull/2321)). + * Bump golang.org/x/oauth2 from 0.25.0 to 0.26.0 ([#2322](https://github.com/databricks/cli/pull/2322)). + * Bump golang.org/x/term from 0.28.0 to 0.29.0 ([#2325](https://github.com/databricks/cli/pull/2325)). + * Bump golang.org/x/text from 0.21.0 to 0.22.0 ([#2323](https://github.com/databricks/cli/pull/2323)). + * Bump golang.org/x/mod from 0.22.0 to 0.23.0 ([#2324](https://github.com/databricks/cli/pull/2324)). + +## [Release] Release v0.240.0 + +Bundles: + * Added support for double underscore variable references ([#2203](https://github.com/databricks/cli/pull/2203)). + * Do not wait for app compute to start on `bundle deploy` ([#2144](https://github.com/databricks/cli/pull/2144)). + * Remove bundle.git.inferred ([#2258](https://github.com/databricks/cli/pull/2258)). + * libs/python: Remove DetectInterpreters ([#2234](https://github.com/databricks/cli/pull/2234)). + +API Changes: + * Added `databricks access-control` command group. + * Added `databricks serving-endpoints http-request` command. + * Changed `databricks serving-endpoints create` command with new required argument order. + * Changed `databricks serving-endpoints get-open-api` command return type to become non-empty. + * Changed `databricks recipients update` command return type to become non-empty. + +OpenAPI commit 0be1b914249781b5e903b7676fd02255755bc851 (2025-01-22) +Dependency updates: + * Bump github.com/databricks/databricks-sdk-go from 0.55.0 to 0.56.1 ([#2238](https://github.com/databricks/cli/pull/2238)). + * Upgrade TF provider to 1.64.1 ([#2247](https://github.com/databricks/cli/pull/2247)). + ## [Release] Release v0.239.1 CLI: diff --git a/Makefile b/Makefile index d30ccef14..0c3860e29 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -default: vendor fmt lint +default: vendor fmt lint tidy PACKAGES=./acceptance/... ./libs/... ./internal/... ./cmd/... ./bundle/... . @@ -9,6 +9,10 @@ GOTESTSUM_CMD ?= gotestsum --format ${GOTESTSUM_FORMAT} --no-summary=skipped lint: golangci-lint run --fix +tidy: + @# not part of golangci-lint, apparently + go mod tidy + lintcheck: golangci-lint run ./... @@ -24,7 +28,7 @@ test: cover: rm -fr ./acceptance/build/cover/ - CLI_GOCOVERDIR=build/cover ${GOTESTSUM_CMD} -- -coverprofile=coverage.txt ${PACKAGES} + VERBOSE_TEST=1 CLI_GOCOVERDIR=build/cover ${GOTESTSUM_CMD} -- -coverprofile=coverage.txt ${PACKAGES} rm -fr ./acceptance/build/cover-merged/ mkdir -p acceptance/build/cover-merged/ go tool covdata merge -i $$(printf '%s,' acceptance/build/cover/* | sed 's/,$$//') -o acceptance/build/cover-merged/ @@ -51,12 +55,12 @@ schema: docs: go run ./bundle/docsgen ./bundle/internal/schema ./bundle/docsgen -INTEGRATION = gotestsum --format github-actions --rerun-fails --jsonfile output.json --packages "./integration/..." -- -parallel 4 -timeout=2h +INTEGRATION = gotestsum --format github-actions --rerun-fails --jsonfile output.json --packages "./acceptance ./integration/..." -- -parallel 4 -timeout=2h -integration: +integration: vendor $(INTEGRATION) -integration-short: - $(INTEGRATION) -short +integration-short: vendor + VERBOSE_TEST=1 $(INTEGRATION) -short -.PHONY: lint lintcheck fmt test cover showcover build snapshot vendor schema integration integration-short acc-cover acc-showcover docs +.PHONY: lint tidy lintcheck fmt test cover showcover build snapshot vendor schema integration integration-short acc-cover acc-showcover docs diff --git a/NOTICE b/NOTICE index ed22084cf..0b1d2da04 100644 --- a/NOTICE +++ b/NOTICE @@ -109,3 +109,12 @@ License - https://github.com/hexops/gotextdiff/blob/main/LICENSE https://github.com/BurntSushi/toml Copyright (c) 2013 TOML authors https://github.com/BurntSushi/toml/blob/master/COPYING + +dario.cat/mergo +Copyright (c) 2013 Dario Castañé. All rights reserved. +Copyright (c) 2012 The Go Authors. All rights reserved. +https://github.com/darccio/mergo/blob/master/LICENSE + +https://github.com/gorilla/mux +Copyright (c) 2023 The Gorilla Authors. All rights reserved. +https://github.com/gorilla/mux/blob/main/LICENSE diff --git a/acceptance/.gitignore b/acceptance/.gitignore new file mode 100644 index 000000000..378eac25d --- /dev/null +++ b/acceptance/.gitignore @@ -0,0 +1 @@ +build diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 91ad09e9e..c0fa960b6 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -2,13 +2,16 @@ package acceptance_test import ( "context" + "encoding/json" "errors" "flag" "fmt" "io" + "net/http" "os" "os/exec" "path/filepath" + "regexp" "runtime" "slices" "sort" @@ -17,15 +20,23 @@ import ( "time" "unicode/utf8" + "github.com/google/uuid" + "github.com/databricks/cli/internal/testutil" "github.com/databricks/cli/libs/env" "github.com/databricks/cli/libs/testdiff" "github.com/databricks/cli/libs/testserver" "github.com/databricks/databricks-sdk-go" + "github.com/databricks/databricks-sdk-go/service/iam" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -var KeepTmp bool +var ( + KeepTmp bool + NoRepl bool + VerboseTest bool = os.Getenv("VERBOSE_TEST") != "" +) // In order to debug CLI running under acceptance test, set this to full subtest name, e.g. "bundle/variables/empty" // Then install your breakpoints and click "debug test" near TestAccept in VSCODE. @@ -40,6 +51,7 @@ var InprocessMode bool func init() { flag.BoolVar(&InprocessMode, "inprocess", SingleTest != "", "Run CLI in the same process as test (for debugging)") flag.BoolVar(&KeepTmp, "keeptmp", false, "Do not delete TMP directory after run") + flag.BoolVar(&NoRepl, "norepl", false, "Do not apply any replacements (for debugging)") } const ( @@ -47,6 +59,8 @@ const ( CleanupScript = "script.cleanup" PrepareScript = "script.prepare" MaxFileSize = 100_000 + // Filename to save replacements to (used by diff.py) + ReplsFile = "repls.json" ) var Scripts = map[string]bool{ @@ -55,6 +69,10 @@ var Scripts = map[string]bool{ PrepareScript: true, } +var Ignored = map[string]bool{ + ReplsFile: true, +} + func TestAccept(t *testing.T) { testAccept(t, InprocessMode, SingleTest) } @@ -63,7 +81,8 @@ func TestInprocessMode(t *testing.T) { if InprocessMode { t.Skip("Already tested by TestAccept") } - require.Equal(t, 1, testAccept(t, true, "selftest")) + require.Equal(t, 1, testAccept(t, true, "selftest/basic")) + require.Equal(t, 1, testAccept(t, true, "selftest/server")) } func testAccept(t *testing.T, InprocessMode bool, singleTest string) int { @@ -71,6 +90,11 @@ func testAccept(t *testing.T, InprocessMode bool, singleTest string) int { cwd, err := os.Getwd() require.NoError(t, err) + buildDir := filepath.Join(cwd, "build", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)) + + // Download terraform and provider and create config; this also creates build directory. + RunCommand(t, []string{"python3", filepath.Join(cwd, "install_terraform.py"), "--targetdir", buildDir}, ".") + coverDir := os.Getenv("CLI_GOCOVERDIR") if coverDir != "" { @@ -87,51 +111,58 @@ func testAccept(t *testing.T, InprocessMode bool, singleTest string) int { t.Setenv("CMD_SERVER_URL", cmdServer.URL) execPath = filepath.Join(cwd, "bin", "callserver.py") } else { - execPath = BuildCLI(t, cwd, coverDir) + execPath = BuildCLI(t, buildDir, coverDir) } t.Setenv("CLI", execPath) - repls.SetPath(execPath, "$CLI") + repls.SetPath(execPath, "[CLI]") // Make helper scripts available t.Setenv("PATH", fmt.Sprintf("%s%c%s", filepath.Join(cwd, "bin"), os.PathListSeparator, os.Getenv("PATH"))) tempHomeDir := t.TempDir() - repls.SetPath(tempHomeDir, "$TMPHOME") + repls.SetPath(tempHomeDir, "[TMPHOME]") t.Logf("$TMPHOME=%v", tempHomeDir) // Make use of uv cache; since we set HomeEnvVar to temporary directory, it is not picked up automatically uvCache := getUVDefaultCacheDir(t) t.Setenv("UV_CACHE_DIR", uvCache) - ctx := context.Background() cloudEnv := os.Getenv("CLOUD_ENV") if cloudEnv == "" { - server := testserver.New(t) - AddHandlers(server) - // Redirect API access to local server: - t.Setenv("DATABRICKS_HOST", server.URL) - t.Setenv("DATABRICKS_TOKEN", "dapi1234") + defaultServer := testserver.New(t) + AddHandlers(defaultServer) + t.Setenv("DATABRICKS_DEFAULT_HOST", defaultServer.URL) homeDir := t.TempDir() // Do not read user's ~/.databrickscfg t.Setenv(env.HomeEnvVar(), homeDir) - - // Prevent CLI from downloading terraform in each test: - t.Setenv("DATABRICKS_TF_EXEC_PATH", tempHomeDir) } - workspaceClient, err := databricks.NewWorkspaceClient() - require.NoError(t, err) + terraformrcPath := filepath.Join(buildDir, ".terraformrc") + t.Setenv("TF_CLI_CONFIG_FILE", terraformrcPath) + t.Setenv("DATABRICKS_TF_CLI_CONFIG_FILE", terraformrcPath) + repls.SetPath(terraformrcPath, "[DATABRICKS_TF_CLI_CONFIG_FILE]") + + terraformExecPath := filepath.Join(buildDir, "terraform") + if runtime.GOOS == "windows" { + terraformExecPath += ".exe" + } + t.Setenv("DATABRICKS_TF_EXEC_PATH", terraformExecPath) + t.Setenv("TERRAFORM", terraformExecPath) + repls.SetPath(terraformExecPath, "[TERRAFORM]") + + // do it last so that full paths match first: + repls.SetPath(buildDir, "[BUILD_DIR]") - user, err := workspaceClient.CurrentUser.Me(ctx) - require.NoError(t, err) - require.NotNil(t, user) - testdiff.PrepareReplacementsUser(t, &repls, *user) - testdiff.PrepareReplacementsWorkspaceClient(t, &repls, workspaceClient) - testdiff.PrepareReplacementsUUID(t, &repls) testdiff.PrepareReplacementsDevVersion(t, &repls) + testdiff.PrepareReplacementSdkVersion(t, &repls) + testdiff.PrepareReplacementsGoVersion(t, &repls) + + repls.SetPath(cwd, "[TESTROOT]") + + repls.Repls = append(repls.Repls, testdiff.Replacement{Old: regexp.MustCompile("dbapi[0-9a-f]+"), New: "[DATABRICKS_TOKEN]"}) testDirs := getTests(t) require.NotEmpty(t, testDirs) @@ -144,8 +175,7 @@ func testAccept(t *testing.T, InprocessMode bool, singleTest string) int { } for _, dir := range testDirs { - testName := strings.ReplaceAll(dir, "\\", "/") - t.Run(testName, func(t *testing.T) { + t.Run(dir, func(t *testing.T) { if !InprocessMode { t.Parallel() } @@ -167,7 +197,8 @@ func getTests(t *testing.T) []string { name := filepath.Base(path) if name == EntryPointScript { // Presence of 'script' marks a test case in this directory - testDirs = append(testDirs, filepath.Dir(path)) + testName := filepath.ToSlash(filepath.Dir(path)) + testDirs = append(testDirs, testName) } return nil }) @@ -185,6 +216,11 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont t.Skipf("Disabled via GOOS.%s setting in %s", runtime.GOOS, configPath) } + cloudEnv := os.Getenv("CLOUD_ENV") + if config.LocalOnly && cloudEnv != "" { + t.Skipf("Disabled via LocalOnly setting in %s (CLOUD_ENV=%s)", configPath, cloudEnv) + } + var tmpDir string var err error if KeepTmp { @@ -197,8 +233,7 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont tmpDir = t.TempDir() } - repls.SetPathWithParents(tmpDir, "$TMPDIR") - repls.Repls = append(repls.Repls, config.Repls...) + repls.SetPathWithParents(tmpDir, "[TMPDIR]") scriptContents := readMergedScriptContents(t, dir) testutil.WriteFile(t, filepath.Join(tmpDir, EntryPointScript), scriptContents) @@ -210,6 +245,101 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont args := []string{"bash", "-euo", "pipefail", EntryPointScript} cmd := exec.Command(args[0], args[1:]...) + cmd.Env = os.Environ() + + var workspaceClient *databricks.WorkspaceClient + var user iam.User + + // Start a new server with a custom configuration if the acceptance test + // specifies a custom server stubs. + var server *testserver.Server + + if cloudEnv == "" { + // Start a new server for this test if either: + // 1. A custom server spec is defined in the test configuration. + // 2. The test is configured to record requests and assert on them. We need + // a duplicate of the default server to record requests because the default + // server otherwise is a shared resource. + + databricksLocalHost := os.Getenv("DATABRICKS_DEFAULT_HOST") + + if len(config.Server) > 0 || config.RecordRequests { + server = testserver.New(t) + if config.RecordRequests { + requestsPath := filepath.Join(tmpDir, "out.requests.txt") + server.RecordRequestsCallback = func(request *testserver.Request) { + req := getLoggedRequest(request, config.IncludeRequestHeaders) + reqJson, err := json.MarshalIndent(req, "", " ") + assert.NoErrorf(t, err, "Failed to indent: %#v", req) + + reqJsonWithRepls := repls.Replace(string(reqJson)) + + f, err := os.OpenFile(requestsPath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644) + assert.NoError(t, err) + defer f.Close() + + _, err = f.WriteString(reqJsonWithRepls + "\n") + assert.NoError(t, err) + } + } + + // We want later stubs takes precedence, because then leaf configs take precedence over parent directory configs + // In gorilla/mux earlier handlers take precedence, so we need to reverse the order + slices.Reverse(config.Server) + + for _, stub := range config.Server { + require.NotEmpty(t, stub.Pattern) + items := strings.Split(stub.Pattern, " ") + require.Len(t, items, 2) + server.Handle(items[0], items[1], func(req testserver.Request) any { + return stub.Response + }) + } + + // The earliest handlers take precedence, add default handlers last + AddHandlers(server) + databricksLocalHost = server.URL + } + + // Each local test should use a new token that will result into a new fake workspace, + // so that test don't interfere with each other. + tokenSuffix := strings.ReplaceAll(uuid.NewString(), "-", "") + config := databricks.Config{ + Host: databricksLocalHost, + Token: "dbapi" + tokenSuffix, + } + workspaceClient, err = databricks.NewWorkspaceClient(&config) + require.NoError(t, err) + + cmd.Env = append(cmd.Env, "DATABRICKS_HOST="+config.Host) + cmd.Env = append(cmd.Env, "DATABRICKS_TOKEN="+config.Token) + + // For the purposes of replacements, use testUser. + // Note, users might have overriden /api/2.0/preview/scim/v2/Me but that should not affect the replacement: + user = testUser + } else { + // Use whatever authentication mechanism is configured by the test runner. + workspaceClient, err = databricks.NewWorkspaceClient(&databricks.Config{}) + require.NoError(t, err) + pUser, err := workspaceClient.CurrentUser.Me(context.Background()) + require.NoError(t, err, "Failed to get current user") + user = *pUser + } + + testdiff.PrepareReplacementsUser(t, &repls, user) + testdiff.PrepareReplacementsWorkspaceClient(t, &repls, workspaceClient) + + // Must be added PrepareReplacementsUser, otherwise conflicts with [USERNAME] + testdiff.PrepareReplacementsUUID(t, &repls) + + // User replacements come last: + repls.Repls = append(repls.Repls, config.Repls...) + + // Save replacements to temp test directory so that it can be read by diff.py + replsJson, err := json.MarshalIndent(repls.Repls, "", " ") + require.NoError(t, err) + testutil.WriteFile(t, filepath.Join(tmpDir, ReplsFile), string(replsJson)) + if coverDir != "" { // Creating individual coverage directory for each test, because writing to the same one // results in sporadic failures like this one (only if tests are running in parallel): @@ -217,9 +347,13 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont coverDir = filepath.Join(coverDir, strings.ReplaceAll(dir, string(os.PathSeparator), "--")) err := os.MkdirAll(coverDir, os.ModePerm) require.NoError(t, err) - cmd.Env = append(os.Environ(), "GOCOVERDIR="+coverDir) + cmd.Env = append(cmd.Env, "GOCOVERDIR="+coverDir) } + absDir, err := filepath.Abs(dir) + require.NoError(t, err) + cmd.Env = append(cmd.Env, "TESTDIR="+absDir) + // Write combined output to a file out, err := os.Create(filepath.Join(tmpDir, "output.txt")) require.NoError(t, err) @@ -241,6 +375,7 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont // Make sure there are not unaccounted for new files files := ListDir(t, tmpDir) + unexpected := []string{} for _, relPath := range files { if _, ok := inputs[relPath]; ok { continue @@ -248,13 +383,20 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont if _, ok := outputs[relPath]; ok { continue } - t.Errorf("Unexpected output: %s", relPath) + if _, ok := Ignored[relPath]; ok { + continue + } + unexpected = append(unexpected, relPath) if strings.HasPrefix(relPath, "out") { // We have a new file starting with "out" // Show the contents & support overwrite mode for it: doComparison(t, repls, dir, tmpDir, relPath, &printedRepls) } } + + if len(unexpected) > 0 { + t.Error("Test produced unexpected files:\n" + strings.Join(unexpected, "\n")) + } } func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirNew, relPath string, printedRepls *bool) { @@ -263,7 +405,7 @@ func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirN bufRef, okRef := tryReading(t, pathRef) bufNew, okNew := tryReading(t, pathNew) if !okRef && !okNew { - t.Errorf("Both files are missing or have errors: %s, %s", pathRef, pathNew) + t.Errorf("Both files are missing or have errors: %s\npathRef: %s\npathNew: %s", relPath, pathRef, pathNew) return } @@ -272,12 +414,13 @@ func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirN // Apply replacements to the new value only. // The reference value is stored after applying replacements. - valueNew = repls.Replace(valueNew) + if !NoRepl { + valueNew = repls.Replace(valueNew) + } // The test did not produce an expected output file. if okRef && !okNew { t.Errorf("Missing output file: %s", relPath) - testdiff.AssertEqualTexts(t, pathRef, pathNew, valueRef, valueNew) if testdiff.OverwriteMode { t.Logf("Removing output file: %s", relPath) require.NoError(t, os.Remove(pathRef)) @@ -287,7 +430,7 @@ func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirN // The test produced an unexpected output file. if !okRef && okNew { - t.Errorf("Unexpected output file: %s", relPath) + t.Errorf("Unexpected output file: %s\npathRef: %s\npathNew: %s", relPath, pathRef, pathNew) testdiff.AssertEqualTexts(t, pathRef, pathNew, valueRef, valueNew) if testdiff.OverwriteMode { t.Logf("Writing output file: %s", relPath) @@ -303,7 +446,7 @@ func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirN testutil.WriteFile(t, pathRef, valueNew) } - if !equal && printedRepls != nil && !*printedRepls { + if VerboseTest && !equal && printedRepls != nil && !*printedRepls { *printedRepls = true var items []string for _, item := range repls.Repls { @@ -350,13 +493,12 @@ func readMergedScriptContents(t *testing.T, dir string) string { return strings.Join(prepares, "\n") } -func BuildCLI(t *testing.T, cwd, coverDir string) string { - execPath := filepath.Join(cwd, "build", "databricks") +func BuildCLI(t *testing.T, buildDir, coverDir string) string { + execPath := filepath.Join(buildDir, "databricks") if runtime.GOOS == "windows" { execPath += ".exe" } - start := time.Now() args := []string{ "go", "build", "-mod", "vendor", @@ -374,20 +516,7 @@ func BuildCLI(t *testing.T, cwd, coverDir string) string { args = append(args, "-buildvcs=false") } - cmd := exec.Command(args[0], args[1:]...) - cmd.Dir = ".." - out, err := cmd.CombinedOutput() - elapsed := time.Since(start) - t.Logf("%s took %s", args, elapsed) - require.NoError(t, err, "go build failed: %s: %s\n%s", args, err, out) - if len(out) > 0 { - t.Logf("go build output: %s: %s", args, out) - } - - // Quick check + warm up cache: - cmd = exec.Command(execPath, "--version") - out, err = cmd.CombinedOutput() - require.NoError(t, err, "%s --version failed: %s\n%s", execPath, err, out) + RunCommand(t, args, "..") return execPath } @@ -525,3 +654,52 @@ func getUVDefaultCacheDir(t *testing.T) string { return cacheDir + "/uv" } } + +func RunCommand(t *testing.T, args []string, dir string) { + start := time.Now() + cmd := exec.Command(args[0], args[1:]...) + cmd.Dir = dir + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + t.Logf("%s took %s", args, elapsed) + + require.NoError(t, err, "%s failed: %s\n%s", args, err, out) + if len(out) > 0 { + t.Logf("%s output: %s", args, out) + } +} + +type LoggedRequest struct { + Headers http.Header `json:"headers,omitempty"` + Method string `json:"method"` + Path string `json:"path"` + Body any `json:"body,omitempty"` + RawBody string `json:"raw_body,omitempty"` +} + +func getLoggedRequest(req *testserver.Request, includedHeaders []string) LoggedRequest { + result := LoggedRequest{ + Method: req.Method, + Path: req.URL.Path, + Headers: filterHeaders(req.Headers, includedHeaders), + } + + if json.Valid(req.Body) { + result.Body = json.RawMessage(req.Body) + } else { + result.RawBody = string(req.Body) + } + + return result +} + +func filterHeaders(h http.Header, includedHeaders []string) http.Header { + headers := make(http.Header) + for k, v := range h { + if !slices.Contains(includedHeaders, k) { + continue + } + headers[k] = v + } + return headers +} diff --git a/acceptance/auth/bundle_and_profile/.databrickscfg b/acceptance/auth/bundle_and_profile/.databrickscfg new file mode 100644 index 000000000..628505286 --- /dev/null +++ b/acceptance/auth/bundle_and_profile/.databrickscfg @@ -0,0 +1,5 @@ +[DEFAULT] +host = $DATABRICKS_HOST + +[profile_name] +host = https://test@non-existing-subdomain.databricks.com diff --git a/acceptance/auth/bundle_and_profile/databricks.yml b/acceptance/auth/bundle_and_profile/databricks.yml new file mode 100644 index 000000000..975661395 --- /dev/null +++ b/acceptance/auth/bundle_and_profile/databricks.yml @@ -0,0 +1,14 @@ +bundle: + name: test-auth + +workspace: + host: $DATABRICKS_HOST + +targets: + dev: + default: true + workspace: + host: $DATABRICKS_HOST + prod: + workspace: + host: https://bar.com diff --git a/acceptance/auth/bundle_and_profile/output.txt b/acceptance/auth/bundle_and_profile/output.txt new file mode 100644 index 000000000..8d2584622 --- /dev/null +++ b/acceptance/auth/bundle_and_profile/output.txt @@ -0,0 +1,32 @@ + +=== Inside the bundle, no flags +>>> errcode [CLI] current-user me +"[USERNAME]" + +=== Inside the bundle, target flags +>>> errcode [CLI] current-user me -t dev +"[USERNAME]" + +=== Inside the bundle, target and matching profile +>>> errcode [CLI] current-user me -t dev -p DEFAULT +"[USERNAME]" + +=== Inside the bundle, profile flag not matching bundle host. Badness: should use profile from flag instead and not fail +>>> errcode [CLI] current-user me -p profile_name +Error: cannot resolve bundle auth configuration: config host mismatch: profile uses host https://non-existing-subdomain.databricks.com, but CLI configured to use [DATABRICKS_TARGET] + +Exit code: 1 + +=== Inside the bundle, target and not matching profile +>>> errcode [CLI] current-user me -t dev -p profile_name +Error: cannot resolve bundle auth configuration: config host mismatch: profile uses host https://non-existing-subdomain.databricks.com, but CLI configured to use [DATABRICKS_TARGET] + +Exit code: 1 + +=== Outside the bundle, no flags +>>> errcode [CLI] current-user me +"[USERNAME]" + +=== Outside the bundle, profile flag +>>> errcode [CLI] current-user me -p profile_name +"[USERNAME]" diff --git a/acceptance/auth/bundle_and_profile/script b/acceptance/auth/bundle_and_profile/script new file mode 100644 index 000000000..b37f5e01d --- /dev/null +++ b/acceptance/auth/bundle_and_profile/script @@ -0,0 +1,30 @@ +# Replace placeholder with an actual host URL +envsubst < databricks.yml > out.yml && mv out.yml databricks.yml +envsubst < .databrickscfg > out && mv out .databrickscfg +export DATABRICKS_CONFIG_FILE=.databrickscfg + +host=$DATABRICKS_HOST +unset DATABRICKS_HOST + +title "Inside the bundle, no flags" +trace errcode $CLI current-user me | jq .userName + +title "Inside the bundle, target flags" +trace errcode $CLI current-user me -t dev | jq .userName + +title "Inside the bundle, target and matching profile" +trace errcode $CLI current-user me -t dev -p DEFAULT | jq .userName + +title "Inside the bundle, profile flag not matching bundle host. Badness: should use profile from flag instead and not fail" +trace errcode $CLI current-user me -p profile_name | jq .userName + +title "Inside the bundle, target and not matching profile" +trace errcode $CLI current-user me -t dev -p profile_name + +cd .. +export DATABRICKS_HOST=$host +title "Outside the bundle, no flags" +trace errcode $CLI current-user me | jq .userName + +title "Outside the bundle, profile flag" +trace errcode $CLI current-user me -p profile_name | jq .userName diff --git a/acceptance/auth/bundle_and_profile/test.toml b/acceptance/auth/bundle_and_profile/test.toml new file mode 100644 index 000000000..1a611ed95 --- /dev/null +++ b/acceptance/auth/bundle_and_profile/test.toml @@ -0,0 +1,12 @@ +Badness = "When -p flag is used inside the bundle folder for any CLI commands, CLI use bundle host anyway instead of profile one" + +# Some of the clouds have DATABRICKS_HOST variable setup without https:// prefix +# In the result, output is replaced with DATABRICKS_URL variable instead of DATABRICKS_HOST +# This is a workaround to replace DATABRICKS_URL with DATABRICKS_HOST +[[Repls]] +Old='DATABRICKS_HOST' +New='DATABRICKS_TARGET' + +[[Repls]] +Old='DATABRICKS_URL' +New='DATABRICKS_TARGET' diff --git a/acceptance/auth/credentials/basic/out.requests.txt b/acceptance/auth/credentials/basic/out.requests.txt new file mode 100644 index 000000000..b549c7423 --- /dev/null +++ b/acceptance/auth/credentials/basic/out.requests.txt @@ -0,0 +1,12 @@ +{ + "headers": { + "Authorization": [ + "Basic [ENCODED_AUTH]" + ], + "User-Agent": [ + "cli/[DEV_VERSION] databricks-sdk-go/[SDK_VERSION] go/[GO_VERSION] os/[OS] cmd/current-user_me cmd-exec-id/[UUID] auth/basic" + ] + }, + "method": "GET", + "path": "/api/2.0/preview/scim/v2/Me" +} diff --git a/acceptance/auth/credentials/basic/output.txt b/acceptance/auth/credentials/basic/output.txt new file mode 100644 index 000000000..c5747c9e4 --- /dev/null +++ b/acceptance/auth/credentials/basic/output.txt @@ -0,0 +1,4 @@ +{ + "id":"[USERID]", + "userName":"[USERNAME]" +} diff --git a/acceptance/auth/credentials/basic/script b/acceptance/auth/credentials/basic/script new file mode 100644 index 000000000..aae249083 --- /dev/null +++ b/acceptance/auth/credentials/basic/script @@ -0,0 +1,8 @@ +# Unset the token which is configured by default +# in acceptance tests +export DATABRICKS_TOKEN="" + +export DATABRICKS_USERNAME=username +export DATABRICKS_PASSWORD=password + +$CLI current-user me diff --git a/acceptance/auth/credentials/basic/test.toml b/acceptance/auth/credentials/basic/test.toml new file mode 100644 index 000000000..4998d81d7 --- /dev/null +++ b/acceptance/auth/credentials/basic/test.toml @@ -0,0 +1,4 @@ +# "username:password" in base64 is dXNlcm5hbWU6cGFzc3dvcmQ=, expect to see this in Authorization header +[[Repls]] +Old = "dXNlcm5hbWU6cGFzc3dvcmQ=" +New = "[ENCODED_AUTH]" diff --git a/acceptance/auth/credentials/oauth/out.requests.txt b/acceptance/auth/credentials/oauth/out.requests.txt new file mode 100644 index 000000000..525e148d8 --- /dev/null +++ b/acceptance/auth/credentials/oauth/out.requests.txt @@ -0,0 +1,34 @@ +{ + "headers": { + "User-Agent": [ + "cli/[DEV_VERSION] databricks-sdk-go/[SDK_VERSION] go/[GO_VERSION] os/[OS]" + ] + }, + "method": "GET", + "path": "/oidc/.well-known/oauth-authorization-server" +} +{ + "headers": { + "Authorization": [ + "Basic [ENCODED_AUTH]" + ], + "User-Agent": [ + "cli/[DEV_VERSION] databricks-sdk-go/[SDK_VERSION] go/[GO_VERSION] os/[OS]" + ] + }, + "method": "POST", + "path": "/oidc/v1/token", + "raw_body": "grant_type=client_credentials\u0026scope=all-apis" +} +{ + "headers": { + "Authorization": [ + "Bearer oauth-token" + ], + "User-Agent": [ + "cli/[DEV_VERSION] databricks-sdk-go/[SDK_VERSION] go/[GO_VERSION] os/[OS] cmd/current-user_me cmd-exec-id/[UUID] auth/oauth-m2m" + ] + }, + "method": "GET", + "path": "/api/2.0/preview/scim/v2/Me" +} diff --git a/acceptance/auth/credentials/oauth/output.txt b/acceptance/auth/credentials/oauth/output.txt new file mode 100644 index 000000000..c5747c9e4 --- /dev/null +++ b/acceptance/auth/credentials/oauth/output.txt @@ -0,0 +1,4 @@ +{ + "id":"[USERID]", + "userName":"[USERNAME]" +} diff --git a/acceptance/auth/credentials/oauth/script b/acceptance/auth/credentials/oauth/script new file mode 100644 index 000000000..e4519e41b --- /dev/null +++ b/acceptance/auth/credentials/oauth/script @@ -0,0 +1,8 @@ +# Unset the token which is configured by default +# in acceptance tests +export DATABRICKS_TOKEN="" + +export DATABRICKS_CLIENT_ID=client_id +export DATABRICKS_CLIENT_SECRET=client_secret + +$CLI current-user me diff --git a/acceptance/auth/credentials/oauth/test.toml b/acceptance/auth/credentials/oauth/test.toml new file mode 100644 index 000000000..2adade96a --- /dev/null +++ b/acceptance/auth/credentials/oauth/test.toml @@ -0,0 +1,5 @@ +# "client_id:client_secret" in base64 is Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=, expect to +# see this in Authorization header +[[Repls]] +Old = "Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=" +New = "[ENCODED_AUTH]" diff --git a/acceptance/auth/credentials/pat/out.requests.txt b/acceptance/auth/credentials/pat/out.requests.txt new file mode 100644 index 000000000..73c448c2f --- /dev/null +++ b/acceptance/auth/credentials/pat/out.requests.txt @@ -0,0 +1,12 @@ +{ + "headers": { + "Authorization": [ + "Bearer dapi1234" + ], + "User-Agent": [ + "cli/[DEV_VERSION] databricks-sdk-go/[SDK_VERSION] go/[GO_VERSION] os/[OS] cmd/current-user_me cmd-exec-id/[UUID] auth/pat" + ] + }, + "method": "GET", + "path": "/api/2.0/preview/scim/v2/Me" +} diff --git a/acceptance/auth/credentials/pat/output.txt b/acceptance/auth/credentials/pat/output.txt new file mode 100644 index 000000000..c5747c9e4 --- /dev/null +++ b/acceptance/auth/credentials/pat/output.txt @@ -0,0 +1,4 @@ +{ + "id":"[USERID]", + "userName":"[USERNAME]" +} diff --git a/acceptance/auth/credentials/pat/script b/acceptance/auth/credentials/pat/script new file mode 100644 index 000000000..ccf1098e7 --- /dev/null +++ b/acceptance/auth/credentials/pat/script @@ -0,0 +1,3 @@ +export DATABRICKS_TOKEN=dapi1234 + +$CLI current-user me diff --git a/acceptance/auth/credentials/test.toml b/acceptance/auth/credentials/test.toml new file mode 100644 index 000000000..89438f43a --- /dev/null +++ b/acceptance/auth/credentials/test.toml @@ -0,0 +1,20 @@ +LocalOnly = true + +RecordRequests = true +IncludeRequestHeaders = ["Authorization", "User-Agent"] + +[[Repls]] +Old = '(linux|darwin|windows)' +New = '[OS]' + +[[Repls]] +Old = " upstream/[A-Za-z0-9.-]+" +New = "" + +[[Repls]] +Old = " upstream-version/[A-Za-z0-9.-]+" +New = "" + +[[Repls]] +Old = " cicd/[A-Za-z0-9.-]+" +New = "" diff --git a/acceptance/bin/diff.py b/acceptance/bin/diff.py new file mode 100755 index 000000000..0a91d57ce --- /dev/null +++ b/acceptance/bin/diff.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +"""This script implements "diff -r -U2 dir1 dir2" but applies replacements first""" + +import sys +import difflib +import json +import re +from pathlib import Path + + +def replaceAll(patterns, s): + for comp, new in patterns: + s = comp.sub(new, s) + return s + + +def main(): + d1, d2 = sys.argv[1:] + d1, d2 = Path(d1), Path(d2) + + with open("repls.json") as f: + repls = json.load(f) + + patterns = [] + for r in repls: + try: + c = re.compile(r["Old"]) + patterns.append((c, r["New"])) + except re.error as e: + print(f"Regex error for pattern {r}: {e}", file=sys.stderr) + + files1 = [str(p.relative_to(d1)) for p in d1.rglob("*") if p.is_file()] + files2 = [str(p.relative_to(d2)) for p in d2.rglob("*") if p.is_file()] + + set1 = set(files1) + set2 = set(files2) + + for f in sorted(set1 | set2): + p1 = d1 / f + p2 = d2 / f + if f not in set2: + print(f"Only in {d1}: {f}") + elif f not in set1: + print(f"Only in {d2}: {f}") + else: + a = [replaceAll(patterns, x) for x in p1.read_text().splitlines(True)] + b = [replaceAll(patterns, x) for x in p2.read_text().splitlines(True)] + if a != b: + p1_str = p1.as_posix() + p2_str = p2.as_posix() + for line in difflib.unified_diff(a, b, p1_str, p2_str, "", "", 2): + print(line, end="") + + +if __name__ == "__main__": + main() diff --git a/acceptance/bin/sort_lines.py b/acceptance/bin/sort_lines.py new file mode 100755 index 000000000..9ac87feee --- /dev/null +++ b/acceptance/bin/sort_lines.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 +""" +Helper to sort lines in text file. Similar to 'sort' but no dependence on locale or presence of 'sort' in PATH. +""" + +import sys + +lines = sys.stdin.readlines() +lines.sort() +sys.stdout.write("".join(lines)) diff --git a/acceptance/build/.gitignore b/acceptance/build/.gitignore deleted file mode 100644 index a48b4db25..000000000 --- a/acceptance/build/.gitignore +++ /dev/null @@ -1 +0,0 @@ -databricks diff --git a/acceptance/bundle/debug/databricks.yml b/acceptance/bundle/debug/databricks.yml new file mode 100644 index 000000000..2c9dd3c90 --- /dev/null +++ b/acceptance/bundle/debug/databricks.yml @@ -0,0 +1,2 @@ +bundle: + name: debug diff --git a/acceptance/bundle/debug/out.stderr.parallel.txt b/acceptance/bundle/debug/out.stderr.parallel.txt new file mode 100644 index 000000000..13c81c511 --- /dev/null +++ b/acceptance/bundle/debug/out.stderr.parallel.txt @@ -0,0 +1,15 @@ +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=fast_validate(readonly) +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=fast_validate(readonly) mutator (read-only)=parallel +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=fast_validate(readonly) mutator (read-only)=parallel mutator (read-only)=validate:SingleNodeCluster +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=fast_validate(readonly) mutator (read-only)=parallel mutator (read-only)=validate:artifact_paths +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=fast_validate(readonly) mutator (read-only)=parallel mutator (read-only)=validate:job_cluster_key_defined +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=fast_validate(readonly) mutator (read-only)=parallel mutator (read-only)=validate:job_task_cluster_spec +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:files_to_sync +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:folder_permissions +10:07:59 Debug: ApplyReadOnly pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:validate_sync_patterns +10:07:59 Debug: Path /Workspace/Users/[USERNAME]/.bundle/debug/default/files has type directory (ID: 0) pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:files_to_sync +10:07:59 Debug: non-retriable error: Workspace path not found pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:files_to_sync sdk=true +< HTTP/0.0 000 OK pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:files_to_sync sdk=true +< } pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:files_to_sync sdk=true +< } pid=12345 mutator=validate mutator (read-only)=parallel mutator (read-only)=validate:files_to_sync sdk=true diff --git a/acceptance/bundle/debug/out.stderr.txt b/acceptance/bundle/debug/out.stderr.txt new file mode 100644 index 000000000..e5867e008 --- /dev/null +++ b/acceptance/bundle/debug/out.stderr.txt @@ -0,0 +1,93 @@ +10:07:59 Info: start pid=12345 version=[DEV_VERSION] args="[CLI], bundle, validate, --debug" +10:07:59 Debug: Found bundle root at [TMPDIR] (file [TMPDIR]/databricks.yml) pid=12345 +10:07:59 Debug: Apply pid=12345 mutator=load +10:07:59 Info: Phase: load pid=12345 mutator=load +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=EntryPoint +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=scripts.preinit +10:07:59 Debug: No script defined for preinit, skipping pid=12345 mutator=load mutator=seq mutator=scripts.preinit +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=ProcessRootIncludes +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=ProcessRootIncludes mutator=seq +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=VerifyCliVersion +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=EnvironmentsToTargets +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=ComputeIdToClusterId +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=InitializeVariables +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=DefineDefaultTarget(default) +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=PythonMutator(load) +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=validate:unique_resource_keys +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=SelectDefaultTarget +10:07:59 Debug: Apply pid=12345 mutator=load mutator=seq mutator=SelectDefaultTarget mutator=SelectTarget(default) +10:07:59 Debug: Apply pid=12345 mutator= +10:07:59 Debug: Apply pid=12345 mutator=initialize +10:07:59 Info: Phase: initialize pid=12345 mutator=initialize +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=validate:AllResourcesHaveValues +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=RewriteSyncPaths +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=SyncDefaultPath +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=SyncInferRoot +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=PopulateCurrentUser +10:07:59 Debug: GET /api/2.0/preview/scim/v2/Me +< HTTP/1.1 200 OK +< { +< "id": "[USERID]", +< "userName": "[USERNAME]" +< } pid=12345 mutator=initialize mutator=seq mutator=PopulateCurrentUser sdk=true +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=LoadGitDetails +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ApplySourceLinkedDeploymentPreset +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=DefineDefaultWorkspaceRoot +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ExpandWorkspaceRoot +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=DefaultWorkspacePaths +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=PrependWorkspacePrefix +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=RewriteWorkspacePrefix +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=SetVariables +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=PythonMutator(init) +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=PythonMutator(load_resources) +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=PythonMutator(apply_mutators) +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ResolveVariableReferences +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ResolveResourceReferences +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ResolveVariableReferences +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=MergeJobClusters +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=MergeJobParameters +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=MergeJobTasks +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=MergePipelineClusters +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=MergeApps +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=CaptureSchemaDependency +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=CheckPermissions +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=SetRunAs +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=OverrideCompute +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ConfigureDashboardDefaults +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ConfigureVolumeDefaults +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ProcessTargetMode +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ApplyPresets +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=DefaultQueueing +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ExpandPipelineGlobPaths +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ConfigureWSFS +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=TranslatePaths +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=PythonWrapperWarning +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=apps.Validate +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ValidateSharedRootPermissions +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=ApplyBundlePermissions +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=FilterCurrentUserFromPermissions +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=metadata.AnnotateJobs +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=metadata.AnnotatePipelines +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=terraform.Initialize +10:07:59 Debug: Using Terraform from DATABRICKS_TF_EXEC_PATH at [TERRAFORM] pid=12345 mutator=initialize mutator=seq mutator=terraform.Initialize +10:07:59 Debug: Using Terraform CLI config from DATABRICKS_TF_CLI_CONFIG_FILE at [DATABRICKS_TF_CLI_CONFIG_FILE] pid=12345 mutator=initialize mutator=seq mutator=terraform.Initialize +10:07:59 Debug: Environment variables for Terraform: ...redacted... pid=12345 mutator=initialize mutator=seq mutator=terraform.Initialize +10:07:59 Debug: Apply pid=12345 mutator=initialize mutator=seq mutator=scripts.postinit +10:07:59 Debug: No script defined for postinit, skipping pid=12345 mutator=initialize mutator=seq mutator=scripts.postinit +10:07:59 Debug: Apply pid=12345 mutator=validate +10:07:59 Debug: GET /api/2.0/workspace/get-status?path=/Workspace/Users/[USERNAME]/.bundle/debug/default/files +< HTTP/1.1 404 Not Found +< { +< "message": "Workspace path not found" +10:07:59 Debug: POST /api/2.0/workspace/mkdirs +> { +> "path": "/Workspace/Users/[USERNAME]/.bundle/debug/default/files" +> } +10:07:59 Debug: GET /api/2.0/workspace/get-status?path=/Workspace/Users/[USERNAME]/.bundle/debug/default/files +< HTTP/1.1 200 OK +< { +< "object_type": "DIRECTORY", +< "path": "/Workspace/Users/[USERNAME]/.bundle/debug/default/files" +10:07:59 Info: completed execution pid=12345 exit_code=0 diff --git a/acceptance/bundle/debug/output.txt b/acceptance/bundle/debug/output.txt new file mode 100644 index 000000000..ed72b360e --- /dev/null +++ b/acceptance/bundle/debug/output.txt @@ -0,0 +1,7 @@ +Name: debug +Target: default +Workspace: + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/debug/default + +Validation OK! diff --git a/acceptance/bundle/debug/script b/acceptance/bundle/debug/script new file mode 100644 index 000000000..005a1a341 --- /dev/null +++ b/acceptance/bundle/debug/script @@ -0,0 +1,4 @@ +$CLI bundle validate --debug 2> full.stderr.txt +grep -vw parallel full.stderr.txt > out.stderr.txt +grep -w parallel full.stderr.txt | sed 's/[0-9]/0/g' | sort_lines.py > out.stderr.parallel.txt +rm full.stderr.txt diff --git a/acceptance/bundle/debug/test.toml b/acceptance/bundle/debug/test.toml new file mode 100644 index 000000000..bb0fcb395 --- /dev/null +++ b/acceptance/bundle/debug/test.toml @@ -0,0 +1,18 @@ +LocalOnly = true + +[[Repls]] +# The keys are unsorted and also vary per OS +Old = 'Environment variables for Terraform: ([A-Z_ ,]+) ' +New = 'Environment variables for Terraform: ...redacted... ' + +[[Repls]] +Old = 'pid=[0-9]+' +New = 'pid=12345' + +[[Repls]] +Old = '\d\d:\d\d:\d\d' +New = '10:07:59' + +[[Repls]] +Old = '\\' +New = '/' diff --git a/acceptance/bundle/generate/git_job/databricks.yml b/acceptance/bundle/generate/git_job/databricks.yml new file mode 100644 index 000000000..adaa7aab3 --- /dev/null +++ b/acceptance/bundle/generate/git_job/databricks.yml @@ -0,0 +1,2 @@ +bundle: + name: git_job diff --git a/acceptance/bundle/generate/git_job/out.job.yml b/acceptance/bundle/generate/git_job/out.job.yml new file mode 100644 index 000000000..0eb2a3fb1 --- /dev/null +++ b/acceptance/bundle/generate/git_job/out.job.yml @@ -0,0 +1,17 @@ +resources: + jobs: + out: + name: gitjob + tasks: + - task_key: test_task + notebook_task: + notebook_path: some/test/notebook.py + - task_key: test_task_2 + notebook_task: + notebook_path: /Workspace/Users/foo@bar.com/some/test/notebook.py + source: WORKSPACE + git_source: + git_branch: main + git_commit: abcdef + git_provider: github + git_url: https://git.databricks.com diff --git a/acceptance/bundle/generate/git_job/output.txt b/acceptance/bundle/generate/git_job/output.txt new file mode 100644 index 000000000..680c92ff9 --- /dev/null +++ b/acceptance/bundle/generate/git_job/output.txt @@ -0,0 +1,2 @@ +Job is using Git source, skipping downloading files +Job configuration successfully saved to out.job.yml diff --git a/acceptance/bundle/generate/git_job/script b/acceptance/bundle/generate/git_job/script new file mode 100644 index 000000000..7598966b0 --- /dev/null +++ b/acceptance/bundle/generate/git_job/script @@ -0,0 +1 @@ +$CLI bundle generate job --existing-job-id 1234 --config-dir . --key out diff --git a/acceptance/bundle/generate/git_job/test.toml b/acceptance/bundle/generate/git_job/test.toml new file mode 100644 index 000000000..28b473245 --- /dev/null +++ b/acceptance/bundle/generate/git_job/test.toml @@ -0,0 +1,33 @@ +LocalOnly = true # This test needs to run against stubbed Databricks API + +[[Server]] +Pattern = "GET /api/2.1/jobs/get" +Response.Body = ''' +{ + "job_id": 11223344, + "settings": { + "name": "gitjob", + "git_source": { + "git_url": "https://git.databricks.com", + "git_provider": "github", + "git_branch": "main", + "git_commit": "abcdef" + }, + "tasks": [ + { + "task_key": "test_task", + "notebook_task": { + "notebook_path": "some/test/notebook.py" + } + }, + { + "task_key": "test_task_2", + "notebook_task": { + "source": "WORKSPACE", + "notebook_path": "/Workspace/Users/foo@bar.com/some/test/notebook.py" + } + } + ] + } +} +''' diff --git a/acceptance/bundle/git-permerror/output.txt b/acceptance/bundle/git-permerror/output.txt index 2b52134ab..730e8255b 100644 --- a/acceptance/bundle/git-permerror/output.txt +++ b/acceptance/bundle/git-permerror/output.txt @@ -2,37 +2,38 @@ >>> chmod 000 .git ->>> $CLI bundle validate +>>> [CLI] bundle validate +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied Name: git-permerror Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/git-permerror/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/git-permerror/default Found 1 error Exit code: 1 ->>> $CLI bundle validate -o json +>>> [CLI] bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied Exit code: 1 { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." } ->>> withdir subdir/a/b $CLI bundle validate -o json +>>> withdir subdir/a/b [CLI] bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied Exit code: 1 { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." } @@ -40,16 +41,18 @@ Exit code: 1 >>> chmod 000 .git/HEAD ->>> $CLI bundle validate -o json +>>> [CLI] bundle validate -o json +Warn: failed to load current branch: open HEAD: permission denied +Warn: failed to load latest commit: open HEAD: permission denied { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." } ->>> withdir subdir/a/b $CLI bundle validate -o json +>>> withdir subdir/a/b [CLI] bundle validate -o json +Warn: failed to load current branch: open HEAD: permission denied +Warn: failed to load latest commit: open HEAD: permission denied { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." } @@ -57,22 +60,22 @@ Exit code: 1 >>> chmod 000 .git/config ->>> $CLI bundle validate -o json +>>> [CLI] bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied Exit code: 1 { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." } ->>> withdir subdir/a/b $CLI bundle validate -o json +>>> withdir subdir/a/b [CLI] bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied Exit code: 1 { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." } diff --git a/acceptance/bundle/git-permerror/test.toml b/acceptance/bundle/git-permerror/test.toml index 3f96e551c..15305cff1 100644 --- a/acceptance/bundle/git-permerror/test.toml +++ b/acceptance/bundle/git-permerror/test.toml @@ -1,4 +1,4 @@ -Badness = "Warning logs not shown; inferred flag is set to true incorrect; bundle_root_path is not correct" +Badness = "inferred flag is set to true incorrect; bundle_root_path is not correct; Warn and Error talk about the same; Warn goes to stderr, Error goes to stdout (for backward compat); Warning about permissions repeated twice" [GOOS] # This test relies on chmod which does not work on Windows diff --git a/acceptance/bundle/help/bundle-deploy/output.txt b/acceptance/bundle/help/bundle-deploy/output.txt index 13c903f3e..84351e375 100644 --- a/acceptance/bundle/help/bundle-deploy/output.txt +++ b/acceptance/bundle/help/bundle-deploy/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle deploy --help +>>> [CLI] bundle deploy --help Deploy bundle Usage: diff --git a/acceptance/bundle/help/bundle-deployment/output.txt b/acceptance/bundle/help/bundle-deployment/output.txt index ddf5b3305..4199703b3 100644 --- a/acceptance/bundle/help/bundle-deployment/output.txt +++ b/acceptance/bundle/help/bundle-deployment/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle deployment --help +>>> [CLI] bundle deployment --help Deployment related commands Usage: diff --git a/acceptance/bundle/help/bundle-destroy/output.txt b/acceptance/bundle/help/bundle-destroy/output.txt index d70164301..5ed9c1b7b 100644 --- a/acceptance/bundle/help/bundle-destroy/output.txt +++ b/acceptance/bundle/help/bundle-destroy/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle destroy --help +>>> [CLI] bundle destroy --help Destroy deployed bundle resources Usage: diff --git a/acceptance/bundle/help/bundle-generate-dashboard/output.txt b/acceptance/bundle/help/bundle-generate-dashboard/output.txt index a63ce0ff8..683175940 100644 --- a/acceptance/bundle/help/bundle-generate-dashboard/output.txt +++ b/acceptance/bundle/help/bundle-generate-dashboard/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle generate dashboard --help +>>> [CLI] bundle generate dashboard --help Generate configuration for a dashboard Usage: diff --git a/acceptance/bundle/help/bundle-generate-job/output.txt b/acceptance/bundle/help/bundle-generate-job/output.txt index adc3f45ae..6a4274223 100644 --- a/acceptance/bundle/help/bundle-generate-job/output.txt +++ b/acceptance/bundle/help/bundle-generate-job/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle generate job --help +>>> [CLI] bundle generate job --help Generate bundle configuration for a job Usage: diff --git a/acceptance/bundle/help/bundle-generate-pipeline/output.txt b/acceptance/bundle/help/bundle-generate-pipeline/output.txt index cf5f70920..05c5573b8 100644 --- a/acceptance/bundle/help/bundle-generate-pipeline/output.txt +++ b/acceptance/bundle/help/bundle-generate-pipeline/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle generate pipeline --help +>>> [CLI] bundle generate pipeline --help Generate bundle configuration for a pipeline Usage: diff --git a/acceptance/bundle/help/bundle-generate/output.txt b/acceptance/bundle/help/bundle-generate/output.txt index 1d77dfdbd..725f19af0 100644 --- a/acceptance/bundle/help/bundle-generate/output.txt +++ b/acceptance/bundle/help/bundle-generate/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle generate --help +>>> [CLI] bundle generate --help Generate bundle configuration Usage: diff --git a/acceptance/bundle/help/bundle-init/output.txt b/acceptance/bundle/help/bundle-init/output.txt index bafe5a187..fbafedea2 100644 --- a/acceptance/bundle/help/bundle-init/output.txt +++ b/acceptance/bundle/help/bundle-init/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle init --help +>>> [CLI] bundle init --help Initialize using a bundle template. TEMPLATE_PATH optionally specifies which template to use. It can be one of the following: diff --git a/acceptance/bundle/help/bundle-open/output.txt b/acceptance/bundle/help/bundle-open/output.txt index 8b98aa850..b8f3f118b 100644 --- a/acceptance/bundle/help/bundle-open/output.txt +++ b/acceptance/bundle/help/bundle-open/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle open --help +>>> [CLI] bundle open --help Open a resource in the browser Usage: diff --git a/acceptance/bundle/help/bundle-run/output.txt b/acceptance/bundle/help/bundle-run/output.txt index 17763a295..4b9efbf2a 100644 --- a/acceptance/bundle/help/bundle-run/output.txt +++ b/acceptance/bundle/help/bundle-run/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle run --help +>>> [CLI] bundle run --help Run the job or pipeline identified by KEY. The KEY is the unique identifier of the resource to run. In addition to diff --git a/acceptance/bundle/help/bundle-schema/output.txt b/acceptance/bundle/help/bundle-schema/output.txt index 8f2983f5b..8b8a6b8e9 100644 --- a/acceptance/bundle/help/bundle-schema/output.txt +++ b/acceptance/bundle/help/bundle-schema/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle schema --help +>>> [CLI] bundle schema --help Generate JSON Schema for bundle configuration Usage: diff --git a/acceptance/bundle/help/bundle-summary/output.txt b/acceptance/bundle/help/bundle-summary/output.txt index 935c4bdc5..534bb8214 100644 --- a/acceptance/bundle/help/bundle-summary/output.txt +++ b/acceptance/bundle/help/bundle-summary/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle summary --help +>>> [CLI] bundle summary --help Summarize resources deployed by this bundle Usage: diff --git a/acceptance/bundle/help/bundle-sync/output.txt b/acceptance/bundle/help/bundle-sync/output.txt index 6588e6978..992138a20 100644 --- a/acceptance/bundle/help/bundle-sync/output.txt +++ b/acceptance/bundle/help/bundle-sync/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle sync --help +>>> [CLI] bundle sync --help Synchronize bundle tree to the workspace Usage: diff --git a/acceptance/bundle/help/bundle-validate/output.txt b/acceptance/bundle/help/bundle-validate/output.txt index a0c350faf..7fd1ae7ea 100644 --- a/acceptance/bundle/help/bundle-validate/output.txt +++ b/acceptance/bundle/help/bundle-validate/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle validate --help +>>> [CLI] bundle validate --help Validate configuration Usage: diff --git a/acceptance/bundle/help/bundle/output.txt b/acceptance/bundle/help/bundle/output.txt index e0e2ea47c..fc6dd623d 100644 --- a/acceptance/bundle/help/bundle/output.txt +++ b/acceptance/bundle/help/bundle/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle --help +>>> [CLI] bundle --help Databricks Asset Bundles let you express data/AI/analytics projects as code. Online documentation: https://docs.databricks.com/en/dev-tools/bundles/index.html diff --git a/acceptance/bundle/includes/non_yaml_in_include/output.txt b/acceptance/bundle/includes/non_yaml_in_include/output.txt index 6006ca14e..f5211cc4b 100644 --- a/acceptance/bundle/includes/non_yaml_in_include/output.txt +++ b/acceptance/bundle/includes/non_yaml_in_include/output.txt @@ -1,7 +1,7 @@ -Error: Files in the 'include' configuration section must be YAML files. +Error: Files in the 'include' configuration section must be YAML or JSON files. in databricks.yml:5:4 -The file test.py in the 'include' configuration section is not a YAML file, and only YAML files are supported. To include files to sync, specify them in the 'sync.include' configuration section instead. +The file test.py in the 'include' configuration section is not a YAML or JSON file, and only such files are supported. To include files to sync, specify them in the 'sync.include' configuration section instead. Name: non_yaml_in_includes diff --git a/acceptance/bundle/override/clusters/output.txt b/acceptance/bundle/override/clusters/output.txt index cff30b3af..a30a7bbff 100644 --- a/acceptance/bundle/override/clusters/output.txt +++ b/acceptance/bundle/override/clusters/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle validate -o json -t default +>>> [CLI] bundle validate -o json -t default { "autoscale": { "max_workers": 7, @@ -15,7 +15,7 @@ "spark_version": "13.3.x-scala2.12" } ->>> $CLI bundle validate -o json -t development +>>> [CLI] bundle validate -o json -t development { "autoscale": { "max_workers": 3, diff --git a/acceptance/bundle/override/job_cluster/output.txt b/acceptance/bundle/override/job_cluster/output.txt index ff6e8316e..e4120e1c3 100644 --- a/acceptance/bundle/override/job_cluster/output.txt +++ b/acceptance/bundle/override/job_cluster/output.txt @@ -1,10 +1,10 @@ ->>> $CLI bundle validate -o json -t development +>>> [CLI] bundle validate -o json -t development { "foo": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/override_job_cluster/development/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/override_job_cluster/development/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", @@ -27,12 +27,12 @@ } } ->>> $CLI bundle validate -o json -t staging +>>> [CLI] bundle validate -o json -t staging { "foo": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/override_job_cluster/staging/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/override_job_cluster/staging/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", diff --git a/acceptance/bundle/override/job_cluster_var/output.txt b/acceptance/bundle/override/job_cluster_var/output.txt index 0b19e5eb2..3545d6987 100644 --- a/acceptance/bundle/override/job_cluster_var/output.txt +++ b/acceptance/bundle/override/job_cluster_var/output.txt @@ -1,10 +1,10 @@ ->>> $CLI bundle validate -o json -t development +>>> [CLI] bundle validate -o json -t development { "foo": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/override_job_cluster/development/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/override_job_cluster/development/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", @@ -27,21 +27,21 @@ } } ->>> $CLI bundle validate -t development +>>> [CLI] bundle validate -t development Name: override_job_cluster Target: development Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/override_job_cluster/development + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/override_job_cluster/development Validation OK! ->>> $CLI bundle validate -o json -t staging +>>> [CLI] bundle validate -o json -t staging { "foo": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/override_job_cluster/staging/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/override_job_cluster/staging/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", @@ -64,11 +64,11 @@ Validation OK! } } ->>> $CLI bundle validate -t staging +>>> [CLI] bundle validate -t staging Name: override_job_cluster Target: staging Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/override_job_cluster/staging + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/override_job_cluster/staging Validation OK! diff --git a/acceptance/bundle/override/job_tasks/out.development.stderr.txt b/acceptance/bundle/override/job_tasks/out.development.stderr.txt index 7b6fef0cc..1873feb35 100644 --- a/acceptance/bundle/override/job_tasks/out.development.stderr.txt +++ b/acceptance/bundle/override/job_tasks/out.development.stderr.txt @@ -1,5 +1,5 @@ ->>> errcode $CLI bundle validate -o json -t development +>>> errcode [CLI] bundle validate -o json -t development Error: file ./test1.py not found diff --git a/acceptance/bundle/override/job_tasks/output.txt b/acceptance/bundle/override/job_tasks/output.txt index 915351d4e..1f7796217 100644 --- a/acceptance/bundle/override/job_tasks/output.txt +++ b/acceptance/bundle/override/job_tasks/output.txt @@ -28,7 +28,7 @@ ] } ->>> errcode $CLI bundle validate -o json -t staging +>>> errcode [CLI] bundle validate -o json -t staging Error: file ./test1.py not found @@ -63,14 +63,14 @@ Exit code: 1 ] } ->>> errcode $CLI bundle validate -t staging +>>> errcode [CLI] bundle validate -t staging Error: file ./test1.py not found Name: override_job_tasks Target: staging Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/override_job_tasks/staging + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/override_job_tasks/staging Found 1 error diff --git a/acceptance/bundle/override/merge-string-map/output.txt b/acceptance/bundle/override/merge-string-map/output.txt index b566aa07f..6e2aef87b 100644 --- a/acceptance/bundle/override/merge-string-map/output.txt +++ b/acceptance/bundle/override/merge-string-map/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle validate -o json -t dev +>>> [CLI] bundle validate -o json -t dev Warning: expected map, found string at resources.clusters.my_cluster in databricks.yml:6:17 @@ -13,7 +13,7 @@ Warning: expected map, found string } } ->>> $CLI bundle validate -t dev +>>> [CLI] bundle validate -t dev Warning: expected map, found string at resources.clusters.my_cluster in databricks.yml:6:17 @@ -21,7 +21,7 @@ Warning: expected map, found string Name: merge-string-map Target: dev Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/merge-string-map/dev + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/merge-string-map/dev Found 1 warning diff --git a/acceptance/bundle/override/pipeline_cluster/output.txt b/acceptance/bundle/override/pipeline_cluster/output.txt index 8babed0ec..d1a67f6b9 100644 --- a/acceptance/bundle/override/pipeline_cluster/output.txt +++ b/acceptance/bundle/override/pipeline_cluster/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle validate -o json -t development +>>> [CLI] bundle validate -o json -t development { "foo": { "clusters": [ @@ -14,14 +14,14 @@ ], "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/override_pipeline_cluster/development/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/override_pipeline_cluster/development/state/metadata.json" }, "name": "job", "permissions": [] } } ->>> $CLI bundle validate -o json -t staging +>>> [CLI] bundle validate -o json -t staging { "foo": { "clusters": [ @@ -36,7 +36,7 @@ ], "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/override_pipeline_cluster/staging/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/override_pipeline_cluster/staging/state/metadata.json" }, "name": "job", "permissions": [] diff --git a/acceptance/bundle/paths/fallback/output.job.json b/acceptance/bundle/paths/fallback/output.job.json index fe9e1cf3d..ac79e0cf6 100644 --- a/acceptance/bundle/paths/fallback/output.job.json +++ b/acceptance/bundle/paths/fallback/output.job.json @@ -2,14 +2,14 @@ { "job_cluster_key": "default", "notebook_task": { - "notebook_path": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/notebook" + "notebook_path": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/notebook" }, "task_key": "notebook_example" }, { "job_cluster_key": "default", "spark_python_task": { - "python_file": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/file.py" + "python_file": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/file.py" }, "task_key": "spark_python_example" }, @@ -19,7 +19,7 @@ "dbt run", "dbt run" ], - "project_directory": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/dbt_project" + "project_directory": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/dbt_project" }, "job_cluster_key": "default", "task_key": "dbt_example" @@ -28,7 +28,7 @@ "job_cluster_key": "default", "sql_task": { "file": { - "path": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/sql.sql" + "path": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/sql.sql" }, "warehouse_id": "cafef00d" }, diff --git a/acceptance/bundle/paths/fallback/output.pipeline.json b/acceptance/bundle/paths/fallback/output.pipeline.json index 38521cb22..7ed4f74e6 100644 --- a/acceptance/bundle/paths/fallback/output.pipeline.json +++ b/acceptance/bundle/paths/fallback/output.pipeline.json @@ -1,22 +1,22 @@ [ { "file": { - "path": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/file1.py" + "path": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/file1.py" } }, { "notebook": { - "path": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/notebook1" + "path": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/notebook1" } }, { "file": { - "path": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/file2.py" + "path": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/file2.py" } }, { "notebook": { - "path": "/Workspace/Users/$USERNAME/.bundle/fallback/development/files/src/notebook2" + "path": "/Workspace/Users/[USERNAME]/.bundle/fallback/development/files/src/notebook2" } } ] diff --git a/acceptance/bundle/paths/fallback/output.txt b/acceptance/bundle/paths/fallback/output.txt index 63121f3d7..85f185851 100644 --- a/acceptance/bundle/paths/fallback/output.txt +++ b/acceptance/bundle/paths/fallback/output.txt @@ -1,15 +1,15 @@ ->>> $CLI bundle validate -t development -o json +>>> [CLI] bundle validate -t development -o json ->>> $CLI bundle validate -t error +>>> [CLI] bundle validate -t error Error: notebook this value is overridden not found. Local notebook references are expected to contain one of the following file extensions: [.py, .r, .scala, .sql, .ipynb] Name: fallback Target: error Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/fallback/error + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/fallback/error Found 1 error diff --git a/acceptance/bundle/paths/nominal/output.job.json b/acceptance/bundle/paths/nominal/output.job.json index 9e1cb4d90..26d19d77c 100644 --- a/acceptance/bundle/paths/nominal/output.job.json +++ b/acceptance/bundle/paths/nominal/output.job.json @@ -2,14 +2,14 @@ { "job_cluster_key": "default", "notebook_task": { - "notebook_path": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/notebook" + "notebook_path": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/notebook" }, "task_key": "notebook_example" }, { "job_cluster_key": "default", "spark_python_task": { - "python_file": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/file.py" + "python_file": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/file.py" }, "task_key": "spark_python_example" }, @@ -19,7 +19,7 @@ "dbt run", "dbt run" ], - "project_directory": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/dbt_project" + "project_directory": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/dbt_project" }, "job_cluster_key": "default", "task_key": "dbt_example" @@ -28,7 +28,7 @@ "job_cluster_key": "default", "sql_task": { "file": { - "path": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/sql.sql" + "path": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/sql.sql" }, "warehouse_id": "cafef00d" }, @@ -68,7 +68,7 @@ "for_each_task": { "task": { "notebook_task": { - "notebook_path": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/notebook" + "notebook_path": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/notebook" } } }, @@ -80,7 +80,7 @@ "task": { "job_cluster_key": "default", "spark_python_task": { - "python_file": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/file.py" + "python_file": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/file.py" } } }, diff --git a/acceptance/bundle/paths/nominal/output.pipeline.json b/acceptance/bundle/paths/nominal/output.pipeline.json index 277b0c4a1..c6f2e0868 100644 --- a/acceptance/bundle/paths/nominal/output.pipeline.json +++ b/acceptance/bundle/paths/nominal/output.pipeline.json @@ -1,22 +1,22 @@ [ { "file": { - "path": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/file1.py" + "path": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/file1.py" } }, { "notebook": { - "path": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/notebook1" + "path": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/notebook1" } }, { "file": { - "path": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/file2.py" + "path": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/file2.py" } }, { "notebook": { - "path": "/Workspace/Users/$USERNAME/.bundle/nominal/development/files/src/notebook2" + "path": "/Workspace/Users/[USERNAME]/.bundle/nominal/development/files/src/notebook2" } } ] diff --git a/acceptance/bundle/paths/nominal/output.txt b/acceptance/bundle/paths/nominal/output.txt index 1badcdec6..40670f4cb 100644 --- a/acceptance/bundle/paths/nominal/output.txt +++ b/acceptance/bundle/paths/nominal/output.txt @@ -1,15 +1,15 @@ ->>> $CLI bundle validate -t development -o json +>>> [CLI] bundle validate -t development -o json ->>> $CLI bundle validate -t error +>>> [CLI] bundle validate -t error Error: notebook this value is overridden not found. Local notebook references are expected to contain one of the following file extensions: [.py, .r, .scala, .sql, .ipynb] Name: nominal Target: error Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/nominal/error + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/nominal/error Found 1 error diff --git a/acceptance/bundle/paths/relative_path_translation/output.txt b/acceptance/bundle/paths/relative_path_translation/output.txt index 362f2ec7b..b13d612b6 100644 --- a/acceptance/bundle/paths/relative_path_translation/output.txt +++ b/acceptance/bundle/paths/relative_path_translation/output.txt @@ -1,4 +1,4 @@ ->>> $CLI bundle validate -t default -o json +>>> [CLI] bundle validate -t default -o json ->>> $CLI bundle validate -t override -o json +>>> [CLI] bundle validate -t override -o json diff --git a/acceptance/bundle/quality_monitor/output.txt b/acceptance/bundle/quality_monitor/output.txt index b3718c802..8a7f64ef2 100644 --- a/acceptance/bundle/quality_monitor/output.txt +++ b/acceptance/bundle/quality_monitor/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle validate -o json -t development +>>> [CLI] bundle validate -o json -t development { "mode": "development", "quality_monitors": { @@ -21,7 +21,7 @@ } } ->>> $CLI bundle validate -o json -t staging +>>> [CLI] bundle validate -o json -t staging { "mode": null, "quality_monitors": { @@ -46,7 +46,7 @@ } } ->>> $CLI bundle validate -o json -t production +>>> [CLI] bundle validate -o json -t production { "mode": null, "quality_monitors": { diff --git a/acceptance/bundle/scripts/output.txt b/acceptance/bundle/scripts/output.txt index ec5978380..68afb2fec 100644 --- a/acceptance/bundle/scripts/output.txt +++ b/acceptance/bundle/scripts/output.txt @@ -1,5 +1,5 @@ ->>> EXITCODE=0 errcode $CLI bundle validate +>>> EXITCODE=0 errcode [CLI] bundle validate Executing 'preinit' script from myscript.py 0 preinit: hello stdout! from myscript.py 0 preinit: hello stderr! @@ -9,12 +9,12 @@ from myscript.py 0 postinit: hello stderr! Name: scripts Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/scripts/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/scripts/default Validation OK! ->>> EXITCODE=1 errcode $CLI bundle validate +>>> EXITCODE=1 errcode [CLI] bundle validate Executing 'preinit' script from myscript.py 1 preinit: hello stdout! from myscript.py 1 preinit: hello stderr! @@ -26,7 +26,7 @@ Found 1 error Exit code: 1 ->>> EXITCODE=0 errcode $CLI bundle deploy +>>> EXITCODE=0 errcode [CLI] bundle deploy Executing 'preinit' script from myscript.py 0 preinit: hello stdout! from myscript.py 0 preinit: hello stderr! @@ -42,11 +42,9 @@ from myscript.py 0 postbuild: hello stderr! Executing 'predeploy' script from myscript.py 0 predeploy: hello stdout! from myscript.py 0 predeploy: hello stderr! -Error: unable to deploy to /Workspace/Users/$USERNAME/.bundle/scripts/default/state as $USERNAME. -Please make sure the current user or one of their groups is listed under the permissions of this bundle. -For assistance, contact the owners of this project. -They may need to redeploy the bundle to apply the new permissions. -Please refer to https://docs.databricks.com/dev-tools/bundles/permissions.html for more on managing permissions. - - -Exit code: 1 +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/scripts/default/files... +Deploying resources... +Deployment complete! +Executing 'postdeploy' script +from myscript.py 0 postdeploy: hello stdout! +from myscript.py 0 postdeploy: hello stderr! diff --git a/acceptance/bundle/syncroot/dotdot-git/output.txt b/acceptance/bundle/syncroot/dotdot-git/output.txt index f1dc5fb01..dbfc8451f 100644 --- a/acceptance/bundle/syncroot/dotdot-git/output.txt +++ b/acceptance/bundle/syncroot/dotdot-git/output.txt @@ -1,10 +1,10 @@ -Error: path "$TMPDIR" is not within repository root "$TMPDIR/myrepo" +Error: path "[TMPDIR]" is not within repository root "[TMPDIR]/myrepo" Name: test-bundle Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/test-bundle/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default Found 1 error diff --git a/acceptance/bundle/syncroot/dotdot-nogit/output.txt b/acceptance/bundle/syncroot/dotdot-nogit/output.txt index 46f617f35..4f189effd 100644 --- a/acceptance/bundle/syncroot/dotdot-nogit/output.txt +++ b/acceptance/bundle/syncroot/dotdot-nogit/output.txt @@ -1,7 +1,7 @@ Name: test-bundle Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/test-bundle/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default Validation OK! diff --git a/acceptance/bundle/templates-machinery/helpers-error/databricks_template_schema.json b/acceptance/bundle/templates-machinery/helpers-error/databricks_template_schema.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers-error/databricks_template_schema.json @@ -0,0 +1 @@ +{} diff --git a/acceptance/bundle/templates-machinery/helpers-error/output.txt b/acceptance/bundle/templates-machinery/helpers-error/output.txt new file mode 100644 index 000000000..6020e944f --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers-error/output.txt @@ -0,0 +1,3 @@ +Error: failed to compute file content for helpers.txt.tmpl. template: :1:14: executing "" at : error calling user_name: + +Exit code: 1 diff --git a/acceptance/bundle/templates-machinery/helpers-error/script b/acceptance/bundle/templates-machinery/helpers-error/script new file mode 100644 index 000000000..d9fcbf62c --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers-error/script @@ -0,0 +1 @@ +$CLI bundle init . diff --git a/acceptance/bundle/templates-machinery/helpers-error/template/helpers.txt.tmpl b/acceptance/bundle/templates-machinery/helpers-error/template/helpers.txt.tmpl new file mode 100644 index 000000000..70e60edac --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers-error/template/helpers.txt.tmpl @@ -0,0 +1 @@ +user_name: {{ user_name }} diff --git a/acceptance/bundle/templates-machinery/helpers-error/test.toml b/acceptance/bundle/templates-machinery/helpers-error/test.toml new file mode 100644 index 000000000..77f4ed94b --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers-error/test.toml @@ -0,0 +1,7 @@ +Badness = '''(minor) error message is not great: executing "" at : error calling user_name:''' +LocalOnly = true + +[[Server]] +Pattern = "GET /api/2.0/preview/scim/v2/Me" +Response.Body = '{}' +Response.StatusCode = 500 diff --git a/acceptance/bundle/templates-machinery/helpers/databricks_template_schema.json b/acceptance/bundle/templates-machinery/helpers/databricks_template_schema.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers/databricks_template_schema.json @@ -0,0 +1 @@ +{} diff --git a/acceptance/bundle/templates-machinery/helpers/output.txt b/acceptance/bundle/templates-machinery/helpers/output.txt new file mode 100644 index 000000000..3126ea5af --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers/output.txt @@ -0,0 +1,2 @@ +✨ Successfully initialized template +user_name: [USERNAME] diff --git a/acceptance/bundle/templates-machinery/helpers/script b/acceptance/bundle/templates-machinery/helpers/script new file mode 100644 index 000000000..1773e7b03 --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers/script @@ -0,0 +1,3 @@ +$CLI bundle init . +cat helpers.txt +rm helpers.txt diff --git a/acceptance/bundle/templates-machinery/helpers/template/helpers.txt.tmpl b/acceptance/bundle/templates-machinery/helpers/template/helpers.txt.tmpl new file mode 100644 index 000000000..70e60edac --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers/template/helpers.txt.tmpl @@ -0,0 +1 @@ +user_name: {{ user_name }} diff --git a/acceptance/bundle/templates-machinery/helpers/test.toml b/acceptance/bundle/templates-machinery/helpers/test.toml new file mode 100644 index 000000000..b76e712fb --- /dev/null +++ b/acceptance/bundle/templates-machinery/helpers/test.toml @@ -0,0 +1 @@ +LocalOnly = true diff --git a/acceptance/bundle/templates-machinery/test.toml b/acceptance/bundle/templates-machinery/test.toml new file mode 100644 index 000000000..9083ecd1b --- /dev/null +++ b/acceptance/bundle/templates-machinery/test.toml @@ -0,0 +1,2 @@ +# Testing template machinery, by default there is no need to check against cloud. +LocalOnly = true diff --git a/acceptance/bundle/templates/wrong-path/output.txt b/acceptance/bundle/templates-machinery/wrong-path/output.txt similarity index 100% rename from acceptance/bundle/templates/wrong-path/output.txt rename to acceptance/bundle/templates-machinery/wrong-path/output.txt diff --git a/acceptance/bundle/templates/wrong-path/script b/acceptance/bundle/templates-machinery/wrong-path/script similarity index 100% rename from acceptance/bundle/templates/wrong-path/script rename to acceptance/bundle/templates-machinery/wrong-path/script diff --git a/acceptance/bundle/templates/wrong-path/test.toml b/acceptance/bundle/templates-machinery/wrong-path/test.toml similarity index 100% rename from acceptance/bundle/templates/wrong-path/test.toml rename to acceptance/bundle/templates-machinery/wrong-path/test.toml diff --git a/acceptance/bundle/templates/wrong-url/output.txt b/acceptance/bundle/templates-machinery/wrong-url/output.txt similarity index 60% rename from acceptance/bundle/templates/wrong-url/output.txt rename to acceptance/bundle/templates-machinery/wrong-url/output.txt index b78cf4b68..6b4f9c459 100644 --- a/acceptance/bundle/templates/wrong-url/output.txt +++ b/acceptance/bundle/templates-machinery/wrong-url/output.txt @@ -1,4 +1,4 @@ -Error: git clone failed: git clone https://invalid-domain-123.databricks.com/hello/world $TMPDIR_GPARENT/world-123456 --no-tags --depth=1: exit status 128. Cloning into '$TMPDIR_GPARENT/world-123456'... +Error: git clone failed: git clone https://invalid-domain-123.databricks.com/hello/world [TMPDIR]_GPARENT/world-123456 --no-tags --depth=1: exit status 128. Cloning into '[TMPDIR]_GPARENT/world-123456'... fatal: unable to access 'https://invalid-domain-123.databricks.com/hello/world/': Could not resolve host: invalid-domain-123.databricks.com diff --git a/acceptance/bundle/templates/wrong-url/script b/acceptance/bundle/templates-machinery/wrong-url/script similarity index 100% rename from acceptance/bundle/templates/wrong-url/script rename to acceptance/bundle/templates-machinery/wrong-url/script diff --git a/acceptance/bundle/templates/wrong-url/test.toml b/acceptance/bundle/templates-machinery/wrong-url/test.toml similarity index 100% rename from acceptance/bundle/templates/wrong-url/test.toml rename to acceptance/bundle/templates-machinery/wrong-url/test.toml diff --git a/acceptance/bundle/templates/dbt-sql/output.txt b/acceptance/bundle/templates/dbt-sql/output.txt index 972c7e152..2699ad554 100644 --- a/acceptance/bundle/templates/dbt-sql/output.txt +++ b/acceptance/bundle/templates/dbt-sql/output.txt @@ -1,32 +1,32 @@ ->>> $CLI bundle init dbt-sql --config-file ./input.json --output-dir output +>>> [CLI] bundle init dbt-sql --config-file ./input.json --output-dir output Welcome to the dbt template for Databricks Asset Bundles! A workspace was selected based on your current profile. For information about how to change this, see https://docs.databricks.com/dev-tools/cli/profiles.html. -workspace_host: $DATABRICKS_URL +workspace_host: [DATABRICKS_URL] 📊 Your new project has been created in the 'my_dbt_sql' directory! If you already have dbt installed, just type 'cd my_dbt_sql; dbt init' to get started. Refer to the README.md file for full "getting started" guide and production setup instructions. ->>> $CLI bundle validate -t dev +>>> [CLI] bundle validate -t dev Name: my_dbt_sql Target: dev Workspace: - Host: $DATABRICKS_URL - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/my_dbt_sql/dev + Host: [DATABRICKS_URL] + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/my_dbt_sql/dev Validation OK! ->>> $CLI bundle validate -t prod +>>> [CLI] bundle validate -t prod Name: my_dbt_sql Target: prod Workspace: - Host: $DATABRICKS_URL - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/my_dbt_sql/prod + Host: [DATABRICKS_URL] + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/my_dbt_sql/prod Validation OK! diff --git a/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/databricks.yml b/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/databricks.yml index cdf3704b9..4285a44eb 100644 --- a/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/databricks.yml +++ b/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/databricks.yml @@ -12,23 +12,21 @@ include: # The default schema, catalog, etc. for dbt are defined in dbt_profiles/profiles.yml targets: dev: - default: true # The default target uses 'mode: development' to create a development copy. # - Deployed resources get prefixed with '[dev my_user_name]' # - Any job schedules and triggers are paused by default. # See also https://docs.databricks.com/dev-tools/bundles/deployment-modes.html. mode: development + default: true workspace: - host: $DATABRICKS_URL + host: [DATABRICKS_URL] prod: mode: production workspace: - host: $DATABRICKS_URL - # We explicitly specify /Workspace/Users/$USERNAME to make sure we only have a single copy. - root_path: /Workspace/Users/$USERNAME/.bundle/${bundle.name}/${bundle.target} + host: [DATABRICKS_URL] + # We explicitly deploy to /Workspace/Users/[USERNAME] to make sure we only have a single copy. + root_path: /Workspace/Users/[USERNAME]/.bundle/${bundle.name}/${bundle.target} permissions: - - user_name: $USERNAME + - user_name: [USERNAME] level: CAN_MANAGE - run_as: - user_name: $USERNAME diff --git a/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/.gitignore b/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/out.gitignore similarity index 100% rename from acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/.gitignore rename to acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/out.gitignore diff --git a/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/profile_template.yml b/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/profile_template.yml index 5e0f0fc29..bdb41ab20 100644 --- a/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/profile_template.yml +++ b/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/profile_template.yml @@ -5,7 +5,7 @@ fixed: type: databricks prompts: host: - default: $DATABRICKS_HOST + default: [DATABRICKS_HOST] token: hint: 'personal access token to use, dapiXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' hide_input: true @@ -16,7 +16,7 @@ prompts: hint: 'initial catalog' default: main schema: - hint: 'personal schema where dbt will build objects during development, example: $USERNAME' + hint: 'personal schema where dbt will build objects during development, example: [USERNAME]' threads: hint: 'threads to use during development, 1 or more' type: 'int' diff --git a/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/resources/my_dbt_sql.job.yml b/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/resources/my_dbt_sql.job.yml index d52f8ed50..b522931f9 100644 --- a/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/resources/my_dbt_sql.job.yml +++ b/acceptance/bundle/templates/dbt-sql/output/my_dbt_sql/resources/my_dbt_sql.job.yml @@ -11,7 +11,7 @@ resources: email_notifications: on_failure: - - $USERNAME + - [USERNAME] tasks: diff --git a/acceptance/bundle/templates/dbt-sql/script b/acceptance/bundle/templates/dbt-sql/script index c4ca817fe..3a2660de5 100644 --- a/acceptance/bundle/templates/dbt-sql/script +++ b/acceptance/bundle/templates/dbt-sql/script @@ -3,3 +3,6 @@ trace $CLI bundle init dbt-sql --config-file ./input.json --output-dir output cd output/my_dbt_sql trace $CLI bundle validate -t dev trace $CLI bundle validate -t prod + +# Do not affect this repository's git behaviour #2318 +mv .gitignore out.gitignore diff --git a/acceptance/bundle/templates/default-python/output.txt b/acceptance/bundle/templates/default-python/output.txt index 5493ac2cf..930e756de 100644 --- a/acceptance/bundle/templates/default-python/output.txt +++ b/acceptance/bundle/templates/default-python/output.txt @@ -1,30 +1,30 @@ ->>> $CLI bundle init default-python --config-file ./input.json --output-dir output +>>> [CLI] bundle init default-python --config-file ./input.json --output-dir output Welcome to the default Python template for Databricks Asset Bundles! -Workspace to use (auto-detected, edit in 'my_default_python/databricks.yml'): $DATABRICKS_URL +Workspace to use (auto-detected, edit in 'my_default_python/databricks.yml'): [DATABRICKS_URL] ✨ Your new project has been created in the 'my_default_python' directory! Please refer to the README.md file for "getting started" instructions. See also the documentation at https://docs.databricks.com/dev-tools/bundles/index.html. ->>> $CLI bundle validate -t dev +>>> [CLI] bundle validate -t dev Name: my_default_python Target: dev Workspace: - Host: $DATABRICKS_URL - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/my_default_python/dev + Host: [DATABRICKS_URL] + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/my_default_python/dev Validation OK! ->>> $CLI bundle validate -t prod +>>> [CLI] bundle validate -t prod Name: my_default_python Target: prod Workspace: - Host: $DATABRICKS_URL - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/my_default_python/prod + Host: [DATABRICKS_URL] + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/my_default_python/prod Validation OK! diff --git a/acceptance/bundle/templates/default-python/output/my_default_python/README.md b/acceptance/bundle/templates/default-python/output/my_default_python/README.md index 97d7d7949..10f570bf4 100644 --- a/acceptance/bundle/templates/default-python/output/my_default_python/README.md +++ b/acceptance/bundle/templates/default-python/output/my_default_python/README.md @@ -37,10 +37,12 @@ The 'my_default_python' project was generated by using the default-python templa ``` $ databricks bundle run ``` - -6. Optionally, install developer tools such as the Databricks extension for Visual Studio Code from - https://docs.databricks.com/dev-tools/vscode-ext.html. Or read the "getting started" documentation for - **Databricks Connect** for instructions on running the included Python code from a different IDE. +6. Optionally, install the Databricks extension for Visual Studio code for local development from + https://docs.databricks.com/dev-tools/vscode-ext.html. It can configure your + virtual environment and setup Databricks Connect for running unit tests locally. + When not using these tools, consult your development environment's documentation + and/or the documentation for Databricks Connect for manually setting up your environment + (https://docs.databricks.com/en/dev-tools/databricks-connect/python/index.html). 7. For documentation on the Databricks asset bundles format used for this project, and for CI/CD configuration, see diff --git a/acceptance/bundle/templates/default-python/output/my_default_python/databricks.yml b/acceptance/bundle/templates/default-python/output/my_default_python/databricks.yml index 3fa777219..6080a368f 100644 --- a/acceptance/bundle/templates/default-python/output/my_default_python/databricks.yml +++ b/acceptance/bundle/templates/default-python/output/my_default_python/databricks.yml @@ -16,16 +16,14 @@ targets: mode: development default: true workspace: - host: $DATABRICKS_URL + host: [DATABRICKS_URL] prod: mode: production workspace: - host: $DATABRICKS_URL - # We explicitly specify /Workspace/Users/$USERNAME to make sure we only have a single copy. - root_path: /Workspace/Users/$USERNAME/.bundle/${bundle.name}/${bundle.target} + host: [DATABRICKS_URL] + # We explicitly deploy to /Workspace/Users/[USERNAME] to make sure we only have a single copy. + root_path: /Workspace/Users/[USERNAME]/.bundle/${bundle.name}/${bundle.target} permissions: - - user_name: $USERNAME + - user_name: [USERNAME] level: CAN_MANAGE - run_as: - user_name: $USERNAME diff --git a/acceptance/bundle/templates/default-python/output/my_default_python/.gitignore b/acceptance/bundle/templates/default-python/output/my_default_python/out.gitignore similarity index 100% rename from acceptance/bundle/templates/default-python/output/my_default_python/.gitignore rename to acceptance/bundle/templates/default-python/output/my_default_python/out.gitignore diff --git a/acceptance/bundle/templates/default-python/output/my_default_python/resources/my_default_python.job.yml b/acceptance/bundle/templates/default-python/output/my_default_python/resources/my_default_python.job.yml index e6148a4ad..d9e31691a 100644 --- a/acceptance/bundle/templates/default-python/output/my_default_python/resources/my_default_python.job.yml +++ b/acceptance/bundle/templates/default-python/output/my_default_python/resources/my_default_python.job.yml @@ -12,7 +12,7 @@ resources: email_notifications: on_failure: - - $USERNAME + - [USERNAME] tasks: - task_key: notebook_task diff --git a/acceptance/bundle/templates/default-python/output/my_default_python/setup.py b/acceptance/bundle/templates/default-python/output/my_default_python/setup.py index 84b24ecb8..548f1035e 100644 --- a/acceptance/bundle/templates/default-python/output/my_default_python/setup.py +++ b/acceptance/bundle/templates/default-python/output/my_default_python/setup.py @@ -23,7 +23,7 @@ setup( # to ensure that changes to wheel package are picked up when used on all-purpose clusters version=my_default_python.__version__ + "+" + local_version, url="https://databricks.com", - author="$USERNAME", + author="[USERNAME]", description="wheel file based on my_default_python/src", packages=find_packages(where="./src"), package_dir={"": "src"}, diff --git a/acceptance/bundle/templates/default-python/script b/acceptance/bundle/templates/default-python/script index b11a7ea21..e5fcb7741 100644 --- a/acceptance/bundle/templates/default-python/script +++ b/acceptance/bundle/templates/default-python/script @@ -3,3 +3,6 @@ trace $CLI bundle init default-python --config-file ./input.json --output-dir ou cd output/my_default_python trace $CLI bundle validate -t dev trace $CLI bundle validate -t prod + +# Do not affect this repository's git behaviour #2318 +mv .gitignore out.gitignore diff --git a/acceptance/bundle/templates/default-sql/output.txt b/acceptance/bundle/templates/default-sql/output.txt index fe0139093..06eff962b 100644 --- a/acceptance/bundle/templates/default-sql/output.txt +++ b/acceptance/bundle/templates/default-sql/output.txt @@ -1,32 +1,32 @@ ->>> $CLI bundle init default-sql --config-file ./input.json --output-dir output +>>> [CLI] bundle init default-sql --config-file ./input.json --output-dir output Welcome to the default SQL template for Databricks Asset Bundles! A workspace was selected based on your current profile. For information about how to change this, see https://docs.databricks.com/dev-tools/cli/profiles.html. -workspace_host: $DATABRICKS_URL +workspace_host: [DATABRICKS_URL] ✨ Your new project has been created in the 'my_default_sql' directory! Please refer to the README.md file for "getting started" instructions. See also the documentation at https://docs.databricks.com/dev-tools/bundles/index.html. ->>> $CLI bundle validate -t dev +>>> [CLI] bundle validate -t dev Name: my_default_sql Target: dev Workspace: - Host: $DATABRICKS_URL - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/my_default_sql/dev + Host: [DATABRICKS_URL] + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/my_default_sql/dev Validation OK! ->>> $CLI bundle validate -t prod +>>> [CLI] bundle validate -t prod Name: my_default_sql Target: prod Workspace: - Host: $DATABRICKS_URL - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/my_default_sql/prod + Host: [DATABRICKS_URL] + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/my_default_sql/prod Validation OK! diff --git a/acceptance/bundle/templates/default-sql/output/my_default_sql/databricks.yml b/acceptance/bundle/templates/default-sql/output/my_default_sql/databricks.yml index 16292bc84..07562ce7a 100644 --- a/acceptance/bundle/templates/default-sql/output/my_default_sql/databricks.yml +++ b/acceptance/bundle/templates/default-sql/output/my_default_sql/databricks.yml @@ -25,7 +25,7 @@ targets: mode: development default: true workspace: - host: $DATABRICKS_URL + host: [DATABRICKS_URL] variables: warehouse_id: f00dcafe catalog: main @@ -34,15 +34,13 @@ targets: prod: mode: production workspace: - host: $DATABRICKS_URL - # We explicitly specify /Workspace/Users/$USERNAME to make sure we only have a single copy. - root_path: /Workspace/Users/$USERNAME/.bundle/${bundle.name}/${bundle.target} + host: [DATABRICKS_URL] + # We explicitly deploy to /Workspace/Users/[USERNAME] to make sure we only have a single copy. + root_path: /Workspace/Users/[USERNAME]/.bundle/${bundle.name}/${bundle.target} variables: warehouse_id: f00dcafe catalog: main schema: default permissions: - - user_name: $USERNAME + - user_name: [USERNAME] level: CAN_MANAGE - run_as: - user_name: $USERNAME diff --git a/acceptance/bundle/templates/default-sql/output/my_default_sql/.gitignore b/acceptance/bundle/templates/default-sql/output/my_default_sql/out.gitignore similarity index 100% rename from acceptance/bundle/templates/default-sql/output/my_default_sql/.gitignore rename to acceptance/bundle/templates/default-sql/output/my_default_sql/out.gitignore diff --git a/acceptance/bundle/templates/default-sql/output/my_default_sql/resources/my_default_sql_sql.job.yml b/acceptance/bundle/templates/default-sql/output/my_default_sql/resources/my_default_sql_sql.job.yml index 86de0f9db..34d60e3d5 100644 --- a/acceptance/bundle/templates/default-sql/output/my_default_sql/resources/my_default_sql_sql.job.yml +++ b/acceptance/bundle/templates/default-sql/output/my_default_sql/resources/my_default_sql_sql.job.yml @@ -12,7 +12,7 @@ resources: email_notifications: on_failure: - - $USERNAME + - [USERNAME] parameters: - name: catalog diff --git a/acceptance/bundle/templates/default-sql/script b/acceptance/bundle/templates/default-sql/script index 66e7a14a2..7ea0d863c 100644 --- a/acceptance/bundle/templates/default-sql/script +++ b/acceptance/bundle/templates/default-sql/script @@ -3,3 +3,6 @@ trace $CLI bundle init default-sql --config-file ./input.json --output-dir outpu cd output/my_default_sql trace $CLI bundle validate -t dev trace $CLI bundle validate -t prod + +# Do not affect this repository's git behaviour #2318 +mv .gitignore out.gitignore diff --git a/acceptance/bundle/templates/experimental-jobs-as-code/output.txt b/acceptance/bundle/templates/experimental-jobs-as-code/output.txt index 10aca003e..984dad604 100644 --- a/acceptance/bundle/templates/experimental-jobs-as-code/output.txt +++ b/acceptance/bundle/templates/experimental-jobs-as-code/output.txt @@ -1,28 +1,28 @@ ->>> $CLI bundle init experimental-jobs-as-code --config-file ./input.json --output-dir output +>>> [CLI] bundle init experimental-jobs-as-code --config-file ./input.json --output-dir output Welcome to (EXPERIMENTAL) "Jobs as code" template for Databricks Asset Bundles! -Workspace to use (auto-detected, edit in 'my_jobs_as_code/databricks.yml'): $DATABRICKS_URL +Workspace to use (auto-detected, edit in 'my_jobs_as_code/databricks.yml'): [DATABRICKS_URL] ✨ Your new project has been created in the 'my_jobs_as_code' directory! Please refer to the README.md file for "getting started" instructions. See also the documentation at https://docs.databricks.com/dev-tools/bundles/index.html. ->>> $CLI bundle validate -t dev --output json -Warning: Ignoring Databricks CLI version constraint for development build. Required: >= 0.238.0, current: $DEV_VERSION +>>> [CLI] bundle validate -t dev --output json +Warning: Ignoring Databricks CLI version constraint for development build. Required: >= 0.238.0, current: [DEV_VERSION] { "jobs": { "my_jobs_as_code_job": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/my_jobs_as_code/dev/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/my_jobs_as_code/dev/state/metadata.json" }, "edit_mode": "UI_LOCKED", "email_notifications": { "on_failure": [ - "$USERNAME" + "[USERNAME]" ] }, "format": "MULTI_TASK", @@ -40,19 +40,19 @@ Warning: Ignoring Databricks CLI version constraint for development build. Requi } ], "max_concurrent_runs": 4, - "name": "[dev $USERNAME] my_jobs_as_code_job", + "name": "[dev [USERNAME]] my_jobs_as_code_job", "permissions": [], "queue": { "enabled": true }, "tags": { - "dev": "$USERNAME" + "dev": "[USERNAME]" }, "tasks": [ { "job_cluster_key": "job_cluster", "notebook_task": { - "notebook_path": "/Workspace/Users/$USERNAME/.bundle/my_jobs_as_code/dev/files/src/notebook" + "notebook_path": "/Workspace/Users/[USERNAME]/.bundle/my_jobs_as_code/dev/files/src/notebook" }, "task_key": "notebook_task" }, diff --git a/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/databricks.yml b/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/databricks.yml index 54e69a256..9299c96e8 100644 --- a/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/databricks.yml +++ b/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/databricks.yml @@ -34,16 +34,16 @@ targets: mode: development default: true workspace: - host: $DATABRICKS_URL + host: [DATABRICKS_URL] prod: mode: production workspace: - host: $DATABRICKS_URL - # We explicitly specify /Workspace/Users/$USERNAME to make sure we only have a single copy. - root_path: /Workspace/Users/$USERNAME/.bundle/${bundle.name}/${bundle.target} + host: [DATABRICKS_URL] + # We explicitly specify /Workspace/Users/[USERNAME] to make sure we only have a single copy. + root_path: /Workspace/Users/[USERNAME]/.bundle/${bundle.name}/${bundle.target} permissions: - - user_name: $USERNAME + - user_name: [USERNAME] level: CAN_MANAGE run_as: - user_name: $USERNAME + user_name: [USERNAME] diff --git a/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/.gitignore b/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/out.gitignore similarity index 100% rename from acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/.gitignore rename to acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/out.gitignore diff --git a/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/resources/my_jobs_as_code_job.py b/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/resources/my_jobs_as_code_job.py index 4854d656f..e8406fd7b 100644 --- a/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/resources/my_jobs_as_code_job.py +++ b/acceptance/bundle/templates/experimental-jobs-as-code/output/my_jobs_as_code/resources/my_jobs_as_code_job.py @@ -17,7 +17,7 @@ my_jobs_as_code_job = Job.from_dict( }, "email_notifications": { "on_failure": [ - "$USERNAME", + "[USERNAME]", ], }, "tasks": [ diff --git a/acceptance/bundle/templates/experimental-jobs-as-code/script b/acceptance/bundle/templates/experimental-jobs-as-code/script index 10188aabd..08e48fc5f 100644 --- a/acceptance/bundle/templates/experimental-jobs-as-code/script +++ b/acceptance/bundle/templates/experimental-jobs-as-code/script @@ -8,3 +8,6 @@ uv sync -q trace $CLI bundle validate -t dev --output json | jq ".resources" rm -fr .venv resources/__pycache__ uv.lock my_jobs_as_code.egg-info + +# Do not affect this repository's git behaviour #2318 +mv .gitignore out.gitignore diff --git a/acceptance/bundle/templates/test.toml b/acceptance/bundle/templates/test.toml new file mode 100644 index 000000000..90539263d --- /dev/null +++ b/acceptance/bundle/templates/test.toml @@ -0,0 +1,2 @@ +# At the moment, there are many differences across different envs w.r.t to catalog use, node type and so on. +LocalOnly = true diff --git a/acceptance/bundle/variables/arg-repeat/output.txt b/acceptance/bundle/variables/arg-repeat/output.txt index 2f9de1a3c..4b97d70a1 100644 --- a/acceptance/bundle/variables/arg-repeat/output.txt +++ b/acceptance/bundle/variables/arg-repeat/output.txt @@ -1,5 +1,5 @@ ->>> errcode $CLI bundle validate --var a=one -o json +>>> errcode [CLI] bundle validate --var a=one -o json { "a": { "default": "hello", @@ -7,7 +7,7 @@ } } ->>> errcode $CLI bundle validate --var a=one --var a=two +>>> errcode [CLI] bundle validate --var a=one --var a=two Error: failed to assign two to a: variable has already been assigned value: one Name: arg-repeat diff --git a/acceptance/bundle/variables/complex-cycle-self/output.txt b/acceptance/bundle/variables/complex-cycle-self/output.txt index fa80154ca..7447de349 100644 --- a/acceptance/bundle/variables/complex-cycle-self/output.txt +++ b/acceptance/bundle/variables/complex-cycle-self/output.txt @@ -3,7 +3,7 @@ Warning: Detected unresolved variables after 11 resolution rounds Name: cycle Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/cycle/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/cycle/default Found 1 warning diff --git a/acceptance/bundle/variables/complex-cycle/output.txt b/acceptance/bundle/variables/complex-cycle/output.txt index fa80154ca..7447de349 100644 --- a/acceptance/bundle/variables/complex-cycle/output.txt +++ b/acceptance/bundle/variables/complex-cycle/output.txt @@ -3,7 +3,7 @@ Warning: Detected unresolved variables after 11 resolution rounds Name: cycle Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/cycle/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/cycle/default Found 1 warning diff --git a/acceptance/bundle/variables/complex/out.default.json b/acceptance/bundle/variables/complex/out.default.json index a1ccd52bc..0804ad588 100644 --- a/acceptance/bundle/variables/complex/out.default.json +++ b/acceptance/bundle/variables/complex/out.default.json @@ -4,7 +4,7 @@ "my_job": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/complex-variables/default/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/complex-variables/default/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", diff --git a/acceptance/bundle/variables/complex/out.dev.json b/acceptance/bundle/variables/complex/out.dev.json index bb939091b..e93c2c297 100644 --- a/acceptance/bundle/variables/complex/out.dev.json +++ b/acceptance/bundle/variables/complex/out.dev.json @@ -4,7 +4,7 @@ "my_job": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/complex-variables/dev/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/complex-variables/dev/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", diff --git a/acceptance/bundle/variables/complex/output.txt b/acceptance/bundle/variables/complex/output.txt index ce295421f..f1d4c04cc 100644 --- a/acceptance/bundle/variables/complex/output.txt +++ b/acceptance/bundle/variables/complex/output.txt @@ -1,10 +1,10 @@ ->>> $CLI bundle validate -o json +>>> [CLI] bundle validate -o json >>> jq .resources.jobs.my_job.tasks[0].task_key out.default.json "task with spark version 13.2.x-scala2.11 and jar /path/to/jar" ->>> $CLI bundle validate -o json -t dev +>>> [CLI] bundle validate -o json -t dev >>> jq .resources.jobs.my_job.tasks[0].task_key out.dev.json "task with spark version 14.2.x-scala2.11 and jar /newpath/to/jar" diff --git a/acceptance/bundle/variables/complex_multiple_files/output.txt b/acceptance/bundle/variables/complex_multiple_files/output.txt index ec2cad1ce..433e6da0c 100644 --- a/acceptance/bundle/variables/complex_multiple_files/output.txt +++ b/acceptance/bundle/variables/complex_multiple_files/output.txt @@ -4,7 +4,7 @@ "my_job": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/complex-variables-multiple-files/dev/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/complex-variables-multiple-files/dev/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", diff --git a/acceptance/bundle/variables/double_underscore/databricks.yml b/acceptance/bundle/variables/double_underscore/databricks.yml new file mode 100644 index 000000000..3bb15d42d --- /dev/null +++ b/acceptance/bundle/variables/double_underscore/databricks.yml @@ -0,0 +1,14 @@ +bundle: + name: double_underscore + +variables: + double__underscore: + description: "This is a variable with a double underscore" + default: "default" + +resources: + jobs: + test_job: + name: "test" + tasks: + - task_key: "test ${var.double__underscore}" diff --git a/acceptance/bundle/variables/double_underscore/output.txt b/acceptance/bundle/variables/double_underscore/output.txt new file mode 100644 index 000000000..0124f5442 --- /dev/null +++ b/acceptance/bundle/variables/double_underscore/output.txt @@ -0,0 +1,7 @@ + +>>> [CLI] bundle validate -o json +[ + { + "task_key": "test default" + } +] diff --git a/acceptance/bundle/variables/double_underscore/script b/acceptance/bundle/variables/double_underscore/script new file mode 100644 index 000000000..a7394df77 --- /dev/null +++ b/acceptance/bundle/variables/double_underscore/script @@ -0,0 +1 @@ +trace $CLI bundle validate -o json | jq .resources.jobs.test_job.tasks diff --git a/acceptance/bundle/variables/empty/output.txt b/acceptance/bundle/variables/empty/output.txt index 8933443df..cbd0f1989 100644 --- a/acceptance/bundle/variables/empty/output.txt +++ b/acceptance/bundle/variables/empty/output.txt @@ -3,8 +3,8 @@ Error: no value assigned to required variable a. Assignment can be done using "- Name: empty${var.a} Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/empty${var.a}/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/empty${var.a}/default Found 1 error diff --git a/acceptance/bundle/variables/env_overrides/output.txt b/acceptance/bundle/variables/env_overrides/output.txt index 06e6e518b..93b3b6716 100644 --- a/acceptance/bundle/variables/env_overrides/output.txt +++ b/acceptance/bundle/variables/env_overrides/output.txt @@ -1,27 +1,27 @@ ->>> $CLI bundle validate -t env-with-single-variable-override -o json +>>> [CLI] bundle validate -t env-with-single-variable-override -o json "default-a dev-b" ->>> $CLI bundle validate -t env-with-two-variable-overrides -o json +>>> [CLI] bundle validate -t env-with-two-variable-overrides -o json "prod-a prod-b" ->>> BUNDLE_VAR_b=env-var-b $CLI bundle validate -t env-with-two-variable-overrides -o json +>>> BUNDLE_VAR_b=env-var-b [CLI] bundle validate -t env-with-two-variable-overrides -o json "prod-a env-var-b" ->>> errcode $CLI bundle validate -t env-missing-a-required-variable-assignment +>>> errcode [CLI] bundle validate -t env-missing-a-required-variable-assignment Error: no value assigned to required variable b. Assignment can be done using "--var", by setting the BUNDLE_VAR_b environment variable, or in .databricks/bundle//variable-overrides.json file Name: test bundle Target: env-missing-a-required-variable-assignment Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/test bundle/env-missing-a-required-variable-assignment + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/test bundle/env-missing-a-required-variable-assignment Found 1 error Exit code: 1 ->>> errcode $CLI bundle validate -t env-using-an-undefined-variable +>>> errcode [CLI] bundle validate -t env-using-an-undefined-variable Error: variable c is not defined but is assigned a value Name: test bundle @@ -30,7 +30,7 @@ Found 1 error Exit code: 1 ->>> $CLI bundle validate -t env-overrides-lookup -o json +>>> [CLI] bundle validate -t env-overrides-lookup -o json { "a": "default-a", "b": "prod-b", diff --git a/acceptance/bundle/variables/file-defaults/output.txt b/acceptance/bundle/variables/file-defaults/output.txt index 73830aae3..234ddcbbd 100644 --- a/acceptance/bundle/variables/file-defaults/output.txt +++ b/acceptance/bundle/variables/file-defaults/output.txt @@ -1,6 +1,6 @@ === variable file ->>> $CLI bundle validate -o json +>>> [CLI] bundle validate -o json { "job_cluster_key": "mlops_stacks-cluster", "new_cluster": { @@ -10,7 +10,7 @@ } === variable file and variable flag ->>> $CLI bundle validate -o json --var=cluster_key=mlops_stacks-cluster-overriden +>>> [CLI] bundle validate -o json --var=cluster_key=mlops_stacks-cluster-overriden { "job_cluster_key": "mlops_stacks-cluster-overriden", "new_cluster": { @@ -20,7 +20,7 @@ } === variable file and environment variable ->>> BUNDLE_VAR_cluster_key=mlops_stacks-cluster-overriden $CLI bundle validate -o json +>>> BUNDLE_VAR_cluster_key=mlops_stacks-cluster-overriden [CLI] bundle validate -o json { "job_cluster_key": "mlops_stacks-cluster-overriden", "new_cluster": { @@ -30,7 +30,7 @@ } === variable has value in config file ->>> $CLI bundle validate -o json --target with_value +>>> [CLI] bundle validate -o json --target with_value { "job_cluster_key": "mlops_stacks-cluster-from-file", "new_cluster": { @@ -39,8 +39,39 @@ } } +=== file cannot be parsed +>>> errcode [CLI] bundle validate -o json --target invalid_json +Error: failed to parse variables file [TMPDIR]/.databricks/bundle/invalid_json/variable-overrides.json: error decoding JSON at :0:0: invalid character 'o' in literal false (expecting 'a') + + +Exit code: 1 +{ + "job_cluster_key": "${var.cluster_key}", + "new_cluster": { + "node_type_id": "${var.cluster.node_type_id}", + "num_workers": "${var.cluster_workers}" + } +} + +=== file has wrong structure +>>> errcode [CLI] bundle validate -o json --target wrong_file_structure +Error: failed to parse variables file [TMPDIR]/.databricks/bundle/wrong_file_structure/variable-overrides.json: invalid format + +Variables file must be a JSON object with the following format: +{"var1": "value1", "var2": "value2"} + + +Exit code: 1 +{ + "job_cluster_key": "${var.cluster_key}", + "new_cluster": { + "node_type_id": "${var.cluster.node_type_id}", + "num_workers": "${var.cluster_workers}" + } +} + === file has variable that is complex but default is string ->>> errcode $CLI bundle validate -o json --target complex_to_string +>>> errcode [CLI] bundle validate -o json --target complex_to_string Error: variable cluster_key is not of type complex, but the value in the variable file is a complex type @@ -54,7 +85,7 @@ Exit code: 1 } === file has variable that is string but default is complex ->>> errcode $CLI bundle validate -o json --target string_to_complex +>>> errcode [CLI] bundle validate -o json --target string_to_complex Error: variable cluster is of type complex, but the value in the variable file is not a complex type @@ -68,7 +99,7 @@ Exit code: 1 } === variable is required but it's not provided in the file ->>> errcode $CLI bundle validate -o json --target without_defaults +>>> errcode [CLI] bundle validate -o json --target without_defaults Error: no value assigned to required variable cluster. Assignment can be done using "--var", by setting the BUNDLE_VAR_cluster environment variable, or in .databricks/bundle//variable-overrides.json file diff --git a/acceptance/bundle/variables/file-defaults/script b/acceptance/bundle/variables/file-defaults/script index c5b208755..8e6fd0d75 100644 --- a/acceptance/bundle/variables/file-defaults/script +++ b/acceptance/bundle/variables/file-defaults/script @@ -14,11 +14,11 @@ trace BUNDLE_VAR_cluster_key=mlops_stacks-cluster-overriden $CLI bundle validate title "variable has value in config file" trace $CLI bundle validate -o json --target with_value | jq $cluster_expr -# title "file cannot be parsed" -# trace errcode $CLI bundle validate -o json --target invalid_json | jq $cluster_expr +title "file cannot be parsed" +trace errcode $CLI bundle validate -o json --target invalid_json | jq $cluster_expr -# title "file has wrong structure" -# trace errcode $CLI bundle validate -o json --target wrong_file_structure | jq $cluster_expr +title "file has wrong structure" +trace errcode $CLI bundle validate -o json --target wrong_file_structure | jq $cluster_expr title "file has variable that is complex but default is string" trace errcode $CLI bundle validate -o json --target complex_to_string | jq $cluster_expr diff --git a/acceptance/bundle/variables/file-defaults/test.toml b/acceptance/bundle/variables/file-defaults/test.toml new file mode 100644 index 000000000..da8854775 --- /dev/null +++ b/acceptance/bundle/variables/file-defaults/test.toml @@ -0,0 +1,4 @@ +# Fix for windows +[[Repls]] +Old = '\\' +New = '/' diff --git a/acceptance/bundle/variables/git-branch/output.txt b/acceptance/bundle/variables/git-branch/output.txt index d6d824394..68f27a3f1 100644 --- a/acceptance/bundle/variables/git-branch/output.txt +++ b/acceptance/bundle/variables/git-branch/output.txt @@ -1,17 +1,17 @@ ->>> $CLI bundle validate -o json +>>> [CLI] bundle validate -o json { "bundle": { "environment": "prod", "git": { "actual_branch": "main", "branch": "", - "bundle_root_path": ".", + "bundle_root_path": "." }, "name": "git", "target": "prod", "terraform": { - "exec_path": "$TMPHOME" + "exec_path": "[TERRAFORM]" } }, "sync": { @@ -27,40 +27,36 @@ } }, "workspace": { - "artifact_path": "/Workspace/Users/$USERNAME/.bundle/git/prod/artifacts", - "current_user": { - "short_name": "$USERNAME", - "userName": "$USERNAME" - }, - "file_path": "/Workspace/Users/$USERNAME/.bundle/git/prod/files", - "resource_path": "/Workspace/Users/$USERNAME/.bundle/git/prod/resources", - "root_path": "/Workspace/Users/$USERNAME/.bundle/git/prod", - "state_path": "/Workspace/Users/$USERNAME/.bundle/git/prod/state" + "artifact_path": "/Workspace/Users/[USERNAME]/.bundle/git/prod/artifacts", + "file_path": "/Workspace/Users/[USERNAME]/.bundle/git/prod/files", + "resource_path": "/Workspace/Users/[USERNAME]/.bundle/git/prod/resources", + "root_path": "/Workspace/Users/[USERNAME]/.bundle/git/prod", + "state_path": "/Workspace/Users/[USERNAME]/.bundle/git/prod/state" } } ->>> $CLI bundle validate +>>> [CLI] bundle validate Name: git Target: prod Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/git/prod + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/git/prod Validation OK! ->>> $CLI bundle validate -o json -t dev +>>> [CLI] bundle validate -o json -t dev { "bundle": { "environment": "dev", "git": { "actual_branch": "main", "branch": "dev-branch", - "bundle_root_path": ".", + "bundle_root_path": "." }, "name": "git", "target": "dev", "terraform": { - "exec_path": "$TMPHOME" + "exec_path": "[TERRAFORM]" } }, "sync": { @@ -76,23 +72,19 @@ Validation OK! } }, "workspace": { - "artifact_path": "/Workspace/Users/$USERNAME/.bundle/git/dev/artifacts", - "current_user": { - "short_name": "$USERNAME", - "userName": "$USERNAME" - }, - "file_path": "/Workspace/Users/$USERNAME/.bundle/git/dev/files", - "resource_path": "/Workspace/Users/$USERNAME/.bundle/git/dev/resources", - "root_path": "/Workspace/Users/$USERNAME/.bundle/git/dev", - "state_path": "/Workspace/Users/$USERNAME/.bundle/git/dev/state" + "artifact_path": "/Workspace/Users/[USERNAME]/.bundle/git/dev/artifacts", + "file_path": "/Workspace/Users/[USERNAME]/.bundle/git/dev/files", + "resource_path": "/Workspace/Users/[USERNAME]/.bundle/git/dev/resources", + "root_path": "/Workspace/Users/[USERNAME]/.bundle/git/dev", + "state_path": "/Workspace/Users/[USERNAME]/.bundle/git/dev/state" } } ->>> $CLI bundle validate -t dev +>>> [CLI] bundle validate -t dev Name: git Target: dev Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/git/dev + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/git/dev Validation OK! diff --git a/acceptance/bundle/variables/git-branch/script b/acceptance/bundle/variables/git-branch/script index aed881f1f..8f99cc01b 100644 --- a/acceptance/bundle/variables/git-branch/script +++ b/acceptance/bundle/variables/git-branch/script @@ -1,6 +1,6 @@ git-repo-init -trace $CLI bundle validate -o json | grep -v '"commit"' +trace $CLI bundle validate -o json | jq 'del(.workspace.current_user, .bundle.git.commit)' trace $CLI bundle validate -trace $CLI bundle validate -o json -t dev | grep -v '"commit"' -trace $CLI bundle validate -t dev | grep -v '"commit"' +trace $CLI bundle validate -o json -t dev | jq 'del(.workspace.current_user, .bundle.git.commit)' +trace $CLI bundle validate -t dev rm -fr .git diff --git a/acceptance/bundle/variables/host/output.txt b/acceptance/bundle/variables/host/output.txt index 89342908c..df0a4527a 100644 --- a/acceptance/bundle/variables/host/output.txt +++ b/acceptance/bundle/variables/host/output.txt @@ -1,5 +1,5 @@ ->>> errcode $CLI bundle validate -o json +>>> errcode [CLI] bundle validate -o json Error: failed during request visitor: parse "https://${var.host}": invalid character "{" in host name { @@ -23,9 +23,10 @@ Error: failed during request visitor: parse "https://${var.host}": invalid chara "host": "${var.host}" } } + Exit code: 1 ->>> errcode $CLI bundle validate +>>> errcode [CLI] bundle validate Error: failed during request visitor: parse "https://${var.host}": invalid character "{" in host name Name: host diff --git a/acceptance/bundle/variables/prepend-workspace-var/output.txt b/acceptance/bundle/variables/prepend-workspace-var/output.txt index 575fac6d4..a48a58fba 100644 --- a/acceptance/bundle/variables/prepend-workspace-var/output.txt +++ b/acceptance/bundle/variables/prepend-workspace-var/output.txt @@ -3,12 +3,11 @@ "bundle": { "environment": "dev", "git": { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." }, "target": "dev", "terraform": { - "exec_path": "$TMPHOME" + "exec_path": "[TERRAFORM]" } }, "resources": { @@ -16,7 +15,7 @@ "my_job": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Users/$USERNAME/path/to/root/state/metadata.json" + "metadata_file_path": "/Users/[USERNAME]/path/to/root/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", @@ -30,7 +29,7 @@ "existing_cluster_id": "500", "python_wheel_task": { "named_parameters": { - "conf-file": "/Users/$USERNAME/path/to/root/files/path/to/config.yaml" + "conf-file": "/Users/[USERNAME]/path/to/root/files/path/to/config.yaml" } }, "task_key": "" @@ -47,21 +46,17 @@ "targets": null, "variables": { "workspace_root": { - "default": "/Users/$USERNAME", + "default": "/Users/[USERNAME]", "description": "root directory in the Databricks workspace to store the asset bundle and associated artifacts", - "value": "/Users/$USERNAME" + "value": "/Users/[USERNAME]" } }, "workspace": { - "artifact_path": "/Users/$USERNAME/path/to/root/artifacts", - "current_user": { - "short_name": "$USERNAME", - "userName": "$USERNAME" - }, - "file_path": "/Users/$USERNAME/path/to/root/files", + "artifact_path": "/Users/[USERNAME]/path/to/root/artifacts", + "file_path": "/Users/[USERNAME]/path/to/root/files", "profile": "profile_name", - "resource_path": "/Users/$USERNAME/path/to/root/resources", - "root_path": "/Users/$USERNAME/path/to/root", - "state_path": "/Users/$USERNAME/path/to/root/state" + "resource_path": "/Users/[USERNAME]/path/to/root/resources", + "root_path": "/Users/[USERNAME]/path/to/root", + "state_path": "/Users/[USERNAME]/path/to/root/state" } -} \ No newline at end of file +} diff --git a/acceptance/bundle/variables/prepend-workspace-var/script b/acceptance/bundle/variables/prepend-workspace-var/script index de6bc8a17..e30ffb9c4 100644 --- a/acceptance/bundle/variables/prepend-workspace-var/script +++ b/acceptance/bundle/variables/prepend-workspace-var/script @@ -1,2 +1,2 @@ echo /Workspace should be prepended on all paths, but it is not the case: #2181 -$CLI bundle validate -o json +$CLI bundle validate -o json | jq 'del(.workspace.current_user)' diff --git a/acceptance/bundle/variables/resolve-builtin/output.txt b/acceptance/bundle/variables/resolve-builtin/output.txt index f060c472e..f37a2a19e 100644 --- a/acceptance/bundle/variables/resolve-builtin/output.txt +++ b/acceptance/bundle/variables/resolve-builtin/output.txt @@ -1,9 +1,5 @@ { "artifact_path": "TestResolveVariableReferences/bar/artifacts", - "current_user": { - "short_name": "$USERNAME", - "userName": "$USERNAME" - }, "file_path": "TestResolveVariableReferences/bar/baz", "resource_path": "TestResolveVariableReferences/bar/resources", "root_path": "TestResolveVariableReferences/bar", diff --git a/acceptance/bundle/variables/resolve-builtin/script b/acceptance/bundle/variables/resolve-builtin/script index fefd9abe6..558d0a7ca 100644 --- a/acceptance/bundle/variables/resolve-builtin/script +++ b/acceptance/bundle/variables/resolve-builtin/script @@ -1 +1 @@ -$CLI bundle validate -o json | jq .workspace +$CLI bundle validate -o json | jq .workspace | jq 'del(.current_user)' diff --git a/acceptance/bundle/variables/resolve-nonstrings/output.txt b/acceptance/bundle/variables/resolve-nonstrings/output.txt index 3a1eb9c47..951ad7a0d 100644 --- a/acceptance/bundle/variables/resolve-nonstrings/output.txt +++ b/acceptance/bundle/variables/resolve-nonstrings/output.txt @@ -20,7 +20,7 @@ "job1": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/TestResolveVariableReferencesForPrimitiveNonStringFields/default/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/TestResolveVariableReferencesForPrimitiveNonStringFields/default/state/metadata.json" }, "edit_mode": "UI_LOCKED", "format": "MULTI_TASK", diff --git a/acceptance/bundle/variables/resolve-vars-in-root-path/output.txt b/acceptance/bundle/variables/resolve-vars-in-root-path/output.txt index c56fbe415..fb828d826 100644 --- a/acceptance/bundle/variables/resolve-vars-in-root-path/output.txt +++ b/acceptance/bundle/variables/resolve-vars-in-root-path/output.txt @@ -1,9 +1,5 @@ { "artifact_path": "TestResolveVariableReferencesToBundleVariables/bar/artifacts", - "current_user": { - "short_name": "$USERNAME", - "userName": "$USERNAME" - }, "file_path": "TestResolveVariableReferencesToBundleVariables/bar/files", "resource_path": "TestResolveVariableReferencesToBundleVariables/bar/resources", "root_path": "TestResolveVariableReferencesToBundleVariables/bar", diff --git a/acceptance/bundle/variables/resolve-vars-in-root-path/script b/acceptance/bundle/variables/resolve-vars-in-root-path/script index fefd9abe6..558d0a7ca 100644 --- a/acceptance/bundle/variables/resolve-vars-in-root-path/script +++ b/acceptance/bundle/variables/resolve-vars-in-root-path/script @@ -1 +1 @@ -$CLI bundle validate -o json | jq .workspace +$CLI bundle validate -o json | jq .workspace | jq 'del(.current_user)' diff --git a/acceptance/bundle/variables/test.toml b/acceptance/bundle/variables/test.toml new file mode 100644 index 000000000..32398e828 --- /dev/null +++ b/acceptance/bundle/variables/test.toml @@ -0,0 +1,3 @@ +# The tests here intend to test variable interpolation via "bundle validate". +# Even though "bundle validate" does a few API calls, that's not the focus there. +LocalOnly = true diff --git a/acceptance/bundle/variables/vanilla/output.txt b/acceptance/bundle/variables/vanilla/output.txt index e98882bb0..3958c39b9 100644 --- a/acceptance/bundle/variables/vanilla/output.txt +++ b/acceptance/bundle/variables/vanilla/output.txt @@ -1,15 +1,15 @@ ->>> BUNDLE_VAR_b=def $CLI bundle validate -o json +>>> BUNDLE_VAR_b=def [CLI] bundle validate -o json "abc def" ->>> errcode $CLI bundle validate +>>> errcode [CLI] bundle validate Error: no value assigned to required variable b. Assignment can be done using "--var", by setting the BUNDLE_VAR_b environment variable, or in .databricks/bundle//variable-overrides.json file Name: ${var.a} ${var.b} Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/${var.a} ${var.b}/default + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/${var.a} ${var.b}/default Found 1 error diff --git a/acceptance/bundle/variables/variable_overrides_in_target/output.txt b/acceptance/bundle/variables/variable_overrides_in_target/output.txt index 8998b691d..d112cf2de 100644 --- a/acceptance/bundle/variables/variable_overrides_in_target/output.txt +++ b/acceptance/bundle/variables/variable_overrides_in_target/output.txt @@ -1,5 +1,5 @@ ->>> $CLI bundle validate -o json -t use-default-variable-values +>>> [CLI] bundle validate -o json -t use-default-variable-values { "pipelines": { "my_pipeline": { @@ -12,7 +12,7 @@ "continuous": true, "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/foobar/use-default-variable-values/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/foobar/use-default-variable-values/state/metadata.json" }, "name": "a_string", "permissions": [] @@ -20,7 +20,7 @@ } } ->>> $CLI bundle validate -o json -t override-string-variable +>>> [CLI] bundle validate -o json -t override-string-variable { "pipelines": { "my_pipeline": { @@ -33,7 +33,7 @@ "continuous": true, "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/foobar/override-string-variable/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/foobar/override-string-variable/state/metadata.json" }, "name": "overridden_string", "permissions": [] @@ -41,7 +41,7 @@ } } ->>> $CLI bundle validate -o json -t override-int-variable +>>> [CLI] bundle validate -o json -t override-int-variable { "pipelines": { "my_pipeline": { @@ -54,7 +54,7 @@ "continuous": true, "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/foobar/override-int-variable/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/foobar/override-int-variable/state/metadata.json" }, "name": "a_string", "permissions": [] @@ -62,7 +62,7 @@ } } ->>> $CLI bundle validate -o json -t override-both-bool-and-string-variables +>>> [CLI] bundle validate -o json -t override-both-bool-and-string-variables { "pipelines": { "my_pipeline": { @@ -75,7 +75,7 @@ "continuous": false, "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/foobar/override-both-bool-and-string-variables/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/foobar/override-both-bool-and-string-variables/state/metadata.json" }, "name": "overridden_string", "permissions": [] diff --git a/acceptance/cmd_server_test.go b/acceptance/cmd_server_test.go index 3f5a6356e..dc48a85d7 100644 --- a/acceptance/cmd_server_test.go +++ b/acceptance/cmd_server_test.go @@ -1,8 +1,8 @@ package acceptance_test import ( + "context" "encoding/json" - "net/http" "os" "strings" "testing" @@ -13,8 +13,8 @@ import ( ) func StartCmdServer(t *testing.T) *testserver.Server { - server := StartServer(t) - server.Handle("/", func(r *http.Request) (any, error) { + server := testserver.New(t) + server.Handle("GET", "/", func(r testserver.Request) any { q := r.URL.Query() args := strings.Split(q.Get("args"), " ") @@ -27,7 +27,7 @@ func StartCmdServer(t *testing.T) *testserver.Server { defer Chdir(t, q.Get("cwd"))() - c := testcli.NewRunner(t, r.Context(), args...) + c := testcli.NewRunner(t, context.Background(), args...) c.Verbose = false stdout, stderr, err := c.Run() result := map[string]any{ @@ -39,7 +39,7 @@ func StartCmdServer(t *testing.T) *testserver.Server { exitcode = 1 } result["exitcode"] = exitcode - return result, nil + return result }) return server } diff --git a/acceptance/config_test.go b/acceptance/config_test.go index 41866c4a7..ec0d1baee 100644 --- a/acceptance/config_test.go +++ b/acceptance/config_test.go @@ -3,21 +3,19 @@ package acceptance_test import ( "os" "path/filepath" - "sync" + "slices" + "strings" "testing" + "dario.cat/mergo" "github.com/BurntSushi/toml" "github.com/databricks/cli/libs/testdiff" + "github.com/databricks/cli/libs/testserver" "github.com/stretchr/testify/require" ) const configFilename = "test.toml" -var ( - configCache map[string]TestConfig - configMutex sync.Mutex -) - type TestConfig struct { // Place to describe what's wrong with this test. Does not affect how the test is run. Badness string @@ -26,63 +24,91 @@ type TestConfig struct { // If absent, default to true. GOOS map[string]bool + // If true, do not run this test against cloud environment + LocalOnly bool + // List of additional replacements to apply on this test. // Old is a regexp, New is a replacement expression. Repls []testdiff.Replacement + + // List of server stubs to load. Example configuration: + // + // [[Server]] + // Pattern = "POST /api/2.1/jobs/create" + // Response.Body = ''' + // { + // "job_id": 1111 + // } + // ''' + Server []ServerStub + + // Record the requests made to the server and write them as output to + // out.requests.txt + RecordRequests bool + + // List of request headers to include when recording requests. + IncludeRequestHeaders []string } -// FindConfig finds the closest config file. -func FindConfig(t *testing.T, dir string) (string, bool) { - shared := false +type ServerStub struct { + // The HTTP method and path to match. Examples: + // 1. /api/2.0/clusters/list (matches all methods) + // 2. GET /api/2.0/clusters/list + Pattern string + + // The response body to return. + Response testserver.Response +} + +// FindConfigs finds all the config relevant for this test, +// ordered from the most outermost (at acceptance/) to current test directory (identified by dir). +// Argument dir must be a relative path from the root of acceptance tests (/acceptance/). +func FindConfigs(t *testing.T, dir string) []string { + configs := []string{} for { path := filepath.Join(dir, configFilename) _, err := os.Stat(path) if err == nil { - return path, shared + configs = append(configs, path) } - shared = true - if dir == "" || dir == "." { break } - if os.IsNotExist(err) { - dir = filepath.Dir(dir) + dir = filepath.Dir(dir) + + if err == nil || os.IsNotExist(err) { continue } t.Fatalf("Error while reading %s: %s", path, err) } - t.Fatal("Config not found: " + configFilename) - return "", shared + slices.Reverse(configs) + return configs } // LoadConfig loads the config file. Non-leaf configs are cached. func LoadConfig(t *testing.T, dir string) (TestConfig, string) { - path, leafConfig := FindConfig(t, dir) + configs := FindConfigs(t, dir) - if leafConfig { - return DoLoadConfig(t, path), path + if len(configs) == 0 { + return TestConfig{}, "(no config)" } - configMutex.Lock() - defer configMutex.Unlock() + result := DoLoadConfig(t, configs[0]) - if configCache == nil { - configCache = make(map[string]TestConfig) + for _, cfgName := range configs[1:] { + cfg := DoLoadConfig(t, cfgName) + err := mergo.Merge(&result, cfg, mergo.WithOverride, mergo.WithAppendSlice) + if err != nil { + t.Fatalf("Error during config merge: %s: %s", cfgName, err) + } } - result, ok := configCache[path] - if ok { - return result, path - } - - result = DoLoadConfig(t, path) - configCache[path] = result - return result, path + return result, strings.Join(configs, ", ") } func DoLoadConfig(t *testing.T, path string) TestConfig { diff --git a/acceptance/install_terraform.py b/acceptance/install_terraform.py new file mode 100755 index 000000000..4cf6a9729 --- /dev/null +++ b/acceptance/install_terraform.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +""" +Script to set up terraform and databricks terraform provider in a local directory: + +- Download terraform. +- Download databricks provider. +- Write a .terraformrc config file that uses this directory. +- The config file contains env vars that need to be set so that databricks CLI uses this terraform and provider. +""" + +import os +import platform +import zipfile +import argparse +import json +from pathlib import Path +from urllib.request import urlretrieve + +os_name = platform.system().lower() + +arch = platform.machine().lower() +arch = {"x86_64": "amd64"}.get(arch, arch) +if os_name == "windows" and arch not in ("386", "amd64"): + # terraform 1.5.5 only has builds for these two. + arch = "amd64" + +terraform_version = "1.5.5" +terraform_file = f"terraform_{terraform_version}_{os_name}_{arch}.zip" +terraform_url = f"https://releases.hashicorp.com/terraform/{terraform_version}/{terraform_file}" +terraform_binary = "terraform.exe" if os_name == "windows" else "terraform" + + +def retrieve(url, path): + if not path.exists(): + print(f"Downloading {url} -> {path}") + urlretrieve(url, path) + + +def read_version(path): + for line in path.open(): + if "ProviderVersion" in line: + # Expecting 'const ProviderVersion = "1.64.1"' + items = line.strip().split() + assert len(items) >= 3, items + assert items[-3:-1] == ["ProviderVersion", "="], items + version = items[-1].strip('"') + assert version, items + return version + raise SystemExit(f"Could not find ProviderVersion in {path}") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--targetdir", default="build", type=Path) + parser.add_argument("--provider-version") + args = parser.parse_args() + target = args.targetdir + + if not args.provider_version: + version_file = Path(__file__).parent.parent / "bundle/internal/tf/codegen/schema/version.go" + assert version_file.exists(), version_file + terraform_provider_version = read_version(version_file) + print(f"Read version {terraform_provider_version} from {version_file}") + else: + terraform_provider_version = args.provider_version + + terraform_provider_file = f"terraform-provider-databricks_{terraform_provider_version}_{os_name}_{arch}.zip" + terraform_provider_url = ( + f"https://github.com/databricks/terraform-provider-databricks/releases/download/v{terraform_provider_version}/{terraform_provider_file}" + ) + + target.mkdir(exist_ok=True, parents=True) + + zip_path = target / terraform_file + terraform_path = target / terraform_binary + terraform_provider_path = target / terraform_provider_file + + retrieve(terraform_url, zip_path) + retrieve(terraform_provider_url, terraform_provider_path) + + if not terraform_path.exists(): + print(f"Extracting {zip_path} -> {terraform_path}") + + with zipfile.ZipFile(zip_path, "r") as zip_ref: + zip_ref.extractall(target) + + terraform_path.chmod(0o755) + + tfplugins_path = target / "tfplugins" + provider_dir = Path(tfplugins_path / f"registry.terraform.io/databricks/databricks/{terraform_provider_version}/{os_name}_{arch}") + if not provider_dir.exists(): + print(f"Extracting {terraform_provider_path} -> {provider_dir}") + os.makedirs(provider_dir, exist_ok=True) + with zipfile.ZipFile(terraform_provider_path, "r") as zip_ref: + zip_ref.extractall(provider_dir) + + files = list(provider_dir.iterdir()) + assert files, provider_dir + + for f in files: + f.chmod(0o755) + + terraformrc_path = target / ".terraformrc" + if not terraformrc_path.exists(): + path = json.dumps(str(tfplugins_path.absolute())) + text = f"""# Set these env variables before running databricks cli: +# export DATABRICKS_TF_CLI_CONFIG_FILE={terraformrc_path.absolute()} +# export DATABRICKS_TF_EXEC_PATH={terraform_path.absolute()} + +provider_installation {{ + filesystem_mirror {{ + path = {path} + include = ["registry.terraform.io/databricks/databricks"] + }} +}} +""" + print(f"Writing {terraformrc_path}:\n{text}") + terraformrc_path.write_text(text) + + +if __name__ == "__main__": + main() diff --git a/acceptance/selftest/out.hello.txt b/acceptance/selftest/basic/out.hello.txt similarity index 100% rename from acceptance/selftest/out.hello.txt rename to acceptance/selftest/basic/out.hello.txt diff --git a/acceptance/selftest/output.txt b/acceptance/selftest/basic/output.txt similarity index 89% rename from acceptance/selftest/output.txt rename to acceptance/selftest/basic/output.txt index 91aa8c33e..cadbdebb5 100644 --- a/acceptance/selftest/output.txt +++ b/acceptance/selftest/basic/output.txt @@ -18,13 +18,13 @@ Exit code: 7 === Capturing pwd >>> python3 -c import os; print(os.getcwd()) -$TMPDIR +[TMPDIR] === Capturing subdir >>> mkdir -p subdir/a/b/c >>> withdir subdir/a/b/c python3 -c import os; print(os.getcwd()) -$TMPDIR/subdir/a/b/c +[TMPDIR]/subdir/a/b/c === Custom output files - everything starting with out is captured and compared >>> echo HELLO @@ -35,5 +35,5 @@ CUSTOM_NUMBER_REGEX 123456 === Testing --version ->>> $CLI --version -Databricks CLI v$DEV_VERSION +>>> [CLI] --version +Databricks CLI v[DEV_VERSION] diff --git a/acceptance/selftest/script b/acceptance/selftest/basic/script similarity index 100% rename from acceptance/selftest/script rename to acceptance/selftest/basic/script diff --git a/acceptance/selftest/basic/test.toml b/acceptance/selftest/basic/test.toml new file mode 100644 index 000000000..762e28ceb --- /dev/null +++ b/acceptance/selftest/basic/test.toml @@ -0,0 +1,20 @@ +# Badness = "Brief description of what's wrong with the test output, if anything" + +#[GOOS] +# Disable on Windows +#windows = false + +# Disable on Mac +#mac = false + +# Disable on Linux +#linux = false + +[[Repls]] +Old = '\b[0-9]{5}\b' +New = "CUSTOM_NUMBER_REGEX" + +[[Repls]] +# Fix path with reverse slashes in the output for Windows. +Old = 'TMPDIR]\\subdir\\a\\b\\c' +New = 'TMPDIR]/subdir/a/b/c' diff --git a/acceptance/selftest/diff/out_dir_a/output.txt b/acceptance/selftest/diff/out_dir_a/output.txt new file mode 100644 index 000000000..303c1867b --- /dev/null +++ b/acceptance/selftest/diff/out_dir_a/output.txt @@ -0,0 +1,7 @@ +Hello! +{ + "id": "[USERID]", + "userName": "[USERNAME]" +} + +Footer \ No newline at end of file diff --git a/acceptance/selftest/diff/out_dir_b/output.txt b/acceptance/selftest/diff/out_dir_b/output.txt new file mode 100644 index 000000000..f4f01af13 --- /dev/null +++ b/acceptance/selftest/diff/out_dir_b/output.txt @@ -0,0 +1,7 @@ +Hello! +{ + "id": "[UUID]", + "userName": "[USERNAME]" +} + +Footer \ No newline at end of file diff --git a/acceptance/selftest/diff/output.txt b/acceptance/selftest/diff/output.txt new file mode 100644 index 000000000..aef99f1e3 --- /dev/null +++ b/acceptance/selftest/diff/output.txt @@ -0,0 +1,13 @@ + +>>> diff.py out_dir_a out_dir_b +Only in out_dir_a: only_in_a +Only in out_dir_b: only_in_b +--- out_dir_a/output.txt ++++ out_dir_b/output.txt +@@ -1,5 +1,5 @@ + Hello! + { +- "id": "[USERID]", ++ "id": "[UUID]", + "userName": "[USERNAME]" + } diff --git a/acceptance/selftest/diff/script b/acceptance/selftest/diff/script new file mode 100644 index 000000000..a7b8706e6 --- /dev/null +++ b/acceptance/selftest/diff/script @@ -0,0 +1,17 @@ +mkdir out_dir_a +mkdir out_dir_b + +touch out_dir_a/only_in_a +touch out_dir_b/only_in_b + +echo Hello! >> out_dir_a/output.txt +echo Hello! >> out_dir_b/output.txt + +curl -s $DATABRICKS_HOST/api/2.0/preview/scim/v2/Me >> out_dir_a/output.txt +printf "\n\nFooter" >> out_dir_a/output.txt +printf '{\n "id": "7d639bad-ac6d-4e6f-abd7-9522a86b0239",\n "userName": "[USERNAME]"\n}\n\nFooter' >> out_dir_b/output.txt + +# Unlike regular diff, diff.py will apply replacements first before doing the comparison +errcode trace diff.py out_dir_a out_dir_b + +rm out_dir_a/only_in_a out_dir_b/only_in_b diff --git a/acceptance/selftest/server/out.requests.txt b/acceptance/selftest/server/out.requests.txt new file mode 100644 index 000000000..34f4c4899 --- /dev/null +++ b/acceptance/selftest/server/out.requests.txt @@ -0,0 +1,12 @@ +{ + "method": "GET", + "path": "/api/2.0/preview/scim/v2/Me" +} +{ + "method": "GET", + "path": "/custom/endpoint" +} +{ + "method": "GET", + "path": "/api/2.0/workspace/get-status" +} diff --git a/acceptance/selftest/server/output.txt b/acceptance/selftest/server/output.txt new file mode 100644 index 000000000..7147f9c9b --- /dev/null +++ b/acceptance/selftest/server/output.txt @@ -0,0 +1,21 @@ + +>>> curl -s [DATABRICKS_URL]/api/2.0/preview/scim/v2/Me +{ + "id": "[USERID]", + "userName": "[USERNAME]" +} +>>> curl -sD - [DATABRICKS_URL]/custom/endpoint?query=param +HTTP/1.1 201 Created +X-Custom-Header: hello +Date: (redacted) +Content-Length: (redacted) +Content-Type: text/plain; charset=utf-8 + +custom +--- +response + +>>> errcode [CLI] workspace get-status /a/b/c +Error: Workspace path not found + +Exit code: 1 diff --git a/acceptance/selftest/server/script b/acceptance/selftest/server/script new file mode 100644 index 000000000..810ea64b6 --- /dev/null +++ b/acceptance/selftest/server/script @@ -0,0 +1,4 @@ +trace curl -s $DATABRICKS_HOST/api/2.0/preview/scim/v2/Me +trace curl -sD - $DATABRICKS_HOST/custom/endpoint?query=param + +trace errcode $CLI workspace get-status /a/b/c diff --git a/acceptance/selftest/server/test.toml b/acceptance/selftest/server/test.toml new file mode 100644 index 000000000..43ad1e85b --- /dev/null +++ b/acceptance/selftest/server/test.toml @@ -0,0 +1,24 @@ +LocalOnly = true +RecordRequests = true + +[[Server]] +Pattern = "GET /custom/endpoint" +Response.Body = '''should not see this response, latter response takes precedence''' + +[[Server]] +Pattern = "GET /custom/endpoint" +Response.Body = '''custom +--- +response +''' +Response.StatusCode = 201 +[Server.Response.Headers] +"X-Custom-Header" = ["hello"] + +[[Repls]] +Old = 'Date: .*' +New = 'Date: (redacted)' + +[[Repls]] +Old = 'Content-Length: [0-9]*' +New = 'Content-Length: (redacted)' diff --git a/acceptance/selftest/test.toml b/acceptance/selftest/test.toml index 9607ec5df..b76e712fb 100644 --- a/acceptance/selftest/test.toml +++ b/acceptance/selftest/test.toml @@ -1,20 +1 @@ -# Badness = "Brief description of what's wrong with the test output, if anything" - -#[GOOS] -# Disable on Windows -#windows = false - -# Disable on Mac -#mac = false - -# Disable on Linux -#linux = false - -[[Repls]] -Old = '\b[0-9]{5}\b' -New = "CUSTOM_NUMBER_REGEX" - -[[Repls]] -# Fix path with reverse slashes in the output for Windows. -Old = '\$TMPDIR\\subdir\\a\\b\\c' -New = '$$TMPDIR/subdir/a/b/c' +LocalOnly = true diff --git a/acceptance/server_test.go b/acceptance/server_test.go index 66de5dcbf..4fc3108d2 100644 --- a/acceptance/server_test.go +++ b/acceptance/server_test.go @@ -1,26 +1,27 @@ package acceptance_test import ( + "encoding/json" + "fmt" "net/http" - "testing" + + "github.com/databricks/databricks-sdk-go/service/catalog" + "github.com/databricks/databricks-sdk-go/service/iam" + + "github.com/databricks/databricks-sdk-go/service/compute" + "github.com/databricks/databricks-sdk-go/service/jobs" "github.com/databricks/cli/libs/testserver" - "github.com/databricks/databricks-sdk-go/service/catalog" - "github.com/databricks/databricks-sdk-go/service/compute" - "github.com/databricks/databricks-sdk-go/service/iam" "github.com/databricks/databricks-sdk-go/service/workspace" ) -func StartServer(t *testing.T) *testserver.Server { - server := testserver.New(t) - t.Cleanup(func() { - server.Close() - }) - return server +var testUser = iam.User{ + Id: "1000012345", + UserName: "tester@databricks.com", } func AddHandlers(server *testserver.Server) { - server.Handle("GET /api/2.0/policies/clusters/list", func(r *http.Request) (any, error) { + server.Handle("GET", "/api/2.0/policies/clusters/list", func(req testserver.Request) any { return compute.ListPoliciesResponse{ Policies: []compute.Policy{ { @@ -32,10 +33,10 @@ func AddHandlers(server *testserver.Server) { Name: "some-test-cluster-policy", }, }, - }, nil + } }) - server.Handle("GET /api/2.0/instance-pools/list", func(r *http.Request) (any, error) { + server.Handle("GET", "/api/2.0/instance-pools/list", func(req testserver.Request) any { return compute.ListInstancePools{ InstancePools: []compute.InstancePoolAndStats{ { @@ -43,10 +44,10 @@ func AddHandlers(server *testserver.Server) { InstancePoolId: "1234", }, }, - }, nil + } }) - server.Handle("GET /api/2.1/clusters/list", func(r *http.Request) (any, error) { + server.Handle("GET", "/api/2.1/clusters/list", func(req testserver.Request) any { return compute.ListClustersResponse{ Clusters: []compute.ClusterDetails{ { @@ -58,33 +59,62 @@ func AddHandlers(server *testserver.Server) { ClusterId: "9876", }, }, - }, nil + } }) - server.Handle("GET /api/2.0/preview/scim/v2/Me", func(r *http.Request) (any, error) { - return iam.User{ - UserName: "tester@databricks.com", - }, nil + server.Handle("GET", "/api/2.0/preview/scim/v2/Me", func(req testserver.Request) any { + return testserver.Response{ + Headers: map[string][]string{"X-Databricks-Org-Id": {"900800700600"}}, + Body: testUser, + } }) - server.Handle("GET /api/2.0/workspace/get-status", func(r *http.Request) (any, error) { - return workspace.ObjectInfo{ - ObjectId: 1001, - ObjectType: "DIRECTORY", - Path: "", - ResourceId: "1001", - }, nil + server.Handle("GET", "/api/2.0/workspace/get-status", func(req testserver.Request) any { + path := req.URL.Query().Get("path") + return req.Workspace.WorkspaceGetStatus(path) }) - server.Handle("GET /api/2.1/unity-catalog/current-metastore-assignment", func(r *http.Request) (any, error) { + server.Handle("POST", "/api/2.0/workspace/mkdirs", func(req testserver.Request) any { + var request workspace.Mkdirs + if err := json.Unmarshal(req.Body, &request); err != nil { + return testserver.Response{ + Body: fmt.Sprintf("internal error: %s", err), + StatusCode: http.StatusInternalServerError, + } + } + + req.Workspace.WorkspaceMkdirs(request) + return "" + }) + + server.Handle("GET", "/api/2.0/workspace/export", func(req testserver.Request) any { + path := req.URL.Query().Get("path") + return req.Workspace.WorkspaceExport(path) + }) + + server.Handle("POST", "/api/2.0/workspace/delete", func(req testserver.Request) any { + path := req.URL.Query().Get("path") + recursive := req.URL.Query().Get("recursive") == "true" + req.Workspace.WorkspaceDelete(path, recursive) + return "" + }) + + server.Handle("POST", "/api/2.0/workspace-files/import-file/{path:.*}", func(req testserver.Request) any { + path := req.Vars["path"] + req.Workspace.WorkspaceFilesImportFile(path, req.Body) + return "" + }) + + server.Handle("GET", "/api/2.1/unity-catalog/current-metastore-assignment", func(req testserver.Request) any { return catalog.MetastoreAssignment{ DefaultCatalogName: "main", - }, nil + } }) - server.Handle("GET /api/2.0/permissions/directories/1001", func(r *http.Request) (any, error) { + server.Handle("GET", "/api/2.0/permissions/directories/{objectId}", func(req testserver.Request) any { + objectId := req.Vars["objectId"] return workspace.WorkspaceObjectPermissions{ - ObjectId: "1001", + ObjectId: objectId, ObjectType: "DIRECTORY", AccessControlList: []workspace.WorkspaceObjectAccessControlResponse{ { @@ -96,10 +126,43 @@ func AddHandlers(server *testserver.Server) { }, }, }, - }, nil + } }) - server.Handle("POST /api/2.0/workspace/mkdirs", func(r *http.Request) (any, error) { - return "{}", nil + server.Handle("POST", "/api/2.1/jobs/create", func(req testserver.Request) any { + var request jobs.CreateJob + if err := json.Unmarshal(req.Body, &request); err != nil { + return testserver.Response{ + Body: fmt.Sprintf("internal error: %s", err), + StatusCode: 500, + } + } + + return req.Workspace.JobsCreate(request) + }) + + server.Handle("GET", "/api/2.1/jobs/get", func(req testserver.Request) any { + jobId := req.URL.Query().Get("job_id") + return req.Workspace.JobsGet(jobId) + }) + + server.Handle("GET", "/api/2.1/jobs/list", func(req testserver.Request) any { + return req.Workspace.JobsList() + }) + + server.Handle("GET", "/oidc/.well-known/oauth-authorization-server", func(_ testserver.Request) any { + return map[string]string{ + "authorization_endpoint": server.URL + "oidc/v1/authorize", + "token_endpoint": server.URL + "/oidc/v1/token", + } + }) + + server.Handle("POST", "/oidc/v1/token", func(_ testserver.Request) any { + return map[string]string{ + "access_token": "oauth-token", + "expires_in": "3600", + "scope": "all-apis", + "token_type": "Bearer", + } }) } diff --git a/acceptance/terraform/main.tf b/acceptance/terraform/main.tf new file mode 100644 index 000000000..674b41a3c --- /dev/null +++ b/acceptance/terraform/main.tf @@ -0,0 +1,25 @@ +terraform { + required_providers { + databricks = { + source = "databricks/databricks" + version = "1.65.1" + } + } + + required_version = "= 1.5.5" +} + +provider "databricks" { + # Optionally, specify the Databricks host and token + # host = "https://" + # token = "" +} + +data "databricks_current_user" "me" { + # Retrieves the current user's information +} + +output "username" { + description = "Username" + value = "${data.databricks_current_user.me.user_name}" +} diff --git a/acceptance/terraform/output.txt b/acceptance/terraform/output.txt new file mode 100644 index 000000000..851785827 --- /dev/null +++ b/acceptance/terraform/output.txt @@ -0,0 +1,51 @@ + +>>> [TERRAFORM] init -no-color -get=false + +Initializing the backend... + +Initializing provider plugins... +- Finding databricks/databricks versions matching "1.65.1"... +- Installing databricks/databricks v1.65.1... +- Installed databricks/databricks v1.65.1 (unauthenticated) + +Terraform has created a lock file .terraform.lock.hcl to record the provider +selections it made above. Include this file in your version control repository +so that Terraform can guarantee to make the same selections by default when +you run "terraform init" in the future. + + +Warning: Incomplete lock file information for providers + +Due to your customized provider installation methods, Terraform was forced to +calculate lock file checksums locally for the following providers: + - databricks/databricks + + +To calculate additional checksums for another platform, run: + terraform providers lock -platform=linux_amd64 +(where linux_amd64 is the platform to generate) + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. + +>>> [TERRAFORM] plan -no-color +data.databricks_current_user.me: Reading... +data.databricks_current_user.me: Read complete after (redacted) [id=[USERID]] + +Changes to Outputs: + + username = "[USERNAME]" + +You can apply this plan to save these new output values to the Terraform +state, without changing any real infrastructure. + +───────────────────────────────────────────────────────────────────────────── + +Note: You didn't use the -out option to save this plan, so Terraform can't +guarantee to take exactly these actions if you run "terraform apply" now. diff --git a/acceptance/terraform/script b/acceptance/terraform/script new file mode 100644 index 000000000..78e35049d --- /dev/null +++ b/acceptance/terraform/script @@ -0,0 +1,14 @@ +# Want to filter out these message: +# Mac: +# The current .terraform.lock.hcl file only includes checksums for +# darwin_arm64, so Terraform running on another platform will fail to install +# these providers. +# +# Linux: +# The current .terraform.lock.hcl file only includes checksums for linux_amd64, +# so Terraform running on another platform will fail to install these +# providers. + +trace $TERRAFORM init -no-color -get=false | grep -v 'includes checksums for' | grep -v 'so Terraform running on another' | grep -v 'providers\.' +trace $TERRAFORM plan -no-color +rm -fr .terraform.lock.hcl .terraform diff --git a/acceptance/terraform/test.toml b/acceptance/terraform/test.toml new file mode 100644 index 000000000..a6849e30f --- /dev/null +++ b/acceptance/terraform/test.toml @@ -0,0 +1,3 @@ +[[Repls]] +Old = 'Read complete after [^\s]+' +New = 'Read complete after (redacted)' diff --git a/acceptance/test.toml b/acceptance/test.toml deleted file mode 100644 index eee94d0ea..000000000 --- a/acceptance/test.toml +++ /dev/null @@ -1,2 +0,0 @@ -# If test directory nor any of its parents do not have test.toml then this file serves as fallback configuration. -# The configurations are not merged across parents; the closest one is used fully. diff --git a/acceptance/workspace/jobs/create-error/out.requests.txt b/acceptance/workspace/jobs/create-error/out.requests.txt new file mode 100644 index 000000000..30f104fd1 --- /dev/null +++ b/acceptance/workspace/jobs/create-error/out.requests.txt @@ -0,0 +1,7 @@ +{ + "method": "POST", + "path": "/api/2.1/jobs/create", + "body": { + "name": "abc" + } +} diff --git a/acceptance/workspace/jobs/create-error/output.txt b/acceptance/workspace/jobs/create-error/output.txt new file mode 100644 index 000000000..0e69eeb4b --- /dev/null +++ b/acceptance/workspace/jobs/create-error/output.txt @@ -0,0 +1,5 @@ + +>>> [CLI] jobs create --json {"name":"abc"} +Error: Invalid access token. + +Exit code: 1 diff --git a/acceptance/workspace/jobs/create-error/script b/acceptance/workspace/jobs/create-error/script new file mode 100644 index 000000000..9ff7b5b87 --- /dev/null +++ b/acceptance/workspace/jobs/create-error/script @@ -0,0 +1 @@ +trace $CLI jobs create --json '{"name":"abc"}' diff --git a/acceptance/workspace/jobs/create-error/test.toml b/acceptance/workspace/jobs/create-error/test.toml new file mode 100644 index 000000000..b45bf77e5 --- /dev/null +++ b/acceptance/workspace/jobs/create-error/test.toml @@ -0,0 +1,12 @@ +LocalOnly = true # request recording currently does not work with cloud environment +RecordRequests = true + +[[Server]] +Pattern = "POST /api/2.1/jobs/create" +Response.Body = ''' +{ + "error_code": "PERMISSION_DENIED", + "message": "Invalid access token." +} +''' +Response.StatusCode = 403 diff --git a/acceptance/workspace/jobs/create/out.requests.txt b/acceptance/workspace/jobs/create/out.requests.txt new file mode 100644 index 000000000..1d200a547 --- /dev/null +++ b/acceptance/workspace/jobs/create/out.requests.txt @@ -0,0 +1,15 @@ +{ + "headers": { + "Authorization": [ + "Bearer [DATABRICKS_TOKEN]" + ], + "User-Agent": [ + "cli/[DEV_VERSION] databricks-sdk-go/[SDK_VERSION] go/[GO_VERSION] os/[OS] cmd/jobs_create cmd-exec-id/[UUID] auth/pat" + ] + }, + "method": "POST", + "path": "/api/2.1/jobs/create", + "body": { + "name": "abc" + } +} diff --git a/acceptance/workspace/jobs/create/output.txt b/acceptance/workspace/jobs/create/output.txt new file mode 100644 index 000000000..50b823aa0 --- /dev/null +++ b/acceptance/workspace/jobs/create/output.txt @@ -0,0 +1,5 @@ + +>>> [CLI] jobs create --json {"name":"abc"} +{ + "job_id":1111 +} diff --git a/acceptance/workspace/jobs/create/script b/acceptance/workspace/jobs/create/script new file mode 100644 index 000000000..9ff7b5b87 --- /dev/null +++ b/acceptance/workspace/jobs/create/script @@ -0,0 +1 @@ +trace $CLI jobs create --json '{"name":"abc"}' diff --git a/acceptance/workspace/jobs/create/test.toml b/acceptance/workspace/jobs/create/test.toml new file mode 100644 index 000000000..1fd9b3cec --- /dev/null +++ b/acceptance/workspace/jobs/create/test.toml @@ -0,0 +1,27 @@ +LocalOnly = true # request recording currently does not work with cloud environment +RecordRequests = true +IncludeRequestHeaders = ["Authorization", "User-Agent"] + +[[Server]] +Pattern = "POST /api/2.1/jobs/create" +Response.Body = ''' +{ + "job_id": 1111 +} +''' + +[[Repls]] +Old = "(linux|darwin|windows)" +New = "[OS]" + +[[Repls]] +Old = " upstream/[A-Za-z0-9.-]+" +New = "" + +[[Repls]] +Old = " upstream-version/[A-Za-z0-9.-]+" +New = "" + +[[Repls]] +Old = " cicd/[A-Za-z0-9.-]+" +New = "" diff --git a/bundle/artifacts/upload.go b/bundle/artifacts/upload.go index c69939e8c..d4625d85d 100644 --- a/bundle/artifacts/upload.go +++ b/bundle/artifacts/upload.go @@ -29,7 +29,7 @@ func (m *cleanUp) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics // We intentionally ignore the error because it is not critical to the deployment err := client.Delete(ctx, ".", filer.DeleteRecursively) if err != nil { - log.Errorf(ctx, "failed to delete %s: %v", uploadPath, err) + log.Debugf(ctx, "failed to delete %s: %v", uploadPath, err) } err = client.Mkdir(ctx, ".") diff --git a/bundle/config/generate/job.go b/bundle/config/generate/job.go index 0cdcbf3ad..934eda2cf 100644 --- a/bundle/config/generate/job.go +++ b/bundle/config/generate/job.go @@ -13,7 +13,6 @@ var ( func ConvertJobToValue(job *jobs.Job) (dyn.Value, error) { value := make(map[string]dyn.Value) - if job.Settings.Tasks != nil { tasks := make([]dyn.Value, 0) for _, task := range job.Settings.Tasks { diff --git a/bundle/config/git.go b/bundle/config/git.go index f9f2f83e5..4b89bc2d2 100644 --- a/bundle/config/git.go +++ b/bundle/config/git.go @@ -8,9 +8,6 @@ type Git struct { // Path to bundle root relative to the git repository root. BundleRootPath string `json:"bundle_root_path,omitempty" bundle:"readonly"` - // Inferred is set to true if the Git details were inferred and weren't set explicitly - Inferred bool `json:"inferred,omitempty" bundle:"readonly"` - // The actual branch according to Git (may be different from the configured branch) ActualBranch string `json:"actual_branch,omitempty" bundle:"readonly"` } diff --git a/bundle/config/loader/process_root_includes.go b/bundle/config/loader/process_root_includes.go index 198095742..69e6dd4e4 100644 --- a/bundle/config/loader/process_root_includes.go +++ b/bundle/config/loader/process_root_includes.go @@ -71,11 +71,11 @@ func (m *processRootIncludes) Apply(ctx context.Context, b *bundle.Bundle) diag. continue } seen[rel] = true - if filepath.Ext(rel) != ".yaml" && filepath.Ext(rel) != ".yml" { + if filepath.Ext(rel) != ".yaml" && filepath.Ext(rel) != ".yml" && filepath.Ext(rel) != ".json" { diags = diags.Append(diag.Diagnostic{ Severity: diag.Error, - Summary: "Files in the 'include' configuration section must be YAML files.", - Detail: fmt.Sprintf("The file %s in the 'include' configuration section is not a YAML file, and only YAML files are supported. To include files to sync, specify them in the 'sync.include' configuration section instead.", rel), + Summary: "Files in the 'include' configuration section must be YAML or JSON files.", + Detail: fmt.Sprintf("The file %s in the 'include' configuration section is not a YAML or JSON file, and only such files are supported. To include files to sync, specify them in the 'sync.include' configuration section instead.", rel), Locations: b.Config.GetLocations(fmt.Sprintf("include[%d]", i)), }) continue diff --git a/bundle/config/mutator/apply_presets.go b/bundle/config/mutator/apply_presets.go index b402053e7..c8e7bf9e8 100644 --- a/bundle/config/mutator/apply_presets.go +++ b/bundle/config/mutator/apply_presets.go @@ -84,7 +84,7 @@ func (m *applyPresets) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnos // Pipelines presets: Prefix, PipelinesDevelopment for key, p := range r.Pipelines { - if p.PipelineSpec == nil { + if p.CreatePipeline == nil { diags = diags.Extend(diag.Errorf("pipeline %s is not defined", key)) continue } diff --git a/bundle/config/mutator/capture_schema_dependency.go b/bundle/config/mutator/capture_schema_dependency.go index 5025c9a0d..2e17a8175 100644 --- a/bundle/config/mutator/capture_schema_dependency.go +++ b/bundle/config/mutator/capture_schema_dependency.go @@ -56,7 +56,7 @@ func resolveVolume(v *resources.Volume, b *bundle.Bundle) { } func resolvePipelineSchema(p *resources.Pipeline, b *bundle.Bundle) { - if p == nil || p.PipelineSpec == nil { + if p == nil || p.CreatePipeline == nil { return } if p.Schema == "" { @@ -71,7 +71,7 @@ func resolvePipelineSchema(p *resources.Pipeline, b *bundle.Bundle) { } func resolvePipelineTarget(p *resources.Pipeline, b *bundle.Bundle) { - if p == nil || p.PipelineSpec == nil { + if p == nil || p.CreatePipeline == nil { return } if p.Target == "" { diff --git a/bundle/config/mutator/capture_schema_dependency_test.go b/bundle/config/mutator/capture_schema_dependency_test.go index 0a94e7748..16fa636ee 100644 --- a/bundle/config/mutator/capture_schema_dependency_test.go +++ b/bundle/config/mutator/capture_schema_dependency_test.go @@ -118,43 +118,43 @@ func TestCaptureSchemaDependencyForPipelinesWithTarget(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "pipeline1": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog1", Schema: "foobar", }, }, "pipeline2": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog2", Schema: "foobar", }, }, "pipeline3": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog1", Schema: "barfoo", }, }, "pipeline4": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalogX", Schema: "foobar", }, }, "pipeline5": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog1", Schema: "schemaX", }, }, "pipeline6": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "", Schema: "foobar", }, }, "pipeline7": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "", Schema: "", Name: "whatever", @@ -179,7 +179,7 @@ func TestCaptureSchemaDependencyForPipelinesWithTarget(t *testing.T) { assert.Equal(t, "", b.Config.Resources.Pipelines["pipeline7"].Schema) assert.Nil(t, b.Config.Resources.Pipelines["nilPipeline"]) - assert.Nil(t, b.Config.Resources.Pipelines["emptyPipeline"].PipelineSpec) + assert.Nil(t, b.Config.Resources.Pipelines["emptyPipeline"].CreatePipeline) for _, k := range []string{"pipeline1", "pipeline2", "pipeline3", "pipeline4", "pipeline5", "pipeline6", "pipeline7"} { assert.Empty(t, b.Config.Resources.Pipelines[k].Target) @@ -214,43 +214,43 @@ func TestCaptureSchemaDependencyForPipelinesWithSchema(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "pipeline1": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog1", Target: "foobar", }, }, "pipeline2": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog2", Target: "foobar", }, }, "pipeline3": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog1", Target: "barfoo", }, }, "pipeline4": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalogX", Target: "foobar", }, }, "pipeline5": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "catalog1", Target: "schemaX", }, }, "pipeline6": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "", Target: "foobar", }, }, "pipeline7": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Catalog: "", Target: "", Name: "whatever", diff --git a/bundle/config/mutator/expand_pipeline_glob_paths_test.go b/bundle/config/mutator/expand_pipeline_glob_paths_test.go index 7cf3c9f3e..c5b1ad39d 100644 --- a/bundle/config/mutator/expand_pipeline_glob_paths_test.go +++ b/bundle/config/mutator/expand_pipeline_glob_paths_test.go @@ -47,7 +47,7 @@ func TestExpandGlobPathsInPipelines(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { Notebook: &pipelines.NotebookLibrary{ diff --git a/bundle/config/mutator/initialize_urls_test.go b/bundle/config/mutator/initialize_urls_test.go index f07a7deb3..8c751079b 100644 --- a/bundle/config/mutator/initialize_urls_test.go +++ b/bundle/config/mutator/initialize_urls_test.go @@ -31,8 +31,8 @@ func TestInitializeURLs(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "pipeline1": { - ID: "3", - PipelineSpec: &pipelines.PipelineSpec{Name: "pipeline1"}, + ID: "3", + CreatePipeline: &pipelines.CreatePipeline{Name: "pipeline1"}, }, }, Experiments: map[string]*resources.MlflowExperiment{ diff --git a/bundle/config/mutator/load_git_details.go b/bundle/config/mutator/load_git_details.go index 3661c6bcd..dea948fcb 100644 --- a/bundle/config/mutator/load_git_details.go +++ b/bundle/config/mutator/load_git_details.go @@ -40,7 +40,6 @@ func (m *loadGitDetails) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagn b.Config.Bundle.Git.ActualBranch = info.CurrentBranch if b.Config.Bundle.Git.Branch == "" { // Only load branch if there's no user defined value - b.Config.Bundle.Git.Inferred = true b.Config.Bundle.Git.Branch = info.CurrentBranch } diff --git a/bundle/config/mutator/merge_pipeline_clusters_test.go b/bundle/config/mutator/merge_pipeline_clusters_test.go index f117d9399..97ec44eea 100644 --- a/bundle/config/mutator/merge_pipeline_clusters_test.go +++ b/bundle/config/mutator/merge_pipeline_clusters_test.go @@ -19,7 +19,7 @@ func TestMergePipelineClusters(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "foo": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Clusters: []pipelines.PipelineCluster{ { NodeTypeId: "i3.xlarge", @@ -68,7 +68,7 @@ func TestMergePipelineClustersCaseInsensitive(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "foo": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Clusters: []pipelines.PipelineCluster{ { Label: "default", diff --git a/bundle/config/mutator/process_target_mode.go b/bundle/config/mutator/process_target_mode.go index 0fe6bd54f..8ee59d809 100644 --- a/bundle/config/mutator/process_target_mode.go +++ b/bundle/config/mutator/process_target_mode.go @@ -73,7 +73,7 @@ func validateDevelopmentMode(b *bundle.Bundle) diag.Diagnostics { // this could be surprising since most users (and tools) expect triggers // to be paused in development. // (Note that there still is an exceptional case where users set the trigger - // status to UNPAUSED at the level of an individual object, whic hwas + // status to UNPAUSED at the level of an individual object, which was // historically allowed.) if p.TriggerPauseStatus == config.Unpaused { diags = diags.Append(diag.Diagnostic{ @@ -134,12 +134,7 @@ func findNonUserPath(b *bundle.Bundle) string { return "" } -func validateProductionMode(ctx context.Context, b *bundle.Bundle, isPrincipalUsed bool) diag.Diagnostics { - if b.Config.Bundle.Git.Inferred { - env := b.Config.Bundle.Target - log.Warnf(ctx, "target with 'mode: production' should specify an explicit 'targets.%s.git' configuration", env) - } - +func validateProductionMode(b *bundle.Bundle, isPrincipalUsed bool) diag.Diagnostics { r := b.Config.Resources for i := range r.Pipelines { if r.Pipelines[i].Development { @@ -149,8 +144,11 @@ func validateProductionMode(ctx context.Context, b *bundle.Bundle, isPrincipalUs // We need to verify that there is only a single deployment of the current target. // The best way to enforce this is to explicitly set root_path. - advice := fmt.Sprintf( - "set 'workspace.root_path' to make sure only one copy is deployed. A common practice is to use a username or principal name in this path, i.e. root_path: /Workspace/Users/%s/.bundle/${bundle.name}/${bundle.target}", + advice := "set 'workspace.root_path' to make sure only one copy is deployed" + adviceDetail := fmt.Sprintf( + "A common practice is to use a username or principal name in this path, i.e. use\n"+ + "\n"+ + " root_path: /Workspace/Users/%s/.bundle/${bundle.name}/${bundle.target}", b.Config.Workspace.CurrentUser.UserName, ) if !isExplicitRootSet(b) { @@ -159,9 +157,21 @@ func validateProductionMode(ctx context.Context, b *bundle.Bundle, isPrincipalUs // and neither is setting a principal. // We only show a warning for these cases since we didn't historically // report an error for them. - return diag.Recommendationf("target with 'mode: production' should %s", advice) + return diag.Diagnostics{ + { + Severity: diag.Recommendation, + Summary: "target with 'mode: production' should " + advice, + Detail: adviceDetail, + }, + } + } + return diag.Diagnostics{ + { + Severity: diag.Error, + Summary: "target with 'mode: production' must " + advice, + Detail: adviceDetail, + }, } - return diag.Errorf("target with 'mode: production' must %s", advice) } return nil } @@ -193,7 +203,7 @@ func (m *processTargetMode) Apply(ctx context.Context, b *bundle.Bundle) diag.Di return diags case config.Production: isPrincipal := iamutil.IsServicePrincipal(b.Config.Workspace.CurrentUser.User) - return validateProductionMode(ctx, b, isPrincipal) + return validateProductionMode(b, isPrincipal) case "": // No action default: diff --git a/bundle/config/mutator/process_target_mode_test.go b/bundle/config/mutator/process_target_mode_test.go index 723b01ee3..eb542c66e 100644 --- a/bundle/config/mutator/process_target_mode_test.go +++ b/bundle/config/mutator/process_target_mode_test.go @@ -88,7 +88,7 @@ func mockBundle(mode config.Mode) *bundle.Bundle { }, }, Pipelines: map[string]*resources.Pipeline{ - "pipeline1": {PipelineSpec: &pipelines.PipelineSpec{Name: "pipeline1", Continuous: true}}, + "pipeline1": {CreatePipeline: &pipelines.CreatePipeline{Name: "pipeline1", Continuous: true}}, }, Experiments: map[string]*resources.MlflowExperiment{ "experiment1": {Experiment: &ml.Experiment{Name: "/Users/lennart.kats@databricks.com/experiment1"}}, @@ -181,7 +181,7 @@ func TestProcessTargetModeDevelopment(t *testing.T) { // Pipeline 1 assert.Equal(t, "[dev lennart] pipeline1", b.Config.Resources.Pipelines["pipeline1"].Name) assert.False(t, b.Config.Resources.Pipelines["pipeline1"].Continuous) - assert.True(t, b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) + assert.True(t, b.Config.Resources.Pipelines["pipeline1"].CreatePipeline.Development) // Experiment 1 assert.Equal(t, "/Users/lennart.kats@databricks.com/[dev lennart] experiment1", b.Config.Resources.Experiments["experiment1"].Name) @@ -316,7 +316,7 @@ func TestProcessTargetModeDefault(t *testing.T) { require.NoError(t, diags.Error()) assert.Equal(t, "job1", b.Config.Resources.Jobs["job1"].Name) assert.Equal(t, "pipeline1", b.Config.Resources.Pipelines["pipeline1"].Name) - assert.False(t, b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) + assert.False(t, b.Config.Resources.Pipelines["pipeline1"].CreatePipeline.Development) assert.Equal(t, "servingendpoint1", b.Config.Resources.ModelServingEndpoints["servingendpoint1"].Name) assert.Equal(t, "registeredmodel1", b.Config.Resources.RegisteredModels["registeredmodel1"].Name) assert.Equal(t, "qualityMonitor1", b.Config.Resources.QualityMonitors["qualityMonitor1"].TableName) @@ -328,16 +328,16 @@ func TestProcessTargetModeDefault(t *testing.T) { func TestProcessTargetModeProduction(t *testing.T) { b := mockBundle(config.Production) - diags := validateProductionMode(context.Background(), b, false) - require.ErrorContains(t, diags.Error(), "target with 'mode: production' must set 'workspace.root_path' to make sure only one copy is deployed. A common practice is to use a username or principal name in this path, i.e. root_path: /Workspace/Users/lennart@company.com/.bundle/${bundle.name}/${bundle.target}") + diags := validateProductionMode(b, false) + require.ErrorContains(t, diags.Error(), "A common practice is to use a username or principal name in this path, i.e. use\n\n root_path: /Workspace/Users/lennart@company.com/.bundle/${bundle.name}/${bundle.target}") b.Config.Workspace.StatePath = "/Shared/.bundle/x/y/state" b.Config.Workspace.ArtifactPath = "/Shared/.bundle/x/y/artifacts" b.Config.Workspace.FilePath = "/Shared/.bundle/x/y/files" b.Config.Workspace.ResourcePath = "/Shared/.bundle/x/y/resources" - diags = validateProductionMode(context.Background(), b, false) - require.ErrorContains(t, diags.Error(), "target with 'mode: production' must set 'workspace.root_path' to make sure only one copy is deployed. A common practice is to use a username or principal name in this path, i.e. root_path: /Workspace/Users/lennart@company.com/.bundle/${bundle.name}/${bundle.target}") + diags = validateProductionMode(b, false) + require.ErrorContains(t, diags.Error(), "A common practice is to use a username or principal name in this path, i.e. use\n\n root_path: /Workspace/Users/lennart@company.com/.bundle/${bundle.name}/${bundle.target}") permissions := []resources.Permission{ { @@ -357,12 +357,12 @@ func TestProcessTargetModeProduction(t *testing.T) { b.Config.Resources.ModelServingEndpoints["servingendpoint1"].Permissions = permissions b.Config.Resources.Clusters["cluster1"].Permissions = permissions - diags = validateProductionMode(context.Background(), b, false) + diags = validateProductionMode(b, false) require.NoError(t, diags.Error()) assert.Equal(t, "job1", b.Config.Resources.Jobs["job1"].Name) assert.Equal(t, "pipeline1", b.Config.Resources.Pipelines["pipeline1"].Name) - assert.False(t, b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) + assert.False(t, b.Config.Resources.Pipelines["pipeline1"].CreatePipeline.Development) assert.Equal(t, "servingendpoint1", b.Config.Resources.ModelServingEndpoints["servingendpoint1"].Name) assert.Equal(t, "registeredmodel1", b.Config.Resources.RegisteredModels["registeredmodel1"].Name) assert.Equal(t, "qualityMonitor1", b.Config.Resources.QualityMonitors["qualityMonitor1"].TableName) @@ -375,11 +375,11 @@ func TestProcessTargetModeProductionOkForPrincipal(t *testing.T) { b := mockBundle(config.Production) // Our target has all kinds of problems when not using service principals ... - diags := validateProductionMode(context.Background(), b, false) + diags := validateProductionMode(b, false) require.Error(t, diags.Error()) // ... but we're much less strict when a principal is used - diags = validateProductionMode(context.Background(), b, true) + diags = validateProductionMode(b, true) require.NoError(t, diags.Error()) } @@ -387,7 +387,7 @@ func TestProcessTargetModeProductionOkWithRootPath(t *testing.T) { b := mockBundle(config.Production) // Our target has all kinds of problems when not using service principals ... - diags := validateProductionMode(context.Background(), b, false) + diags := validateProductionMode(b, false) require.Error(t, diags.Error()) // ... but we're okay if we specify a root path @@ -396,7 +396,7 @@ func TestProcessTargetModeProductionOkWithRootPath(t *testing.T) { RootPath: "some-root-path", }, } - diags = validateProductionMode(context.Background(), b, false) + diags = validateProductionMode(b, false) require.NoError(t, diags.Error()) } @@ -568,5 +568,5 @@ func TestPipelinesDevelopmentDisabled(t *testing.T) { diags := bundle.Apply(context.Background(), b, m) require.NoError(t, diags.Error()) - assert.False(t, b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) + assert.False(t, b.Config.Resources.Pipelines["pipeline1"].CreatePipeline.Development) } diff --git a/bundle/config/mutator/python/python_locations.go b/bundle/config/mutator/python/python_locations.go index 2fa86bea0..9cb65c302 100644 --- a/bundle/config/mutator/python/python_locations.go +++ b/bundle/config/mutator/python/python_locations.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + pathlib "path" "path/filepath" "github.com/databricks/cli/libs/dyn" @@ -99,7 +100,7 @@ func removeVirtualLocations(locations []dyn.Location) []dyn.Location { // parsePythonLocations parses locations.json from the Python mutator. // // locations file is newline-separated JSON objects with pythonLocationEntry structure. -func parsePythonLocations(input io.Reader) (*pythonLocations, error) { +func parsePythonLocations(bundleRoot string, input io.Reader) (*pythonLocations, error) { decoder := json.NewDecoder(input) locations := newPythonLocations() @@ -116,6 +117,12 @@ func parsePythonLocations(input io.Reader) (*pythonLocations, error) { return nil, fmt.Errorf("failed to parse python location: %s", err) } + // Output can contain both relative paths and absolute paths outside of bundle root. + // Mutator pipeline expects all path to be absolute at this point, so make all paths absolute. + if !pathlib.IsAbs(entry.File) { + entry.File = filepath.Join(bundleRoot, entry.File) + } + location := dyn.Location{ File: entry.File, Line: entry.Line, diff --git a/bundle/config/mutator/python/python_locations_test.go b/bundle/config/mutator/python/python_locations_test.go index 32afcc92b..2860af820 100644 --- a/bundle/config/mutator/python/python_locations_test.go +++ b/bundle/config/mutator/python/python_locations_test.go @@ -165,12 +165,28 @@ func TestLoadOutput(t *testing.T) { require.Equal(t, filepath.Join(bundleRoot, generatedFileName), notebookPath.Locations()[0].File) } -func TestParsePythonLocations(t *testing.T) { - expected := dyn.Location{File: "foo.py", Line: 1, Column: 2} +func TestParsePythonLocations_absolutePath(t *testing.T) { + // output can contain absolute path that is outside of the bundle root + expected := dyn.Location{File: "/Shared/foo.py", Line: 1, Column: 2} - input := `{"path": "foo", "file": "foo.py", "line": 1, "column": 2}` + input := `{"path": "foo", "file": "/Shared/foo.py", "line": 1, "column": 2}` reader := bytes.NewReader([]byte(input)) - locations, err := parsePythonLocations(reader) + locations, err := parsePythonLocations("/tmp/", reader) + + assert.NoError(t, err) + + assert.True(t, locations.keys["foo"].exists) + assert.Equal(t, expected, locations.keys["foo"].location) +} + +func TestParsePythonLocations_relativePath(t *testing.T) { + // output can contain relative paths, we expect all locations to be absolute + // at this stage of mutator pipeline + expected := dyn.Location{File: filepath.Clean("/tmp/my_project/foo.py"), Line: 1, Column: 2} + + input := `{"path": "foo", "file": "foo.py", "line": 1, "column": 2}` + reader := bytes.NewReader([]byte(input)) + locations, err := parsePythonLocations(filepath.Clean("/tmp/my_project"), reader) assert.NoError(t, err) diff --git a/bundle/config/mutator/python/python_mutator.go b/bundle/config/mutator/python/python_mutator.go index cd2e286e5..f75f111cf 100644 --- a/bundle/config/mutator/python/python_mutator.go +++ b/bundle/config/mutator/python/python_mutator.go @@ -331,7 +331,7 @@ func (m *pythonMutator) runPythonMutator(ctx context.Context, root dyn.Value, op return dyn.InvalidValue, diag.Errorf("failed to load diagnostics: %s", pythonDiagnosticsErr) } - locations, err := loadLocationsFile(locationsPath) + locations, err := loadLocationsFile(opts.bundleRootPath, locationsPath) if err != nil { return dyn.InvalidValue, diag.Errorf("failed to load locations: %s", err) } @@ -381,7 +381,7 @@ func writeInputFile(inputPath string, input dyn.Value) error { } // loadLocationsFile loads locations.json containing source locations for generated YAML. -func loadLocationsFile(locationsPath string) (*pythonLocations, error) { +func loadLocationsFile(bundleRoot, locationsPath string) (*pythonLocations, error) { locationsFile, err := os.Open(locationsPath) if errors.Is(err, fs.ErrNotExist) { return newPythonLocations(), nil @@ -391,7 +391,7 @@ func loadLocationsFile(locationsPath string) (*pythonLocations, error) { defer locationsFile.Close() - return parsePythonLocations(locationsFile) + return parsePythonLocations(bundleRoot, locationsFile) } func loadOutputFile(rootPath, outputPath string, locations *pythonLocations) (dyn.Value, diag.Diagnostics) { diff --git a/bundle/config/mutator/python/python_mutator_test.go b/bundle/config/mutator/python/python_mutator_test.go index 322fb79e8..9d957e797 100644 --- a/bundle/config/mutator/python/python_mutator_test.go +++ b/bundle/config/mutator/python/python_mutator_test.go @@ -54,6 +54,8 @@ func TestPythonMutator_Name_applyMutators(t *testing.T) { func TestPythonMutator_loadResources(t *testing.T) { withFakeVEnv(t, ".venv") + rootPath := filepath.Join(t.TempDir(), "my_project") + b := loadYaml("databricks.yml", ` experimental: python: @@ -64,6 +66,9 @@ func TestPythonMutator_loadResources(t *testing.T) { job0: name: job_0`) + // set rootPath so that we can make absolute paths in dyn.Location + b.BundleRootPath = rootPath + ctx := withProcessStub( t, []string{ @@ -120,7 +125,7 @@ func TestPythonMutator_loadResources(t *testing.T) { assert.Equal(t, []dyn.Location{ { - File: "src/examples/job1.py", + File: filepath.Join(rootPath, "src/examples/job1.py"), Line: 5, Column: 7, }, diff --git a/bundle/config/mutator/resolve_variable_references_test.go b/bundle/config/mutator/resolve_variable_references_test.go index 44f6c8dbb..30969dc49 100644 --- a/bundle/config/mutator/resolve_variable_references_test.go +++ b/bundle/config/mutator/resolve_variable_references_test.go @@ -20,7 +20,7 @@ func TestResolveVariableReferencesWithSourceLinkedDeployment(t *testing.T) { true, func(t *testing.T, b *bundle.Bundle) { // Variables that use workspace file path should have SyncRootValue during resolution phase - require.Equal(t, "sync/root/path", b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Configuration["source"]) + require.Equal(t, "sync/root/path", b.Config.Resources.Pipelines["pipeline1"].CreatePipeline.Configuration["source"]) // The file path itself should remain the same require.Equal(t, "file/path", b.Config.Workspace.FilePath) @@ -29,7 +29,7 @@ func TestResolveVariableReferencesWithSourceLinkedDeployment(t *testing.T) { { false, func(t *testing.T, b *bundle.Bundle) { - require.Equal(t, "file/path", b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Configuration["source"]) + require.Equal(t, "file/path", b.Config.Resources.Pipelines["pipeline1"].CreatePipeline.Configuration["source"]) require.Equal(t, "file/path", b.Config.Workspace.FilePath) }, }, @@ -48,7 +48,7 @@ func TestResolveVariableReferencesWithSourceLinkedDeployment(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "pipeline1": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Configuration: map[string]string{ "source": "${workspace.file_path}", }, diff --git a/bundle/config/mutator/translate_paths_test.go b/bundle/config/mutator/translate_paths_test.go index aa6488ab0..6cfe5718a 100644 --- a/bundle/config/mutator/translate_paths_test.go +++ b/bundle/config/mutator/translate_paths_test.go @@ -179,7 +179,7 @@ func TestTranslatePaths(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { Notebook: &pipelines.NotebookLibrary{ @@ -333,7 +333,7 @@ func TestTranslatePathsInSubdirectories(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { File: &pipelines.FileLibrary{ @@ -488,7 +488,7 @@ func TestPipelineNotebookDoesNotExistError(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { Notebook: &pipelines.NotebookLibrary{ @@ -532,7 +532,7 @@ func TestPipelineNotebookDoesNotExistErrorWithoutExtension(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { Notebook: &pipelines.NotebookLibrary{ @@ -572,7 +572,7 @@ func TestPipelineFileDoesNotExistError(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { File: &pipelines.FileLibrary{ @@ -677,7 +677,7 @@ func TestPipelineNotebookLibraryWithFileSourceError(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { Notebook: &pipelines.NotebookLibrary{ @@ -712,7 +712,7 @@ func TestPipelineFileLibraryWithNotebookSourceError(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { File: &pipelines.FileLibrary{ @@ -916,7 +916,7 @@ func TestTranslatePathsWithSourceLinkedDeployment(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Libraries: []pipelines.PipelineLibrary{ { Notebook: &pipelines.NotebookLibrary{ diff --git a/bundle/config/resources/pipeline.go b/bundle/config/resources/pipeline.go index 5127d07ba..57d9c4f19 100644 --- a/bundle/config/resources/pipeline.go +++ b/bundle/config/resources/pipeline.go @@ -16,7 +16,7 @@ type Pipeline struct { ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"` URL string `json:"url,omitempty" bundle:"internal"` - *pipelines.PipelineSpec + *pipelines.CreatePipeline } func (s *Pipeline) UnmarshalJSON(b []byte) error { @@ -59,5 +59,5 @@ func (s *Pipeline) GetURL() string { } func (s *Pipeline) IsNil() bool { - return s.PipelineSpec == nil + return s.CreatePipeline == nil } diff --git a/bundle/config/validate/single_node_cluster_test.go b/bundle/config/validate/single_node_cluster_test.go index c3ead8ef6..be93420c6 100644 --- a/bundle/config/validate/single_node_cluster_test.go +++ b/bundle/config/validate/single_node_cluster_test.go @@ -238,7 +238,7 @@ func TestValidateSingleNodeClusterFailForPipelineClusters(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "foo": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Clusters: []pipelines.PipelineCluster{ { SparkConf: tc.sparkConf, @@ -493,7 +493,7 @@ func TestValidateSingleNodeClusterPassPipelineClusters(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "foo": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Clusters: []pipelines.PipelineCluster{ { SparkConf: tc.sparkConf, diff --git a/bundle/deploy/metadata/annotate_pipelines.go b/bundle/deploy/metadata/annotate_pipelines.go index 990f48907..407aaea6e 100644 --- a/bundle/deploy/metadata/annotate_pipelines.go +++ b/bundle/deploy/metadata/annotate_pipelines.go @@ -20,11 +20,11 @@ func (m *annotatePipelines) Name() string { func (m *annotatePipelines) Apply(_ context.Context, b *bundle.Bundle) diag.Diagnostics { for _, pipeline := range b.Config.Resources.Pipelines { - if pipeline.PipelineSpec == nil { + if pipeline.CreatePipeline == nil { continue } - pipeline.PipelineSpec.Deployment = &pipelines.PipelineDeployment{ + pipeline.CreatePipeline.Deployment = &pipelines.PipelineDeployment{ Kind: pipelines.DeploymentKindBundle, MetadataFilePath: metadataFilePath(b), } diff --git a/bundle/deploy/metadata/annotate_pipelines_test.go b/bundle/deploy/metadata/annotate_pipelines_test.go index 448a022d0..606292724 100644 --- a/bundle/deploy/metadata/annotate_pipelines_test.go +++ b/bundle/deploy/metadata/annotate_pipelines_test.go @@ -21,12 +21,12 @@ func TestAnnotatePipelinesMutator(t *testing.T) { Resources: config.Resources{ Pipelines: map[string]*resources.Pipeline{ "my-pipeline-1": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Name: "My Pipeline One", }, }, "my-pipeline-2": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Name: "My Pipeline Two", }, }, @@ -43,14 +43,14 @@ func TestAnnotatePipelinesMutator(t *testing.T) { Kind: pipelines.DeploymentKindBundle, MetadataFilePath: "/a/b/c/metadata.json", }, - b.Config.Resources.Pipelines["my-pipeline-1"].PipelineSpec.Deployment) + b.Config.Resources.Pipelines["my-pipeline-1"].CreatePipeline.Deployment) assert.Equal(t, &pipelines.PipelineDeployment{ Kind: pipelines.DeploymentKindBundle, MetadataFilePath: "/a/b/c/metadata.json", }, - b.Config.Resources.Pipelines["my-pipeline-2"].PipelineSpec.Deployment) + b.Config.Resources.Pipelines["my-pipeline-2"].CreatePipeline.Deployment) } func TestAnnotatePipelinesMutatorPipelineWithoutASpec(t *testing.T) { diff --git a/bundle/deploy/metadata/compute_test.go b/bundle/deploy/metadata/compute_test.go index c6fa9bddb..64f899695 100644 --- a/bundle/deploy/metadata/compute_test.go +++ b/bundle/deploy/metadata/compute_test.go @@ -31,7 +31,6 @@ func TestComputeMetadataMutator(t *testing.T) { OriginURL: "www.host.com", Commit: "abcd", BundleRootPath: "a/b/c/d", - Inferred: true, }, }, Resources: config.Resources{ @@ -72,9 +71,6 @@ func TestComputeMetadataMutator(t *testing.T) { OriginURL: "www.host.com", Commit: "abcd", BundleRootPath: "a/b/c/d", - - // Test that this field doesn't carry over into the metadata. - Inferred: false, }, }, Resources: metadata.Resources{ diff --git a/bundle/deploy/terraform/convert_test.go b/bundle/deploy/terraform/convert_test.go index afc1fb22a..53d861b32 100644 --- a/bundle/deploy/terraform/convert_test.go +++ b/bundle/deploy/terraform/convert_test.go @@ -203,7 +203,7 @@ func TestBundleToTerraformForEachTaskLibraries(t *testing.T) { func TestBundleToTerraformPipeline(t *testing.T) { src := resources.Pipeline{ - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Name: "my pipeline", Libraries: []pipelines.PipelineLibrary{ { @@ -759,7 +759,7 @@ func TestTerraformToBundleEmptyRemoteResources(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "test_pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Name: "test_pipeline", }, }, @@ -898,12 +898,12 @@ func TestTerraformToBundleModifiedResources(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "test_pipeline": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Name: "test_pipeline", }, }, "test_pipeline_new": { - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Name: "test_pipeline_new", }, }, diff --git a/bundle/deploy/terraform/init.go b/bundle/deploy/terraform/init.go index 5957611a4..a204222d0 100644 --- a/bundle/deploy/terraform/init.go +++ b/bundle/deploy/terraform/init.go @@ -101,9 +101,9 @@ var envCopy = []string{ // same auxiliary programs (e.g. `az`, or `gcloud`) as the CLI. "PATH", - // Include $AZURE_CONFIG_FILE in set of environment variables to pass along. + // Include $AZURE_CONFIG_DIR in set of environment variables to pass along. // This is set in Azure DevOps by the AzureCLI@2 task. - "AZURE_CONFIG_FILE", + "AZURE_CONFIG_DIR", // Include $TF_CLI_CONFIG_FILE to override terraform provider in development. // See: https://developer.hashicorp.com/terraform/cli/config/config-file#explicit-installation-method-configuration diff --git a/bundle/deploy/terraform/init_test.go b/bundle/deploy/terraform/init_test.go index c7a4ffe4a..4645ed007 100644 --- a/bundle/deploy/terraform/init_test.go +++ b/bundle/deploy/terraform/init_test.go @@ -292,7 +292,7 @@ func TestInheritEnvVars(t *testing.T) { t.Setenv("HOME", "/home/testuser") t.Setenv("PATH", "/foo:/bar") t.Setenv("TF_CLI_CONFIG_FILE", "/tmp/config.tfrc") - t.Setenv("AZURE_CONFIG_FILE", "/tmp/foo/bar") + t.Setenv("AZURE_CONFIG_DIR", "/tmp/foo/bar") ctx := context.Background() env := map[string]string{} @@ -301,7 +301,7 @@ func TestInheritEnvVars(t *testing.T) { assert.Equal(t, "/home/testuser", env["HOME"]) assert.Equal(t, "/foo:/bar", env["PATH"]) assert.Equal(t, "/tmp/config.tfrc", env["TF_CLI_CONFIG_FILE"]) - assert.Equal(t, "/tmp/foo/bar", env["AZURE_CONFIG_FILE"]) + assert.Equal(t, "/tmp/foo/bar", env["AZURE_CONFIG_DIR"]) } } diff --git a/bundle/deploy/terraform/tfdyn/convert_pipeline.go b/bundle/deploy/terraform/tfdyn/convert_pipeline.go index ea0c94d66..53a986864 100644 --- a/bundle/deploy/terraform/tfdyn/convert_pipeline.go +++ b/bundle/deploy/terraform/tfdyn/convert_pipeline.go @@ -21,6 +21,11 @@ func convertPipelineResource(ctx context.Context, vin dyn.Value) (dyn.Value, err return dyn.InvalidValue, err } + vout, err = dyn.DropKeys(vout, []string{"allow_duplicate_names", "dry_run"}) + if err != nil { + return dyn.InvalidValue, err + } + // Normalize the output value to the target schema. vout, diags := convert.Normalize(schema.ResourcePipeline{}, vout) for _, diag := range diags { diff --git a/bundle/deploy/terraform/tfdyn/convert_pipeline_test.go b/bundle/deploy/terraform/tfdyn/convert_pipeline_test.go index 0239bad18..63d023c43 100644 --- a/bundle/deploy/terraform/tfdyn/convert_pipeline_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_pipeline_test.go @@ -15,8 +15,17 @@ import ( func TestConvertPipeline(t *testing.T) { src := resources.Pipeline{ - PipelineSpec: &pipelines.PipelineSpec{ + CreatePipeline: &pipelines.CreatePipeline{ Name: "my pipeline", + // This fields is not part of TF schema yet, but once we upgrade to TF version that supports it, this test will fail because run_as + // will be exposed which is expected and test will need to be updated. + RunAs: &pipelines.RunAs{ + UserName: "foo@bar.com", + }, + // We expect AllowDuplicateNames and DryRun to be ignored and not passed to the TF output. + // This is not supported by TF now, so we don't want to expose it. + AllowDuplicateNames: true, + DryRun: true, Libraries: []pipelines.PipelineLibrary{ { Notebook: &pipelines.NotebookLibrary{ @@ -113,6 +122,9 @@ func TestConvertPipeline(t *testing.T) { "num_workers": int64(1), }, }, + "run_as": map[string]any{ + "user_name": "foo@bar.com", + }, }, out.Pipeline["my_pipeline"]) // Assert equality on the permissions diff --git a/bundle/docsgen/main.go b/bundle/docsgen/main.go index ad737feea..84bf4779f 100644 --- a/bundle/docsgen/main.go +++ b/bundle/docsgen/main.go @@ -130,6 +130,6 @@ func assignAnnotation(s *jsonschema.Schema, a annotation.Descriptor) { s.MarkdownDescription = a.MarkdownDescription } if a.MarkdownExamples != "" { - s.Examples = []any{a.MarkdownExamples} + s.Examples = []string{a.MarkdownExamples} } } diff --git a/bundle/docsgen/markdown.go b/bundle/docsgen/markdown.go index a1fd54f94..f5e4ed05f 100644 --- a/bundle/docsgen/markdown.go +++ b/bundle/docsgen/markdown.go @@ -102,6 +102,8 @@ func formatDescription(a attributeNode) string { return s } +// Docs framework does not allow special characters in anchor links and strip them out by default +// We need to clean them up to make sure the links pass the validation func cleanAnchor(s string) string { s = strings.ReplaceAll(s, "<", "") s = strings.ReplaceAll(s, ">", "") diff --git a/bundle/docsgen/markdown_test.go b/bundle/docsgen/markdown_test.go new file mode 100644 index 000000000..d4f32230e --- /dev/null +++ b/bundle/docsgen/markdown_test.go @@ -0,0 +1,42 @@ +package main + +import ( + "path/filepath" + "testing" + + "github.com/databricks/cli/internal/testutil" + "github.com/stretchr/testify/require" +) + +func TestBuildMarkdownAnchors(t *testing.T) { + nodes := []rootNode{ + { + Title: "some_field", + TopLevel: true, + Type: "Map", + Description: "This is a description", + Attributes: []attributeNode{ + { + Title: "my_attribute", + Type: "Map", + Description: "Desc with link", + Link: "some_field..my_attribute", + }, + }, + }, + { + Title: "some_field..my_attribute", + TopLevel: false, + Type: "Boolean", + Description: "Another description", + }, + } + tmpDir := t.TempDir() + path := filepath.Join(tmpDir, "output.md") + + err := buildMarkdown(nodes, path, "Header") + require.NoError(t, err) + + expected := testutil.ReadFile(t, "testdata/anchors.md") + testutil.AssertFileContents(t, path, expected) +} diff --git a/bundle/docsgen/nodes.go b/bundle/docsgen/nodes.go index 7cc92a207..6645e9ccc 100644 --- a/bundle/docsgen/nodes.go +++ b/bundle/docsgen/nodes.go @@ -220,9 +220,9 @@ func isCycleField(field string) bool { } func getExample(v *jsonschema.Schema) string { - examples := v.Examples + examples := getExamples(v.Examples) if len(examples) == 0 { return "" } - return examples[0].(string) + return examples[0] } diff --git a/bundle/docsgen/output/reference.md b/bundle/docsgen/output/reference.md index 629252d25..ff12805d7 100644 --- a/bundle/docsgen/output/reference.md +++ b/bundle/docsgen/output/reference.md @@ -1,62 +1,63 @@ --- -description: 'Configuration reference for databricks.yml' +description: Configuration reference for databricks.yml --- # Configuration reference -This article provides reference for keys supported by Databricks Asset Bundles configuration (YAML). See [_](/dev-tools/bundles/index.md). +This article provides reference for keys supported by Databricks Asset Bundles configuration (YAML). See [\_](/dev-tools/bundles/index.md). -For complete bundle examples, see [_](/dev-tools/bundles/resource-examples.md) and the [bundle-examples GitHub repository](https://github.com/databricks/bundle-examples). +For complete bundle examples, see [\_](/dev-tools/bundles/resource-examples.md) and the [bundle-examples GitHub repository](https://github.com/databricks/bundle-examples). - ## artifacts - -**`Type: Map`** - -Defines the attributes to build artifacts, where each key is the name of the artifact, and the value is a Map that defines the artifact build settings. For information about the `artifacts` mapping, see [_](/dev-tools/bundles/settings.md#artifacts). -Artifact settings defined in the top level of the bundle configuration can be overridden in the `targets` mapping. See [_](/dev-tools/bundles/artifact-overrides.md). - +**`Type: Map`** + +Defines the attributes to build artifacts, where each key is the name of the artifact, and the value is a Map that defines the artifact build settings. For information about the `artifacts` mapping, see [\_](/dev-tools/bundles/settings.md#artifacts). + +Artifact settings defined in the top level of the bundle configuration can be overridden in the `targets` mapping. See [\_](/dev-tools/bundles/artifact-overrides.md). + ```yaml artifacts: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `build` - String - An optional set of non-default build commands to run locally before deployment. - + - - `executable` - String - The executable type. Valid values are `bash`, `sh`, and `cmd`. - + +<<<<<<< HEAD + - - `files` - - Sequence - - The source files for the artifact. See [_](#artifactsnamefiles). - + - Sequence + - # The source files for the artifact. See [\_](#artifactsnamefiles). + * - `files` - Sequence - The source files for the artifact. See [\_](#artifactsnamefiles). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `path` - String - The location where the built artifact will be saved. - + - - `type` - String - Required. The type of the artifact. Valid values are `whl`. - + ::: - - + **Example** - + ```yaml artifacts: default: @@ -64,287 +65,284 @@ artifacts: build: poetry build path: . ``` - + ### artifacts.\.files - + **`Type: Sequence`** - + The source files for the artifact. - - - + :::list-table - + - - Key - Type - Description - + - - `source` - String - Required. The path of the files used to build the artifact. - + ::: - - + ## bundle - + **`Type: Map`** - + The bundle attributes when deploying to this target, - - - + :::list-table - + - - Key - Type - Description - + - - `cluster_id` - String - - The ID of a cluster to use to run the bundle. See [_](/dev-tools/bundles/settings.md#cluster_id). - + - The ID of a cluster to use to run the bundle. See [\_](/dev-tools/bundles/settings.md#cluster_id). + - - `compute_id` - String - - - + - + - - `databricks_cli_version` - String - - The Databricks CLI version to use for the bundle. See [_](/dev-tools/bundles/settings.md#databricks_cli_version). - + - The Databricks CLI version to use for the bundle. See [\_](/dev-tools/bundles/settings.md#databricks_cli_version). + +<<<<<<< HEAD + - - `deployment` - Map - - The definition of the bundle deployment. For supported attributes see [_](/dev-tools/bundles/deployment-modes.md). See [_](#bundledeployment). - + - The definition of the bundle deployment. For supported attributes see [\_](/dev-tools/bundles/deployment-modes.md). See [\_](#bundledeployment). + - - `git` - - Map - - The Git version control details that are associated with your bundle. For supported attributes see [_](/dev-tools/bundles/settings.md#git). See [_](#bundlegit). - + + - Map + - # The Git version control details that are associated with your bundle. For supported attributes see [\_](/dev-tools/bundles/settings.md#git). See [\_](#bundlegit). + + * - `deployment` + - Map + - The definition of the bundle deployment. For supported attributes see [\_](/dev-tools/bundles/deployment-modes.md). See [\_](#bundledeployment). + + * - `git` - Map - The Git version control details that are associated with your bundle. For supported attributes see [\_](/dev-tools/bundles/settings.md#git). See [\_](#bundlegit). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `name` - String - The name of the bundle. - + - - `uuid` - String - Reserved. A Universally Unique Identifier (UUID) for the bundle that uniquely identifies the bundle in internal Databricks systems. This is generated when a bundle project is initialized using a Databricks template (using the `databricks bundle init` command). - + ::: - - + ### bundle.deployment - + **`Type: Map`** - -The definition of the bundle deployment. For supported attributes see [_](/dev-tools/bundles/deployment-modes.md). - - - + +The definition of the bundle deployment. For supported attributes see [\_](/dev-tools/bundles/deployment-modes.md). + :::list-table - + - - Key - Type - Description - + - - `fail_on_active_runs` - Boolean - Whether to fail on active runs. If this is set to true a deployment that is running can be interrupted. - + +<<<<<<< HEAD + - - `lock` - Map - - The deployment lock attributes. See [_](#bundledeploymentlock). - -::: - - + - The deployment lock attributes. See [\_](#bundledeploymentlock). + +# ::: + +- - `lock` - Map - The deployment lock attributes. See [\_](#bundledeploymentlock). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + ### bundle.deployment.lock - + **`Type: Map`** - + The deployment lock attributes. - - - + :::list-table - + - - Key - Type - Description - + - - `enabled` - Boolean - Whether this lock is enabled. - + - - `force` - Boolean - Whether to force this lock if it is enabled. - + ::: - - + ### bundle.git - + **`Type: Map`** - -The Git version control details that are associated with your bundle. For supported attributes see [_](/dev-tools/bundles/settings.md#git). - - - + +The Git version control details that are associated with your bundle. For supported attributes see [\_](/dev-tools/bundles/settings.md#git). + :::list-table - + - - Key - Type - Description - + - - `branch` - String - - The Git branch name. See [_](/dev-tools/bundles/settings.md#git). - + - The Git branch name. See [\_](/dev-tools/bundles/settings.md#git). + - - `origin_url` - String - - The origin URL of the repository. See [_](/dev-tools/bundles/settings.md#git). - + - The origin URL of the repository. See [\_](/dev-tools/bundles/settings.md#git). + ::: - - + ## experimental - + **`Type: Map`** - + Defines attributes for experimental features. - - - + :::list-table - + - - Key - Type - Description - + +<<<<<<< HEAD + - - `pydabs` - Map - - The PyDABs configuration. See [_](#experimentalpydabs). - + - The PyDABs configuration. See [\_](#experimentalpydabs). + - - `python` - - Map - - Configures loading of Python code defined with 'databricks-bundles' package. See [_](#experimentalpython). - + + - Map + - # Configures loading of Python code defined with 'databricks-bundles' package. See [\_](#experimentalpython). + + * - `pydabs` + - Map + - The PyDABs configuration. See [\_](#experimentalpydabs). + + * - `python` - Map - Configures loading of Python code defined with 'databricks-bundles' package. See [\_](#experimentalpython). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `python_wheel_wrapper` - Boolean - Whether to use a Python wheel wrapper. - + - - `scripts` - Map - The commands to run. - + - - `use_legacy_run_as` - Boolean - Whether to use the legacy run_as behavior. - + ::: - - + ### experimental.pydabs - + **`Type: Map`** - + The PyDABs configuration. - - - + :::list-table - + - - Key - Type - Description - + - - `enabled` - Boolean - Whether or not PyDABs (Private Preview) is enabled - + - - `import` - Sequence - The PyDABs project to import to discover resources, resource generator and mutators - + - - `venv_path` - String - The Python virtual environment path - + ::: - - + ### experimental.python - + **`Type: Map`** - + Configures loading of Python code defined with 'databricks-bundles' package. - - - + :::list-table - + - - Key - Type - Description - + - - `mutators` - Sequence - - Mutators contains a list of fully qualified function paths to mutator functions. Example: ["my_project.mutators:add_default_cluster"] - + - Mutators contains a list of fully qualified function paths to mutator functions. Example: ["my_project.mutators:add_default_cluster"] + - - `resources` - Sequence - - Resources contains a list of fully qualified function paths to load resources defined in Python code. Example: ["my_project.resources:load_resources"] - + - Resources contains a list of fully qualified function paths to load resources defined in Python code. Example: ["my_project.resources:load_resources"] + - - `venv_path` - String - - VEnvPath is path to the virtual environment. If enabled, Python code will execute within this environment. If disabled, it defaults to using the Python interpreter available in the current shell. - + - VEnvPath is path to the virtual environment. If enabled, Python code will execute within this environment. If disabled, it defaults to using the Python interpreter available in the current shell. + ::: - - + ## include - + **`Type: Sequence`** - -Specifies a list of path globs that contain configuration files to include within the bundle. See [_](/dev-tools/bundles/settings.md#include) - - + +Specifies a list of path globs that contain configuration files to include within the bundle. See [\_](/dev-tools/bundles/settings.md#include) + ## permissions - + **`Type: Sequence`** - + A Sequence that defines the permissions to apply to experiments, jobs, pipelines, and models defined in the bundle, where each item in the sequence is a permission for a specific entity. -See [_](/dev-tools/bundles/settings.md#permissions) and [_](/dev-tools/bundles/permissions.md). - - - +See [\_](/dev-tools/bundles/settings.md#permissions) and [\_](/dev-tools/bundles/permissions.md). + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + **Example** - + ```yaml permissions: - level: CAN_VIEW @@ -354,53 +352,50 @@ permissions: - level: CAN_RUN service_principal_name: 123456-abcdef ``` - + ## presets - + **`Type: Map`** - -Defines bundle deployment presets. See [_](/dev-tools/bundles/deployment-modes.md#presets). - - - + +Defines bundle deployment presets. See [\_](/dev-tools/bundles/deployment-modes.md#presets). + :::list-table - + - - Key - Type - Description - + - - `jobs_max_concurrent_runs` - Integer - The maximum concurrent runs for a job. - + - - `name_prefix` - String - The prefix for job runs of the bundle. - + - - `pipelines_development` - Boolean - Whether pipeline deployments should be locked in development mode. - + - - `source_linked_deployment` - Boolean - Whether to link the deployment to the bundle source. - + - - `tags` - Map - The tags for the bundle deployment. - + - - `trigger_pause_status` - String - A pause status to apply to all job triggers and schedules. Valid values are PAUSED or UNPAUSED. - + ::: - - + ## resources - + **`Type: Map`** - -A Map that defines the resources for the bundle, where each key is the name of the resource, and the value is a Map that defines the resource. For more information about Databricks Asset Bundles supported resources, and resource definition reference, see [_](/dev-tools/bundles/resources.md). + +A Map that defines the resources for the bundle, where each key is the name of the resource, and the value is a Map that defines the resource. For more information about Databricks Asset Bundles supported resources, and resource definition reference, see [\_](/dev-tools/bundles/resources.md). ```yaml resources: @@ -408,963 +403,971 @@ resources: : : ``` - - - + :::list-table - + - - Key - Type - Description - + - - `apps` - Map - - - + - + - - `clusters` - Map - - The cluster definitions for the bundle, where each key is the name of a cluster. See [_](/dev-tools/bundles/resources.md#clusters) - + - The cluster definitions for the bundle, where each key is the name of a cluster. See [\_](/dev-tools/bundles/resources.md#clusters) + - - `dashboards` - Map - - The dashboard definitions for the bundle, where each key is the name of the dashboard. See [_](/dev-tools/bundles/resources.md#dashboards) - + - The dashboard definitions for the bundle, where each key is the name of the dashboard. See [\_](/dev-tools/bundles/resources.md#dashboards) + - - `experiments` - Map - - The experiment definitions for the bundle, where each key is the name of the experiment. See [_](/dev-tools/bundles/resources.md#experiments) - + - The experiment definitions for the bundle, where each key is the name of the experiment. See [\_](/dev-tools/bundles/resources.md#experiments) + - - `jobs` - Map - - The job definitions for the bundle, where each key is the name of the job. See [_](/dev-tools/bundles/resources.md#jobs) - + - The job definitions for the bundle, where each key is the name of the job. See [\_](/dev-tools/bundles/resources.md#jobs) + - - `model_serving_endpoints` - Map - - The model serving endpoint definitions for the bundle, where each key is the name of the model serving endpoint. See [_](/dev-tools/bundles/resources.md#model_serving_endpoints) - + - The model serving endpoint definitions for the bundle, where each key is the name of the model serving endpoint. See [\_](/dev-tools/bundles/resources.md#model_serving_endpoints) + - - `models` - Map - - The model definitions for the bundle, where each key is the name of the model. See [_](/dev-tools/bundles/resources.md#models) - + - The model definitions for the bundle, where each key is the name of the model. See [\_](/dev-tools/bundles/resources.md#models) + - - `pipelines` - Map - - The pipeline definitions for the bundle, where each key is the name of the pipeline. See [_](/dev-tools/bundles/resources.md#pipelines) - + - The pipeline definitions for the bundle, where each key is the name of the pipeline. See [\_](/dev-tools/bundles/resources.md#pipelines) + - - `quality_monitors` - Map - - The quality monitor definitions for the bundle, where each key is the name of the quality monitor. See [_](/dev-tools/bundles/resources.md#quality_monitors) - + - The quality monitor definitions for the bundle, where each key is the name of the quality monitor. See [\_](/dev-tools/bundles/resources.md#quality_monitors) + - - `registered_models` - Map - - The registered model definitions for the bundle, where each key is the name of the Unity Catalog registered model. See [_](/dev-tools/bundles/resources.md#registered_models) - + - The registered model definitions for the bundle, where each key is the name of the Unity Catalog registered model. See [\_](/dev-tools/bundles/resources.md#registered_models) + - - `schemas` - Map - - The schema definitions for the bundle, where each key is the name of the schema. See [_](/dev-tools/bundles/resources.md#schemas) - + - The schema definitions for the bundle, where each key is the name of the schema. See [\_](/dev-tools/bundles/resources.md#schemas) + - - `volumes` - Map - - The volume definitions for the bundle, where each key is the name of the volume. See [_](/dev-tools/bundles/resources.md#volumes) - + - The volume definitions for the bundle, where each key is the name of the volume. See [\_](/dev-tools/bundles/resources.md#volumes) + ::: - - + ## run_as - + **`Type: Map`** - -The identity to use when running Databricks Asset Bundles workflows. See [_](/dev-tools/bundles/run-as.md). - - - + +The identity to use when running Databricks Asset Bundles workflows. See [\_](/dev-tools/bundles/run-as.md). + :::list-table - + - - Key - Type - Description - + - - `service_principal_name` - String - The application ID of an active service principal. Setting this field requires the `servicePrincipal/user` role. - + - - `user_name` - String - The email of an active workspace user. Non-admin users can only set this field to their own email. - + ::: - - + ## sync - + **`Type: Map`** - -The files and file paths to include or exclude in the bundle. See [_](/dev-tools/bundles/settings.md#sync). - - - + +The files and file paths to include or exclude in the bundle. See [\_](/dev-tools/bundles/settings.md#sync). + :::list-table - + - - Key - Type - Description - + - - `exclude` - Sequence - A list of files or folders to exclude from the bundle. - + - - `include` - Sequence - A list of files or folders to include in the bundle. - + - - `paths` - Sequence - The local folder paths, which can be outside the bundle root, to synchronize to the workspace when the bundle is deployed. - + ::: - - + ## targets - + **`Type: Map`** - -Defines deployment targets for the bundle. See [_](/dev-tools/bundles/settings.md#targets) - + +Defines deployment targets for the bundle. See [\_](/dev-tools/bundles/settings.md#targets) + ```yaml targets: : : ``` - - + :::list-table - + - - Key - Type - Description - + +<<<<<<< HEAD + - - `artifacts` - Map - - The artifacts to include in the target deployment. See [_](#targetsnameartifacts). - + - The artifacts to include in the target deployment. See [\_](#targetsnameartifacts). + - - `bundle` - - Map - - The bundle attributes when deploying to this target. See [_](#targetsnamebundle). - + + - Map + - # The bundle attributes when deploying to this target. See [\_](#targetsnamebundle). + + * - `artifacts` + - Map + - The artifacts to include in the target deployment. See [\_](#targetsnameartifacts). + + * - `bundle` - Map - The bundle attributes when deploying to this target. See [\_](#targetsnamebundle). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `cluster_id` - String - The ID of the cluster to use for this target. - + - - `compute_id` - String - Deprecated. The ID of the compute to use for this target. - + - - `default` - Boolean - Whether this target is the default target. - + +<<<<<<< HEAD + - - `git` - - Map - - The Git version control settings for the target. See [_](#targetsnamegit). - + - Map + - # The Git version control settings for the target. See [\_](#targetsnamegit). + * - `git` - Map - The Git version control settings for the target. See [\_](#targetsnamegit). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `mode` - String - - The deployment mode for the target. Valid values are `development` or `production`. See [_](/dev-tools/bundles/deployment-modes.md). - + - The deployment mode for the target. Valid values are `development` or `production`. See [\_](/dev-tools/bundles/deployment-modes.md). + +<<<<<<< HEAD + - - `permissions` - Sequence - - The permissions for deploying and running the bundle in the target. See [_](#targetsnamepermissions). - + - The permissions for deploying and running the bundle in the target. See [\_](#targetsnamepermissions). + - - `presets` - Map - - The deployment presets for the target. See [_](#targetsnamepresets). - + - The deployment presets for the target. See [\_](#targetsnamepresets). + - - `resources` - Map - - The resource definitions for the target. See [_](#targetsnameresources). - + - The resource definitions for the target. See [\_](#targetsnameresources). + - - `run_as` - Map - - The identity to use to run the bundle, see [_](/dev-tools/bundles/run-as.md). See [_](#targetsnamerun_as). - + - The identity to use to run the bundle, see [\_](/dev-tools/bundles/run-as.md). See [\_](#targetsnamerun_as). + - - `sync` - Map - - The local paths to sync to the target workspace when a bundle is run or deployed. See [_](#targetsnamesync). - + - The local paths to sync to the target workspace when a bundle is run or deployed. See [\_](#targetsnamesync). + - - `variables` - Map - - The custom variable definitions for the target. See [_](#targetsnamevariables). - + - The custom variable definitions for the target. See [\_](#targetsnamevariables). + - - `workspace` - Map - - The Databricks workspace for the target. See [_](#targetsnameworkspace). - -::: - - + - The Databricks workspace for the target. See [\_](#targetsnameworkspace). + +# ::: + +- - `permissions` + - Sequence + - The permissions for deploying and running the bundle in the target. See [\_](#targetsnamepermissions). + +- - `presets` + - Map + - The deployment presets for the target. See [\_](#targetsnamepresets). + +- - `resources` + - Map + - The resource definitions for the target. See [\_](#targetsnameresources). + +- - `run_as` + - Map + - The identity to use to run the bundle, see [\_](/dev-tools/bundles/run-as.md). See [\_](#targetsnamerun_as). + +- - `sync` + - Map + - The local paths to sync to the target workspace when a bundle is run or deployed. See [\_](#targetsnamesync). + +- - `variables` + - Map + - The custom variable definitions for the target. See [\_](#targetsnamevariables). + +- - `workspace` - Map - The Databricks workspace for the target. See [\_](#targetsnameworkspace). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + ### targets.\.artifacts - + **`Type: Map`** - + The artifacts to include in the target deployment. - + ```yaml artifacts: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `build` - String - An optional set of non-default build commands to run locally before deployment. - + - - `executable` - String - The executable type. Valid values are `bash`, `sh`, and `cmd`. - + +<<<<<<< HEAD + - - `files` - - Sequence - - The source files for the artifact. See [_](#targetsnameartifactsnamefiles). - + - Sequence + - # The source files for the artifact. See [\_](#targetsnameartifactsnamefiles). + * - `files` - Sequence - The source files for the artifact. See [\_](#targetsnameartifactsnamefiles). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `path` - String - The location where the built artifact will be saved. - + - - `type` - String - Required. The type of the artifact. Valid values are `whl`. - + ::: - - + ### targets.\.artifacts.\.files - + **`Type: Sequence`** - + The source files for the artifact. - - - + :::list-table - + - - Key - Type - Description - + - - `source` - String - Required. The path of the files used to build the artifact. - + ::: - - + ### targets.\.bundle - + **`Type: Map`** - + The bundle attributes when deploying to this target. - - - + :::list-table - + - - Key - Type - Description - + - - `cluster_id` - String - - The ID of a cluster to use to run the bundle. See [_](/dev-tools/bundles/settings.md#cluster_id). - + - The ID of a cluster to use to run the bundle. See [\_](/dev-tools/bundles/settings.md#cluster_id). + - - `compute_id` - String - - - + - + - - `databricks_cli_version` - String - - The Databricks CLI version to use for the bundle. See [_](/dev-tools/bundles/settings.md#databricks_cli_version). - + - The Databricks CLI version to use for the bundle. See [\_](/dev-tools/bundles/settings.md#databricks_cli_version). + +<<<<<<< HEAD + - - `deployment` - Map - - The definition of the bundle deployment. For supported attributes see [_](/dev-tools/bundles/deployment-modes.md). See [_](#targetsnamebundledeployment). - + - The definition of the bundle deployment. For supported attributes see [\_](/dev-tools/bundles/deployment-modes.md). See [\_](#targetsnamebundledeployment). + - - `git` - - Map - - The Git version control details that are associated with your bundle. For supported attributes see [_](/dev-tools/bundles/settings.md#git). See [_](#targetsnamebundlegit). - + + - Map + - # The Git version control details that are associated with your bundle. For supported attributes see [\_](/dev-tools/bundles/settings.md#git). See [\_](#targetsnamebundlegit). + + * - `deployment` + - Map + - The definition of the bundle deployment. For supported attributes see [\_](/dev-tools/bundles/deployment-modes.md). See [\_](#targetsnamebundledeployment). + + * - `git` - Map - The Git version control details that are associated with your bundle. For supported attributes see [\_](/dev-tools/bundles/settings.md#git). See [\_](#targetsnamebundlegit). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `name` - String - The name of the bundle. - + - - `uuid` - String - Reserved. A Universally Unique Identifier (UUID) for the bundle that uniquely identifies the bundle in internal Databricks systems. This is generated when a bundle project is initialized using a Databricks template (using the `databricks bundle init` command). - + ::: - - + ### targets.\.bundle.deployment - + **`Type: Map`** - -The definition of the bundle deployment. For supported attributes see [_](/dev-tools/bundles/deployment-modes.md). - - - + +The definition of the bundle deployment. For supported attributes see [\_](/dev-tools/bundles/deployment-modes.md). + :::list-table - + - - Key - Type - Description - + - - `fail_on_active_runs` - Boolean - Whether to fail on active runs. If this is set to true a deployment that is running can be interrupted. - + +<<<<<<< HEAD + - - `lock` - Map - - The deployment lock attributes. See [_](#targetsnamebundledeploymentlock). - -::: - - + - The deployment lock attributes. See [\_](#targetsnamebundledeploymentlock). + +# ::: + +- - `lock` - Map - The deployment lock attributes. See [\_](#targetsnamebundledeploymentlock). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + ### targets.\.bundle.deployment.lock - + **`Type: Map`** - + The deployment lock attributes. - - - + :::list-table - + - - Key - Type - Description - + - - `enabled` - Boolean - Whether this lock is enabled. - + - - `force` - Boolean - Whether to force this lock if it is enabled. - + ::: - - + ### targets.\.bundle.git - + **`Type: Map`** - -The Git version control details that are associated with your bundle. For supported attributes see [_](/dev-tools/bundles/settings.md#git). - - - + +The Git version control details that are associated with your bundle. For supported attributes see [\_](/dev-tools/bundles/settings.md#git). + :::list-table - + - - Key - Type - Description - + - - `branch` - String - - The Git branch name. See [_](/dev-tools/bundles/settings.md#git). - + - The Git branch name. See [\_](/dev-tools/bundles/settings.md#git). + - - `origin_url` - String - - The origin URL of the repository. See [_](/dev-tools/bundles/settings.md#git). - + - The origin URL of the repository. See [\_](/dev-tools/bundles/settings.md#git). + ::: - - + ### targets.\.git - + **`Type: Map`** - + The Git version control settings for the target. - - - + :::list-table - + - - Key - Type - Description - + - - `branch` - String - - The Git branch name. See [_](/dev-tools/bundles/settings.md#git). - + - The Git branch name. See [\_](/dev-tools/bundles/settings.md#git). + - - `origin_url` - String - - The origin URL of the repository. See [_](/dev-tools/bundles/settings.md#git). - + - The origin URL of the repository. See [\_](/dev-tools/bundles/settings.md#git). + ::: - - + ### targets.\.permissions - + **`Type: Sequence`** - + The permissions for deploying and running the bundle in the target. - - - + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + ### targets.\.presets - + **`Type: Map`** - + The deployment presets for the target. - - - + :::list-table - + - - Key - Type - Description - + - - `jobs_max_concurrent_runs` - Integer - The maximum concurrent runs for a job. - + - - `name_prefix` - String - The prefix for job runs of the bundle. - + - - `pipelines_development` - Boolean - Whether pipeline deployments should be locked in development mode. - + - - `source_linked_deployment` - Boolean - Whether to link the deployment to the bundle source. - + - - `tags` - Map - The tags for the bundle deployment. - + - - `trigger_pause_status` - String - A pause status to apply to all job triggers and schedules. Valid values are PAUSED or UNPAUSED. - + ::: - - + ### targets.\.resources - + **`Type: Map`** - + The resource definitions for the target. - - - + :::list-table - + - - Key - Type - Description - + - - `apps` - Map - - - + - + - - `clusters` - Map - - The cluster definitions for the bundle, where each key is the name of a cluster. See [_](/dev-tools/bundles/resources.md#clusters) - + - The cluster definitions for the bundle, where each key is the name of a cluster. See [\_](/dev-tools/bundles/resources.md#clusters) + - - `dashboards` - Map - - The dashboard definitions for the bundle, where each key is the name of the dashboard. See [_](/dev-tools/bundles/resources.md#dashboards) - + - The dashboard definitions for the bundle, where each key is the name of the dashboard. See [\_](/dev-tools/bundles/resources.md#dashboards) + - - `experiments` - Map - - The experiment definitions for the bundle, where each key is the name of the experiment. See [_](/dev-tools/bundles/resources.md#experiments) - + - The experiment definitions for the bundle, where each key is the name of the experiment. See [\_](/dev-tools/bundles/resources.md#experiments) + - - `jobs` - Map - - The job definitions for the bundle, where each key is the name of the job. See [_](/dev-tools/bundles/resources.md#jobs) - + - The job definitions for the bundle, where each key is the name of the job. See [\_](/dev-tools/bundles/resources.md#jobs) + - - `model_serving_endpoints` - Map - - The model serving endpoint definitions for the bundle, where each key is the name of the model serving endpoint. See [_](/dev-tools/bundles/resources.md#model_serving_endpoints) - + - The model serving endpoint definitions for the bundle, where each key is the name of the model serving endpoint. See [\_](/dev-tools/bundles/resources.md#model_serving_endpoints) + - - `models` - Map - - The model definitions for the bundle, where each key is the name of the model. See [_](/dev-tools/bundles/resources.md#models) - + - The model definitions for the bundle, where each key is the name of the model. See [\_](/dev-tools/bundles/resources.md#models) + - - `pipelines` - Map - - The pipeline definitions for the bundle, where each key is the name of the pipeline. See [_](/dev-tools/bundles/resources.md#pipelines) - + - The pipeline definitions for the bundle, where each key is the name of the pipeline. See [\_](/dev-tools/bundles/resources.md#pipelines) + - - `quality_monitors` - Map - - The quality monitor definitions for the bundle, where each key is the name of the quality monitor. See [_](/dev-tools/bundles/resources.md#quality_monitors) - + - The quality monitor definitions for the bundle, where each key is the name of the quality monitor. See [\_](/dev-tools/bundles/resources.md#quality_monitors) + - - `registered_models` - Map - - The registered model definitions for the bundle, where each key is the name of the Unity Catalog registered model. See [_](/dev-tools/bundles/resources.md#registered_models) - + - The registered model definitions for the bundle, where each key is the name of the Unity Catalog registered model. See [\_](/dev-tools/bundles/resources.md#registered_models) + - - `schemas` - Map - - The schema definitions for the bundle, where each key is the name of the schema. See [_](/dev-tools/bundles/resources.md#schemas) - + - The schema definitions for the bundle, where each key is the name of the schema. See [\_](/dev-tools/bundles/resources.md#schemas) + - - `volumes` - Map - - The volume definitions for the bundle, where each key is the name of the volume. See [_](/dev-tools/bundles/resources.md#volumes) - + - The volume definitions for the bundle, where each key is the name of the volume. See [\_](/dev-tools/bundles/resources.md#volumes) + ::: - - + ### targets.\.run_as - + **`Type: Map`** - -The identity to use to run the bundle, see [_](/dev-tools/bundles/run-as.md). - - - + +The identity to use to run the bundle, see [\_](/dev-tools/bundles/run-as.md). + :::list-table - + - - Key - Type - Description - + - - `service_principal_name` - String - The application ID of an active service principal. Setting this field requires the `servicePrincipal/user` role. - + - - `user_name` - String - The email of an active workspace user. Non-admin users can only set this field to their own email. - + ::: - - + ### targets.\.sync - + **`Type: Map`** - + The local paths to sync to the target workspace when a bundle is run or deployed. - - - + :::list-table - + - - Key - Type - Description - + - - `exclude` - Sequence - A list of files or folders to exclude from the bundle. - + - - `include` - Sequence - A list of files or folders to include in the bundle. - + - - `paths` - Sequence - The local folder paths, which can be outside the bundle root, to synchronize to the workspace when the bundle is deployed. - + ::: - - + ### targets.\.variables - + **`Type: Map`** - + The custom variable definitions for the target. - + ```yaml variables: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `default` - Any - - - + - + - - `description` - String - The description of the variable. - + +<<<<<<< HEAD + - - `lookup` - - Map - - The name of the alert, cluster_policy, cluster, dashboard, instance_pool, job, metastore, pipeline, query, service_principal, or warehouse object for which to retrieve an ID. See [_](#targetsnamevariablesnamelookup). - + - Map + - # The name of the alert, cluster*policy, cluster, dashboard, instance_pool, job, metastore, pipeline, query, service_principal, or warehouse object for which to retrieve an ID. See [*](#targetsnamevariablesnamelookup). + * - `lookup` - Map - The name of the alert, cluster*policy, cluster, dashboard, instance_pool, job, metastore, pipeline, query, service_principal, or warehouse object for which to retrieve an ID. See [*](#targetsnamevariablesnamelookup). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `type` - String - The type of the variable. - + ::: - - + ### targets.\.variables.\.lookup - + **`Type: Map`** - + The name of the alert, cluster_policy, cluster, dashboard, instance_pool, job, metastore, pipeline, query, service_principal, or warehouse object for which to retrieve an ID. - - - + :::list-table - + - - Key - Type - Description - + - - `alert` - String - - - + - + - - `cluster` - String - - - + - + - - `cluster_policy` - String - - - + - + - - `dashboard` - String - - - + - + - - `instance_pool` - String - - - + - + - - `job` - String - - - + - + - - `metastore` - String - - - + - + - - `notification_destination` - String - - - + - + - - `pipeline` - String - - - + - + - - `query` - String - - - + - + - - `service_principal` - String - - - + - + - - `warehouse` - String - - - + - + ::: - - + ### targets.\.workspace - + **`Type: Map`** - + The Databricks workspace for the target. - - - + :::list-table - + - - Key - Type - Description - + - - `artifact_path` - String - The artifact path to use within the workspace for both deployments and workflow runs - + - - `auth_type` - String - The authentication type. - + - - `azure_client_id` - String - The Azure client ID - + - - `azure_environment` - String - The Azure environment - + - - `azure_login_app_id` - String - The Azure login app ID - + - - `azure_tenant_id` - String - The Azure tenant ID - + - - `azure_use_msi` - Boolean - Whether to use MSI for Azure - + - - `azure_workspace_resource_id` - String - The Azure workspace resource ID - + - - `client_id` - String - The client ID for the workspace - + - - `file_path` - String - The file path to use within the workspace for both deployments and workflow runs - + - - `google_service_account` - String - The Google service account name - + - - `host` - String - The Databricks workspace host URL - + - - `profile` - String - The Databricks workspace profile name - + - - `resource_path` - String - The workspace resource path - + - - `root_path` - String - The Databricks workspace root path - + - - `state_path` - String - The workspace state path - + ::: - - + ## variables - + **`Type: Map`** - -Defines a custom variable for the bundle. See [_](/dev-tools/bundles/settings.md#variables). - + +Defines a custom variable for the bundle. See [\_](/dev-tools/bundles/settings.md#variables). + ```yaml variables: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `default` - Any - - - + - + - - `description` - String - The description of the variable - + +<<<<<<< HEAD + - - `lookup` - - Map - - The name of the `alert`, `cluster_policy`, `cluster`, `dashboard`, `instance_pool`, `job`, `metastore`, `pipeline`, `query`, `service_principal`, or `warehouse` object for which to retrieve an ID. See [_](#variablesnamelookup). - + - Map + - # The name of the `alert`, `cluster_policy`, `cluster`, `dashboard`, `instance_pool`, `job`, `metastore`, `pipeline`, `query`, `service_principal`, or `warehouse` object for which to retrieve an ID. See [\_](#variablesnamelookup). + * - `lookup` - Map - The name of the `alert`, `cluster_policy`, `cluster`, `dashboard`, `instance_pool`, `job`, `metastore`, `pipeline`, `query`, `service_principal`, or `warehouse` object for which to retrieve an ID. See [\_](#variablesnamelookup). + > > > > > > > 4881fd873b6b615c79e5e792cdf62aac86d49642 + - - `type` - String - The type of the variable. - + ::: - - + ### variables.\.lookup - + **`Type: Map`** - + The name of the `alert`, `cluster_policy`, `cluster`, `dashboard`, `instance_pool`, `job`, `metastore`, `pipeline`, `query`, `service_principal`, or `warehouse` object for which to retrieve an ID. - - - + :::list-table - + - - Key - Type - Description - + - - `alert` - String - - - + - + - - `cluster` - String - - - + - + - - `cluster_policy` - String - - - + - + - - `dashboard` - String - - - + - + - - `instance_pool` - String - - - + - + - - `job` - String - - - + - + - - `metastore` - String - - - + - + - - `notification_destination` - String - - - + - + - - `pipeline` - String - - - + - + - - `query` - String - - - + - + - - `service_principal` - String - - - + - + - - `warehouse` - String - - - + - + ::: - - + ## workspace - + **`Type: Map`** - -Defines the Databricks workspace for the bundle. See [_](/dev-tools/bundles/settings.md#workspace). - - - + +Defines the Databricks workspace for the bundle. See [\_](/dev-tools/bundles/settings.md#workspace). + :::list-table - + - - Key - Type - Description - + - - `artifact_path` - String - The artifact path to use within the workspace for both deployments and workflow runs - + - - `auth_type` - String - The authentication type. - + - - `azure_client_id` - String - The Azure client ID - + - - `azure_environment` - String - The Azure environment - + - - `azure_login_app_id` - String - The Azure login app ID - + - - `azure_tenant_id` - String - The Azure tenant ID - + - - `azure_use_msi` - Boolean - Whether to use MSI for Azure - + - - `azure_workspace_resource_id` - String - The Azure workspace resource ID - + - - `client_id` - String - The client ID for the workspace - + - - `file_path` - String - The file path to use within the workspace for both deployments and workflow runs - + - - `google_service_account` - String - The Google service account name - + - - `host` - String - The Databricks workspace host URL - + - - `profile` - String - The Databricks workspace profile name - + - - `resource_path` - String - The workspace resource path - + - - `root_path` - String - The Databricks workspace root path - + - - `state_path` - String - The workspace state path - + ::: - \ No newline at end of file diff --git a/bundle/docsgen/output/resources.md b/bundle/docsgen/output/resources.md index 4a0fff2fb..22ebb5f56 100644 --- a/bundle/docsgen/output/resources.md +++ b/bundle/docsgen/output/resources.md @@ -1,10 +1,10 @@ --- -description: 'Learn about resources supported by Databricks Asset Bundles and how to configure them.' +description: Learn about resources supported by Databricks Asset Bundles and how to configure them. --- -# :re[DABS] resources +# resources :re[DABS] allows you to specify information about the :re[Databricks] resources used by the bundle in the `resources` mapping in the bundle configuration. See [resources mapping](settings.md#resources) and [resources key reference](reference.md#resources). @@ -74,671 +74,580 @@ The `databricks bundle validate` command returns warnings if unknown resource pr ::: - ## apps - -**`Type: Map`** - - +**`Type: Map`** + ```yaml apps: : : ``` - - + :::list-table - + - - Key - Type - Description - -- - `active_deployment` - - Map - - See [_](#appsnameactive_deployment). - -- - `app_status` - - Map - - See [_](#appsnameapp_status). - -- - `compute_status` - - Map - - See [_](#appsnamecompute_status). - + + * - `active_deployment` + - Map + - See [\_](#appsnameactive_deployment). + + * - `app_status` + - Map + - See [\_](#appsnameapp_status). + + * - `compute_status` + - Map + - See [\_](#appsnamecompute_status). + - - `config` - Map - - - + - + - - `create_time` - String - - - + - + - - `creator` - String - - - + - + - - `default_source_code_path` - String - - - + - + - - `description` - String - - - + - + - - `name` - String - - - -- - `pending_deployment` - - Map - - See [_](#appsnamepending_deployment). - -- - `permissions` - - Sequence - - See [_](#appsnamepermissions). - -- - `resources` - - Sequence - - See [_](#appsnameresources). - + - - - `pending_deployment` + - Map + - See [\_](#appsnamepending_deployment). + + - - `permissions` + - Sequence + - See [\_](#appsnamepermissions). + + - - `resources` + - Sequence + - See [\_](#appsnameresources). + - - `service_principal_client_id` - String - - - + - + - - `service_principal_id` - Integer - - - + - + - - `service_principal_name` - String - - - + - + - - `source_code_path` - String - - - + - + - - `update_time` - String - - - + - + - - `updater` - String - - - + - + - - `url` - String - - - -::: - - -### apps.\.active_deployment - -**`Type: Map`** - + - + +::: + +### apps.\.active_deployment + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `create_time` - String - - - + - + - - `creator` - String - - - -- - `deployment_artifacts` - - Map - - See [_](#appsnameactive_deploymentdeployment_artifacts). - + - - - `deployment_artifacts` + - Map + - See [\_](#appsnameactive_deploymentdeployment_artifacts). + - - `deployment_id` - String - - - + - + - - `mode` - String - - - + - + - - `source_code_path` - String - - - -- - `status` - - Map - - See [_](#appsnameactive_deploymentstatus). - + - - - `status` + - Map + - See [\_](#appsnameactive_deploymentstatus). + - - `update_time` - String - - - -::: - - -### apps.\.active_deployment.deployment_artifacts - -**`Type: Map`** - + - + +::: + +### apps.\.active_deployment.deployment_artifacts + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `source_code_path` - String - - - + - + ::: - - + ### apps.\.active_deployment.status - -**`Type: Map`** - - - - +**`Type: Map`** + :::list-table - + - - Key - Type - Description - + - - `message` - String - - - + - + - - `state` - String - - - + - + ::: - - + ### apps.\.app_status - -**`Type: Map`** - - - - +**`Type: Map`** + :::list-table - + - - Key - Type - Description - + - - `message` - String - - - + - + - - `state` - String - - - -::: - - -### apps.\.compute_status - -**`Type: Map`** - + - + +::: + +### apps.\.compute_status + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `message` - String - - - + - + - - `state` - String - State of the app compute. - -::: - - -### apps.\.pending_deployment - -**`Type: Map`** - - - - +::: + +### apps.\.pending_deployment + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - + - - `create_time` - String - - - + - + - - `creator` - String - - - -- - `deployment_artifacts` - - Map - - See [_](#appsnamepending_deploymentdeployment_artifacts). - + - - - `deployment_artifacts` + - Map + - See [\_](#appsnamepending_deploymentdeployment_artifacts). + - - `deployment_id` - String - - - + - + - - `mode` - String - - - + - + - - `source_code_path` - String - - - -- - `status` - - Map - - See [_](#appsnamepending_deploymentstatus). - + - - - `status` + - Map + - See [\_](#appsnamepending_deploymentstatus). + - - `update_time` - String - - - -::: - - -### apps.\.pending_deployment.deployment_artifacts - -**`Type: Map`** - + - + +::: + +### apps.\.pending_deployment.deployment_artifacts + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `source_code_path` - String - - - -::: - - -### apps.\.pending_deployment.status - -**`Type: Map`** - + - + +::: + +### apps.\.pending_deployment.status + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `message` - String - - - + - + - - `state` - String - - - -::: - - -### apps.\.permissions - -**`Type: Sequence`** - + - + +::: + +### apps.\.permissions + +**`Type: Sequence`** - - - :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - -::: - - -### apps.\.resources - -**`Type: Sequence`** - - - - +::: + +### apps.\.resources + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `description` - String - Description of the App Resource. - -- - `job` - - Map - - See [_](#appsnameresourcesjob). - + + * - `job` + - Map + - See [\_](#appsnameresourcesjob). + - - `name` - String - Name of the App Resource. - -- - `secret` - - Map - - See [_](#appsnameresourcessecret). - -- - `serving_endpoint` - - Map - - See [_](#appsnameresourcesserving_endpoint). - -- - `sql_warehouse` - - Map - - See [_](#appsnameresourcessql_warehouse). - -::: - - -### apps.\.resources.job - -**`Type: Map`** - - - - + * - `secret` + - Map + - See [\_](#appsnameresourcessecret). + + * - `serving_endpoint` + - Map + - See [\_](#appsnameresourcesserving_endpoint). + + * - `sql_warehouse` + - Map + - See [\_](#appsnameresourcessql_warehouse). + +### apps.\.resources.job + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + - - `permission` - String - - - -::: - - -### apps.\.resources.secret - -**`Type: Map`** - + - + +::: + +### apps.\.resources.secret + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `key` - String - - - + - + - - `permission` - String - Permission to grant on the secret scope. Supported permissions are: "READ", "WRITE", "MANAGE". - + - - `scope` - String - - - -::: - - -### apps.\.resources.serving_endpoint - -**`Type: Map`** - + - + +::: + +### apps.\.resources.serving_endpoint + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `name` - String - - - + - + - - `permission` - String - - - -::: - - -### apps.\.resources.sql_warehouse - -**`Type: Map`** - + - + +::: + +### apps.\.resources.sql_warehouse + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + - - `permission` - String - - - + - + ::: - - + ## clusters - + **`Type: Map`** - + The cluster resource defines an [all-purpose cluster](/api/workspace/clusters/create). - + ```yaml clusters: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `apply_policy_default_values` - Boolean - When set to true, fixed and default values from the policy will be used for fields that are omitted. When set to false, only fixed values from the policy will be applied. - -- - `autoscale` - - Map - - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [_](#clustersnameautoscale). - + + * - `autoscale` + - Map + - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [\_](#clustersnameautoscale). + - - `autotermination_minutes` - Integer - Automatically terminates the cluster after it is inactive for this time in minutes. If not set, this cluster will not be automatically terminated. If specified, the threshold must be between 10 and 10000 minutes. Users can also set this value to 0 to explicitly disable automatic termination. - -- - `aws_attributes` - - Map - - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [_](#clustersnameaws_attributes). - -- - `azure_attributes` - - Map - - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [_](#clustersnameazure_attributes). - -- - `cluster_log_conf` - - Map - - The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. See [_](#clustersnamecluster_log_conf). - + + * - `aws_attributes` + - Map + - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [\_](#clustersnameaws_attributes). + + * - `azure_attributes` + - Map + - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [\_](#clustersnameazure_attributes). + + * - `cluster_log_conf` + - Map + - The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. See [\_](#clustersnamecluster_log_conf). + - - `cluster_name` - String - - Cluster name requested by the user. This doesn't have to be unique. If not specified at creation, the cluster name will be an empty string. - + - Cluster name requested by the user. This doesn't have to be unique. If not specified at creation, the cluster name will be an empty string. + - - `custom_tags` - Map - - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags - + - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags + - - `data_security_mode` - String - - Data security mode decides what data governance model to use when accessing data from a cluster. The following modes can only be used with `kind`. * `DATA_SECURITY_MODE_AUTO`: Databricks will choose the most appropriate access mode depending on your compute configuration. * `DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`. * `DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`. The following modes can be used regardless of `kind`. * `NONE`: No security isolation for multiple users sharing the cluster. Data governance features are not available in this mode. * `SINGLE_USER`: A secure cluster that can only be exclusively used by a single user specified in `single_user_name`. Most programming languages, cluster features and data governance features are available in this mode. * `USER_ISOLATION`: A secure cluster that can be shared by multiple users. Cluster users are fully isolated so that they cannot see each other's data and credentials. Most data governance features are supported in this mode. But programming languages and cluster features might be limited. The following modes are deprecated starting with Databricks Runtime 15.0 and will be removed for future Databricks Runtime versions: * `LEGACY_TABLE_ACL`: This mode is for users migrating from legacy Table ACL clusters. * `LEGACY_PASSTHROUGH`: This mode is for users migrating from legacy Passthrough on high concurrency clusters. * `LEGACY_SINGLE_USER`: This mode is for users migrating from legacy Passthrough on standard clusters. * `LEGACY_SINGLE_USER_STANDARD`: This mode provides a way that doesn’t have UC nor passthrough enabled. - -- - `docker_image` - - Map - - See [_](#clustersnamedocker_image). - + - Data security mode decides what data governance model to use when accessing data from a cluster. The following modes can only be used with `kind`. _ `DATA_SECURITY_MODE_AUTO`: Databricks will choose the most appropriate access mode depending on your compute configuration. _ `DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`. _ `DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`. The following modes can be used regardless of `kind`. _ `NONE`: No security isolation for multiple users sharing the cluster. Data governance features are not available in this mode. _ `SINGLE_USER`: A secure cluster that can only be exclusively used by a single user specified in `single_user_name`. Most programming languages, cluster features and data governance features are available in this mode. _ `USER_ISOLATION`: A secure cluster that can be shared by multiple users. Cluster users are fully isolated so that they cannot see each other's data and credentials. Most data governance features are supported in this mode. But programming languages and cluster features might be limited. The following modes are deprecated starting with Databricks Runtime 15.0 and will be removed for future Databricks Runtime versions: _ `LEGACY_TABLE_ACL`: This mode is for users migrating from legacy Table ACL clusters. _ `LEGACY_PASSTHROUGH`: This mode is for users migrating from legacy Passthrough on high concurrency clusters. _ `LEGACY_SINGLE_USER`: This mode is for users migrating from legacy Passthrough on standard clusters. _ `LEGACY_SINGLE_USER_STANDARD`: This mode provides a way that doesn’t have UC nor passthrough enabled. + + * - `docker_image` + - Map + - See [\_](#clustersnamedocker_image). + - - `driver_instance_pool_id` - String - The optional ID of the instance pool for the driver of the cluster belongs. The pool cluster uses the instance pool with id (instance_pool_id) if the driver pool is not assigned. - + - - `driver_node_type_id` - String - - The node type of the Spark driver. Note that this field is optional; if unset, the driver node type will be set as the same value as `node_type_id` defined above. - + - The node type of the Spark driver. Note that this field is optional; if unset, the driver node type will be set as the same value as `node_type_id` defined above. + - - `enable_elastic_disk` - Boolean - Autoscaling Local Storage: when enabled, this cluster will dynamically acquire additional disk space when its Spark workers are running low on disk space. This feature requires specific AWS permissions to function correctly - refer to the User Guide for more details. - + - - `enable_local_disk_encryption` - Boolean - Whether to enable LUKS on cluster VMs' local disks - -- - `gcp_attributes` - - Map - - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [_](#clustersnamegcp_attributes). - -- - `init_scripts` - - Sequence - - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [_](#clustersnameinit_scripts). - + + * - `gcp_attributes` + - Map + - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [\_](#clustersnamegcp_attributes). + + * - `init_scripts` + - Sequence + - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [\_](#clustersnameinit_scripts). + - - `instance_pool_id` - String - The optional ID of the instance pool to which the cluster belongs. - + - - `is_single_node` - Boolean - - This field can only be used with `kind`. When set to true, Databricks will automatically set single node related `custom_tags`, `spark_conf`, and `num_workers` - + - This field can only be used with `kind`. When set to true, Databricks will automatically set single node related `custom_tags`, `spark_conf`, and `num_workers` + - - `kind` - String - - - + - + - - `node_type_id` - String - - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. - + - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. + - - `num_workers` - Integer - - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. - -- - `permissions` - - Sequence - - See [_](#clustersnamepermissions). - + - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. + + * - `permissions` + - Sequence + - See [\_](#clustersnamepermissions). + - - `policy_id` - String - The ID of the cluster policy used to create the cluster if applicable. - + - - `runtime_engine` - String - - Determines the cluster's runtime engine, either standard or Photon. This field is not compatible with legacy `spark_version` values that contain `-photon-`. Remove `-photon-` from the `spark_version` and set `runtime_engine` to `PHOTON`. If left unspecified, the runtime engine defaults to standard unless the spark_version contains -photon-, in which case Photon will be used. - + - Determines the cluster's runtime engine, either standard or Photon. This field is not compatible with legacy `spark_version` values that contain `-photon-`. Remove `-photon-` from the `spark_version` and set `runtime_engine` to `PHOTON`. If left unspecified, the runtime engine defaults to standard unless the spark_version contains -photon-, in which case Photon will be used. + - - `single_user_name` - String - Single user name if data_security_mode is `SINGLE_USER` - + - - `spark_conf` - Map - - An object containing a set of optional, user-specified Spark configuration key-value pairs. Users can also pass in a string of extra JVM options to the driver and the executors via `spark.driver.extraJavaOptions` and `spark.executor.extraJavaOptions` respectively. - + - An object containing a set of optional, user-specified Spark configuration key-value pairs. Users can also pass in a string of extra JVM options to the driver and the executors via `spark.driver.extraJavaOptions` and `spark.executor.extraJavaOptions` respectively. + - - `spark_env_vars` - Map - - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` - + - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` + - - `spark_version` - String - - The Spark version of the cluster, e.g. `3.3.x-scala2.11`. A list of available Spark versions can be retrieved by using the :method:clusters/sparkVersions API call. - + - The Spark version of the cluster, e.g. `3.3.x-scala2.11`. A list of available Spark versions can be retrieved by using the :method:clusters/sparkVersions API call. + - - `ssh_public_keys` - Sequence - SSH public key contents that will be added to each Spark node in this cluster. The corresponding private keys can be used to login with the user name `ubuntu` on port `2200`. Up to 10 keys can be specified. - + - - `use_ml_runtime` - Boolean - - This field can only be used with `kind`. `effective_spark_version` is determined by `spark_version` (DBR release), this field `use_ml_runtime`, and whether `node_type_id` is gpu node or not. - -- - `workload_type` - - Map - - See [_](#clustersnameworkload_type). - -::: - - + - This field can only be used with `kind`. `effective_spark_version` is determined by `spark_version` (DBR release), this field `use_ml_runtime`, and whether `node_type_id` is gpu node or not. + + * - `workload_type` + - Map + - See [\_](#clustersnameworkload_type). + **Example** - + The following example creates a cluster named `my_cluster` and sets that as the cluster to use to run the notebook in `my_job`: ```yaml @@ -764,723 +673,642 @@ resources: notebook_task: notebook_path: "./src/my_notebook.py" ``` - + ### clusters.\.autoscale - + **`Type: Map`** - + Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. - - - + :::list-table - + - - Key - Type - Description - + - - `max_workers` - Integer - The maximum number of workers to which the cluster can scale up when overloaded. Note that `max_workers` must be strictly greater than `min_workers`. - + - - `min_workers` - Integer - The minimum number of workers to which the cluster can scale down when underutilized. It is also the initial number of workers the cluster will have after creation. - + ::: - - + ### clusters.\.aws_attributes - + **`Type: Map`** - + Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. - + - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. + - - `ebs_volume_count` - Integer - - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. - + - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. + - - `ebs_volume_iops` - Integer - If using gp3 volumes, what IOPS to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_size` - Integer - The size of each EBS volume (in GiB) launched for each instance. For general purpose SSD, this value must be within the range 100 - 4096. For throughput optimized HDD, this value must be within the range 500 - 4096. - + - - `ebs_volume_throughput` - Integer - If using gp3 volumes, what throughput to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_type` - String - The type of EBS volumes that will be launched with this cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. If this value is greater than 0, the cluster driver node in particular will be placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - + - - `instance_profile_arn` - String - - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. - + - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. + - - `spot_bid_price_percent` - Integer - - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. - + - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. + - - `zone_id` - String - Identifier for the availability zone/datacenter in which the cluster resides. This string will be of a form like "us-west-2a". The provided availability zone must be in the same region as the Databricks deployment. For example, "us-west-2a" is not a valid zone id if the Databricks deployment resides in the "us-east-1" region. This is an optional field at cluster creation, and if not specified, a default zone will be used. If the zone specified is "auto", will try to place cluster in a zone with high availability, and will retry placement in a different AZ if there is not enough capacity. The list of available zones as well as the default value can be found by using the `List Zones` method. - + ::: - - + ### clusters.\.azure_attributes - + **`Type: Map`** - + Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero (which only happens on pool clusters), this availability type will be used for the entire cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. This value should be greater than 0, to make sure the cluster driver node is placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - -- - `log_analytics_info` - - Map - - Defines values necessary to configure and run Azure Log Analytics agent. See [_](#clustersnameazure_attributeslog_analytics_info). - + + * - `log_analytics_info` + - Map + - Defines values necessary to configure and run Azure Log Analytics agent. See [\_](#clustersnameazure_attributeslog_analytics_info). + - - `spot_bid_max_price` - Any - The max bid price to be used for Azure spot instances. The Max price for the bid cannot be higher than the on-demand price of the instance. If not specified, the default value is -1, which specifies that the instance cannot be evicted on the basis of price, and only on the basis of availability. Further, the value should > 0 or -1. - + ::: - - + ### clusters.\.azure_attributes.log_analytics_info - + **`Type: Map`** - + Defines values necessary to configure and run Azure Log Analytics agent - - - + :::list-table - + - - Key - Type - Description - + - - `log_analytics_primary_key` - String - - - + - + - - `log_analytics_workspace_id` - String - - - + - + ::: - - + ### clusters.\.cluster_log_conf - + **`Type: Map`** - + The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. - - - + :::list-table - + - - Key - Type - Description - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#clustersnamecluster_log_confdbfs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#clustersnamecluster_log_confs3). - -::: - - + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#clustersnamecluster_log_confdbfs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#clustersnamecluster_log_confs3). + ### clusters.\.cluster_log_conf.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### clusters.\.cluster_log_conf.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - -::: - - -### clusters.\.docker_image - -**`Type: Map`** - - - - +::: + +### clusters.\.docker_image + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - -- - `basic_auth` - - Map - - See [_](#clustersnamedocker_imagebasic_auth). - + + * - `basic_auth` + - Map + - See [\_](#clustersnamedocker_imagebasic_auth). + - - `url` - String - URL of the docker image. - -::: - - -### clusters.\.docker_image.basic_auth - -**`Type: Map`** - - - - +::: + +### clusters.\.docker_image.basic_auth + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - + - - `password` - String - Password of the user - + - - `username` - String - Name of the user - + ::: - - + ### clusters.\.gcp_attributes - + **`Type: Map`** - + Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - This field determines whether the instance pool will contain preemptible VMs, on-demand VMs, or preemptible VMs with a fallback to on-demand VMs if the former is unavailable. - + - - `boot_disk_size` - Integer - boot disk size in GB - + - - `google_service_account` - String - If provided, the cluster will impersonate the google service account when accessing gcloud services (like GCS). The google service account must have previously been added to the Databricks environment by an account administrator. - + - - `local_ssd_count` - Integer - If provided, each node (workers and driver) in the cluster will have this number of local SSDs attached. Each local SSD is 375GB in size. Refer to [GCP documentation](https://cloud.google.com/compute/docs/disks/local-ssd#choose_number_local_ssds) for the supported number of local SSDs for each instance type. - + - - `use_preemptible_executors` - Boolean - This field determines whether the spark executors will be scheduled to run on preemptible VMs (when set to true) versus standard compute engine VMs (when set to false; default). Note: Soon to be deprecated, use the availability field instead. - + - - `zone_id` - String - Identifier for the availability zone in which the cluster resides. This can be one of the following: - "HA" => High availability, spread nodes across availability zones for a Databricks deployment region [default] - "AUTO" => Databricks picks an availability zone to schedule the cluster on. - A GCP availability zone => Pick One of the available zones for (machine type + region) from https://cloud.google.com/compute/docs/regions-zones. - -::: - - -### clusters.\.init_scripts - -**`Type: Sequence`** - -The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. - - - -:::list-table - -- - Key - - Type - - Description - -- - `abfss` - - Map - - See [_](#clustersnameinit_scriptsabfss). - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#clustersnameinit_scriptsdbfs). - -- - `file` - - Map - - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [_](#clustersnameinit_scriptsfile). - -- - `gcs` - - Map - - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [_](#clustersnameinit_scriptsgcs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#clustersnameinit_scriptss3). - -- - `volumes` - - Map - - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [_](#clustersnameinit_scriptsvolumes). - -- - `workspace` - - Map - - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [_](#clustersnameinit_scriptsworkspace). - -::: - - -### clusters.\.init_scripts.abfss - -**`Type: Map`** - - - - +::: + +### clusters.\.init_scripts + +**`Type: Sequence`** + +The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. + :::list-table - + - - Key - Type - Description - + + * - `abfss` + - Map + - destination needs to be provided. e.g. `{ "abfss" : { "destination" : "abfss://@.dfs.core.windows.net/" } }. See [\_](#clustersnameinit_scriptsabfss). + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#clustersnameinit_scriptsdbfs). + + * - `file` + - Map + - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [\_](#clustersnameinit_scriptsfile). + + * - `gcs` + - Map + - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [\_](#clustersnameinit_scriptsgcs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#clustersnameinit_scriptss3). + + * - `volumes` + - Map + - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [\_](#clustersnameinit_scriptsvolumes). + + * - `workspace` + - Map + - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [\_](#clustersnameinit_scriptsworkspace). + +### clusters.\.init_scripts.abfss + +**`Type: Map`** + +:::list-table + +- - Key + - Type + - Description + - - `destination` - String - abfss destination, e.g. `abfss://@.dfs.core.windows.net/`. - + ::: - - + ### clusters.\.init_scripts.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### clusters.\.init_scripts.file - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - local file destination, e.g. `file:/my/local/file.sh` - + ::: - - + ### clusters.\.init_scripts.gcs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - GCS destination/URI, e.g. `gs://my-bucket/some-prefix` - + ::: - - + ### clusters.\.init_scripts.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + ::: - - + ### clusters.\.init_scripts.volumes - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - Unity Catalog Volumes file destination, e.g. `/Volumes/my-init.sh` - + ::: - - + ### clusters.\.init_scripts.workspace - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - workspace files destination, e.g. `/Users/user1@databricks.com/my-init.sh` - -::: - - -### clusters.\.permissions - -**`Type: Sequence`** - - - - +::: + +### clusters.\.permissions + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - -::: - - -### clusters.\.workload_type - -**`Type: Map`** - - - - -:::list-table - -- - Key - - Type - - Description - -- - `clients` - - Map - - defined what type of clients can use the cluster. E.g. Notebooks, Jobs. See [_](#clustersnameworkload_typeclients). - ::: - - -### clusters.\.workload_type.clients - + +### clusters.\.workload_type + **`Type: Map`** - - defined what type of clients can use the cluster. E.g. Notebooks, Jobs - - - + :::list-table - + - - Key - Type - Description - + + * - `clients` + - Map + - defined what type of clients can use the cluster. E.g. Notebooks, Jobs. See [\_](#clustersnameworkload_typeclients). + +### clusters.\.workload_type.clients + +**`Type: Map`** + +defined what type of clients can use the cluster. E.g. Notebooks, Jobs + +:::list-table + +- - Key + - Type + - Description + - - `jobs` - Boolean - With jobs set, the cluster can be used for jobs - + - - `notebooks` - Boolean - With notebooks set, this cluster can be used for notebooks - + ::: - - + ## dashboards - + **`Type: Map`** - -The dashboard resource allows you to manage [AI/BI dashboards](/api/workspace/lakeview/create) in a bundle. For information about AI/BI dashboards, see [_](/dashboards/index.md). - + +The dashboard resource allows you to manage [AI/BI dashboards](/api/workspace/lakeview/create) in a bundle. For information about AI/BI dashboards, see [\_](/dashboards/index.md). + ```yaml dashboards: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `create_time` - String - The timestamp of when the dashboard was created. - + - - `dashboard_id` - String - UUID identifying the dashboard. - + - - `display_name` - String - The display name of the dashboard. - + - - `embed_credentials` - Boolean - - - + - + - - `etag` - String - The etag for the dashboard. Can be optionally provided on updates to ensure that the dashboard has not been modified since the last read. This field is excluded in List Dashboards responses. - + - - `file_path` - String - - - + - + - - `lifecycle_state` - String - The state of the dashboard resource. Used for tracking trashed status. - + - - `parent_path` - String - The workspace path of the folder containing the dashboard. Includes leading slash and no trailing slash. This field is excluded in List Dashboards responses. - + - - `path` - String - The workspace path of the dashboard asset, including the file name. Exported dashboards always have the file extension `.lvdash.json`. This field is excluded in List Dashboards responses. - -- - `permissions` - - Sequence - - See [_](#dashboardsnamepermissions). - + + * - `permissions` + - Sequence + - See [\_](#dashboardsnamepermissions). + - - `serialized_dashboard` - Any - The contents of the dashboard in serialized string form. This field is excluded in List Dashboards responses. Use the [get dashboard API](https://docs.databricks.com/api/workspace/lakeview/get) to retrieve an example response, which includes the `serialized_dashboard` field. This field provides the structure of the JSON string that represents the dashboard's layout and components. - + - - `update_time` - String - The timestamp of when the dashboard was last updated by the user. This field is excluded in List Dashboards responses. - + - - `warehouse_id` - String - The warehouse ID used to run the dashboard. - -::: - - -**Example** - -The following example includes and deploys the sample __NYC Taxi Trip Analysis__ dashboard to the Databricks workspace. -``` yaml +::: + +**Example** + +The following example includes and deploys the sample **NYC Taxi Trip Analysis** dashboard to the Databricks workspace. + +```yaml resources: dashboards: nyc_taxi_trip_analysis: @@ -1488,99 +1316,91 @@ resources: file_path: ../src/nyc_taxi_trip_analysis.lvdash.json warehouse_id: ${var.warehouse_id} ``` -If you use the UI to modify the dashboard, modifications made through the UI are not applied to the dashboard JSON file in the local bundle unless you explicitly update it using `bundle generate`. You can use the `--watch` option to continuously poll and retrieve changes to the dashboard. See [_](/dev-tools/cli/bundle-commands.md#generate). -In addition, if you attempt to deploy a bundle that contains a dashboard JSON file that is different than the one in the remote workspace, an error will occur. To force the deploy and overwrite the dashboard in the remote workspace with the local one, use the `--force` option. See [_](/dev-tools/cli/bundle-commands.md#deploy). - +If you use the UI to modify the dashboard, modifications made through the UI are not applied to the dashboard JSON file in the local bundle unless you explicitly update it using `bundle generate`. You can use the `--watch` option to continuously poll and retrieve changes to the dashboard. See [\_](/dev-tools/cli/bundle-commands.md#generate). + +In addition, if you attempt to deploy a bundle that contains a dashboard JSON file that is different than the one in the remote workspace, an error will occur. To force the deploy and overwrite the dashboard in the remote workspace with the local one, use the `--force` option. See [\_](/dev-tools/cli/bundle-commands.md#deploy). + ### dashboards.\.permissions - -**`Type: Sequence`** - - - - +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + ## experiments - + **`Type: Map`** - -The experiment resource allows you to define [MLflow experiments](/api/workspace/experiments/createexperiment) in a bundle. For information about MLflow experiments, see [_](/mlflow/experiments.md). - + +The experiment resource allows you to define [MLflow experiments](/api/workspace/experiments/createexperiment) in a bundle. For information about MLflow experiments, see [\_](/mlflow/experiments.md). + ```yaml experiments: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `artifact_location` - String - Location where artifacts for the experiment are stored. - + - - `creation_time` - Integer - Creation time - + - - `experiment_id` - String - Unique identifier for the experiment. - + - - `last_update_time` - Integer - Last update time - + - - `lifecycle_stage` - String - Current life cycle stage of the experiment: "active" or "deleted". Deleted experiments are not returned by APIs. - + - - `name` - String - Human readable name that identifies the experiment. - -- - `permissions` - - Sequence - - See [_](#experimentsnamepermissions). - -- - `tags` - - Sequence - - Tags: Additional metadata key-value pairs. See [_](#experimentsnametags). - -::: - - + + * - `permissions` + - Sequence + - See [\_](#experimentsnamepermissions). + + * - `tags` + - Sequence + - Tags: Additional metadata key-value pairs. See [\_](#experimentsnametags). + **Example** - + The following example defines an experiment that all users can view: ```yaml @@ -1593,185 +1413,177 @@ resources: group_name: users description: MLflow experiment used to track runs ``` - -### experiments.\.permissions - -**`Type: Sequence`** - - - - +### experiments.\.permissions + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + ### experiments.\.tags - + **`Type: Sequence`** - + Tags: Additional metadata key-value pairs. - - - + :::list-table - + - - Key - Type - Description - + - - `key` - String - The tag key. - + - - `value` - String - The tag value. - + ::: - - + ## jobs - + **`Type: Map`** - -The job resource allows you to define [jobs and their corresponding tasks](/api/workspace/jobs/create) in your bundle. For information about jobs, see [_](/jobs/index.md). For a tutorial that uses a Databricks Asset Bundles template to create a job, see [_](/dev-tools/bundles/jobs-tutorial.md). - + +The job resource allows you to define [jobs and their corresponding tasks](/api/workspace/jobs/create) in your bundle. For information about jobs, see [\_](/jobs/index.md). For a tutorial that uses a Databricks Asset Bundles template to create a job, see [\_](/dev-tools/bundles/jobs-tutorial.md). + ```yaml jobs: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `budget_policy_id` - String - The id of the user specified budget policy to use for this job. If not specified, a default budget policy may be applied when creating or modifying the job. See `effective_budget_policy_id` for the budget policy used by this workload. - -- - `continuous` - - Map - - An optional continuous property for this job. The continuous property will ensure that there is always one run executing. Only one of `schedule` and `continuous` can be used. See [_](#jobsnamecontinuous). - -- - `deployment` - - Map - - Deployment information for jobs managed by external sources. See [_](#jobsnamedeployment). - + + * - `continuous` + - Map + - An optional continuous property for this job. The continuous property will ensure that there is always one run executing. Only one of `schedule` and `continuous` can be used. See [\_](#jobsnamecontinuous). + + * - `deployment` + - Map + - Deployment information for jobs managed by external sources. See [\_](#jobsnamedeployment). + - - `description` - String - An optional description for the job. The maximum length is 27700 characters in UTF-8 encoding. - + - - `edit_mode` - String - - Edit mode of the job. * `UI_LOCKED`: The job is in a locked UI state and cannot be modified. * `EDITABLE`: The job is in an editable state and can be modified. - -- - `email_notifications` - - Map - - An optional set of email addresses that is notified when runs of this job begin or complete as well as when this job is deleted. See [_](#jobsnameemail_notifications). - -- - `environments` - - Sequence - - A list of task execution environment specifications that can be referenced by serverless tasks of this job. An environment is required to be present for serverless tasks. For serverless notebook tasks, the environment is accessible in the notebook environment panel. For other serverless tasks, the task environment is required to be specified using environment_key in the task settings. See [_](#jobsnameenvironments). - + - Edit mode of the job. _ `UI_LOCKED`: The job is in a locked UI state and cannot be modified. _ `EDITABLE`: The job is in an editable state and can be modified. + + * - `email_notifications` + - Map + - An optional set of email addresses that is notified when runs of this job begin or complete as well as when this job is deleted. See [\_](#jobsnameemail_notifications). + + * - `environments` + - Sequence + - A list of task execution environment specifications that can be referenced by serverless tasks of this job. An environment is required to be present for serverless tasks. For serverless notebook tasks, the environment is accessible in the notebook environment panel. For other serverless tasks, the task environment is required to be specified using environment*key in the task settings. See [*](#jobsnameenvironments). + - - `format` - String - Used to tell what is the format of the job. This field is ignored in Create/Update/Reset calls. When using the Jobs API 2.1 this value is always set to `"MULTI_TASK"`. - -- - `git_source` - - Map - - An optional specification for a remote Git repository containing the source code used by tasks. Version-controlled source code is supported by notebook, dbt, Python script, and SQL File tasks. If `git_source` is set, these tasks retrieve the file from the remote repository by default. However, this behavior can be overridden by setting `source` to `WORKSPACE` on the task. Note: dbt and SQL File tasks support only version-controlled sources. If dbt or SQL File tasks are used, `git_source` must be defined on the job. See [_](#jobsnamegit_source). - -- - `health` - - Map - - An optional set of health rules that can be defined for this job. See [_](#jobsnamehealth). - -- - `job_clusters` - - Sequence - - A list of job cluster specifications that can be shared and reused by tasks of this job. Libraries cannot be declared in a shared job cluster. You must declare dependent libraries in task settings. If more than 100 job clusters are available, you can paginate through them using :method:jobs/get. See [_](#jobsnamejob_clusters). - + + * - `git_source` + - Map + - An optional specification for a remote Git repository containing the source code used by tasks. Version-controlled source code is supported by notebook, dbt, Python script, and SQL File tasks. If `git_source` is set, these tasks retrieve the file from the remote repository by default. However, this behavior can be overridden by setting `source` to `WORKSPACE` on the task. Note: dbt and SQL File tasks support only version-controlled sources. If dbt or SQL File tasks are used, `git_source` must be defined on the job. See [\_](#jobsnamegit_source). + + * - `health` + - Map + - An optional set of health rules that can be defined for this job. See [\_](#jobsnamehealth). + + * - `job_clusters` + - Sequence + - A list of job cluster specifications that can be shared and reused by tasks of this job. Libraries cannot be declared in a shared job cluster. You must declare dependent libraries in task settings. If more than 100 job clusters are available, you can paginate through them using :method:jobs/get. See [\_](#jobsnamejob_clusters). + - - `max_concurrent_runs` - Integer - An optional maximum allowed number of concurrent runs of the job. Set this value if you want to be able to execute multiple runs of the same job concurrently. This is useful for example if you trigger your job on a frequent schedule and want to allow consecutive runs to overlap with each other, or if you want to trigger multiple runs which differ by their input parameters. This setting affects only new runs. For example, suppose the job’s concurrency is 4 and there are 4 concurrent active runs. Then setting the concurrency to 3 won’t kill any of the active runs. However, from then on, new runs are skipped unless there are fewer than 3 active runs. This value cannot exceed 1000. Setting this value to `0` causes all new runs to be skipped. - + - - `name` - String - An optional name for the job. The maximum length is 4096 bytes in UTF-8 encoding. - -- - `notification_settings` - - Map - - Optional notification settings that are used when sending notifications to each of the `email_notifications` and `webhook_notifications` for this job. See [_](#jobsnamenotification_settings). - -- - `parameters` - - Sequence - - Job-level parameter definitions. See [_](#jobsnameparameters). - -- - `permissions` - - Sequence - - See [_](#jobsnamepermissions). - -- - `queue` - - Map - - The queue settings of the job. See [_](#jobsnamequeue). - -- - `run_as` - - Map - - Write-only setting. Specifies the user or service principal that the job runs as. If not specified, the job runs as the user who created the job. Either `user_name` or `service_principal_name` should be specified. If not, an error is thrown. See [_](#jobsnamerun_as). - -- - `schedule` - - Map - - An optional periodic schedule for this job. The default behavior is that the job only runs when triggered by clicking “Run Now” in the Jobs UI or sending an API request to `runNow`. See [_](#jobsnameschedule). - + + * - `notification_settings` + - Map + - Optional notification settings that are used when sending notifications to each of the `email_notifications` and `webhook_notifications` for this job. See [\_](#jobsnamenotification_settings). + + * - `parameters` + - Sequence + - Job-level parameter definitions. See [\_](#jobsnameparameters). + + * - `performance_target` + - String + - PerformanceTarget defines how performant or cost efficient the execution of run on serverless should be. + + * - `permissions` + - Sequence + - See [\_](#jobsnamepermissions). + + * - `queue` + - Map + - The queue settings of the job. See [\_](#jobsnamequeue). + + * - `run_as` + - Map + - Write-only setting. Specifies the user or service principal that the job runs as. If not specified, the job runs as the user who created the job. Either `user_name` or `service_principal_name` should be specified. If not, an error is thrown. See [\_](#jobsnamerun_as). + + * - `schedule` + - Map + - An optional periodic schedule for this job. The default behavior is that the job only runs when triggered by clicking “Run Now” in the Jobs UI or sending an API request to `runNow`. See [\_](#jobsnameschedule). + - - `tags` - Map - A map of tags associated with the job. These are forwarded to the cluster as cluster tags for jobs clusters, and are subject to the same limitations as cluster tags. A maximum of 25 tags can be added to the job. - -- - `tasks` - - Sequence - - A list of task specifications to be executed by this job. If more than 100 tasks are available, you can paginate through them using :method:jobs/get. Use the `next_page_token` field at the object root to determine if more results are available. See [_](#jobsnametasks). - + + * - `tasks` + - Sequence + - A list of task specifications to be executed by this job. If more than 100 tasks are available, you can paginate through them using :method:jobs/get. Use the `next_page_token` field at the object root to determine if more results are available. See [\_](#jobsnametasks). + - - `timeout_seconds` - Integer - An optional timeout applied to each run of this job. A value of `0` means no timeout. - -- - `trigger` - - Map - - A configuration to trigger a run when certain conditions are met. The default behavior is that the job runs only when triggered by clicking “Run Now” in the Jobs UI or sending an API request to `runNow`. See [_](#jobsnametrigger). - -- - `webhook_notifications` - - Map - - A collection of system notification IDs to notify when runs of this job begin or complete. See [_](#jobsnamewebhook_notifications). - -::: - - + + * - `trigger` + - Map + - A configuration to trigger a run when certain conditions are met. The default behavior is that the job runs only when triggered by clicking “Run Now” in the Jobs UI or sending an API request to `runNow`. See [\_](#jobsnametrigger). + + * - `webhook_notifications` + - Map + - A collection of system notification IDs to notify when runs of this job begin or complete. See [\_](#jobsnamewebhook_notifications). + **Example** - + The following example defines a job with the resource key `hello-job` with one notebook task: ```yaml @@ -1785,2750 +1597,2460 @@ resources: notebook_path: ./hello.py ``` -For information about defining job tasks and overriding job settings, see [_](/dev-tools/bundles/job-task-types.md), [_](/dev-tools/bundles/job-task-override.md), and [_](/dev-tools/bundles/cluster-override.md). - +For information about defining job tasks and overriding job settings, see [\_](/dev-tools/bundles/job-task-types.md), [\_](/dev-tools/bundles/job-task-override.md), and [\_](/dev-tools/bundles/cluster-override.md). + ### jobs.\.continuous - + **`Type: Map`** - + An optional continuous property for this job. The continuous property will ensure that there is always one run executing. Only one of `schedule` and `continuous` can be used. - - - + :::list-table - + - - Key - Type - Description - + - - `pause_status` - String - Indicate whether the continuous execution of the job is paused or not. Defaults to UNPAUSED. - + ::: - - + ### jobs.\.deployment - + **`Type: Map`** - + Deployment information for jobs managed by external sources. - - - + :::list-table - + - - Key - Type - Description - + - - `kind` - String - - The kind of deployment that manages the job. * `BUNDLE`: The job is managed by Databricks Asset Bundle. - + - The kind of deployment that manages the job. \* `BUNDLE`: The job is managed by Databricks Asset Bundle. + - - `metadata_file_path` - String - Path of the file that contains deployment metadata. - + ::: - - + ### jobs.\.email_notifications - + **`Type: Map`** - + An optional set of email addresses that is notified when runs of this job begin or complete as well as when this job is deleted. - - - + :::list-table - + - - Key - Type - Description - + - - `no_alert_for_skipped_runs` - Boolean - If true, do not send email to recipients specified in `on_failure` if the run is skipped. This field is `deprecated`. Please use the `notification_settings.no_alert_for_skipped_runs` field. - + - - `on_duration_warning_threshold_exceeded` - Sequence - A list of email addresses to be notified when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. If no rule for the `RUN_DURATION_SECONDS` metric is specified in the `health` field for the job, notifications are not sent. - + - - `on_failure` - Sequence - A list of email addresses to be notified when a run unsuccessfully completes. A run is considered to have completed unsuccessfully if it ends with an `INTERNAL_ERROR` `life_cycle_state` or a `FAILED`, or `TIMED_OUT` result_state. If this is not specified on job creation, reset, or update the list is empty, and notifications are not sent. - + - - `on_start` - Sequence - A list of email addresses to be notified when a run begins. If not specified on job creation, reset, or update, the list is empty, and notifications are not sent. - + - - `on_streaming_backlog_exceeded` - Sequence - A list of email addresses to notify when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. - + - - `on_success` - Sequence - A list of email addresses to be notified when a run successfully completes. A run is considered to have completed successfully if it ends with a `TERMINATED` `life_cycle_state` and a `SUCCESS` result_state. If not specified on job creation, reset, or update, the list is empty, and notifications are not sent. - + ::: - - + ### jobs.\.environments - + **`Type: Sequence`** - + A list of task execution environment specifications that can be referenced by serverless tasks of this job. An environment is required to be present for serverless tasks. For serverless notebook tasks, the environment is accessible in the notebook environment panel. For other serverless tasks, the task environment is required to be specified using environment_key in the task settings. - - - + :::list-table - + - - Key - Type - Description - + - - `environment_key` - String - The key of an environment. It has to be unique within a job. - -- - `spec` - - Map - - The environment entity used to preserve serverless environment side panel and jobs' environment for non-notebook task. In this minimal environment spec, only pip dependencies are supported. See [_](#jobsnameenvironmentsspec). - -::: - - + + * - `spec` + - Map + - The environment entity used to preserve serverless environment side panel and jobs' environment for non-notebook task. In this minimal environment spec, only pip dependencies are supported. See [\_](#jobsnameenvironmentsspec). + ### jobs.\.environments.spec - + **`Type: Map`** - + The environment entity used to preserve serverless environment side panel and jobs' environment for non-notebook task. In this minimal environment spec, only pip dependencies are supported. - - - + :::list-table - + - - Key - Type - Description - + - - `client` - String - Client version used by the environment The client is the user-facing environment of the runtime. Each client comes with a specific set of pre-installed libraries. The version is a string, consisting of the major client version. - + - - `dependencies` - Sequence - - - + - + ::: - - + ### jobs.\.git_source - + **`Type: Map`** - + An optional specification for a remote Git repository containing the source code used by tasks. Version-controlled source code is supported by notebook, dbt, Python script, and SQL File tasks. If `git_source` is set, these tasks retrieve the file from the remote repository by default. However, this behavior can be overridden by setting `source` to `WORKSPACE` on the task. Note: dbt and SQL File tasks support only version-controlled sources. If dbt or SQL File tasks are used, `git_source` must be defined on the job. - - - + :::list-table - + - - Key - Type - Description - + - - `git_branch` - String - Name of the branch to be checked out and used by this job. This field cannot be specified in conjunction with git_tag or git_commit. - + - - `git_commit` - String - Commit to be checked out and used by this job. This field cannot be specified in conjunction with git_branch or git_tag. - + - - `git_provider` - String - Unique identifier of the service used to host the Git repository. The value is case insensitive. - -- - `git_snapshot` - - Map - - Read-only state of the remote repository at the time the job was run. This field is only included on job runs. See [_](#jobsnamegit_sourcegit_snapshot). - + + * - `git_snapshot` + - Map + - Read-only state of the remote repository at the time the job was run. This field is only included on job runs. See [\_](#jobsnamegit_sourcegit_snapshot). + - - `git_tag` - String - Name of the tag to be checked out and used by this job. This field cannot be specified in conjunction with git_branch or git_commit. - + - - `git_url` - String - URL of the repository to be cloned by this job. - -- - `job_source` - - Map - - The source of the job specification in the remote repository when the job is source controlled. See [_](#jobsnamegit_sourcejob_source). - -::: - - + + * - `job_source` + - Map + - The source of the job specification in the remote repository when the job is source controlled. See [\_](#jobsnamegit_sourcejob_source). + ### jobs.\.git_source.git_snapshot - + **`Type: Map`** - + Read-only state of the remote repository at the time the job was run. This field is only included on job runs. - - - + :::list-table - + - - Key - Type - Description - + - - `used_commit` - String - Commit that was used to execute the run. If git_branch was specified, this points to the HEAD of the branch at the time of the run; if git_tag was specified, this points to the commit the tag points to. - + ::: - - + ### jobs.\.git_source.job_source - + **`Type: Map`** - + The source of the job specification in the remote repository when the job is source controlled. - - - + :::list-table - + - - Key - Type - Description - + - - `dirty_state` - String - - Dirty state indicates the job is not fully synced with the job specification in the remote repository. Possible values are: * `NOT_SYNCED`: The job is not yet synced with the remote job specification. Import the remote job specification from UI to make the job fully synced. * `DISCONNECTED`: The job is temporary disconnected from the remote job specification and is allowed for live edit. Import the remote job specification again from UI to make the job fully synced. - + - Dirty state indicates the job is not fully synced with the job specification in the remote repository. Possible values are: _ `NOT_SYNCED`: The job is not yet synced with the remote job specification. Import the remote job specification from UI to make the job fully synced. _ `DISCONNECTED`: The job is temporary disconnected from the remote job specification and is allowed for live edit. Import the remote job specification again from UI to make the job fully synced. + - - `import_from_git_branch` - String - Name of the branch which the job is imported from. - + - - `job_config_path` - String - Path of the job YAML file that contains the job specification. - -::: - - -### jobs.\.health - -**`Type: Map`** - -An optional set of health rules that can be defined for this job. - - - -:::list-table - -- - Key - - Type - - Description - -- - `rules` - - Sequence - - See [_](#jobsnamehealthrules). - -::: - - -### jobs.\.health.rules - -**`Type: Sequence`** - - - - +::: + +### jobs.\.health + +**`Type: Map`** + +An optional set of health rules that can be defined for this job. + :::list-table - + - - Key - Type - Description - + + * - `rules` + - Sequence + - See [\_](#jobsnamehealthrules). + +### jobs.\.health.rules + +**`Type: Sequence`** + +:::list-table + +- - Key + - Type + - Description + - - `metric` - String - - Specifies the health metric that is being evaluated for a particular health rule. * `RUN_DURATION_SECONDS`: Expected total time for a run in seconds. * `STREAMING_BACKLOG_BYTES`: An estimate of the maximum bytes of data waiting to be consumed across all streams. This metric is in Public Preview. * `STREAMING_BACKLOG_RECORDS`: An estimate of the maximum offset lag across all streams. This metric is in Public Preview. * `STREAMING_BACKLOG_SECONDS`: An estimate of the maximum consumer delay across all streams. This metric is in Public Preview. * `STREAMING_BACKLOG_FILES`: An estimate of the maximum number of outstanding files across all streams. This metric is in Public Preview. - + - Specifies the health metric that is being evaluated for a particular health rule. _ `RUN_DURATION_SECONDS`: Expected total time for a run in seconds. _ `STREAMING_BACKLOG_BYTES`: An estimate of the maximum bytes of data waiting to be consumed across all streams. This metric is in Public Preview. _ `STREAMING_BACKLOG_RECORDS`: An estimate of the maximum offset lag across all streams. This metric is in Public Preview. _ `STREAMING_BACKLOG_SECONDS`: An estimate of the maximum consumer delay across all streams. This metric is in Public Preview. \* `STREAMING_BACKLOG_FILES`: An estimate of the maximum number of outstanding files across all streams. This metric is in Public Preview. + - - `op` - String - Specifies the operator used to compare the health metric value with the specified threshold. - + - - `value` - Integer - Specifies the threshold value that the health metric should obey to satisfy the health rule. - + ::: - - + ### jobs.\.job_clusters - + **`Type: Sequence`** - + A list of job cluster specifications that can be shared and reused by tasks of this job. Libraries cannot be declared in a shared job cluster. You must declare dependent libraries in task settings. If more than 100 job clusters are available, you can paginate through them using :method:jobs/get. - - - + :::list-table - + - - Key - Type - Description - + - - `job_cluster_key` - String - A unique name for the job cluster. This field is required and must be unique within the job. `JobTaskSettings` may refer to this field to determine which cluster to launch for the task execution. - -- - `new_cluster` - - Map - - If new_cluster, a description of a cluster that is created for each task. See [_](#jobsnamejob_clustersnew_cluster). - -::: - - + + * - `new_cluster` + - Map + - If new*cluster, a description of a cluster that is created for each task. See [*](#jobsnamejob_clustersnew_cluster). + ### jobs.\.job_clusters.new_cluster - + **`Type: Map`** - + If new_cluster, a description of a cluster that is created for each task. - - - + :::list-table - + - - Key - Type - Description - + - - `apply_policy_default_values` - Boolean - When set to true, fixed and default values from the policy will be used for fields that are omitted. When set to false, only fixed values from the policy will be applied. - -- - `autoscale` - - Map - - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [_](#jobsnamejob_clustersnew_clusterautoscale). - + + * - `autoscale` + - Map + - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [\_](#jobsnamejob_clustersnew_clusterautoscale). + - - `autotermination_minutes` - Integer - Automatically terminates the cluster after it is inactive for this time in minutes. If not set, this cluster will not be automatically terminated. If specified, the threshold must be between 10 and 10000 minutes. Users can also set this value to 0 to explicitly disable automatic termination. - -- - `aws_attributes` - - Map - - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [_](#jobsnamejob_clustersnew_clusteraws_attributes). - -- - `azure_attributes` - - Map - - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [_](#jobsnamejob_clustersnew_clusterazure_attributes). - -- - `cluster_log_conf` - - Map - - The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. See [_](#jobsnamejob_clustersnew_clustercluster_log_conf). - + + * - `aws_attributes` + - Map + - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [\_](#jobsnamejob_clustersnew_clusteraws_attributes). + + * - `azure_attributes` + - Map + - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [\_](#jobsnamejob_clustersnew_clusterazure_attributes). + + * - `cluster_log_conf` + - Map + - The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. See [\_](#jobsnamejob_clustersnew_clustercluster_log_conf). + - - `cluster_name` - String - - Cluster name requested by the user. This doesn't have to be unique. If not specified at creation, the cluster name will be an empty string. - + - Cluster name requested by the user. This doesn't have to be unique. If not specified at creation, the cluster name will be an empty string. + - - `custom_tags` - Map - - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags - + - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags + - - `data_security_mode` - String - - Data security mode decides what data governance model to use when accessing data from a cluster. The following modes can only be used with `kind`. * `DATA_SECURITY_MODE_AUTO`: Databricks will choose the most appropriate access mode depending on your compute configuration. * `DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`. * `DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`. The following modes can be used regardless of `kind`. * `NONE`: No security isolation for multiple users sharing the cluster. Data governance features are not available in this mode. * `SINGLE_USER`: A secure cluster that can only be exclusively used by a single user specified in `single_user_name`. Most programming languages, cluster features and data governance features are available in this mode. * `USER_ISOLATION`: A secure cluster that can be shared by multiple users. Cluster users are fully isolated so that they cannot see each other's data and credentials. Most data governance features are supported in this mode. But programming languages and cluster features might be limited. The following modes are deprecated starting with Databricks Runtime 15.0 and will be removed for future Databricks Runtime versions: * `LEGACY_TABLE_ACL`: This mode is for users migrating from legacy Table ACL clusters. * `LEGACY_PASSTHROUGH`: This mode is for users migrating from legacy Passthrough on high concurrency clusters. * `LEGACY_SINGLE_USER`: This mode is for users migrating from legacy Passthrough on standard clusters. * `LEGACY_SINGLE_USER_STANDARD`: This mode provides a way that doesn’t have UC nor passthrough enabled. - -- - `docker_image` - - Map - - See [_](#jobsnamejob_clustersnew_clusterdocker_image). - + - Data security mode decides what data governance model to use when accessing data from a cluster. The following modes can only be used with `kind`. _ `DATA_SECURITY_MODE_AUTO`: Databricks will choose the most appropriate access mode depending on your compute configuration. _ `DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`. _ `DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`. The following modes can be used regardless of `kind`. _ `NONE`: No security isolation for multiple users sharing the cluster. Data governance features are not available in this mode. _ `SINGLE_USER`: A secure cluster that can only be exclusively used by a single user specified in `single_user_name`. Most programming languages, cluster features and data governance features are available in this mode. _ `USER_ISOLATION`: A secure cluster that can be shared by multiple users. Cluster users are fully isolated so that they cannot see each other's data and credentials. Most data governance features are supported in this mode. But programming languages and cluster features might be limited. The following modes are deprecated starting with Databricks Runtime 15.0 and will be removed for future Databricks Runtime versions: _ `LEGACY_TABLE_ACL`: This mode is for users migrating from legacy Table ACL clusters. _ `LEGACY_PASSTHROUGH`: This mode is for users migrating from legacy Passthrough on high concurrency clusters. _ `LEGACY_SINGLE_USER`: This mode is for users migrating from legacy Passthrough on standard clusters. _ `LEGACY_SINGLE_USER_STANDARD`: This mode provides a way that doesn’t have UC nor passthrough enabled. + + * - `docker_image` + - Map + - See [\_](#jobsnamejob_clustersnew_clusterdocker_image). + - - `driver_instance_pool_id` - String - The optional ID of the instance pool for the driver of the cluster belongs. The pool cluster uses the instance pool with id (instance_pool_id) if the driver pool is not assigned. - + - - `driver_node_type_id` - String - - The node type of the Spark driver. Note that this field is optional; if unset, the driver node type will be set as the same value as `node_type_id` defined above. - + - The node type of the Spark driver. Note that this field is optional; if unset, the driver node type will be set as the same value as `node_type_id` defined above. + - - `enable_elastic_disk` - Boolean - Autoscaling Local Storage: when enabled, this cluster will dynamically acquire additional disk space when its Spark workers are running low on disk space. This feature requires specific AWS permissions to function correctly - refer to the User Guide for more details. - + - - `enable_local_disk_encryption` - Boolean - Whether to enable LUKS on cluster VMs' local disks - -- - `gcp_attributes` - - Map - - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [_](#jobsnamejob_clustersnew_clustergcp_attributes). - -- - `init_scripts` - - Sequence - - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [_](#jobsnamejob_clustersnew_clusterinit_scripts). - + + * - `gcp_attributes` + - Map + - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [\_](#jobsnamejob_clustersnew_clustergcp_attributes). + + * - `init_scripts` + - Sequence + - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [\_](#jobsnamejob_clustersnew_clusterinit_scripts). + - - `instance_pool_id` - String - The optional ID of the instance pool to which the cluster belongs. - + - - `is_single_node` - Boolean - - This field can only be used with `kind`. When set to true, Databricks will automatically set single node related `custom_tags`, `spark_conf`, and `num_workers` - + - This field can only be used with `kind`. When set to true, Databricks will automatically set single node related `custom_tags`, `spark_conf`, and `num_workers` + - - `kind` - String - - - + - + - - `node_type_id` - String - - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. - + - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. + - - `num_workers` - Integer - - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. - + - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. + - - `policy_id` - String - The ID of the cluster policy used to create the cluster if applicable. - + - - `runtime_engine` - String - - Determines the cluster's runtime engine, either standard or Photon. This field is not compatible with legacy `spark_version` values that contain `-photon-`. Remove `-photon-` from the `spark_version` and set `runtime_engine` to `PHOTON`. If left unspecified, the runtime engine defaults to standard unless the spark_version contains -photon-, in which case Photon will be used. - + - Determines the cluster's runtime engine, either standard or Photon. This field is not compatible with legacy `spark_version` values that contain `-photon-`. Remove `-photon-` from the `spark_version` and set `runtime_engine` to `PHOTON`. If left unspecified, the runtime engine defaults to standard unless the spark_version contains -photon-, in which case Photon will be used. + - - `single_user_name` - String - Single user name if data_security_mode is `SINGLE_USER` - + - - `spark_conf` - Map - - An object containing a set of optional, user-specified Spark configuration key-value pairs. Users can also pass in a string of extra JVM options to the driver and the executors via `spark.driver.extraJavaOptions` and `spark.executor.extraJavaOptions` respectively. - + - An object containing a set of optional, user-specified Spark configuration key-value pairs. Users can also pass in a string of extra JVM options to the driver and the executors via `spark.driver.extraJavaOptions` and `spark.executor.extraJavaOptions` respectively. + - - `spark_env_vars` - Map - - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` - + - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` + - - `spark_version` - String - - The Spark version of the cluster, e.g. `3.3.x-scala2.11`. A list of available Spark versions can be retrieved by using the :method:clusters/sparkVersions API call. - + - The Spark version of the cluster, e.g. `3.3.x-scala2.11`. A list of available Spark versions can be retrieved by using the :method:clusters/sparkVersions API call. + - - `ssh_public_keys` - Sequence - SSH public key contents that will be added to each Spark node in this cluster. The corresponding private keys can be used to login with the user name `ubuntu` on port `2200`. Up to 10 keys can be specified. - + - - `use_ml_runtime` - Boolean - - This field can only be used with `kind`. `effective_spark_version` is determined by `spark_version` (DBR release), this field `use_ml_runtime`, and whether `node_type_id` is gpu node or not. - -- - `workload_type` - - Map - - See [_](#jobsnamejob_clustersnew_clusterworkload_type). - -::: - - + - This field can only be used with `kind`. `effective_spark_version` is determined by `spark_version` (DBR release), this field `use_ml_runtime`, and whether `node_type_id` is gpu node or not. + + * - `workload_type` + - Map + - See [\_](#jobsnamejob_clustersnew_clusterworkload_type). + ### jobs.\.job_clusters.new_cluster.autoscale - + **`Type: Map`** - + Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. - - - + :::list-table - + - - Key - Type - Description - + - - `max_workers` - Integer - The maximum number of workers to which the cluster can scale up when overloaded. Note that `max_workers` must be strictly greater than `min_workers`. - + - - `min_workers` - Integer - The minimum number of workers to which the cluster can scale down when underutilized. It is also the initial number of workers the cluster will have after creation. - + ::: - - + ### jobs.\.job_clusters.new_cluster.aws_attributes - + **`Type: Map`** - + Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. - + - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. + - - `ebs_volume_count` - Integer - - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. - + - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. + - - `ebs_volume_iops` - Integer - If using gp3 volumes, what IOPS to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_size` - Integer - The size of each EBS volume (in GiB) launched for each instance. For general purpose SSD, this value must be within the range 100 - 4096. For throughput optimized HDD, this value must be within the range 500 - 4096. - + - - `ebs_volume_throughput` - Integer - If using gp3 volumes, what throughput to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_type` - String - The type of EBS volumes that will be launched with this cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. If this value is greater than 0, the cluster driver node in particular will be placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - + - - `instance_profile_arn` - String - - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. - + - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. + - - `spot_bid_price_percent` - Integer - - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. - + - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. + - - `zone_id` - String - Identifier for the availability zone/datacenter in which the cluster resides. This string will be of a form like "us-west-2a". The provided availability zone must be in the same region as the Databricks deployment. For example, "us-west-2a" is not a valid zone id if the Databricks deployment resides in the "us-east-1" region. This is an optional field at cluster creation, and if not specified, a default zone will be used. If the zone specified is "auto", will try to place cluster in a zone with high availability, and will retry placement in a different AZ if there is not enough capacity. The list of available zones as well as the default value can be found by using the `List Zones` method. - + ::: - - + ### jobs.\.job_clusters.new_cluster.azure_attributes - + **`Type: Map`** - + Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero (which only happens on pool clusters), this availability type will be used for the entire cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. This value should be greater than 0, to make sure the cluster driver node is placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - -- - `log_analytics_info` - - Map - - Defines values necessary to configure and run Azure Log Analytics agent. See [_](#jobsnamejob_clustersnew_clusterazure_attributeslog_analytics_info). - + + * - `log_analytics_info` + - Map + - Defines values necessary to configure and run Azure Log Analytics agent. See [\_](#jobsnamejob_clustersnew_clusterazure_attributeslog_analytics_info). + - - `spot_bid_max_price` - Any - The max bid price to be used for Azure spot instances. The Max price for the bid cannot be higher than the on-demand price of the instance. If not specified, the default value is -1, which specifies that the instance cannot be evicted on the basis of price, and only on the basis of availability. Further, the value should > 0 or -1. - + ::: - - + ### jobs.\.job_clusters.new_cluster.azure_attributes.log_analytics_info - + **`Type: Map`** - + Defines values necessary to configure and run Azure Log Analytics agent - - - + :::list-table - + - - Key - Type - Description - + - - `log_analytics_primary_key` - String - - - + - + - - `log_analytics_workspace_id` - String - - - + - + ::: - - + ### jobs.\.job_clusters.new_cluster.cluster_log_conf - + **`Type: Map`** - + The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. - - - + :::list-table - + - - Key - Type - Description - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#jobsnamejob_clustersnew_clustercluster_log_confdbfs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#jobsnamejob_clustersnew_clustercluster_log_confs3). - -::: - - + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#jobsnamejob_clustersnew_clustercluster_log_confdbfs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#jobsnamejob_clustersnew_clustercluster_log_confs3). + ### jobs.\.job_clusters.new_cluster.cluster_log_conf.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### jobs.\.job_clusters.new_cluster.cluster_log_conf.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - -::: - - -### jobs.\.job_clusters.new_cluster.docker_image - -**`Type: Map`** - - - - +::: + +### jobs.\.job_clusters.new_cluster.docker_image + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - -- - `basic_auth` - - Map - - See [_](#jobsnamejob_clustersnew_clusterdocker_imagebasic_auth). - + + * - `basic_auth` + - Map + - See [\_](#jobsnamejob_clustersnew_clusterdocker_imagebasic_auth). + - - `url` - String - URL of the docker image. - -::: - - -### jobs.\.job_clusters.new_cluster.docker_image.basic_auth - -**`Type: Map`** - - - - +::: + +### jobs.\.job_clusters.new_cluster.docker_image.basic_auth + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - + - - `password` - String - Password of the user - + - - `username` - String - Name of the user - + ::: - - + ### jobs.\.job_clusters.new_cluster.gcp_attributes - + **`Type: Map`** - + Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - This field determines whether the instance pool will contain preemptible VMs, on-demand VMs, or preemptible VMs with a fallback to on-demand VMs if the former is unavailable. - + - - `boot_disk_size` - Integer - boot disk size in GB - + - - `google_service_account` - String - If provided, the cluster will impersonate the google service account when accessing gcloud services (like GCS). The google service account must have previously been added to the Databricks environment by an account administrator. - + - - `local_ssd_count` - Integer - If provided, each node (workers and driver) in the cluster will have this number of local SSDs attached. Each local SSD is 375GB in size. Refer to [GCP documentation](https://cloud.google.com/compute/docs/disks/local-ssd#choose_number_local_ssds) for the supported number of local SSDs for each instance type. - + - - `use_preemptible_executors` - Boolean - This field determines whether the spark executors will be scheduled to run on preemptible VMs (when set to true) versus standard compute engine VMs (when set to false; default). Note: Soon to be deprecated, use the availability field instead. - + - - `zone_id` - String - Identifier for the availability zone in which the cluster resides. This can be one of the following: - "HA" => High availability, spread nodes across availability zones for a Databricks deployment region [default] - "AUTO" => Databricks picks an availability zone to schedule the cluster on. - A GCP availability zone => Pick One of the available zones for (machine type + region) from https://cloud.google.com/compute/docs/regions-zones. - -::: - - -### jobs.\.job_clusters.new_cluster.init_scripts - -**`Type: Sequence`** - -The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. - - - -:::list-table - -- - Key - - Type - - Description - -- - `abfss` - - Map - - See [_](#jobsnamejob_clustersnew_clusterinit_scriptsabfss). - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#jobsnamejob_clustersnew_clusterinit_scriptsdbfs). - -- - `file` - - Map - - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [_](#jobsnamejob_clustersnew_clusterinit_scriptsfile). - -- - `gcs` - - Map - - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [_](#jobsnamejob_clustersnew_clusterinit_scriptsgcs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#jobsnamejob_clustersnew_clusterinit_scriptss3). - -- - `volumes` - - Map - - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [_](#jobsnamejob_clustersnew_clusterinit_scriptsvolumes). - -- - `workspace` - - Map - - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [_](#jobsnamejob_clustersnew_clusterinit_scriptsworkspace). - -::: - - -### jobs.\.job_clusters.new_cluster.init_scripts.abfss - -**`Type: Map`** - - - - +::: + +### jobs.\.job_clusters.new_cluster.init_scripts + +**`Type: Sequence`** + +The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. + :::list-table - + - - Key - Type - Description - + + * - `abfss` + - Map + - destination needs to be provided. e.g. `{ "abfss" : { "destination" : "abfss://@.dfs.core.windows.net/" } }. See [\_](#jobsnamejob_clustersnew_clusterinit_scriptsabfss). + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#jobsnamejob_clustersnew_clusterinit_scriptsdbfs). + + * - `file` + - Map + - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [\_](#jobsnamejob_clustersnew_clusterinit_scriptsfile). + + * - `gcs` + - Map + - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [\_](#jobsnamejob_clustersnew_clusterinit_scriptsgcs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#jobsnamejob_clustersnew_clusterinit_scriptss3). + + * - `volumes` + - Map + - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [\_](#jobsnamejob_clustersnew_clusterinit_scriptsvolumes). + + * - `workspace` + - Map + - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [\_](#jobsnamejob_clustersnew_clusterinit_scriptsworkspace). + +### jobs.\.job_clusters.new_cluster.init_scripts.abfss + +**`Type: Map`** + +:::list-table + +- - Key + - Type + - Description + - - `destination` - String - abfss destination, e.g. `abfss://@.dfs.core.windows.net/`. - + ::: - - + ### jobs.\.job_clusters.new_cluster.init_scripts.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### jobs.\.job_clusters.new_cluster.init_scripts.file - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - local file destination, e.g. `file:/my/local/file.sh` - + ::: - - + ### jobs.\.job_clusters.new_cluster.init_scripts.gcs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - GCS destination/URI, e.g. `gs://my-bucket/some-prefix` - + ::: - - + ### jobs.\.job_clusters.new_cluster.init_scripts.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + ::: - - + ### jobs.\.job_clusters.new_cluster.init_scripts.volumes - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - Unity Catalog Volumes file destination, e.g. `/Volumes/my-init.sh` - + ::: - - + ### jobs.\.job_clusters.new_cluster.init_scripts.workspace - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - workspace files destination, e.g. `/Users/user1@databricks.com/my-init.sh` - -::: - - -### jobs.\.job_clusters.new_cluster.workload_type - -**`Type: Map`** - - - - -:::list-table - -- - Key - - Type - - Description - -- - `clients` - - Map - - defined what type of clients can use the cluster. E.g. Notebooks, Jobs. See [_](#jobsnamejob_clustersnew_clusterworkload_typeclients). - ::: - - -### jobs.\.job_clusters.new_cluster.workload_type.clients - + +### jobs.\.job_clusters.new_cluster.workload_type + **`Type: Map`** - - defined what type of clients can use the cluster. E.g. Notebooks, Jobs - - - + :::list-table - + - - Key - Type - Description - + + * - `clients` + - Map + - defined what type of clients can use the cluster. E.g. Notebooks, Jobs. See [\_](#jobsnamejob_clustersnew_clusterworkload_typeclients). + +### jobs.\.job_clusters.new_cluster.workload_type.clients + +**`Type: Map`** + +defined what type of clients can use the cluster. E.g. Notebooks, Jobs + +:::list-table + +- - Key + - Type + - Description + - - `jobs` - Boolean - With jobs set, the cluster can be used for jobs - + - - `notebooks` - Boolean - With notebooks set, this cluster can be used for notebooks - + ::: - - + ### jobs.\.notification_settings - + **`Type: Map`** - + Optional notification settings that are used when sending notifications to each of the `email_notifications` and `webhook_notifications` for this job. - - - + :::list-table - + - - Key - Type - Description - + - - `no_alert_for_canceled_runs` - Boolean - If true, do not send notifications to recipients specified in `on_failure` if the run is canceled. - + - - `no_alert_for_skipped_runs` - Boolean - If true, do not send notifications to recipients specified in `on_failure` if the run is skipped. - + ::: - - + ### jobs.\.parameters - + **`Type: Sequence`** - + Job-level parameter definitions - - - + :::list-table - + - - Key - Type - Description - + - - `default` - String - Default value of the parameter. - + - - `name` - String - The name of the defined parameter. May only contain alphanumeric characters, `_`, `-`, and `.` - -::: - - -### jobs.\.permissions - -**`Type: Sequence`** - - - - +::: + +### jobs.\.permissions + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + ### jobs.\.queue - + **`Type: Map`** - + The queue settings of the job. - - - + :::list-table - + - - Key - Type - Description - + - - `enabled` - Boolean - If true, enable queueing for the job. This is a required field. - + ::: - - + ### jobs.\.run_as - + **`Type: Map`** - + Write-only setting. Specifies the user or service principal that the job runs as. If not specified, the job runs as the user who created the job. Either `user_name` or `service_principal_name` should be specified. If not, an error is thrown. - - - + :::list-table - + - - Key - Type - Description - + - - `service_principal_name` - String - The application ID of an active service principal. Setting this field requires the `servicePrincipal/user` role. - + - - `user_name` - String - The email of an active workspace user. Non-admin users can only set this field to their own email. - + ::: - - + ### jobs.\.schedule - + **`Type: Map`** - + An optional periodic schedule for this job. The default behavior is that the job only runs when triggered by clicking “Run Now” in the Jobs UI or sending an API request to `runNow`. - - - + :::list-table - + - - Key - Type - Description - + - - `pause_status` - String - Indicate whether this schedule is paused or not. - + - - `quartz_cron_expression` - String - A Cron expression using Quartz syntax that describes the schedule for a job. See [Cron Trigger](http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) for details. This field is required. - + - - `timezone_id` - String - A Java timezone ID. The schedule for a job is resolved with respect to this timezone. See [Java TimeZone](https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html) for details. This field is required. - + ::: - - + ### jobs.\.tasks - + **`Type: Sequence`** - + A list of task specifications to be executed by this job. If more than 100 tasks are available, you can paginate through them using :method:jobs/get. Use the `next_page_token` field at the object root to determine if more results are available. - - - + :::list-table - + - - Key - Type - Description - -- - `clean_rooms_notebook_task` - - Map - - The task runs a [clean rooms](https://docs.databricks.com/en/clean-rooms/index.html) notebook when the `clean_rooms_notebook_task` field is present. See [_](#jobsnametasksclean_rooms_notebook_task). - -- - `condition_task` - - Map - - The task evaluates a condition that can be used to control the execution of other tasks when the `condition_task` field is present. The condition task does not require a cluster to execute and does not support retries or notifications. See [_](#jobsnametaskscondition_task). - -- - `dbt_task` - - Map - - The task runs one or more dbt commands when the `dbt_task` field is present. The dbt task requires both Databricks SQL and the ability to use a serverless or a pro SQL warehouse. See [_](#jobsnametasksdbt_task). - -- - `depends_on` - - Sequence - - An optional array of objects specifying the dependency graph of the task. All tasks specified in this field must complete before executing this task. The task will run only if the `run_if` condition is true. The key is `task_key`, and the value is the name assigned to the dependent task. See [_](#jobsnametasksdepends_on). - + + * - `clean_rooms_notebook_task` + - Map + - The task runs a [clean rooms](https://docs.databricks.com/en/clean-rooms/index.html) notebook when the `clean_rooms_notebook_task` field is present. See [\_](#jobsnametasksclean_rooms_notebook_task). + + * - `condition_task` + - Map + - The task evaluates a condition that can be used to control the execution of other tasks when the `condition_task` field is present. The condition task does not require a cluster to execute and does not support retries or notifications. See [\_](#jobsnametaskscondition_task). + + * - `dbt_task` + - Map + - The task runs one or more dbt commands when the `dbt_task` field is present. The dbt task requires both Databricks SQL and the ability to use a serverless or a pro SQL warehouse. See [\_](#jobsnametasksdbt_task). + + * - `depends_on` + - Sequence + - An optional array of objects specifying the dependency graph of the task. All tasks specified in this field must complete before executing this task. The task will run only if the `run_if` condition is true. The key is `task_key`, and the value is the name assigned to the dependent task. See [\_](#jobsnametasksdepends_on). + - - `description` - String - An optional description for this task. - + - - `disable_auto_optimization` - Boolean - An option to disable auto optimization in serverless - -- - `email_notifications` - - Map - - An optional set of email addresses that is notified when runs of this task begin or complete as well as when this task is deleted. The default behavior is to not send any emails. See [_](#jobsnametasksemail_notifications). - + + * - `email_notifications` + - Map + - An optional set of email addresses that is notified when runs of this task begin or complete as well as when this task is deleted. The default behavior is to not send any emails. See [\_](#jobsnametasksemail_notifications). + - - `environment_key` - String - The key that references an environment spec in a job. This field is required for Python script, Python wheel and dbt tasks when using serverless compute. - + - - `existing_cluster_id` - String - If existing_cluster_id, the ID of an existing cluster that is used for all runs. When running jobs or tasks on an existing cluster, you may need to manually restart the cluster if it stops responding. We suggest running jobs and tasks on new clusters for greater reliability - -- - `for_each_task` - - Map - - The task executes a nested task for every input provided when the `for_each_task` field is present. See [_](#jobsnametasksfor_each_task). - -- - `health` - - Map - - An optional set of health rules that can be defined for this job. See [_](#jobsnametaskshealth). - + + * - `for_each_task` + - Map + - The task executes a nested task for every input provided when the `for_each_task` field is present. See [\_](#jobsnametasksfor_each_task). + + * - `health` + - Map + - An optional set of health rules that can be defined for this job. See [\_](#jobsnametaskshealth). + - - `job_cluster_key` - String - If job_cluster_key, this task is executed reusing the cluster specified in `job.settings.job_clusters`. - -- - `libraries` - - Sequence - - An optional list of libraries to be installed on the cluster. The default value is an empty list. See [_](#jobsnametaskslibraries). - + + * - `libraries` + - Sequence + - An optional list of libraries to be installed on the cluster. The default value is an empty list. See [\_](#jobsnametaskslibraries). + - - `max_retries` - Integer - An optional maximum number of times to retry an unsuccessful run. A run is considered to be unsuccessful if it completes with the `FAILED` result_state or `INTERNAL_ERROR` `life_cycle_state`. The value `-1` means to retry indefinitely and the value `0` means to never retry. - + - - `min_retry_interval_millis` - Integer - An optional minimal interval in milliseconds between the start of the failed run and the subsequent retry run. The default behavior is that unsuccessful runs are immediately retried. - -- - `new_cluster` - - Map - - If new_cluster, a description of a new cluster that is created for each run. See [_](#jobsnametasksnew_cluster). - -- - `notebook_task` - - Map - - The task runs a notebook when the `notebook_task` field is present. See [_](#jobsnametasksnotebook_task). - -- - `notification_settings` - - Map - - Optional notification settings that are used when sending notifications to each of the `email_notifications` and `webhook_notifications` for this task. See [_](#jobsnametasksnotification_settings). - -- - `pipeline_task` - - Map - - The task triggers a pipeline update when the `pipeline_task` field is present. Only pipelines configured to use triggered more are supported. See [_](#jobsnametaskspipeline_task). - -- - `python_wheel_task` - - Map - - The task runs a Python wheel when the `python_wheel_task` field is present. See [_](#jobsnametaskspython_wheel_task). - + + * - `new_cluster` + - Map + - If new*cluster, a description of a new cluster that is created for each run. See [*](#jobsnametasksnew_cluster). + + * - `notebook_task` + - Map + - The task runs a notebook when the `notebook_task` field is present. See [\_](#jobsnametasksnotebook_task). + + * - `notification_settings` + - Map + - Optional notification settings that are used when sending notifications to each of the `email_notifications` and `webhook_notifications` for this task. See [\_](#jobsnametasksnotification_settings). + + * - `pipeline_task` + - Map + - The task triggers a pipeline update when the `pipeline_task` field is present. Only pipelines configured to use triggered more are supported. See [\_](#jobsnametaskspipeline_task). + + * - `python_wheel_task` + - Map + - The task runs a Python wheel when the `python_wheel_task` field is present. See [\_](#jobsnametaskspython_wheel_task). + - - `retry_on_timeout` - Boolean - An optional policy to specify whether to retry a job when it times out. The default behavior is to not retry on timeout. - + - - `run_if` - String - - An optional value specifying the condition determining whether the task is run once its dependencies have been completed. * `ALL_SUCCESS`: All dependencies have executed and succeeded * `AT_LEAST_ONE_SUCCESS`: At least one dependency has succeeded * `NONE_FAILED`: None of the dependencies have failed and at least one was executed * `ALL_DONE`: All dependencies have been completed * `AT_LEAST_ONE_FAILED`: At least one dependency failed * `ALL_FAILED`: ALl dependencies have failed - -- - `run_job_task` - - Map - - The task triggers another job when the `run_job_task` field is present. See [_](#jobsnametasksrun_job_task). - -- - `spark_jar_task` - - Map - - The task runs a JAR when the `spark_jar_task` field is present. See [_](#jobsnametasksspark_jar_task). - -- - `spark_python_task` - - Map - - The task runs a Python file when the `spark_python_task` field is present. See [_](#jobsnametasksspark_python_task). - -- - `spark_submit_task` - - Map - - (Legacy) The task runs the spark-submit script when the `spark_submit_task` field is present. This task can run only on new clusters and is not compatible with serverless compute. In the `new_cluster` specification, `libraries` and `spark_conf` are not supported. Instead, use `--jars` and `--py-files` to add Java and Python libraries and `--conf` to set the Spark configurations. `master`, `deploy-mode`, and `executor-cores` are automatically configured by Databricks; you _cannot_ specify them in parameters. By default, the Spark submit job uses all available memory (excluding reserved memory for Databricks services). You can set `--driver-memory`, and `--executor-memory` to a smaller value to leave some room for off-heap usage. The `--jars`, `--py-files`, `--files` arguments support DBFS and S3 paths. See [_](#jobsnametasksspark_submit_task). - -- - `sql_task` - - Map - - The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when the `sql_task` field is present. See [_](#jobsnametaskssql_task). - + - An optional value specifying the condition determining whether the task is run once its dependencies have been completed. _ `ALL_SUCCESS`: All dependencies have executed and succeeded _ `AT_LEAST_ONE_SUCCESS`: At least one dependency has succeeded _ `NONE_FAILED`: None of the dependencies have failed and at least one was executed _ `ALL_DONE`: All dependencies have been completed _ `AT_LEAST_ONE_FAILED`: At least one dependency failed _ `ALL_FAILED`: ALl dependencies have failed + + * - `run_job_task` + - Map + - The task triggers another job when the `run_job_task` field is present. See [\_](#jobsnametasksrun_job_task). + + * - `spark_jar_task` + - Map + - The task runs a JAR when the `spark_jar_task` field is present. See [\_](#jobsnametasksspark_jar_task). + + * - `spark_python_task` + - Map + - The task runs a Python file when the `spark_python_task` field is present. See [\_](#jobsnametasksspark_python_task). + + * - `spark_submit_task` + - Map + - (Legacy) The task runs the spark-submit script when the `spark_submit_task` field is present. This task can run only on new clusters and is not compatible with serverless compute. In the `new_cluster` specification, `libraries` and `spark_conf` are not supported. Instead, use `--jars` and `--py-files` to add Java and Python libraries and `--conf` to set the Spark configurations. `master`, `deploy-mode`, and `executor-cores` are automatically configured by Databricks; you _cannot_ specify them in parameters. By default, the Spark submit job uses all available memory (excluding reserved memory for Databricks services). You can set `--driver-memory`, and `--executor-memory` to a smaller value to leave some room for off-heap usage. The `--jars`, `--py-files`, `--files` arguments support DBFS and S3 paths. See [\_](#jobsnametasksspark_submit_task). + + * - `sql_task` + - Map + - The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when the `sql_task` field is present. See [\_](#jobsnametaskssql_task). + - - `task_key` - String - A unique name for the task. This field is used to refer to this task from other tasks. This field is required and must be unique within its parent job. On Update or Reset, this field is used to reference the tasks to be updated or reset. - + - - `timeout_seconds` - Integer - An optional timeout applied to each run of this job task. A value of `0` means no timeout. - -- - `webhook_notifications` - - Map - - A collection of system notification IDs to notify when runs of this task begin or complete. The default behavior is to not send any system notifications. See [_](#jobsnametaskswebhook_notifications). - -::: - - + + * - `webhook_notifications` + - Map + - A collection of system notification IDs to notify when runs of this task begin or complete. The default behavior is to not send any system notifications. See [\_](#jobsnametaskswebhook_notifications). + ### jobs.\.tasks.clean_rooms_notebook_task - + **`Type: Map`** - + The task runs a [clean rooms](https://docs.databricks.com/en/clean-rooms/index.html) notebook when the `clean_rooms_notebook_task` field is present. - - - + :::list-table - + - - Key - Type - Description - + - - `clean_room_name` - String - The clean room that the notebook belongs to. - + - - `etag` - String - Checksum to validate the freshness of the notebook resource (i.e. the notebook being run is the latest version). It can be fetched by calling the :method:cleanroomassets/get API. - + - - `notebook_base_parameters` - Map - Base parameters to be used for the clean room notebook job. - + - - `notebook_name` - String - Name of the notebook being run. - + ::: - - + ### jobs.\.tasks.condition_task - + **`Type: Map`** - + The task evaluates a condition that can be used to control the execution of other tasks when the `condition_task` field is present. The condition task does not require a cluster to execute and does not support retries or notifications. - - - + :::list-table - + - - Key - Type - Description - + - - `left` - String - The left operand of the condition task. Can be either a string value or a job state or parameter reference. - + - - `op` - String - - * `EQUAL_TO`, `NOT_EQUAL` operators perform string comparison of their operands. This means that `“12.0” == “12”` will evaluate to `false`. * `GREATER_THAN`, `GREATER_THAN_OR_EQUAL`, `LESS_THAN`, `LESS_THAN_OR_EQUAL` operators perform numeric comparison of their operands. `“12.0” >= “12”` will evaluate to `true`, `“10.0” >= “12”` will evaluate to `false`. The boolean comparison to task values can be implemented with operators `EQUAL_TO`, `NOT_EQUAL`. If a task value was set to a boolean value, it will be serialized to `“true”` or `“false”` for the comparison. - + - - `EQUAL_TO`, `NOT_EQUAL` operators perform string comparison of their operands. This means that `“12.0” == “12”` will evaluate to `false`. \* `GREATER_THAN`, `GREATER_THAN_OR_EQUAL`, `LESS_THAN`, `LESS_THAN_OR_EQUAL` operators perform numeric comparison of their operands. `“12.0” >= “12”` will evaluate to `true`, `“10.0” >= “12”` will evaluate to `false`. The boolean comparison to task values can be implemented with operators `EQUAL_TO`, `NOT_EQUAL`. If a task value was set to a boolean value, it will be serialized to `“true”` or `“false”` for the comparison. + - - `right` - String - The right operand of the condition task. Can be either a string value or a job state or parameter reference. - + ::: - - + ### jobs.\.tasks.dbt_task - + **`Type: Map`** - + The task runs one or more dbt commands when the `dbt_task` field is present. The dbt task requires both Databricks SQL and the ability to use a serverless or a pro SQL warehouse. - - - + :::list-table - + - - Key - Type - Description - + - - `catalog` - String - Optional name of the catalog to use. The value is the top level in the 3-level namespace of Unity Catalog (catalog / schema / relation). The catalog value can only be specified if a warehouse_id is specified. Requires dbt-databricks >= 1.1.1. - + - - `commands` - Sequence - A list of dbt commands to execute. All commands must start with `dbt`. This parameter must not be empty. A maximum of up to 10 commands can be provided. - + - - `profiles_directory` - String - Optional (relative) path to the profiles directory. Can only be specified if no warehouse_id is specified. If no warehouse_id is specified and this folder is unset, the root directory is used. - + - - `project_directory` - String - Path to the project directory. Optional for Git sourced tasks, in which case if no value is provided, the root of the Git repository is used. - + - - `schema` - String - Optional schema to write to. This parameter is only used when a warehouse_id is also provided. If not provided, the `default` schema is used. - + - - `source` - String - - Optional location type of the project directory. When set to `WORKSPACE`, the project will be retrieved from the local Databricks workspace. When set to `GIT`, the project will be retrieved from a Git repository defined in `git_source`. If the value is empty, the task will use `GIT` if `git_source` is defined and `WORKSPACE` otherwise. * `WORKSPACE`: Project is located in Databricks workspace. * `GIT`: Project is located in cloud Git provider. - + - Optional location type of the project directory. When set to `WORKSPACE`, the project will be retrieved from the local Databricks workspace. When set to `GIT`, the project will be retrieved from a Git repository defined in `git_source`. If the value is empty, the task will use `GIT` if `git_source` is defined and `WORKSPACE` otherwise. _ `WORKSPACE`: Project is located in Databricks workspace. _ `GIT`: Project is located in cloud Git provider. + - - `warehouse_id` - String - ID of the SQL warehouse to connect to. If provided, we automatically generate and provide the profile and connection details to dbt. It can be overridden on a per-command basis by using the `--profiles-dir` command line argument. - + ::: - - + ### jobs.\.tasks.depends_on - + **`Type: Sequence`** - + An optional array of objects specifying the dependency graph of the task. All tasks specified in this field must complete before executing this task. The task will run only if the `run_if` condition is true. The key is `task_key`, and the value is the name assigned to the dependent task. - - - + :::list-table - + - - Key - Type - Description - + - - `outcome` - String - Can only be specified on condition task dependencies. The outcome of the dependent task that must be met for this task to run. - + - - `task_key` - String - The name of the task this task depends on. - + ::: - - + ### jobs.\.tasks.email_notifications - + **`Type: Map`** - + An optional set of email addresses that is notified when runs of this task begin or complete as well as when this task is deleted. The default behavior is to not send any emails. - - - + :::list-table - + - - Key - Type - Description - + - - `no_alert_for_skipped_runs` - Boolean - If true, do not send email to recipients specified in `on_failure` if the run is skipped. This field is `deprecated`. Please use the `notification_settings.no_alert_for_skipped_runs` field. - + - - `on_duration_warning_threshold_exceeded` - Sequence - A list of email addresses to be notified when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. If no rule for the `RUN_DURATION_SECONDS` metric is specified in the `health` field for the job, notifications are not sent. - + - - `on_failure` - Sequence - A list of email addresses to be notified when a run unsuccessfully completes. A run is considered to have completed unsuccessfully if it ends with an `INTERNAL_ERROR` `life_cycle_state` or a `FAILED`, or `TIMED_OUT` result_state. If this is not specified on job creation, reset, or update the list is empty, and notifications are not sent. - + - - `on_start` - Sequence - A list of email addresses to be notified when a run begins. If not specified on job creation, reset, or update, the list is empty, and notifications are not sent. - + - - `on_streaming_backlog_exceeded` - Sequence - A list of email addresses to notify when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. - + - - `on_success` - Sequence - A list of email addresses to be notified when a run successfully completes. A run is considered to have completed successfully if it ends with a `TERMINATED` `life_cycle_state` and a `SUCCESS` result_state. If not specified on job creation, reset, or update, the list is empty, and notifications are not sent. - + ::: - - + ### jobs.\.tasks.for_each_task - + **`Type: Map`** - + The task executes a nested task for every input provided when the `for_each_task` field is present. - - - + :::list-table - + - - Key - Type - Description - + - - `concurrency` - Integer - An optional maximum allowed number of concurrent runs of the task. Set this value if you want to be able to execute multiple runs of the task concurrently. - + - - `inputs` - String - Array for task to iterate on. This can be a JSON string or a reference to an array parameter. - + - - `task` - Map - Configuration for the task that will be run for each element in the array - -::: - - -### jobs.\.tasks.health - -**`Type: Map`** - -An optional set of health rules that can be defined for this job. - - - -:::list-table - -- - Key - - Type - - Description - -- - `rules` - - Sequence - - See [_](#jobsnametaskshealthrules). - -::: - - -### jobs.\.tasks.health.rules - -**`Type: Sequence`** - - - - +::: + +### jobs.\.tasks.health + +**`Type: Map`** + +An optional set of health rules that can be defined for this job. + :::list-table - + - - Key - Type - Description - + + * - `rules` + - Sequence + - See [\_](#jobsnametaskshealthrules). + +### jobs.\.tasks.health.rules + +**`Type: Sequence`** + +:::list-table + +- - Key + - Type + - Description + - - `metric` - String - - Specifies the health metric that is being evaluated for a particular health rule. * `RUN_DURATION_SECONDS`: Expected total time for a run in seconds. * `STREAMING_BACKLOG_BYTES`: An estimate of the maximum bytes of data waiting to be consumed across all streams. This metric is in Public Preview. * `STREAMING_BACKLOG_RECORDS`: An estimate of the maximum offset lag across all streams. This metric is in Public Preview. * `STREAMING_BACKLOG_SECONDS`: An estimate of the maximum consumer delay across all streams. This metric is in Public Preview. * `STREAMING_BACKLOG_FILES`: An estimate of the maximum number of outstanding files across all streams. This metric is in Public Preview. - + - Specifies the health metric that is being evaluated for a particular health rule. _ `RUN_DURATION_SECONDS`: Expected total time for a run in seconds. _ `STREAMING_BACKLOG_BYTES`: An estimate of the maximum bytes of data waiting to be consumed across all streams. This metric is in Public Preview. _ `STREAMING_BACKLOG_RECORDS`: An estimate of the maximum offset lag across all streams. This metric is in Public Preview. _ `STREAMING_BACKLOG_SECONDS`: An estimate of the maximum consumer delay across all streams. This metric is in Public Preview. \* `STREAMING_BACKLOG_FILES`: An estimate of the maximum number of outstanding files across all streams. This metric is in Public Preview. + - - `op` - String - Specifies the operator used to compare the health metric value with the specified threshold. - + - - `value` - Integer - Specifies the threshold value that the health metric should obey to satisfy the health rule. - + ::: - - + ### jobs.\.tasks.libraries - + **`Type: Sequence`** - + An optional list of libraries to be installed on the cluster. The default value is an empty list. - - - + :::list-table - + - - Key - Type - Description - -- - `cran` - - Map - - Specification of a CRAN library to be installed as part of the library. See [_](#jobsnametaskslibrariescran). - + + * - `cran` + - Map + - Specification of a CRAN library to be installed as part of the library. See [\_](#jobsnametaskslibrariescran). + - - `egg` - String - Deprecated. URI of the egg library to install. Installing Python egg files is deprecated and is not supported in Databricks Runtime 14.0 and above. - + - - `jar` - String - URI of the JAR library to install. Supported URIs include Workspace paths, Unity Catalog Volumes paths, and S3 URIs. For example: `{ "jar": "/Workspace/path/to/library.jar" }`, `{ "jar" : "/Volumes/path/to/library.jar" }` or `{ "jar": "s3://my-bucket/library.jar" }`. If S3 is used, please make sure the cluster has read access on the library. You may need to launch the cluster with an IAM role to access the S3 URI. - -- - `maven` - - Map - - Specification of a maven library to be installed. For example: `{ "coordinates": "org.jsoup:jsoup:1.7.2" }`. See [_](#jobsnametaskslibrariesmaven). - -- - `pypi` - - Map - - Specification of a PyPi library to be installed. For example: `{ "package": "simplejson" }`. See [_](#jobsnametaskslibrariespypi). - + + * - `maven` + - Map + - Specification of a maven library to be installed. For example: `{ "coordinates": "org.jsoup:jsoup:1.7.2" }`. See [\_](#jobsnametaskslibrariesmaven). + + * - `pypi` + - Map + - Specification of a PyPi library to be installed. For example: `{ "package": "simplejson" }`. See [\_](#jobsnametaskslibrariespypi). + - - `requirements` - String - URI of the requirements.txt file to install. Only Workspace paths and Unity Catalog Volumes paths are supported. For example: `{ "requirements": "/Workspace/path/to/requirements.txt" }` or `{ "requirements" : "/Volumes/path/to/requirements.txt" }` - + - - `whl` - String - URI of the wheel library to install. Supported URIs include Workspace paths, Unity Catalog Volumes paths, and S3 URIs. For example: `{ "whl": "/Workspace/path/to/library.whl" }`, `{ "whl" : "/Volumes/path/to/library.whl" }` or `{ "whl": "s3://my-bucket/library.whl" }`. If S3 is used, please make sure the cluster has read access on the library. You may need to launch the cluster with an IAM role to access the S3 URI. - + ::: - - + ### jobs.\.tasks.libraries.cran - + **`Type: Map`** - + Specification of a CRAN library to be installed as part of the library - - - + :::list-table - + - - Key - Type - Description - + - - `package` - String - The name of the CRAN package to install. - + - - `repo` - String - The repository where the package can be found. If not specified, the default CRAN repo is used. - + ::: - - + ### jobs.\.tasks.libraries.maven - + **`Type: Map`** - + Specification of a maven library to be installed. For example: `{ "coordinates": "org.jsoup:jsoup:1.7.2" }` - - - + :::list-table - + - - Key - Type - Description - + - - `coordinates` - String - Gradle-style maven coordinates. For example: "org.jsoup:jsoup:1.7.2". - + - - `exclusions` - Sequence - - List of dependences to exclude. For example: `["slf4j:slf4j", "*:hadoop-client"]`. Maven dependency exclusions: https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html. - + - List of dependences to exclude. For example: `["slf4j:slf4j", "*:hadoop-client"]`. Maven dependency exclusions: https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html. + - - `repo` - String - Maven repo to install the Maven package from. If omitted, both Maven Central Repository and Spark Packages are searched. - + ::: - - + ### jobs.\.tasks.libraries.pypi - + **`Type: Map`** - + Specification of a PyPi library to be installed. For example: `{ "package": "simplejson" }` - - - + :::list-table - + - - Key - Type - Description - + - - `package` - String - The name of the pypi package to install. An optional exact version specification is also supported. Examples: "simplejson" and "simplejson==3.8.0". - + - - `repo` - String - The repository where the package can be found. If not specified, the default pip index is used. - + ::: - - + ### jobs.\.tasks.new_cluster - + **`Type: Map`** - + If new_cluster, a description of a new cluster that is created for each run. - - - + :::list-table - + - - Key - Type - Description - + - - `apply_policy_default_values` - Boolean - When set to true, fixed and default values from the policy will be used for fields that are omitted. When set to false, only fixed values from the policy will be applied. - -- - `autoscale` - - Map - - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [_](#jobsnametasksnew_clusterautoscale). - + + * - `autoscale` + - Map + - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [\_](#jobsnametasksnew_clusterautoscale). + - - `autotermination_minutes` - Integer - Automatically terminates the cluster after it is inactive for this time in minutes. If not set, this cluster will not be automatically terminated. If specified, the threshold must be between 10 and 10000 minutes. Users can also set this value to 0 to explicitly disable automatic termination. - -- - `aws_attributes` - - Map - - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [_](#jobsnametasksnew_clusteraws_attributes). - -- - `azure_attributes` - - Map - - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [_](#jobsnametasksnew_clusterazure_attributes). - -- - `cluster_log_conf` - - Map - - The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. See [_](#jobsnametasksnew_clustercluster_log_conf). - + + * - `aws_attributes` + - Map + - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [\_](#jobsnametasksnew_clusteraws_attributes). + + * - `azure_attributes` + - Map + - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [\_](#jobsnametasksnew_clusterazure_attributes). + + * - `cluster_log_conf` + - Map + - The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. See [\_](#jobsnametasksnew_clustercluster_log_conf). + - - `cluster_name` - String - - Cluster name requested by the user. This doesn't have to be unique. If not specified at creation, the cluster name will be an empty string. - + - Cluster name requested by the user. This doesn't have to be unique. If not specified at creation, the cluster name will be an empty string. + - - `custom_tags` - Map - - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags - + - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags + - - `data_security_mode` - String - - Data security mode decides what data governance model to use when accessing data from a cluster. The following modes can only be used with `kind`. * `DATA_SECURITY_MODE_AUTO`: Databricks will choose the most appropriate access mode depending on your compute configuration. * `DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`. * `DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`. The following modes can be used regardless of `kind`. * `NONE`: No security isolation for multiple users sharing the cluster. Data governance features are not available in this mode. * `SINGLE_USER`: A secure cluster that can only be exclusively used by a single user specified in `single_user_name`. Most programming languages, cluster features and data governance features are available in this mode. * `USER_ISOLATION`: A secure cluster that can be shared by multiple users. Cluster users are fully isolated so that they cannot see each other's data and credentials. Most data governance features are supported in this mode. But programming languages and cluster features might be limited. The following modes are deprecated starting with Databricks Runtime 15.0 and will be removed for future Databricks Runtime versions: * `LEGACY_TABLE_ACL`: This mode is for users migrating from legacy Table ACL clusters. * `LEGACY_PASSTHROUGH`: This mode is for users migrating from legacy Passthrough on high concurrency clusters. * `LEGACY_SINGLE_USER`: This mode is for users migrating from legacy Passthrough on standard clusters. * `LEGACY_SINGLE_USER_STANDARD`: This mode provides a way that doesn’t have UC nor passthrough enabled. - -- - `docker_image` - - Map - - See [_](#jobsnametasksnew_clusterdocker_image). - + - Data security mode decides what data governance model to use when accessing data from a cluster. The following modes can only be used with `kind`. _ `DATA_SECURITY_MODE_AUTO`: Databricks will choose the most appropriate access mode depending on your compute configuration. _ `DATA_SECURITY_MODE_STANDARD`: Alias for `USER_ISOLATION`. _ `DATA_SECURITY_MODE_DEDICATED`: Alias for `SINGLE_USER`. The following modes can be used regardless of `kind`. _ `NONE`: No security isolation for multiple users sharing the cluster. Data governance features are not available in this mode. _ `SINGLE_USER`: A secure cluster that can only be exclusively used by a single user specified in `single_user_name`. Most programming languages, cluster features and data governance features are available in this mode. _ `USER_ISOLATION`: A secure cluster that can be shared by multiple users. Cluster users are fully isolated so that they cannot see each other's data and credentials. Most data governance features are supported in this mode. But programming languages and cluster features might be limited. The following modes are deprecated starting with Databricks Runtime 15.0 and will be removed for future Databricks Runtime versions: _ `LEGACY_TABLE_ACL`: This mode is for users migrating from legacy Table ACL clusters. _ `LEGACY_PASSTHROUGH`: This mode is for users migrating from legacy Passthrough on high concurrency clusters. _ `LEGACY_SINGLE_USER`: This mode is for users migrating from legacy Passthrough on standard clusters. _ `LEGACY_SINGLE_USER_STANDARD`: This mode provides a way that doesn’t have UC nor passthrough enabled. + + * - `docker_image` + - Map + - See [\_](#jobsnametasksnew_clusterdocker_image). + - - `driver_instance_pool_id` - String - The optional ID of the instance pool for the driver of the cluster belongs. The pool cluster uses the instance pool with id (instance_pool_id) if the driver pool is not assigned. - + - - `driver_node_type_id` - String - - The node type of the Spark driver. Note that this field is optional; if unset, the driver node type will be set as the same value as `node_type_id` defined above. - + - The node type of the Spark driver. Note that this field is optional; if unset, the driver node type will be set as the same value as `node_type_id` defined above. + - - `enable_elastic_disk` - Boolean - Autoscaling Local Storage: when enabled, this cluster will dynamically acquire additional disk space when its Spark workers are running low on disk space. This feature requires specific AWS permissions to function correctly - refer to the User Guide for more details. - + - - `enable_local_disk_encryption` - Boolean - Whether to enable LUKS on cluster VMs' local disks - -- - `gcp_attributes` - - Map - - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [_](#jobsnametasksnew_clustergcp_attributes). - -- - `init_scripts` - - Sequence - - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [_](#jobsnametasksnew_clusterinit_scripts). - + + * - `gcp_attributes` + - Map + - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [\_](#jobsnametasksnew_clustergcp_attributes). + + * - `init_scripts` + - Sequence + - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [\_](#jobsnametasksnew_clusterinit_scripts). + - - `instance_pool_id` - String - The optional ID of the instance pool to which the cluster belongs. - + - - `is_single_node` - Boolean - - This field can only be used with `kind`. When set to true, Databricks will automatically set single node related `custom_tags`, `spark_conf`, and `num_workers` - + - This field can only be used with `kind`. When set to true, Databricks will automatically set single node related `custom_tags`, `spark_conf`, and `num_workers` + - - `kind` - String - - - + - + - - `node_type_id` - String - - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. - + - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. + - - `num_workers` - Integer - - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. - + - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. + - - `policy_id` - String - The ID of the cluster policy used to create the cluster if applicable. - + - - `runtime_engine` - String - - Determines the cluster's runtime engine, either standard or Photon. This field is not compatible with legacy `spark_version` values that contain `-photon-`. Remove `-photon-` from the `spark_version` and set `runtime_engine` to `PHOTON`. If left unspecified, the runtime engine defaults to standard unless the spark_version contains -photon-, in which case Photon will be used. - + - Determines the cluster's runtime engine, either standard or Photon. This field is not compatible with legacy `spark_version` values that contain `-photon-`. Remove `-photon-` from the `spark_version` and set `runtime_engine` to `PHOTON`. If left unspecified, the runtime engine defaults to standard unless the spark_version contains -photon-, in which case Photon will be used. + - - `single_user_name` - String - Single user name if data_security_mode is `SINGLE_USER` - + - - `spark_conf` - Map - - An object containing a set of optional, user-specified Spark configuration key-value pairs. Users can also pass in a string of extra JVM options to the driver and the executors via `spark.driver.extraJavaOptions` and `spark.executor.extraJavaOptions` respectively. - + - An object containing a set of optional, user-specified Spark configuration key-value pairs. Users can also pass in a string of extra JVM options to the driver and the executors via `spark.driver.extraJavaOptions` and `spark.executor.extraJavaOptions` respectively. + - - `spark_env_vars` - Map - - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` - + - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` + - - `spark_version` - String - - The Spark version of the cluster, e.g. `3.3.x-scala2.11`. A list of available Spark versions can be retrieved by using the :method:clusters/sparkVersions API call. - + - The Spark version of the cluster, e.g. `3.3.x-scala2.11`. A list of available Spark versions can be retrieved by using the :method:clusters/sparkVersions API call. + - - `ssh_public_keys` - Sequence - SSH public key contents that will be added to each Spark node in this cluster. The corresponding private keys can be used to login with the user name `ubuntu` on port `2200`. Up to 10 keys can be specified. - + - - `use_ml_runtime` - Boolean - - This field can only be used with `kind`. `effective_spark_version` is determined by `spark_version` (DBR release), this field `use_ml_runtime`, and whether `node_type_id` is gpu node or not. - -- - `workload_type` - - Map - - See [_](#jobsnametasksnew_clusterworkload_type). - -::: - - + - This field can only be used with `kind`. `effective_spark_version` is determined by `spark_version` (DBR release), this field `use_ml_runtime`, and whether `node_type_id` is gpu node or not. + + * - `workload_type` + - Map + - See [\_](#jobsnametasksnew_clusterworkload_type). + ### jobs.\.tasks.new_cluster.autoscale - + **`Type: Map`** - + Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. - - - + :::list-table - + - - Key - Type - Description - + - - `max_workers` - Integer - The maximum number of workers to which the cluster can scale up when overloaded. Note that `max_workers` must be strictly greater than `min_workers`. - + - - `min_workers` - Integer - The minimum number of workers to which the cluster can scale down when underutilized. It is also the initial number of workers the cluster will have after creation. - + ::: - - + ### jobs.\.tasks.new_cluster.aws_attributes - + **`Type: Map`** - + Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. - + - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. + - - `ebs_volume_count` - Integer - - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. - + - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. + - - `ebs_volume_iops` - Integer - If using gp3 volumes, what IOPS to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_size` - Integer - The size of each EBS volume (in GiB) launched for each instance. For general purpose SSD, this value must be within the range 100 - 4096. For throughput optimized HDD, this value must be within the range 500 - 4096. - + - - `ebs_volume_throughput` - Integer - If using gp3 volumes, what throughput to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_type` - String - The type of EBS volumes that will be launched with this cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. If this value is greater than 0, the cluster driver node in particular will be placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - + - - `instance_profile_arn` - String - - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. - + - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. + - - `spot_bid_price_percent` - Integer - - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. - + - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. + - - `zone_id` - String - Identifier for the availability zone/datacenter in which the cluster resides. This string will be of a form like "us-west-2a". The provided availability zone must be in the same region as the Databricks deployment. For example, "us-west-2a" is not a valid zone id if the Databricks deployment resides in the "us-east-1" region. This is an optional field at cluster creation, and if not specified, a default zone will be used. If the zone specified is "auto", will try to place cluster in a zone with high availability, and will retry placement in a different AZ if there is not enough capacity. The list of available zones as well as the default value can be found by using the `List Zones` method. - + ::: - - + ### jobs.\.tasks.new_cluster.azure_attributes - + **`Type: Map`** - + Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero (which only happens on pool clusters), this availability type will be used for the entire cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. This value should be greater than 0, to make sure the cluster driver node is placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - -- - `log_analytics_info` - - Map - - Defines values necessary to configure and run Azure Log Analytics agent. See [_](#jobsnametasksnew_clusterazure_attributeslog_analytics_info). - + + * - `log_analytics_info` + - Map + - Defines values necessary to configure and run Azure Log Analytics agent. See [\_](#jobsnametasksnew_clusterazure_attributeslog_analytics_info). + - - `spot_bid_max_price` - Any - The max bid price to be used for Azure spot instances. The Max price for the bid cannot be higher than the on-demand price of the instance. If not specified, the default value is -1, which specifies that the instance cannot be evicted on the basis of price, and only on the basis of availability. Further, the value should > 0 or -1. - + ::: - - + ### jobs.\.tasks.new_cluster.azure_attributes.log_analytics_info - + **`Type: Map`** - + Defines values necessary to configure and run Azure Log Analytics agent - - - + :::list-table - + - - Key - Type - Description - + - - `log_analytics_primary_key` - String - - - + - + - - `log_analytics_workspace_id` - String - - - + - + ::: - - + ### jobs.\.tasks.new_cluster.cluster_log_conf - + **`Type: Map`** - + The configuration for delivering spark logs to a long-term storage destination. Two kinds of destinations (dbfs and s3) are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. - - - + :::list-table - + - - Key - Type - Description - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#jobsnametasksnew_clustercluster_log_confdbfs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#jobsnametasksnew_clustercluster_log_confs3). - -::: - - + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#jobsnametasksnew_clustercluster_log_confdbfs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#jobsnametasksnew_clustercluster_log_confs3). + ### jobs.\.tasks.new_cluster.cluster_log_conf.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### jobs.\.tasks.new_cluster.cluster_log_conf.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - -::: - - -### jobs.\.tasks.new_cluster.docker_image - -**`Type: Map`** - - - - +::: + +### jobs.\.tasks.new_cluster.docker_image + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - -- - `basic_auth` - - Map - - See [_](#jobsnametasksnew_clusterdocker_imagebasic_auth). - + + * - `basic_auth` + - Map + - See [\_](#jobsnametasksnew_clusterdocker_imagebasic_auth). + - - `url` - String - URL of the docker image. - -::: - - -### jobs.\.tasks.new_cluster.docker_image.basic_auth - -**`Type: Map`** - - - - +::: + +### jobs.\.tasks.new_cluster.docker_image.basic_auth + +**`Type: Map`** + :::list-table - + - - Key - Type - Description - + - - `password` - String - Password of the user - + - - `username` - String - Name of the user - + ::: - - + ### jobs.\.tasks.new_cluster.gcp_attributes - + **`Type: Map`** - + Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - This field determines whether the instance pool will contain preemptible VMs, on-demand VMs, or preemptible VMs with a fallback to on-demand VMs if the former is unavailable. - + - - `boot_disk_size` - Integer - boot disk size in GB - + - - `google_service_account` - String - If provided, the cluster will impersonate the google service account when accessing gcloud services (like GCS). The google service account must have previously been added to the Databricks environment by an account administrator. - + - - `local_ssd_count` - Integer - If provided, each node (workers and driver) in the cluster will have this number of local SSDs attached. Each local SSD is 375GB in size. Refer to [GCP documentation](https://cloud.google.com/compute/docs/disks/local-ssd#choose_number_local_ssds) for the supported number of local SSDs for each instance type. - + - - `use_preemptible_executors` - Boolean - This field determines whether the spark executors will be scheduled to run on preemptible VMs (when set to true) versus standard compute engine VMs (when set to false; default). Note: Soon to be deprecated, use the availability field instead. - + - - `zone_id` - String - Identifier for the availability zone in which the cluster resides. This can be one of the following: - "HA" => High availability, spread nodes across availability zones for a Databricks deployment region [default] - "AUTO" => Databricks picks an availability zone to schedule the cluster on. - A GCP availability zone => Pick One of the available zones for (machine type + region) from https://cloud.google.com/compute/docs/regions-zones. - -::: - - -### jobs.\.tasks.new_cluster.init_scripts - -**`Type: Sequence`** - -The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. - - - -:::list-table - -- - Key - - Type - - Description - -- - `abfss` - - Map - - See [_](#jobsnametasksnew_clusterinit_scriptsabfss). - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#jobsnametasksnew_clusterinit_scriptsdbfs). - -- - `file` - - Map - - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [_](#jobsnametasksnew_clusterinit_scriptsfile). - -- - `gcs` - - Map - - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [_](#jobsnametasksnew_clusterinit_scriptsgcs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#jobsnametasksnew_clusterinit_scriptss3). - -- - `volumes` - - Map - - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [_](#jobsnametasksnew_clusterinit_scriptsvolumes). - -- - `workspace` - - Map - - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [_](#jobsnametasksnew_clusterinit_scriptsworkspace). - -::: - - -### jobs.\.tasks.new_cluster.init_scripts.abfss - -**`Type: Map`** - - - - +::: + +### jobs.\.tasks.new_cluster.init_scripts + +**`Type: Sequence`** + +The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. + :::list-table - + - - Key - Type - Description - + + * - `abfss` + - Map + - destination needs to be provided. e.g. `{ "abfss" : { "destination" : "abfss://@.dfs.core.windows.net/" } }. See [\_](#jobsnametasksnew_clusterinit_scriptsabfss). + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#jobsnametasksnew_clusterinit_scriptsdbfs). + + * - `file` + - Map + - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [\_](#jobsnametasksnew_clusterinit_scriptsfile). + + * - `gcs` + - Map + - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [\_](#jobsnametasksnew_clusterinit_scriptsgcs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#jobsnametasksnew_clusterinit_scriptss3). + + * - `volumes` + - Map + - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [\_](#jobsnametasksnew_clusterinit_scriptsvolumes). + + * - `workspace` + - Map + - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [\_](#jobsnametasksnew_clusterinit_scriptsworkspace). + +### jobs.\.tasks.new_cluster.init_scripts.abfss + +**`Type: Map`** + +:::list-table + +- - Key + - Type + - Description + - - `destination` - String - abfss destination, e.g. `abfss://@.dfs.core.windows.net/`. - + ::: - - + ### jobs.\.tasks.new_cluster.init_scripts.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### jobs.\.tasks.new_cluster.init_scripts.file - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - local file destination, e.g. `file:/my/local/file.sh` - + ::: - - + ### jobs.\.tasks.new_cluster.init_scripts.gcs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - GCS destination/URI, e.g. `gs://my-bucket/some-prefix` - + ::: - - + ### jobs.\.tasks.new_cluster.init_scripts.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + ::: - - + ### jobs.\.tasks.new_cluster.init_scripts.volumes - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - Unity Catalog Volumes file destination, e.g. `/Volumes/my-init.sh` - + ::: - - + ### jobs.\.tasks.new_cluster.init_scripts.workspace - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - workspace files destination, e.g. `/Users/user1@databricks.com/my-init.sh` - -::: - - -### jobs.\.tasks.new_cluster.workload_type - -**`Type: Map`** - - - - -:::list-table - -- - Key - - Type - - Description - -- - `clients` - - Map - - defined what type of clients can use the cluster. E.g. Notebooks, Jobs. See [_](#jobsnametasksnew_clusterworkload_typeclients). - ::: - - -### jobs.\.tasks.new_cluster.workload_type.clients - + +### jobs.\.tasks.new_cluster.workload_type + **`Type: Map`** - - defined what type of clients can use the cluster. E.g. Notebooks, Jobs - - - + :::list-table - + - - Key - Type - Description - + + * - `clients` + - Map + - defined what type of clients can use the cluster. E.g. Notebooks, Jobs. See [\_](#jobsnametasksnew_clusterworkload_typeclients). + +### jobs.\.tasks.new_cluster.workload_type.clients + +**`Type: Map`** + +defined what type of clients can use the cluster. E.g. Notebooks, Jobs + +:::list-table + +- - Key + - Type + - Description + - - `jobs` - Boolean - With jobs set, the cluster can be used for jobs - + - - `notebooks` - Boolean - With notebooks set, this cluster can be used for notebooks - + ::: - - + ### jobs.\.tasks.notebook_task - + **`Type: Map`** - + The task runs a notebook when the `notebook_task` field is present. - - - + :::list-table - + - - Key - Type - Description - + - - `base_parameters` - Map - - Base parameters to be used for each run of this job. If the run is initiated by a call to :method:jobs/run Now with parameters specified, the two parameters maps are merged. If the same key is specified in `base_parameters` and in `run-now`, the value from `run-now` is used. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. If the notebook takes a parameter that is not specified in the job’s `base_parameters` or the `run-now` override parameters, the default value from the notebook is used. Retrieve these parameters in a notebook using [dbutils.widgets.get](https://docs.databricks.com/dev-tools/databricks-utils.html#dbutils-widgets). The JSON representation of this field cannot exceed 1MB. - + - Base parameters to be used for each run of this job. If the run is initiated by a call to :method:jobs/run Now with parameters specified, the two parameters maps are merged. If the same key is specified in `base_parameters` and in `run-now`, the value from `run-now` is used. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. If the notebook takes a parameter that is not specified in the job’s `base_parameters` or the `run-now` override parameters, the default value from the notebook is used. Retrieve these parameters in a notebook using [dbutils.widgets.get](https://docs.databricks.com/dev-tools/databricks-utils.html#dbutils-widgets). The JSON representation of this field cannot exceed 1MB. + - - `notebook_path` - String - The path of the notebook to be run in the Databricks workspace or remote repository. For notebooks stored in the Databricks workspace, the path must be absolute and begin with a slash. For notebooks stored in a remote repository, the path must be relative. This field is required. - + - - `source` - String - - Optional location type of the notebook. When set to `WORKSPACE`, the notebook will be retrieved from the local Databricks workspace. When set to `GIT`, the notebook will be retrieved from a Git repository defined in `git_source`. If the value is empty, the task will use `GIT` if `git_source` is defined and `WORKSPACE` otherwise. * `WORKSPACE`: Notebook is located in Databricks workspace. * `GIT`: Notebook is located in cloud Git provider. - + - Optional location type of the notebook. When set to `WORKSPACE`, the notebook will be retrieved from the local Databricks workspace. When set to `GIT`, the notebook will be retrieved from a Git repository defined in `git_source`. If the value is empty, the task will use `GIT` if `git_source` is defined and `WORKSPACE` otherwise. _ `WORKSPACE`: Notebook is located in Databricks workspace. _ `GIT`: Notebook is located in cloud Git provider. + - - `warehouse_id` - String - - Optional `warehouse_id` to run the notebook on a SQL warehouse. Classic SQL warehouses are NOT supported, please use serverless or pro SQL warehouses. Note that SQL warehouses only support SQL cells; if the notebook contains non-SQL cells, the run will fail. - + - Optional `warehouse_id` to run the notebook on a SQL warehouse. Classic SQL warehouses are NOT supported, please use serverless or pro SQL warehouses. Note that SQL warehouses only support SQL cells; if the notebook contains non-SQL cells, the run will fail. + ::: - - + ### jobs.\.tasks.notification_settings - + **`Type: Map`** - + Optional notification settings that are used when sending notifications to each of the `email_notifications` and `webhook_notifications` for this task. - - - + :::list-table - + - - Key - Type - Description - + - - `alert_on_last_attempt` - Boolean - If true, do not send notifications to recipients specified in `on_start` for the retried runs and do not send notifications to recipients specified in `on_failure` until the last retry of the run. - + - - `no_alert_for_canceled_runs` - Boolean - If true, do not send notifications to recipients specified in `on_failure` if the run is canceled. - + - - `no_alert_for_skipped_runs` - Boolean - If true, do not send notifications to recipients specified in `on_failure` if the run is skipped. - + ::: - - + ### jobs.\.tasks.pipeline_task - + **`Type: Map`** - + The task triggers a pipeline update when the `pipeline_task` field is present. Only pipelines configured to use triggered more are supported. - - - + :::list-table - + - - Key - Type - Description - + - - `full_refresh` - Boolean - If true, triggers a full refresh on the delta live table. - + - - `pipeline_id` - String - The full name of the pipeline task to execute. - + ::: - - + ### jobs.\.tasks.python_wheel_task - + **`Type: Map`** - + The task runs a Python wheel when the `python_wheel_task` field is present. - - - + :::list-table - + - - Key - Type - Description - + - - `entry_point` - String - Named entry point to use, if it does not exist in the metadata of the package it executes the function from the package directly using `$packageName.$entryPoint()` - + - - `named_parameters` - Map - Command-line parameters passed to Python wheel task in the form of `["--name=task", "--data=dbfs:/path/to/data.json"]`. Leave it empty if `parameters` is not null. - + - - `package_name` - String - Name of the package to execute - + - - `parameters` - Sequence - Command-line parameters passed to Python wheel task. Leave it empty if `named_parameters` is not null. - + ::: - - + ### jobs.\.tasks.run_job_task - + **`Type: Map`** - + The task triggers another job when the `run_job_task` field is present. - - - + :::list-table - + - - Key - Type - Description - + - - `dbt_commands` - Sequence - An array of commands to execute for jobs with the dbt task, for example `"dbt_commands": ["dbt deps", "dbt seed", "dbt deps", "dbt seed", "dbt run"]` - + - - `jar_params` - Sequence - - A list of parameters for jobs with Spark JAR tasks, for example `"jar_params": ["john doe", "35"]`. The parameters are used to invoke the main function of the main class specified in the Spark JAR task. If not specified upon `run-now`, it defaults to an empty list. jar_params cannot be specified in conjunction with notebook_params. The JSON representation of this field (for example `{"jar_params":["john doe","35"]}`) cannot exceed 10,000 bytes. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. - + - A list of parameters for jobs with Spark JAR tasks, for example `"jar_params": ["john doe", "35"]`. The parameters are used to invoke the main function of the main class specified in the Spark JAR task. If not specified upon `run-now`, it defaults to an empty list. jar_params cannot be specified in conjunction with notebook_params. The JSON representation of this field (for example `{"jar_params":["john doe","35"]}`) cannot exceed 10,000 bytes. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. + - - `job_id` - Integer - ID of the job to trigger. - + - - `job_parameters` - Map - Job-level parameters used to trigger the job. - + - - `notebook_params` - Map - - A map from keys to values for jobs with notebook task, for example `"notebook_params": {"name": "john doe", "age": "35"}`. The map is passed to the notebook and is accessible through the [dbutils.widgets.get](https://docs.databricks.com/dev-tools/databricks-utils.html) function. If not specified upon `run-now`, the triggered run uses the job’s base parameters. notebook_params cannot be specified in conjunction with jar_params. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. The JSON representation of this field (for example `{"notebook_params":{"name":"john doe","age":"35"}}`) cannot exceed 10,000 bytes. - -- - `pipeline_params` - - Map - - Controls whether the pipeline should perform a full refresh. See [_](#jobsnametasksrun_job_taskpipeline_params). - + - A map from keys to values for jobs with notebook task, for example `"notebook_params": {"name": "john doe", "age": "35"}`. The map is passed to the notebook and is accessible through the [dbutils.widgets.get](https://docs.databricks.com/dev-tools/databricks-utils.html) function. If not specified upon `run-now`, the triggered run uses the job’s base parameters. notebook_params cannot be specified in conjunction with jar_params. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. The JSON representation of this field (for example `{"notebook_params":{"name":"john doe","age":"35"}}`) cannot exceed 10,000 bytes. + + * - `pipeline_params` + - Map + - Controls whether the pipeline should perform a full refresh. See [\_](#jobsnametasksrun_job_taskpipeline_params). + - - `python_named_params` - Map - - - + - + - - `python_params` - Sequence - - A list of parameters for jobs with Python tasks, for example `"python_params": ["john doe", "35"]`. The parameters are passed to Python file as command-line parameters. If specified upon `run-now`, it would overwrite the parameters specified in job setting. The JSON representation of this field (for example `{"python_params":["john doe","35"]}`) cannot exceed 10,000 bytes. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. Important These parameters accept only Latin characters (ASCII character set). Using non-ASCII characters returns an error. Examples of invalid, non-ASCII characters are Chinese, Japanese kanjis, and emojis. - + - A list of parameters for jobs with Python tasks, for example `"python_params": ["john doe", "35"]`. The parameters are passed to Python file as command-line parameters. If specified upon `run-now`, it would overwrite the parameters specified in job setting. The JSON representation of this field (for example `{"python_params":["john doe","35"]}`) cannot exceed 10,000 bytes. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. Important These parameters accept only Latin characters (ASCII character set). Using non-ASCII characters returns an error. Examples of invalid, non-ASCII characters are Chinese, Japanese kanjis, and emojis. + - - `spark_submit_params` - Sequence - - A list of parameters for jobs with spark submit task, for example `"spark_submit_params": ["--class", "org.apache.spark.examples.SparkPi"]`. The parameters are passed to spark-submit script as command-line parameters. If specified upon `run-now`, it would overwrite the parameters specified in job setting. The JSON representation of this field (for example `{"python_params":["john doe","35"]}`) cannot exceed 10,000 bytes. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs Important These parameters accept only Latin characters (ASCII character set). Using non-ASCII characters returns an error. Examples of invalid, non-ASCII characters are Chinese, Japanese kanjis, and emojis. - + - A list of parameters for jobs with spark submit task, for example `"spark_submit_params": ["--class", "org.apache.spark.examples.SparkPi"]`. The parameters are passed to spark-submit script as command-line parameters. If specified upon `run-now`, it would overwrite the parameters specified in job setting. The JSON representation of this field (for example `{"python_params":["john doe","35"]}`) cannot exceed 10,000 bytes. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs Important These parameters accept only Latin characters (ASCII character set). Using non-ASCII characters returns an error. Examples of invalid, non-ASCII characters are Chinese, Japanese kanjis, and emojis. + - - `sql_params` - Map - A map from keys to values for jobs with SQL task, for example `"sql_params": {"name": "john doe", "age": "35"}`. The SQL alert task does not support custom parameters. - + ::: - - + ### jobs.\.tasks.run_job_task.pipeline_params - + **`Type: Map`** - + Controls whether the pipeline should perform a full refresh - - - + :::list-table - + - - Key - Type - Description - + - - `full_refresh` - Boolean - If true, triggers a full refresh on the delta live table. - + ::: - - + ### jobs.\.tasks.spark_jar_task - + **`Type: Map`** - + The task runs a JAR when the `spark_jar_task` field is present. - - - + :::list-table - + - - Key - Type - Description - + - - `jar_uri` - String - Deprecated since 04/2016. Provide a `jar` through the `libraries` field instead. For an example, see :method:jobs/create. - + - - `main_class_name` - String - - The full name of the class containing the main method to be executed. This class must be contained in a JAR provided as a library. The code must use `SparkContext.getOrCreate` to obtain a Spark context; otherwise, runs of the job fail. - + - The full name of the class containing the main method to be executed. This class must be contained in a JAR provided as a library. The code must use `SparkContext.getOrCreate` to obtain a Spark context; otherwise, runs of the job fail. + - - `parameters` - Sequence - - Parameters passed to the main method. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. - + - Parameters passed to the main method. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. + - - `run_as_repl` - Boolean - Deprecated. A value of `false` is no longer supported. - + ::: - - + ### jobs.\.tasks.spark_python_task - + **`Type: Map`** - + The task runs a Python file when the `spark_python_task` field is present. - - - + :::list-table - + - - Key - Type - Description - + - - `parameters` - Sequence - - Command line parameters passed to the Python file. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. - + - Command line parameters passed to the Python file. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. + - - `python_file` - String - The Python file to be executed. Cloud file URIs (such as dbfs:/, s3:/, adls:/, gcs:/) and workspace paths are supported. For python files stored in the Databricks workspace, the path must be absolute and begin with `/`. For files stored in a remote repository, the path must be relative. This field is required. - + - - `source` - String - - Optional location type of the Python file. When set to `WORKSPACE` or not specified, the file will be retrieved from the local Databricks workspace or cloud location (if the `python_file` has a URI format). When set to `GIT`, the Python file will be retrieved from a Git repository defined in `git_source`. * `WORKSPACE`: The Python file is located in a Databricks workspace or at a cloud filesystem URI. * `GIT`: The Python file is located in a remote Git repository. - + - Optional location type of the Python file. When set to `WORKSPACE` or not specified, the file will be retrieved from the local Databricks workspace or cloud location (if the `python_file` has a URI format). When set to `GIT`, the Python file will be retrieved from a Git repository defined in `git_source`. _ `WORKSPACE`: The Python file is located in a Databricks workspace or at a cloud filesystem URI. _ `GIT`: The Python file is located in a remote Git repository. + ::: - - + ### jobs.\.tasks.spark_submit_task - + **`Type: Map`** - + (Legacy) The task runs the spark-submit script when the `spark_submit_task` field is present. This task can run only on new clusters and is not compatible with serverless compute. In the `new_cluster` specification, `libraries` and `spark_conf` are not supported. Instead, use `--jars` and `--py-files` to add Java and Python libraries and `--conf` to set the Spark configurations. @@ -4538,720 +4060,629 @@ In the `new_cluster` specification, `libraries` and `spark_conf` are not support By default, the Spark submit job uses all available memory (excluding reserved memory for Databricks services). You can set `--driver-memory`, and `--executor-memory` to a smaller value to leave some room for off-heap usage. The `--jars`, `--py-files`, `--files` arguments support DBFS and S3 paths. - - - + :::list-table - + - - Key - Type - Description - + - - `parameters` - Sequence - - Command-line parameters passed to spark submit. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. - + - Command-line parameters passed to spark submit. Use [Task parameter variables](https://docs.databricks.com/jobs.html#parameter-variables) to set parameters containing information about job runs. + ::: - - + ### jobs.\.tasks.sql_task - + **`Type: Map`** - + The task runs a SQL query or file, or it refreshes a SQL alert or a legacy SQL dashboard when the `sql_task` field is present. - - - + :::list-table - + - - Key - Type - Description - -- - `alert` - - Map - - If alert, indicates that this job must refresh a SQL alert. See [_](#jobsnametaskssql_taskalert). - -- - `dashboard` - - Map - - If dashboard, indicates that this job must refresh a SQL dashboard. See [_](#jobsnametaskssql_taskdashboard). - -- - `file` - - Map - - If file, indicates that this job runs a SQL file in a remote Git repository. See [_](#jobsnametaskssql_taskfile). - + + * - `alert` + - Map + - If alert, indicates that this job must refresh a SQL alert. See [\_](#jobsnametaskssql_taskalert). + + * - `dashboard` + - Map + - If dashboard, indicates that this job must refresh a SQL dashboard. See [\_](#jobsnametaskssql_taskdashboard). + + * - `file` + - Map + - If file, indicates that this job runs a SQL file in a remote Git repository. See [\_](#jobsnametaskssql_taskfile). + - - `parameters` - Map - Parameters to be used for each run of this job. The SQL alert task does not support custom parameters. - -- - `query` - - Map - - If query, indicates that this job must execute a SQL query. See [_](#jobsnametaskssql_taskquery). - + + * - `query` + - Map + - If query, indicates that this job must execute a SQL query. See [\_](#jobsnametaskssql_taskquery). + - - `warehouse_id` - String - The canonical identifier of the SQL warehouse. Recommended to use with serverless or pro SQL warehouses. Classic SQL warehouses are only supported for SQL alert, dashboard and query tasks and are limited to scheduled single-task jobs. - + ::: - - + ### jobs.\.tasks.sql_task.alert - + **`Type: Map`** - + If alert, indicates that this job must refresh a SQL alert. - - - + :::list-table - + - - Key - Type - Description - + - - `alert_id` - String - The canonical identifier of the SQL alert. - + - - `pause_subscriptions` - Boolean - If true, the alert notifications are not sent to subscribers. - -- - `subscriptions` - - Sequence - - If specified, alert notifications are sent to subscribers. See [_](#jobsnametaskssql_taskalertsubscriptions). - -::: - - + + * - `subscriptions` + - Sequence + - If specified, alert notifications are sent to subscribers. See [\_](#jobsnametaskssql_taskalertsubscriptions). + ### jobs.\.tasks.sql_task.alert.subscriptions - + **`Type: Sequence`** - + If specified, alert notifications are sent to subscribers. - - - + :::list-table - + - - Key - Type - Description - + - - `destination_id` - String - The canonical identifier of the destination to receive email notification. This parameter is mutually exclusive with user_name. You cannot set both destination_id and user_name for subscription notifications. - + - - `user_name` - String - The user name to receive the subscription email. This parameter is mutually exclusive with destination_id. You cannot set both destination_id and user_name for subscription notifications. - + ::: - - + ### jobs.\.tasks.sql_task.dashboard - + **`Type: Map`** - + If dashboard, indicates that this job must refresh a SQL dashboard. - - - + :::list-table - + - - Key - Type - Description - + - - `custom_subject` - String - Subject of the email sent to subscribers of this task. - + - - `dashboard_id` - String - The canonical identifier of the SQL dashboard. - + - - `pause_subscriptions` - Boolean - If true, the dashboard snapshot is not taken, and emails are not sent to subscribers. - -- - `subscriptions` - - Sequence - - If specified, dashboard snapshots are sent to subscriptions. See [_](#jobsnametaskssql_taskdashboardsubscriptions). - -::: - - + + * - `subscriptions` + - Sequence + - If specified, dashboard snapshots are sent to subscriptions. See [\_](#jobsnametaskssql_taskdashboardsubscriptions). + ### jobs.\.tasks.sql_task.dashboard.subscriptions - + **`Type: Sequence`** - + If specified, dashboard snapshots are sent to subscriptions. - - - + :::list-table - + - - Key - Type - Description - + - - `destination_id` - String - The canonical identifier of the destination to receive email notification. This parameter is mutually exclusive with user_name. You cannot set both destination_id and user_name for subscription notifications. - + - - `user_name` - String - The user name to receive the subscription email. This parameter is mutually exclusive with destination_id. You cannot set both destination_id and user_name for subscription notifications. - + ::: - - + ### jobs.\.tasks.sql_task.file - + **`Type: Map`** - + If file, indicates that this job runs a SQL file in a remote Git repository. - - - + :::list-table - + - - Key - Type - Description - + - - `path` - String - Path of the SQL file. Must be relative if the source is a remote Git repository and absolute for workspace paths. - + - - `source` - String - - Optional location type of the SQL file. When set to `WORKSPACE`, the SQL file will be retrieved from the local Databricks workspace. When set to `GIT`, the SQL file will be retrieved from a Git repository defined in `git_source`. If the value is empty, the task will use `GIT` if `git_source` is defined and `WORKSPACE` otherwise. * `WORKSPACE`: SQL file is located in Databricks workspace. * `GIT`: SQL file is located in cloud Git provider. - + - Optional location type of the SQL file. When set to `WORKSPACE`, the SQL file will be retrieved from the local Databricks workspace. When set to `GIT`, the SQL file will be retrieved from a Git repository defined in `git_source`. If the value is empty, the task will use `GIT` if `git_source` is defined and `WORKSPACE` otherwise. _ `WORKSPACE`: SQL file is located in Databricks workspace. _ `GIT`: SQL file is located in cloud Git provider. + ::: - - + ### jobs.\.tasks.sql_task.query - + **`Type: Map`** - + If query, indicates that this job must execute a SQL query. - - - + :::list-table - + - - Key - Type - Description - + - - `query_id` - String - The canonical identifier of the SQL query. - + ::: - - + ### jobs.\.tasks.webhook_notifications - + **`Type: Map`** - + A collection of system notification IDs to notify when runs of this task begin or complete. The default behavior is to not send any system notifications. - - - + :::list-table - + - - Key - Type - Description - -- - `on_duration_warning_threshold_exceeded` - - Sequence - - An optional list of system notification IDs to call when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. A maximum of 3 destinations can be specified for the `on_duration_warning_threshold_exceeded` property. See [_](#jobsnametaskswebhook_notificationson_duration_warning_threshold_exceeded). - -- - `on_failure` - - Sequence - - An optional list of system notification IDs to call when the run fails. A maximum of 3 destinations can be specified for the `on_failure` property. See [_](#jobsnametaskswebhook_notificationson_failure). - -- - `on_start` - - Sequence - - An optional list of system notification IDs to call when the run starts. A maximum of 3 destinations can be specified for the `on_start` property. See [_](#jobsnametaskswebhook_notificationson_start). - -- - `on_streaming_backlog_exceeded` - - Sequence - - An optional list of system notification IDs to call when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. A maximum of 3 destinations can be specified for the `on_streaming_backlog_exceeded` property. See [_](#jobsnametaskswebhook_notificationson_streaming_backlog_exceeded). - -- - `on_success` - - Sequence - - An optional list of system notification IDs to call when the run completes successfully. A maximum of 3 destinations can be specified for the `on_success` property. See [_](#jobsnametaskswebhook_notificationson_success). - -::: - - + + * - `on_duration_warning_threshold_exceeded` + - Sequence + - An optional list of system notification IDs to call when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. A maximum of 3 destinations can be specified for the `on_duration_warning_threshold_exceeded` property. See [\_](#jobsnametaskswebhook_notificationson_duration_warning_threshold_exceeded). + + * - `on_failure` + - Sequence + - An optional list of system notification IDs to call when the run fails. A maximum of 3 destinations can be specified for the `on_failure` property. See [\_](#jobsnametaskswebhook_notificationson_failure). + + * - `on_start` + - Sequence + - An optional list of system notification IDs to call when the run starts. A maximum of 3 destinations can be specified for the `on_start` property. See [\_](#jobsnametaskswebhook_notificationson_start). + + * - `on_streaming_backlog_exceeded` + - Sequence + - An optional list of system notification IDs to call when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. A maximum of 3 destinations can be specified for the `on_streaming_backlog_exceeded` property. See [\_](#jobsnametaskswebhook_notificationson_streaming_backlog_exceeded). + + * - `on_success` + - Sequence + - An optional list of system notification IDs to call when the run completes successfully. A maximum of 3 destinations can be specified for the `on_success` property. See [\_](#jobsnametaskswebhook_notificationson_success). + ### jobs.\.tasks.webhook_notifications.on_duration_warning_threshold_exceeded - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. A maximum of 3 destinations can be specified for the `on_duration_warning_threshold_exceeded` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.tasks.webhook_notifications.on_failure - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the run fails. A maximum of 3 destinations can be specified for the `on_failure` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.tasks.webhook_notifications.on_start - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the run starts. A maximum of 3 destinations can be specified for the `on_start` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.tasks.webhook_notifications.on_streaming_backlog_exceeded - + **`Type: Sequence`** - + An optional list of system notification IDs to call when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. A maximum of 3 destinations can be specified for the `on_streaming_backlog_exceeded` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.tasks.webhook_notifications.on_success - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the run completes successfully. A maximum of 3 destinations can be specified for the `on_success` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.trigger - + **`Type: Map`** - + A configuration to trigger a run when certain conditions are met. The default behavior is that the job runs only when triggered by clicking “Run Now” in the Jobs UI or sending an API request to `runNow`. - - - + :::list-table - + - - Key - Type - Description - -- - `file_arrival` - - Map - - File arrival trigger settings. See [_](#jobsnametriggerfile_arrival). - + + * - `file_arrival` + - Map + - File arrival trigger settings. See [\_](#jobsnametriggerfile_arrival). + - - `pause_status` - String - Whether this trigger is paused or not. - -- - `periodic` - - Map - - Periodic trigger settings. See [_](#jobsnametriggerperiodic). - -- - `table` - - Map - - Old table trigger settings name. Deprecated in favor of `table_update`. See [_](#jobsnametriggertable). - -- - `table_update` - - Map - - See [_](#jobsnametriggertable_update). - -::: - - + + * - `periodic` + - Map + - Periodic trigger settings. See [\_](#jobsnametriggerperiodic). + + * - `table` + - Map + - Old table trigger settings name. Deprecated in favor of `table_update`. See [\_](#jobsnametriggertable). + + * - `table_update` + - Map + - See [\_](#jobsnametriggertable_update). + ### jobs.\.trigger.file_arrival - + **`Type: Map`** - + File arrival trigger settings. - - - + :::list-table - + - - Key - Type - Description - + - - `min_time_between_triggers_seconds` - Integer - If set, the trigger starts a run only after the specified amount of time passed since the last time the trigger fired. The minimum allowed value is 60 seconds - + - - `url` - String - URL to be monitored for file arrivals. The path must point to the root or a subpath of the external location. - + - - `wait_after_last_change_seconds` - Integer - If set, the trigger starts a run only after no file activity has occurred for the specified amount of time. This makes it possible to wait for a batch of incoming files to arrive before triggering a run. The minimum allowed value is 60 seconds. - + ::: - - + ### jobs.\.trigger.periodic - + **`Type: Map`** - + Periodic trigger settings. - - - + :::list-table - + - - Key - Type - Description - + - - `interval` - Integer - The interval at which the trigger should run. - + - - `unit` - String - The unit of time for the interval. - -::: - - -### jobs.\.trigger.table - -**`Type: Map`** - -Old table trigger settings name. Deprecated in favor of `table_update`. - - - -:::list-table - -- - Key - - Type - - Description - -- - `condition` - - String - - The table(s) condition based on which to trigger a job run. - -- - `min_time_between_triggers_seconds` - - Integer - - If set, the trigger starts a run only after the specified amount of time has passed since the last time the trigger fired. The minimum allowed value is 60 seconds. - -- - `table_names` - - Sequence - - A list of Delta tables to monitor for changes. The table name must be in the format `catalog_name.schema_name.table_name`. - -- - `wait_after_last_change_seconds` - - Integer - - If set, the trigger starts a run only after no table updates have occurred for the specified time and can be used to wait for a series of table updates before triggering a run. The minimum allowed value is 60 seconds. - -::: - - -### jobs.\.trigger.table_update - -**`Type: Map`** - - - - +::: + +### jobs.\.trigger.table + +**`Type: Map`** + +Old table trigger settings name. Deprecated in favor of `table_update`. + :::list-table - + - - Key - Type - Description - + - - `condition` - String - The table(s) condition based on which to trigger a job run. - + - - `min_time_between_triggers_seconds` - Integer - If set, the trigger starts a run only after the specified amount of time has passed since the last time the trigger fired. The minimum allowed value is 60 seconds. - + - - `table_names` - Sequence - A list of Delta tables to monitor for changes. The table name must be in the format `catalog_name.schema_name.table_name`. - + - - `wait_after_last_change_seconds` - Integer - If set, the trigger starts a run only after no table updates have occurred for the specified time and can be used to wait for a series of table updates before triggering a run. The minimum allowed value is 60 seconds. - + ::: - - -### jobs.\.webhook_notifications - + +### jobs.\.trigger.table_update + **`Type: Map`** - + +:::list-table + +- - Key + - Type + - Description + +- - `condition` + - String + - The table(s) condition based on which to trigger a job run. + +- - `min_time_between_triggers_seconds` + - Integer + - If set, the trigger starts a run only after the specified amount of time has passed since the last time the trigger fired. The minimum allowed value is 60 seconds. + +- - `table_names` + - Sequence + - A list of Delta tables to monitor for changes. The table name must be in the format `catalog_name.schema_name.table_name`. + +- - `wait_after_last_change_seconds` + - Integer + - If set, the trigger starts a run only after no table updates have occurred for the specified time and can be used to wait for a series of table updates before triggering a run. The minimum allowed value is 60 seconds. + +::: + +### jobs.\.webhook_notifications + +**`Type: Map`** + A collection of system notification IDs to notify when runs of this job begin or complete. - - - + :::list-table - + - - Key - Type - Description - -- - `on_duration_warning_threshold_exceeded` - - Sequence - - An optional list of system notification IDs to call when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. A maximum of 3 destinations can be specified for the `on_duration_warning_threshold_exceeded` property. See [_](#jobsnamewebhook_notificationson_duration_warning_threshold_exceeded). - -- - `on_failure` - - Sequence - - An optional list of system notification IDs to call when the run fails. A maximum of 3 destinations can be specified for the `on_failure` property. See [_](#jobsnamewebhook_notificationson_failure). - -- - `on_start` - - Sequence - - An optional list of system notification IDs to call when the run starts. A maximum of 3 destinations can be specified for the `on_start` property. See [_](#jobsnamewebhook_notificationson_start). - -- - `on_streaming_backlog_exceeded` - - Sequence - - An optional list of system notification IDs to call when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. A maximum of 3 destinations can be specified for the `on_streaming_backlog_exceeded` property. See [_](#jobsnamewebhook_notificationson_streaming_backlog_exceeded). - -- - `on_success` - - Sequence - - An optional list of system notification IDs to call when the run completes successfully. A maximum of 3 destinations can be specified for the `on_success` property. See [_](#jobsnamewebhook_notificationson_success). - -::: - - + + * - `on_duration_warning_threshold_exceeded` + - Sequence + - An optional list of system notification IDs to call when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. A maximum of 3 destinations can be specified for the `on_duration_warning_threshold_exceeded` property. See [\_](#jobsnamewebhook_notificationson_duration_warning_threshold_exceeded). + + * - `on_failure` + - Sequence + - An optional list of system notification IDs to call when the run fails. A maximum of 3 destinations can be specified for the `on_failure` property. See [\_](#jobsnamewebhook_notificationson_failure). + + * - `on_start` + - Sequence + - An optional list of system notification IDs to call when the run starts. A maximum of 3 destinations can be specified for the `on_start` property. See [\_](#jobsnamewebhook_notificationson_start). + + * - `on_streaming_backlog_exceeded` + - Sequence + - An optional list of system notification IDs to call when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. A maximum of 3 destinations can be specified for the `on_streaming_backlog_exceeded` property. See [\_](#jobsnamewebhook_notificationson_streaming_backlog_exceeded). + + * - `on_success` + - Sequence + - An optional list of system notification IDs to call when the run completes successfully. A maximum of 3 destinations can be specified for the `on_success` property. See [\_](#jobsnamewebhook_notificationson_success). + ### jobs.\.webhook_notifications.on_duration_warning_threshold_exceeded - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the duration of a run exceeds the threshold specified for the `RUN_DURATION_SECONDS` metric in the `health` field. A maximum of 3 destinations can be specified for the `on_duration_warning_threshold_exceeded` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.webhook_notifications.on_failure - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the run fails. A maximum of 3 destinations can be specified for the `on_failure` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.webhook_notifications.on_start - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the run starts. A maximum of 3 destinations can be specified for the `on_start` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.webhook_notifications.on_streaming_backlog_exceeded - + **`Type: Sequence`** - + An optional list of system notification IDs to call when any streaming backlog thresholds are exceeded for any stream. Streaming backlog thresholds can be set in the `health` field using the following metrics: `STREAMING_BACKLOG_BYTES`, `STREAMING_BACKLOG_RECORDS`, `STREAMING_BACKLOG_SECONDS`, or `STREAMING_BACKLOG_FILES`. Alerting is based on the 10-minute average of these metrics. If the issue persists, notifications are resent every 30 minutes. A maximum of 3 destinations can be specified for the `on_streaming_backlog_exceeded` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ### jobs.\.webhook_notifications.on_success - + **`Type: Sequence`** - + An optional list of system notification IDs to call when the run completes successfully. A maximum of 3 destinations can be specified for the `on_success` property. - - - + :::list-table - + - - Key - Type - Description - + - - `id` - String - - - + - + ::: - - + ## model_serving_endpoints - + **`Type: Map`** - -The model_serving_endpoint resource allows you to define [model serving endpoints](/api/workspace/servingendpoints/create). See [_](/machine-learning/model-serving/manage-serving-endpoints.md). - + +The model*serving_endpoint resource allows you to define [model serving endpoints](/api/workspace/servingendpoints/create). See [*](/machine-learning/model-serving/manage-serving-endpoints.md). + ```yaml model_serving_endpoints: : : ``` - - + :::list-table - + - - Key - Type - Description - -- - `ai_gateway` - - Map - - The AI Gateway configuration for the serving endpoint. NOTE: Only external model and provisioned throughput endpoints are currently supported. See [_](#model_serving_endpointsnameai_gateway). - -- - `config` - - Map - - The core config of the serving endpoint. See [_](#model_serving_endpointsnameconfig). - + + * - `ai_gateway` + - Map + - The AI Gateway configuration for the serving endpoint. NOTE: Only external model and provisioned throughput endpoints are currently supported. See [\_](#model_serving_endpointsnameai_gateway). + + * - `config` + - Map + - The core config of the serving endpoint. See [\_](#model_serving_endpointsnameconfig). + - - `name` - String - The name of the serving endpoint. This field is required and must be unique across a Databricks workspace. An endpoint name can consist of alphanumeric characters, dashes, and underscores. - -- - `permissions` - - Sequence - - See [_](#model_serving_endpointsnamepermissions). - -- - `rate_limits` - - Sequence - - Rate limits to be applied to the serving endpoint. NOTE: this field is deprecated, please use AI Gateway to manage rate limits. See [_](#model_serving_endpointsnamerate_limits). - + + * - `permissions` + - Sequence + - See [\_](#model_serving_endpointsnamepermissions). + + * - `rate_limits` + - Sequence + - Rate limits to be applied to the serving endpoint. NOTE: this field is deprecated, please use AI Gateway to manage rate limits. See [\_](#model_serving_endpointsnamerate_limits). + - - `route_optimized` - Boolean - Enable route optimization for the serving endpoint. - -- - `tags` - - Sequence - - Tags to be attached to the serving endpoint and automatically propagated to billing logs. See [_](#model_serving_endpointsnametags). - -::: - - + + * - `tags` + - Sequence + - Tags to be attached to the serving endpoint and automatically propagated to billing logs. See [\_](#model_serving_endpointsnametags). + **Example** - + The following example defines a Unity Catalog model serving endpoint: ```yaml @@ -5261,1246 +4692,1147 @@ resources: name: "uc-model-endpoint" config: served_entities: - - entity_name: "myCatalog.mySchema.my-ads-model" - entity_version: "10" - workload_size: "Small" - scale_to_zero_enabled: "true" + - entity_name: "myCatalog.mySchema.my-ads-model" + entity_version: "10" + workload_size: "Small" + scale_to_zero_enabled: "true" traffic_config: routes: - - served_model_name: "my-ads-model-10" - traffic_percentage: "100" + - served_model_name: "my-ads-model-10" + traffic_percentage: "100" tags: - - key: "team" - value: "data science" + - key: "team" + value: "data science" ``` - + ### model_serving_endpoints.\.ai_gateway - + **`Type: Map`** - + The AI Gateway configuration for the serving endpoint. NOTE: Only external model and provisioned throughput endpoints are currently supported. - - - + :::list-table - + - - Key - Type - Description - -- - `guardrails` - - Map - - Configuration for AI Guardrails to prevent unwanted data and unsafe data in requests and responses. See [_](#model_serving_endpointsnameai_gatewayguardrails). - -- - `inference_table_config` - - Map - - Configuration for payload logging using inference tables. Use these tables to monitor and audit data being sent to and received from model APIs and to improve model quality. See [_](#model_serving_endpointsnameai_gatewayinference_table_config). - -- - `rate_limits` - - Sequence - - Configuration for rate limits which can be set to limit endpoint traffic. See [_](#model_serving_endpointsnameai_gatewayrate_limits). - -- - `usage_tracking_config` - - Map - - Configuration to enable usage tracking using system tables. These tables allow you to monitor operational usage on endpoints and their associated costs. See [_](#model_serving_endpointsnameai_gatewayusage_tracking_config). - -::: - - + + * - `guardrails` + - Map + - Configuration for AI Guardrails to prevent unwanted data and unsafe data in requests and responses. See [\_](#model_serving_endpointsnameai_gatewayguardrails). + + * - `inference_table_config` + - Map + - Configuration for payload logging using inference tables. Use these tables to monitor and audit data being sent to and received from model APIs and to improve model quality. See [\_](#model_serving_endpointsnameai_gatewayinference_table_config). + + * - `rate_limits` + - Sequence + - Configuration for rate limits which can be set to limit endpoint traffic. See [\_](#model_serving_endpointsnameai_gatewayrate_limits). + + * - `usage_tracking_config` + - Map + - Configuration to enable usage tracking using system tables. These tables allow you to monitor operational usage on endpoints and their associated costs. See [\_](#model_serving_endpointsnameai_gatewayusage_tracking_config). + ### model_serving_endpoints.\.ai_gateway.guardrails - + **`Type: Map`** - + Configuration for AI Guardrails to prevent unwanted data and unsafe data in requests and responses. - - - + :::list-table - + - - Key - Type - Description - -- - `input` - - Map - - Configuration for input guardrail filters. See [_](#model_serving_endpointsnameai_gatewayguardrailsinput). - -- - `output` - - Map - - Configuration for output guardrail filters. See [_](#model_serving_endpointsnameai_gatewayguardrailsoutput). - -::: - - + + * - `input` + - Map + - Configuration for input guardrail filters. See [\_](#model_serving_endpointsnameai_gatewayguardrailsinput). + + * - `output` + - Map + - Configuration for output guardrail filters. See [\_](#model_serving_endpointsnameai_gatewayguardrailsoutput). + ### model_serving_endpoints.\.ai_gateway.guardrails.input - + **`Type: Map`** - + Configuration for input guardrail filters. - - - + :::list-table - + - - Key - Type - Description - + - - `invalid_keywords` - Sequence - List of invalid keywords. AI guardrail uses keyword or string matching to decide if the keyword exists in the request or response content. - -- - `pii` - - Map - - Configuration for guardrail PII filter. See [_](#model_serving_endpointsnameai_gatewayguardrailsinputpii). - + + * - `pii` + - Map + - Configuration for guardrail PII filter. See [\_](#model_serving_endpointsnameai_gatewayguardrailsinputpii). + - - `safety` - Boolean - Indicates whether the safety filter is enabled. - + - - `valid_topics` - Sequence - The list of allowed topics. Given a chat request, this guardrail flags the request if its topic is not in the allowed topics. - + ::: - - + ### model_serving_endpoints.\.ai_gateway.guardrails.input.pii - + **`Type: Map`** - + Configuration for guardrail PII filter. - - - + :::list-table - + - - Key - Type - Description - + - - `behavior` - String - Configuration for input guardrail filters. - + ::: - - + ### model_serving_endpoints.\.ai_gateway.guardrails.output - + **`Type: Map`** - + Configuration for output guardrail filters. - - - + :::list-table - + - - Key - Type - Description - + - - `invalid_keywords` - Sequence - List of invalid keywords. AI guardrail uses keyword or string matching to decide if the keyword exists in the request or response content. - -- - `pii` - - Map - - Configuration for guardrail PII filter. See [_](#model_serving_endpointsnameai_gatewayguardrailsoutputpii). - + + * - `pii` + - Map + - Configuration for guardrail PII filter. See [\_](#model_serving_endpointsnameai_gatewayguardrailsoutputpii). + - - `safety` - Boolean - Indicates whether the safety filter is enabled. - + - - `valid_topics` - Sequence - The list of allowed topics. Given a chat request, this guardrail flags the request if its topic is not in the allowed topics. - + ::: - - + ### model_serving_endpoints.\.ai_gateway.guardrails.output.pii - + **`Type: Map`** - + Configuration for guardrail PII filter. - - - + :::list-table - + - - Key - Type - Description - + - - `behavior` - String - Configuration for input guardrail filters. - + ::: - - + ### model_serving_endpoints.\.ai_gateway.inference_table_config - + **`Type: Map`** - + Configuration for payload logging using inference tables. Use these tables to monitor and audit data being sent to and received from model APIs and to improve model quality. - - - + :::list-table - + - - Key - Type - Description - + - - `catalog_name` - String - The name of the catalog in Unity Catalog. Required when enabling inference tables. NOTE: On update, you have to disable inference table first in order to change the catalog name. - + - - `enabled` - Boolean - Indicates whether the inference table is enabled. - + - - `schema_name` - String - The name of the schema in Unity Catalog. Required when enabling inference tables. NOTE: On update, you have to disable inference table first in order to change the schema name. - + - - `table_name_prefix` - String - The prefix of the table in Unity Catalog. NOTE: On update, you have to disable inference table first in order to change the prefix name. - + ::: - - + ### model_serving_endpoints.\.ai_gateway.rate_limits - + **`Type: Sequence`** - + Configuration for rate limits which can be set to limit endpoint traffic. - - - + :::list-table - + - - Key - Type - Description - + - - `calls` - Integer - Used to specify how many calls are allowed for a key within the renewal_period. - + - - `key` - String - Key field for a rate limit. Currently, only 'user' and 'endpoint' are supported, with 'endpoint' being the default if not specified. - + - - `renewal_period` - String - Renewal period field for a rate limit. Currently, only 'minute' is supported. - + ::: - - + ### model_serving_endpoints.\.ai_gateway.usage_tracking_config - + **`Type: Map`** - + Configuration to enable usage tracking using system tables. These tables allow you to monitor operational usage on endpoints and their associated costs. - - - + :::list-table - + - - Key - Type - Description - + - - `enabled` - Boolean - Whether to enable usage tracking. - + ::: - - + ### model_serving_endpoints.\.config - + **`Type: Map`** - + The core config of the serving endpoint. - - - + :::list-table - + - - Key - Type - Description - -- - `auto_capture_config` - - Map - - Configuration for Inference Tables which automatically logs requests and responses to Unity Catalog. Note: this field is deprecated for creating new provisioned throughput endpoints, or updating existing provisioned throughput endpoints that never have inference table configured; in these cases please use AI Gateway to manage inference tables. See [_](#model_serving_endpointsnameconfigauto_capture_config). - -- - `served_entities` - - Sequence - - The list of served entities under the serving endpoint config. See [_](#model_serving_endpointsnameconfigserved_entities). - -- - `served_models` - - Sequence - - (Deprecated, use served_entities instead) The list of served models under the serving endpoint config. See [_](#model_serving_endpointsnameconfigserved_models). - -- - `traffic_config` - - Map - - The traffic configuration associated with the serving endpoint config. See [_](#model_serving_endpointsnameconfigtraffic_config). - -::: - - + + * - `auto_capture_config` + - Map + - Configuration for Inference Tables which automatically logs requests and responses to Unity Catalog. Note: this field is deprecated for creating new provisioned throughput endpoints, or updating existing provisioned throughput endpoints that never have inference table configured; in these cases please use AI Gateway to manage inference tables. See [\_](#model_serving_endpointsnameconfigauto_capture_config). + + * - `served_entities` + - Sequence + - The list of served entities under the serving endpoint config. See [\_](#model_serving_endpointsnameconfigserved_entities). + + * - `served_models` + - Sequence + - (Deprecated, use served*entities instead) The list of served models under the serving endpoint config. See [*](#model_serving_endpointsnameconfigserved_models). + + * - `traffic_config` + - Map + - The traffic configuration associated with the serving endpoint config. See [\_](#model_serving_endpointsnameconfigtraffic_config). + ### model_serving_endpoints.\.config.auto_capture_config - + **`Type: Map`** - + Configuration for Inference Tables which automatically logs requests and responses to Unity Catalog. Note: this field is deprecated for creating new provisioned throughput endpoints, or updating existing provisioned throughput endpoints that never have inference table configured; in these cases please use AI Gateway to manage inference tables. - - - + :::list-table - + - - Key - Type - Description - + - - `catalog_name` - String - The name of the catalog in Unity Catalog. NOTE: On update, you cannot change the catalog name if the inference table is already enabled. - + - - `enabled` - Boolean - Indicates whether the inference table is enabled. - + - - `schema_name` - String - The name of the schema in Unity Catalog. NOTE: On update, you cannot change the schema name if the inference table is already enabled. - + - - `table_name_prefix` - String - The prefix of the table in Unity Catalog. NOTE: On update, you cannot change the prefix name if the inference table is already enabled. - + ::: - - + ### model_serving_endpoints.\.config.served_entities - + **`Type: Sequence`** - + The list of served entities under the serving endpoint config. - - - + :::list-table - + - - Key - Type - Description - + - - `entity_name` - String - The name of the entity to be served. The entity may be a model in the Databricks Model Registry, a model in the Unity Catalog (UC), or a function of type FEATURE_SPEC in the UC. If it is a UC object, the full name of the object should be given in the form of **catalog_name.schema_name.model_name**. - + - - `entity_version` - String - - - + - + - - `environment_vars` - Map - An object containing a set of optional, user-specified environment variable key-value pairs used for serving this entity. Note: this is an experimental feature and subject to change. Example entity environment variables that refer to Databricks secrets: `{"OPENAI_API_KEY": "{{secrets/my_scope/my_key}}", "DATABRICKS_TOKEN": "{{secrets/my_scope2/my_key2}}"}` - -- - `external_model` - - Map - - The external model to be served. NOTE: Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified with the latter set being used for custom model serving for a Databricks registered model. For an existing endpoint with external_model, it cannot be updated to an endpoint without external_model. If the endpoint is created without external_model, users cannot update it to add external_model later. The task type of all external models within an endpoint must be the same. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_model). - + + * - `external_model` + - Map + - The external model to be served. NOTE: Only one of external*model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified with the latter set being used for custom model serving for a Databricks registered model. For an existing endpoint with external_model, it cannot be updated to an endpoint without external_model. If the endpoint is created without external_model, users cannot update it to add external_model later. The task type of all external models within an endpoint must be the same. See [*](#model_serving_endpointsnameconfigserved_entitiesexternal_model). + - - `instance_profile_arn` - String - ARN of the instance profile that the served entity uses to access AWS resources. - + - - `max_provisioned_throughput` - Integer - The maximum tokens per second that the endpoint can scale up to. - + - - `min_provisioned_throughput` - Integer - The minimum tokens per second that the endpoint can scale down to. - + - - `name` - String - The name of a served entity. It must be unique across an endpoint. A served entity name can consist of alphanumeric characters, dashes, and underscores. If not specified for an external model, this field defaults to external_model.name, with '.' and ':' replaced with '-', and if not specified for other entities, it defaults to entity_name-entity_version. - + - - `scale_to_zero_enabled` - Boolean - Whether the compute resources for the served entity should scale down to zero. - + - - `workload_size` - String - The workload size of the served entity. The workload size corresponds to a range of provisioned concurrency that the compute autoscales between. A single unit of provisioned concurrency can process one request at a time. Valid workload sizes are "Small" (4 - 4 provisioned concurrency), "Medium" (8 - 16 provisioned concurrency), and "Large" (16 - 64 provisioned concurrency). If scale-to-zero is enabled, the lower bound of the provisioned concurrency for each workload size is 0. - + - - `workload_type` - String - The workload type of the served entity. The workload type selects which type of compute to use in the endpoint. The default value for this parameter is "CPU". For deep learning workloads, GPU acceleration is available by selecting workload types like GPU_SMALL and others. See the available [GPU types](https://docs.databricks.com/en/machine-learning/model-serving/create-manage-serving-endpoints.html#gpu-workload-types). - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model - + **`Type: Map`** - + The external model to be served. NOTE: Only one of external_model and (entity_name, entity_version, workload_size, workload_type, and scale_to_zero_enabled) can be specified with the latter set being used for custom model serving for a Databricks registered model. For an existing endpoint with external_model, it cannot be updated to an endpoint without external_model. If the endpoint is created without external_model, users cannot update it to add external_model later. The task type of all external models within an endpoint must be the same. - - - + :::list-table - + - - Key - Type - Description - -- - `ai21labs_config` - - Map - - AI21Labs Config. Only required if the provider is 'ai21labs'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelai21labs_config). - -- - `amazon_bedrock_config` - - Map - - Amazon Bedrock Config. Only required if the provider is 'amazon-bedrock'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelamazon_bedrock_config). - -- - `anthropic_config` - - Map - - Anthropic Config. Only required if the provider is 'anthropic'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelanthropic_config). - -- - `cohere_config` - - Map - - Cohere Config. Only required if the provider is 'cohere'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelcohere_config). - -- - `databricks_model_serving_config` - - Map - - Databricks Model Serving Config. Only required if the provider is 'databricks-model-serving'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modeldatabricks_model_serving_config). - -- - `google_cloud_vertex_ai_config` - - Map - - Google Cloud Vertex AI Config. Only required if the provider is 'google-cloud-vertex-ai'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelgoogle_cloud_vertex_ai_config). - + + * - `ai21labs_config` + - Map + - AI21Labs Config. Only required if the provider is 'ai21labs'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelai21labs_config). + + * - `amazon_bedrock_config` + - Map + - Amazon Bedrock Config. Only required if the provider is 'amazon-bedrock'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelamazon_bedrock_config). + + * - `anthropic_config` + - Map + - Anthropic Config. Only required if the provider is 'anthropic'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelanthropic_config). + + * - `cohere_config` + - Map + - Cohere Config. Only required if the provider is 'cohere'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelcohere_config). + + * - `databricks_model_serving_config` + - Map + - Databricks Model Serving Config. Only required if the provider is 'databricks-model-serving'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modeldatabricks_model_serving_config). + + * - `google_cloud_vertex_ai_config` + - Map + - Google Cloud Vertex AI Config. Only required if the provider is 'google-cloud-vertex-ai'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelgoogle_cloud_vertex_ai_config). + - - `name` - String - The name of the external model. - -- - `openai_config` - - Map - - OpenAI Config. Only required if the provider is 'openai'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelopenai_config). - -- - `palm_config` - - Map - - PaLM Config. Only required if the provider is 'palm'. See [_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelpalm_config). - + + * - `openai_config` + - Map + - OpenAI Config. Only required if the provider is 'openai'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelopenai_config). + + * - `palm_config` + - Map + - PaLM Config. Only required if the provider is 'palm'. See [\_](#model_serving_endpointsnameconfigserved_entitiesexternal_modelpalm_config). + - - `provider` - String - The name of the provider for the external model. Currently, the supported providers are 'ai21labs', 'anthropic', 'amazon-bedrock', 'cohere', 'databricks-model-serving', 'google-cloud-vertex-ai', 'openai', and 'palm'. - + - - `task` - String - The task type of the external model. - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.ai21labs_config - + **`Type: Map`** - + AI21Labs Config. Only required if the provider is 'ai21labs'. - - - + :::list-table - + - - Key - Type - Description - + - - `ai21labs_api_key` - String - The Databricks secret key reference for an AI21 Labs API key. If you prefer to paste your API key directly, see `ai21labs_api_key_plaintext`. You must provide an API key using one of the following fields: `ai21labs_api_key` or `ai21labs_api_key_plaintext`. - + - - `ai21labs_api_key_plaintext` - String - An AI21 Labs API key provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `ai21labs_api_key`. You must provide an API key using one of the following fields: `ai21labs_api_key` or `ai21labs_api_key_plaintext`. - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.amazon_bedrock_config - + **`Type: Map`** - + Amazon Bedrock Config. Only required if the provider is 'amazon-bedrock'. - - - + :::list-table - + - - Key - Type - Description - + - - `aws_access_key_id` - String - The Databricks secret key reference for an AWS access key ID with permissions to interact with Bedrock services. If you prefer to paste your API key directly, see `aws_access_key_id_plaintext`. You must provide an API key using one of the following fields: `aws_access_key_id` or `aws_access_key_id_plaintext`. - + - - `aws_access_key_id_plaintext` - String - An AWS access key ID with permissions to interact with Bedrock services provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `aws_access_key_id`. You must provide an API key using one of the following fields: `aws_access_key_id` or `aws_access_key_id_plaintext`. - + - - `aws_region` - String - The AWS region to use. Bedrock has to be enabled there. - + - - `aws_secret_access_key` - String - The Databricks secret key reference for an AWS secret access key paired with the access key ID, with permissions to interact with Bedrock services. If you prefer to paste your API key directly, see `aws_secret_access_key_plaintext`. You must provide an API key using one of the following fields: `aws_secret_access_key` or `aws_secret_access_key_plaintext`. - + - - `aws_secret_access_key_plaintext` - String - An AWS secret access key paired with the access key ID, with permissions to interact with Bedrock services provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `aws_secret_access_key`. You must provide an API key using one of the following fields: `aws_secret_access_key` or `aws_secret_access_key_plaintext`. - + - - `bedrock_provider` - String - The underlying provider in Amazon Bedrock. Supported values (case insensitive) include: Anthropic, Cohere, AI21Labs, Amazon. - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.anthropic_config - + **`Type: Map`** - + Anthropic Config. Only required if the provider is 'anthropic'. - - - + :::list-table - + - - Key - Type - Description - + - - `anthropic_api_key` - String - The Databricks secret key reference for an Anthropic API key. If you prefer to paste your API key directly, see `anthropic_api_key_plaintext`. You must provide an API key using one of the following fields: `anthropic_api_key` or `anthropic_api_key_plaintext`. - + - - `anthropic_api_key_plaintext` - String - The Anthropic API key provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `anthropic_api_key`. You must provide an API key using one of the following fields: `anthropic_api_key` or `anthropic_api_key_plaintext`. - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.cohere_config - + **`Type: Map`** - + Cohere Config. Only required if the provider is 'cohere'. - - - + :::list-table - + - - Key - Type - Description - + - - `cohere_api_base` - String - This is an optional field to provide a customized base URL for the Cohere API. If left unspecified, the standard Cohere base URL is used. - + - - `cohere_api_key` - String - The Databricks secret key reference for a Cohere API key. If you prefer to paste your API key directly, see `cohere_api_key_plaintext`. You must provide an API key using one of the following fields: `cohere_api_key` or `cohere_api_key_plaintext`. - + - - `cohere_api_key_plaintext` - String - The Cohere API key provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `cohere_api_key`. You must provide an API key using one of the following fields: `cohere_api_key` or `cohere_api_key_plaintext`. - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.databricks_model_serving_config - + **`Type: Map`** - + Databricks Model Serving Config. Only required if the provider is 'databricks-model-serving'. - - - + :::list-table - + - - Key - Type - Description - + - - `databricks_api_token` - String - The Databricks secret key reference for a Databricks API token that corresponds to a user or service principal with Can Query access to the model serving endpoint pointed to by this external model. If you prefer to paste your API key directly, see `databricks_api_token_plaintext`. You must provide an API key using one of the following fields: `databricks_api_token` or `databricks_api_token_plaintext`. - + - - `databricks_api_token_plaintext` - String - The Databricks API token that corresponds to a user or service principal with Can Query access to the model serving endpoint pointed to by this external model provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `databricks_api_token`. You must provide an API key using one of the following fields: `databricks_api_token` or `databricks_api_token_plaintext`. - + - - `databricks_workspace_url` - String - The URL of the Databricks workspace containing the model serving endpoint pointed to by this external model. - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.google_cloud_vertex_ai_config - + **`Type: Map`** - + Google Cloud Vertex AI Config. Only required if the provider is 'google-cloud-vertex-ai'. - - - + :::list-table - + - - Key - Type - Description - + - - `private_key` - String - - The Databricks secret key reference for a private key for the service account which has access to the Google Cloud Vertex AI Service. See [Best practices for managing service account keys]. If you prefer to paste your API key directly, see `private_key_plaintext`. You must provide an API key using one of the following fields: `private_key` or `private_key_plaintext` [Best practices for managing service account keys]: https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys - + - The Databricks secret key reference for a private key for the service account which has access to the Google Cloud Vertex AI Service. See [Best practices for managing service account keys]. If you prefer to paste your API key directly, see `private_key_plaintext`. You must provide an API key using one of the following fields: `private_key` or `private_key_plaintext` [Best practices for managing service account keys]: https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys + - - `private_key_plaintext` - String - - The private key for the service account which has access to the Google Cloud Vertex AI Service provided as a plaintext secret. See [Best practices for managing service account keys]. If you prefer to reference your key using Databricks Secrets, see `private_key`. You must provide an API key using one of the following fields: `private_key` or `private_key_plaintext`. [Best practices for managing service account keys]: https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys - + - The private key for the service account which has access to the Google Cloud Vertex AI Service provided as a plaintext secret. See [Best practices for managing service account keys]. If you prefer to reference your key using Databricks Secrets, see `private_key`. You must provide an API key using one of the following fields: `private_key` or `private_key_plaintext`. [Best practices for managing service account keys]: https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys + - - `project_id` - String - This is the Google Cloud project id that the service account is associated with. - + - - `region` - String - - This is the region for the Google Cloud Vertex AI Service. See [supported regions] for more details. Some models are only available in specific regions. [supported regions]: https://cloud.google.com/vertex-ai/docs/general/locations - + - This is the region for the Google Cloud Vertex AI Service. See [supported regions] for more details. Some models are only available in specific regions. [supported regions]: https://cloud.google.com/vertex-ai/docs/general/locations + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.openai_config - + **`Type: Map`** - + OpenAI Config. Only required if the provider is 'openai'. - - - + :::list-table - + - - Key - Type - Description - + - - `microsoft_entra_client_id` - String - This field is only required for Azure AD OpenAI and is the Microsoft Entra Client ID. - + - - `microsoft_entra_client_secret` - String - The Databricks secret key reference for a client secret used for Microsoft Entra ID authentication. If you prefer to paste your client secret directly, see `microsoft_entra_client_secret_plaintext`. You must provide an API key using one of the following fields: `microsoft_entra_client_secret` or `microsoft_entra_client_secret_plaintext`. - + - - `microsoft_entra_client_secret_plaintext` - String - The client secret used for Microsoft Entra ID authentication provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `microsoft_entra_client_secret`. You must provide an API key using one of the following fields: `microsoft_entra_client_secret` or `microsoft_entra_client_secret_plaintext`. - + - - `microsoft_entra_tenant_id` - String - This field is only required for Azure AD OpenAI and is the Microsoft Entra Tenant ID. - + - - `openai_api_base` - String - This is a field to provide a customized base URl for the OpenAI API. For Azure OpenAI, this field is required, and is the base URL for the Azure OpenAI API service provided by Azure. For other OpenAI API types, this field is optional, and if left unspecified, the standard OpenAI base URL is used. - + - - `openai_api_key` - String - The Databricks secret key reference for an OpenAI API key using the OpenAI or Azure service. If you prefer to paste your API key directly, see `openai_api_key_plaintext`. You must provide an API key using one of the following fields: `openai_api_key` or `openai_api_key_plaintext`. - + - - `openai_api_key_plaintext` - String - The OpenAI API key using the OpenAI or Azure service provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `openai_api_key`. You must provide an API key using one of the following fields: `openai_api_key` or `openai_api_key_plaintext`. - + - - `openai_api_type` - String - This is an optional field to specify the type of OpenAI API to use. For Azure OpenAI, this field is required, and adjust this parameter to represent the preferred security access validation protocol. For access token validation, use azure. For authentication using Azure Active Directory (Azure AD) use, azuread. - + - - `openai_api_version` - String - This is an optional field to specify the OpenAI API version. For Azure OpenAI, this field is required, and is the version of the Azure OpenAI service to utilize, specified by a date. - + - - `openai_deployment_name` - String - This field is only required for Azure OpenAI and is the name of the deployment resource for the Azure OpenAI service. - + - - `openai_organization` - String - This is an optional field to specify the organization in OpenAI or Azure OpenAI. - + ::: - - + ### model_serving_endpoints.\.config.served_entities.external_model.palm_config - + **`Type: Map`** - + PaLM Config. Only required if the provider is 'palm'. - - - + :::list-table - + - - Key - Type - Description - + - - `palm_api_key` - String - The Databricks secret key reference for a PaLM API key. If you prefer to paste your API key directly, see `palm_api_key_plaintext`. You must provide an API key using one of the following fields: `palm_api_key` or `palm_api_key_plaintext`. - + - - `palm_api_key_plaintext` - String - The PaLM API key provided as a plaintext string. If you prefer to reference your key using Databricks Secrets, see `palm_api_key`. You must provide an API key using one of the following fields: `palm_api_key` or `palm_api_key_plaintext`. - + ::: - - + ### model_serving_endpoints.\.config.served_models - + **`Type: Sequence`** - + (Deprecated, use served_entities instead) The list of served models under the serving endpoint config. - - - + :::list-table - + - - Key - Type - Description - + - - `environment_vars` - Map - An object containing a set of optional, user-specified environment variable key-value pairs used for serving this entity. Note: this is an experimental feature and subject to change. Example entity environment variables that refer to Databricks secrets: `{"OPENAI_API_KEY": "{{secrets/my_scope/my_key}}", "DATABRICKS_TOKEN": "{{secrets/my_scope2/my_key2}}"}` - + - - `instance_profile_arn` - String - ARN of the instance profile that the served entity uses to access AWS resources. - + - - `max_provisioned_throughput` - Integer - The maximum tokens per second that the endpoint can scale up to. - + - - `min_provisioned_throughput` - Integer - The minimum tokens per second that the endpoint can scale down to. - + - - `model_name` - String - - - + - + - - `model_version` - String - - - + - + - - `name` - String - The name of a served entity. It must be unique across an endpoint. A served entity name can consist of alphanumeric characters, dashes, and underscores. If not specified for an external model, this field defaults to external_model.name, with '.' and ':' replaced with '-', and if not specified for other entities, it defaults to entity_name-entity_version. - + - - `scale_to_zero_enabled` - Boolean - Whether the compute resources for the served entity should scale down to zero. - + - - `workload_size` - String - The workload size of the served entity. The workload size corresponds to a range of provisioned concurrency that the compute autoscales between. A single unit of provisioned concurrency can process one request at a time. Valid workload sizes are "Small" (4 - 4 provisioned concurrency), "Medium" (8 - 16 provisioned concurrency), and "Large" (16 - 64 provisioned concurrency). If scale-to-zero is enabled, the lower bound of the provisioned concurrency for each workload size is 0. - + - - `workload_type` - String - The workload type of the served entity. The workload type selects which type of compute to use in the endpoint. The default value for this parameter is "CPU". For deep learning workloads, GPU acceleration is available by selecting workload types like GPU_SMALL and others. See the available [GPU types](https://docs.databricks.com/en/machine-learning/model-serving/create-manage-serving-endpoints.html#gpu-workload-types). - + ::: - - + ### model_serving_endpoints.\.config.traffic_config - + **`Type: Map`** - + The traffic configuration associated with the serving endpoint config. - - - + :::list-table - + - - Key - Type - Description - -- - `routes` - - Sequence - - The list of routes that define traffic to each served entity. See [_](#model_serving_endpointsnameconfigtraffic_configroutes). - -::: - - + + * - `routes` + - Sequence + - The list of routes that define traffic to each served entity. See [\_](#model_serving_endpointsnameconfigtraffic_configroutes). + ### model_serving_endpoints.\.config.traffic_config.routes - + **`Type: Sequence`** - + The list of routes that define traffic to each served entity. - - - + :::list-table - + - - Key - Type - Description - + - - `served_model_name` - String - The name of the served model this route configures traffic for. - + - - `traffic_percentage` - Integer - The percentage of endpoint traffic to send to this route. It must be an integer between 0 and 100 inclusive. - -::: - - -### model_serving_endpoints.\.permissions - -**`Type: Sequence`** - - - - +::: + +### model_serving_endpoints.\.permissions + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + ### model_serving_endpoints.\.rate_limits - + **`Type: Sequence`** - + Rate limits to be applied to the serving endpoint. NOTE: this field is deprecated, please use AI Gateway to manage rate limits. - - - + :::list-table - + - - Key - Type - Description - + - - `calls` - Integer - Used to specify how many calls are allowed for a key within the renewal_period. - + - - `key` - String - Key field for a serving endpoint rate limit. Currently, only 'user' and 'endpoint' are supported, with 'endpoint' being the default if not specified. - + - - `renewal_period` - String - Renewal period field for a serving endpoint rate limit. Currently, only 'minute' is supported. - + ::: - - + ### model_serving_endpoints.\.tags - + **`Type: Sequence`** - + Tags to be attached to the serving endpoint and automatically propagated to billing logs. - - - + :::list-table - + - - Key - Type - Description - + - - `key` - String - Key field for a serving endpoint tag. - + - - `value` - String - Optional value field for a serving endpoint tag. - + ::: - - + ## models - + **`Type: Map`** - + The model resource allows you to define [legacy models](/api/workspace/modelregistry/createmodel) in bundles. Databricks recommends you use Unity Catalog [registered models](#registered-model) instead. - + ```yaml models: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `creation_timestamp` - Integer - Timestamp recorded when this `registered_model` was created. - + - - `description` - String - Description of this `registered_model`. - + - - `last_updated_timestamp` - Integer - Timestamp recorded when metadata for this `registered_model` was last updated. - -- - `latest_versions` - - Sequence - - Collection of latest model versions for each stage. Only contains models with current `READY` status. See [_](#modelsnamelatest_versions). - + + * - `latest_versions` + - Sequence + - Collection of latest model versions for each stage. Only contains models with current `READY` status. See [\_](#modelsnamelatest_versions). + - - `name` - String - Unique name for the model. - -- - `permissions` - - Sequence - - See [_](#modelsnamepermissions). - -- - `tags` - - Sequence - - Tags: Additional metadata key-value pairs for this `registered_model`. See [_](#modelsnametags). - + + * - `permissions` + - Sequence + - See [\_](#modelsnamepermissions). + + * - `tags` + - Sequence + - Tags: Additional metadata key-value pairs for this `registered_model`. See [\_](#modelsnametags). + - - `user_id` - String - User that created this `registered_model` - + ::: - - + ### models.\.latest_versions - + **`Type: Sequence`** - + Collection of latest model versions for each stage. Only contains models with current `READY` status. - - - + :::list-table - + - - Key - Type - Description - + - - `creation_timestamp` - Integer - Timestamp recorded when this `model_version` was created. - + - - `current_stage` - String - Current stage for this `model_version`. - + - - `description` - String - Description of this `model_version`. - + - - `last_updated_timestamp` - Integer - Timestamp recorded when metadata for this `model_version` was last updated. - + - - `name` - String - Unique name of the model - + - - `run_id` - String - MLflow run ID used when creating `model_version`, if `source` was generated by an experiment run stored in MLflow tracking server. - + - - `run_link` - String - Run Link: Direct link to the run that generated this version - + - - `source` - String - URI indicating the location of the source model artifacts, used when creating `model_version` - + - - `status` - String - Current status of `model_version` - + - - `status_message` - String - Details on current `status`, if it is pending or failed. - -- - `tags` - - Sequence - - Tags: Additional metadata key-value pairs for this `model_version`. See [_](#modelsnamelatest_versionstags). - + + * - `tags` + - Sequence + - Tags: Additional metadata key-value pairs for this `model_version`. See [\_](#modelsnamelatest_versionstags). + - - `user_id` - String - User that created this `model_version`. - + - - `version` - String - Model's version number. - + ::: - - + ### models.\.latest_versions.tags - + **`Type: Sequence`** - + Tags: Additional metadata key-value pairs for this `model_version`. - - - + :::list-table - + - - Key - Type - Description - + - - `key` - String - The tag key. - + - - `value` - String - The tag value. - -::: - - -### models.\.permissions - -**`Type: Sequence`** - - - - +::: + +### models.\.permissions + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + ### models.\.tags - + **`Type: Sequence`** - + Tags: Additional metadata key-value pairs for this `registered_model`. - - - + :::list-table - + - - Key - Type - Description - + - - `key` - String - The tag key. - + - - `value` - String - The tag value. - + ::: - - + ## pipelines - + **`Type: Map`** - -The pipeline resource allows you to create Delta Live Tables [pipelines](/api/workspace/pipelines/create). For information about pipelines, see [_](/delta-live-tables/index.md). For a tutorial that uses the Databricks Asset Bundles template to create a pipeline, see [_](/dev-tools/bundles/pipelines-tutorial.md). - + +The pipeline resource allows you to create Delta Live Tables [pipelines](/api/workspace/pipelines/create). For information about pipelines, see [\_](/delta-live-tables/index.md). For a tutorial that uses the Databricks Asset Bundles template to create a pipeline, see [\_](/dev-tools/bundles/pipelines-tutorial.md). + ```yaml pipelines: : : ``` - - + :::list-table - + - - Key - Type - Description - -- - `budget_policy_id` - - String - - Budget policy of this pipeline. - + + * - `allow_duplicate_names` + - Boolean + - If false, deployment will fail if name conflicts with that of another pipeline. + + * - `budget_policy_id` + - String + - Budget policy of this pipeline. + - - `catalog` - String - A catalog in Unity Catalog to publish data from this pipeline to. If `target` is specified, tables in this pipeline are published to a `target` schema inside `catalog` (for example, `catalog`.`target`.`table`). If `target` is not specified, no data is published to Unity Catalog. - + - - `channel` - String - DLT Release Channel that specifies which version to use. - -- - `clusters` - - Sequence - - Cluster settings for this pipeline deployment. See [_](#pipelinesnameclusters). - + + * - `clusters` + - Sequence + - Cluster settings for this pipeline deployment. See [\_](#pipelinesnameclusters). + - - `configuration` - Map - String-String configuration for this pipeline execution. - + - - `continuous` - Boolean - Whether the pipeline is continuous or triggered. This replaces `trigger`. - -- - `deployment` - - Map - - Deployment type of this pipeline. See [_](#pipelinesnamedeployment). - + + * - `deployment` + - Map + - Deployment type of this pipeline. See [\_](#pipelinesnamedeployment). + - - `development` - Boolean - Whether the pipeline is in Development mode. Defaults to false. - -- - `edition` - - String - - Pipeline product edition. - -- - `filters` - - Map - - Filters on which Pipeline packages to include in the deployed graph. See [_](#pipelinesnamefilters). - -- - `gateway_definition` - - Map - - The definition of a gateway pipeline to support change data capture. See [_](#pipelinesnamegateway_definition). - + + * - `dry_run` + - Boolean + - + + * - `edition` + - String + - Pipeline product edition. + + * - `filters` + - Map + - Filters on which Pipeline packages to include in the deployed graph. See [\_](#pipelinesnamefilters). + + * - `gateway_definition` + - Map + - The definition of a gateway pipeline to support change data capture. See [\_](#pipelinesnamegateway_definition). + - - `id` - String - Unique identifier for this pipeline. - -- - `ingestion_definition` - - Map - - The configuration for a managed ingestion pipeline. These settings cannot be used with the 'libraries', 'target' or 'catalog' settings. See [_](#pipelinesnameingestion_definition). - -- - `libraries` - - Sequence - - Libraries or code needed by this deployment. See [_](#pipelinesnamelibraries). - + + * - `ingestion_definition` + - Map + - The configuration for a managed ingestion pipeline. These settings cannot be used with the 'libraries', 'target' or 'catalog' settings. See [\_](#pipelinesnameingestion_definition). + + * - `libraries` + - Sequence + - Libraries or code needed by this deployment. See [\_](#pipelinesnamelibraries). + - - `name` - String - Friendly identifier for this pipeline. - -- - `notifications` - - Sequence - - List of notification settings for this pipeline. See [_](#pipelinesnamenotifications). - -- - `permissions` - - Sequence - - See [_](#pipelinesnamepermissions). - + + * - `notifications` + - Sequence + - List of notification settings for this pipeline. See [\_](#pipelinesnamenotifications). + + * - `permissions` + - Sequence + - See [\_](#pipelinesnamepermissions). + - - `photon` - Boolean - Whether Photon is enabled for this pipeline. - -- - `restart_window` - - Map - - Restart window of this pipeline. See [_](#pipelinesnamerestart_window). - + + * - `restart_window` + - Map + - Restart window of this pipeline. See [\_](#pipelinesnamerestart_window). + + * - `run_as` + - Map + - Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as. If not specified, the pipeline runs as the user who created the pipeline. Only `user_name` or `service_principal_name` can be specified. If both are specified, an error is thrown. See [\_](#pipelinesnamerun_as). + - - `schema` - String - The default schema (database) where tables are read from or published to. The presence of this field implies that the pipeline is in direct publishing mode. - + - - `serverless` - Boolean - Whether serverless compute is enabled for this pipeline. - + - - `storage` - String - DBFS root directory for storing checkpoints and tables. - + - - `target` - String - Target schema (database) to add tables in this pipeline to. If not specified, no data is published to the Hive metastore or Unity Catalog. To publish to Unity Catalog, also specify `catalog`. - -- - `trigger` - - Map - - Which pipeline trigger to use. Deprecated: Use `continuous` instead. See [_](#pipelinesnametrigger). - -::: - - + + * - `trigger` + - Map + - Which pipeline trigger to use. Deprecated: Use `continuous` instead. See [\_](#pipelinesnametrigger). + **Example** - + The following example defines a pipeline with the resource key `hello-pipeline`: ```yaml @@ -6520,1356 +5852,1233 @@ resources: - notebook: path: ./pipeline.py ``` - + ### pipelines.\.clusters - + **`Type: Sequence`** - + Cluster settings for this pipeline deployment. - - - + :::list-table - + - - Key - Type - Description - + - - `apply_policy_default_values` - Boolean - Note: This field won't be persisted. Only API users will check this field. - -- - `autoscale` - - Map - - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [_](#pipelinesnameclustersautoscale). - -- - `aws_attributes` - - Map - - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [_](#pipelinesnameclustersaws_attributes). - -- - `azure_attributes` - - Map - - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [_](#pipelinesnameclustersazure_attributes). - -- - `cluster_log_conf` - - Map - - The configuration for delivering spark logs to a long-term storage destination. Only dbfs destinations are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. . See [_](#pipelinesnameclusterscluster_log_conf). - + + * - `autoscale` + - Map + - Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. See [\_](#pipelinesnameclustersautoscale). + + * - `aws_attributes` + - Map + - Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. See [\_](#pipelinesnameclustersaws_attributes). + + * - `azure_attributes` + - Map + - Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. See [\_](#pipelinesnameclustersazure_attributes). + + * - `cluster_log_conf` + - Map + - The configuration for delivering spark logs to a long-term storage destination. Only dbfs destinations are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. . See [\_](#pipelinesnameclusterscluster_log_conf). + - - `custom_tags` - Map - - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags - + - Additional tags for cluster resources. Databricks will tag all cluster resources (e.g., AWS instances and EBS volumes) with these tags in addition to `default_tags`. Notes: - Currently, Databricks allows at most 45 custom tags - Clusters can only reuse cloud resources if the resources' tags are a subset of the cluster tags + - - `driver_instance_pool_id` - String - The optional ID of the instance pool for the driver of the cluster belongs. The pool cluster uses the instance pool with id (instance_pool_id) if the driver pool is not assigned. - + - - `driver_node_type_id` - String - The node type of the Spark driver. Note that this field is optional; if unset, the driver node type will be set as the same value as `node_type_id` defined above. - + - - `enable_local_disk_encryption` - Boolean - Whether to enable local disk encryption for the cluster. - -- - `gcp_attributes` - - Map - - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [_](#pipelinesnameclustersgcp_attributes). - -- - `init_scripts` - - Sequence - - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [_](#pipelinesnameclustersinit_scripts). - + + * - `gcp_attributes` + - Map + - Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. See [\_](#pipelinesnameclustersgcp_attributes). + + * - `init_scripts` + - Sequence + - The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. See [\_](#pipelinesnameclustersinit_scripts). + - - `instance_pool_id` - String - The optional ID of the instance pool to which the cluster belongs. - + - - `label` - String - A label for the cluster specification, either `default` to configure the default cluster, or `maintenance` to configure the maintenance cluster. This field is optional. The default value is `default`. - + - - `node_type_id` - String - - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. - + - This field encodes, through a single value, the resources available to each of the Spark nodes in this cluster. For example, the Spark nodes can be provisioned and optimized for memory or compute intensive workloads. A list of available node types can be retrieved by using the :method:clusters/listNodeTypes API call. + - - `num_workers` - Integer - - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. - + - Number of worker nodes that this cluster should have. A cluster has one Spark Driver and `num_workers` Executors for a total of `num_workers` + 1 Spark nodes. Note: When reading the properties of a cluster, this field reflects the desired number of workers rather than the actual current number of workers. For instance, if a cluster is resized from 5 to 10 workers, this field will immediately be updated to reflect the target size of 10 workers, whereas the workers listed in `spark_info` will gradually increase from 5 to 10 as the new nodes are provisioned. + - - `policy_id` - String - The ID of the cluster policy used to create the cluster if applicable. - + - - `spark_conf` - Map - - An object containing a set of optional, user-specified Spark configuration key-value pairs. See :method:clusters/create for more details. - + - An object containing a set of optional, user-specified Spark configuration key-value pairs. See :method:clusters/create for more details. + - - `spark_env_vars` - Map - - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` - + - An object containing a set of optional, user-specified environment variable key-value pairs. Please note that key-value pair of the form (X,Y) will be exported as is (i.e., `export X='Y'`) while launching the driver and workers. In order to specify an additional set of `SPARK_DAEMON_JAVA_OPTS`, we recommend appending them to `$SPARK_DAEMON_JAVA_OPTS` as shown in the example below. This ensures that all default databricks managed environmental variables are included as well. Example Spark environment variables: `{"SPARK_WORKER_MEMORY": "28000m", "SPARK_LOCAL_DIRS": "/local_disk0"}` or `{"SPARK_DAEMON_JAVA_OPTS": "$SPARK_DAEMON_JAVA_OPTS -Dspark.shuffle.service.enabled=true"}` + - - `ssh_public_keys` - Sequence - SSH public key contents that will be added to each Spark node in this cluster. The corresponding private keys can be used to login with the user name `ubuntu` on port `2200`. Up to 10 keys can be specified. - + ::: - - + ### pipelines.\.clusters.autoscale - + **`Type: Map`** - + Parameters needed in order to automatically scale clusters up and down based on load. Note: autoscaling works best with DB runtime versions 3.0 or later. - - - + :::list-table - + - - Key - Type - Description - + - - `max_workers` - Integer - The maximum number of workers to which the cluster can scale up when overloaded. `max_workers` must be strictly greater than `min_workers`. - + - - `min_workers` - Integer - The minimum number of workers the cluster can scale down to when underutilized. It is also the initial number of workers the cluster will have after creation. - + - - `mode` - String - - Databricks Enhanced Autoscaling optimizes cluster utilization by automatically allocating cluster resources based on workload volume, with minimal impact to the data processing latency of your pipelines. Enhanced Autoscaling is available for `updates` clusters only. The legacy autoscaling feature is used for `maintenance` clusters. - + - Databricks Enhanced Autoscaling optimizes cluster utilization by automatically allocating cluster resources based on workload volume, with minimal impact to the data processing latency of your pipelines. Enhanced Autoscaling is available for `updates` clusters only. The legacy autoscaling feature is used for `maintenance` clusters. + ::: - - + ### pipelines.\.clusters.aws_attributes - + **`Type: Map`** - + Attributes related to clusters running on Amazon Web Services. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. - + - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero, this availability type will be used for the entire cluster. + - - `ebs_volume_count` - Integer - - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. - + - The number of volumes launched for each instance. Users can choose up to 10 volumes. This feature is only enabled for supported node types. Legacy node types cannot specify custom EBS volumes. For node types with no instance store, at least one EBS volume needs to be specified; otherwise, cluster creation will fail. These EBS volumes will be mounted at `/ebs0`, `/ebs1`, and etc. Instance store volumes will be mounted at `/local_disk0`, `/local_disk1`, and etc. If EBS volumes are attached, Databricks will configure Spark to use only the EBS volumes for scratch storage because heterogenously sized scratch devices can lead to inefficient disk utilization. If no EBS volumes are attached, Databricks will configure Spark to use instance store volumes. Please note that if EBS volumes are specified, then the Spark configuration `spark.local.dir` will be overridden. + - - `ebs_volume_iops` - Integer - If using gp3 volumes, what IOPS to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_size` - Integer - The size of each EBS volume (in GiB) launched for each instance. For general purpose SSD, this value must be within the range 100 - 4096. For throughput optimized HDD, this value must be within the range 500 - 4096. - + - - `ebs_volume_throughput` - Integer - If using gp3 volumes, what throughput to use for the disk. If this is not set, the maximum performance of a gp2 volume with the same volume size will be used. - + - - `ebs_volume_type` - String - The type of EBS volumes that will be launched with this cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. If this value is greater than 0, the cluster driver node in particular will be placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - + - - `instance_profile_arn` - String - - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. - + - Nodes for this cluster will only be placed on AWS instances with this instance profile. If ommitted, nodes will be placed on instances without an IAM instance profile. The instance profile must have previously been added to the Databricks environment by an account administrator. This feature may only be available to certain customer plans. If this field is ommitted, we will pull in the default from the conf if it exists. + - - `spot_bid_price_percent` - Integer - - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. - + - The bid price for AWS spot instances, as a percentage of the corresponding instance type's on-demand price. For example, if this field is set to 50, and the cluster needs a new `r3.xlarge` spot instance, then the bid price is half of the price of on-demand `r3.xlarge` instances. Similarly, if this field is set to 200, the bid price is twice the price of on-demand `r3.xlarge` instances. If not specified, the default value is 100. When spot instances are requested for this cluster, only spot instances whose bid price percentage matches this field will be considered. Note that, for safety, we enforce this field to be no more than 10000. The default value and documentation here should be kept consistent with CommonConf.defaultSpotBidPricePercent and CommonConf.maxSpotBidPricePercent. + - - `zone_id` - String - Identifier for the availability zone/datacenter in which the cluster resides. This string will be of a form like "us-west-2a". The provided availability zone must be in the same region as the Databricks deployment. For example, "us-west-2a" is not a valid zone id if the Databricks deployment resides in the "us-east-1" region. This is an optional field at cluster creation, and if not specified, a default zone will be used. If the zone specified is "auto", will try to place cluster in a zone with high availability, and will retry placement in a different AZ if there is not enough capacity. The list of available zones as well as the default value can be found by using the `List Zones` method. - + ::: - - + ### pipelines.\.clusters.azure_attributes - + **`Type: Map`** - + Attributes related to clusters running on Microsoft Azure. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - Availability type used for all subsequent nodes past the `first_on_demand` ones. Note: If `first_on_demand` is zero (which only happens on pool clusters), this availability type will be used for the entire cluster. - + - - `first_on_demand` - Integer - The first `first_on_demand` nodes of the cluster will be placed on on-demand instances. This value should be greater than 0, to make sure the cluster driver node is placed on an on-demand instance. If this value is greater than or equal to the current cluster size, all nodes will be placed on on-demand instances. If this value is less than the current cluster size, `first_on_demand` nodes will be placed on on-demand instances and the remainder will be placed on `availability` instances. Note that this value does not affect cluster size and cannot currently be mutated over the lifetime of a cluster. - -- - `log_analytics_info` - - Map - - Defines values necessary to configure and run Azure Log Analytics agent. See [_](#pipelinesnameclustersazure_attributeslog_analytics_info). - + + * - `log_analytics_info` + - Map + - Defines values necessary to configure and run Azure Log Analytics agent. See [\_](#pipelinesnameclustersazure_attributeslog_analytics_info). + - - `spot_bid_max_price` - Any - The max bid price to be used for Azure spot instances. The Max price for the bid cannot be higher than the on-demand price of the instance. If not specified, the default value is -1, which specifies that the instance cannot be evicted on the basis of price, and only on the basis of availability. Further, the value should > 0 or -1. - + ::: - - + ### pipelines.\.clusters.azure_attributes.log_analytics_info - + **`Type: Map`** - + Defines values necessary to configure and run Azure Log Analytics agent - - - + :::list-table - + - - Key - Type - Description - + - - `log_analytics_primary_key` - String - - - + - + - - `log_analytics_workspace_id` - String - - - + - + ::: - - + ### pipelines.\.clusters.cluster_log_conf - + **`Type: Map`** - + The configuration for delivering spark logs to a long-term storage destination. Only dbfs destinations are supported. Only one destination can be specified for one cluster. If the conf is given, the logs will be delivered to the destination every `5 mins`. The destination of driver logs is `$destination/$clusterId/driver`, while the destination of executor logs is `$destination/$clusterId/executor`. - - - :::list-table - + - - Key - Type - Description - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#pipelinesnameclusterscluster_log_confdbfs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#pipelinesnameclusterscluster_log_confs3). - -::: - - + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#pipelinesnameclusterscluster_log_confdbfs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#pipelinesnameclusterscluster_log_confs3). + ### pipelines.\.clusters.cluster_log_conf.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### pipelines.\.clusters.cluster_log_conf.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + ::: - - + ### pipelines.\.clusters.gcp_attributes - + **`Type: Map`** - + Attributes related to clusters running on Google Cloud Platform. If not specified at cluster creation, a set of default values will be used. - - - + :::list-table - + - - Key - Type - Description - + - - `availability` - String - This field determines whether the instance pool will contain preemptible VMs, on-demand VMs, or preemptible VMs with a fallback to on-demand VMs if the former is unavailable. - + - - `boot_disk_size` - Integer - boot disk size in GB - + - - `google_service_account` - String - If provided, the cluster will impersonate the google service account when accessing gcloud services (like GCS). The google service account must have previously been added to the Databricks environment by an account administrator. - + - - `local_ssd_count` - Integer - If provided, each node (workers and driver) in the cluster will have this number of local SSDs attached. Each local SSD is 375GB in size. Refer to [GCP documentation](https://cloud.google.com/compute/docs/disks/local-ssd#choose_number_local_ssds) for the supported number of local SSDs for each instance type. - + - - `use_preemptible_executors` - Boolean - This field determines whether the spark executors will be scheduled to run on preemptible VMs (when set to true) versus standard compute engine VMs (when set to false; default). Note: Soon to be deprecated, use the availability field instead. - + - - `zone_id` - String - Identifier for the availability zone in which the cluster resides. This can be one of the following: - "HA" => High availability, spread nodes across availability zones for a Databricks deployment region [default] - "AUTO" => Databricks picks an availability zone to schedule the cluster on. - A GCP availability zone => Pick One of the available zones for (machine type + region) from https://cloud.google.com/compute/docs/regions-zones. - -::: - - -### pipelines.\.clusters.init_scripts - -**`Type: Sequence`** - -The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. - - - -:::list-table - -- - Key - - Type - - Description - -- - `abfss` - - Map - - See [_](#pipelinesnameclustersinit_scriptsabfss). - -- - `dbfs` - - Map - - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [_](#pipelinesnameclustersinit_scriptsdbfs). - -- - `file` - - Map - - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [_](#pipelinesnameclustersinit_scriptsfile). - -- - `gcs` - - Map - - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [_](#pipelinesnameclustersinit_scriptsgcs). - -- - `s3` - - Map - - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [_](#pipelinesnameclustersinit_scriptss3). - -- - `volumes` - - Map - - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [_](#pipelinesnameclustersinit_scriptsvolumes). - -- - `workspace` - - Map - - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [_](#pipelinesnameclustersinit_scriptsworkspace). - -::: - - -### pipelines.\.clusters.init_scripts.abfss - -**`Type: Map`** - - - - +::: + +### pipelines.\.clusters.init_scripts + +**`Type: Sequence`** + +The configuration for storing init scripts. Any number of destinations can be specified. The scripts are executed sequentially in the order provided. If `cluster_log_conf` is specified, init script logs are sent to `//init_scripts`. + :::list-table - + - - Key - Type - Description - + + * - `abfss` + - Map + - destination needs to be provided. e.g. `{ "abfss" : { "destination" : "abfss://@.dfs.core.windows.net/" } }. See [\_](#pipelinesnameclustersinit_scriptsabfss). + + * - `dbfs` + - Map + - destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }`. See [\_](#pipelinesnameclustersinit_scriptsdbfs). + + * - `file` + - Map + - destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }`. See [\_](#pipelinesnameclustersinit_scriptsfile). + + * - `gcs` + - Map + - destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }`. See [\_](#pipelinesnameclustersinit_scriptsgcs). + + * - `s3` + - Map + - destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. See [\_](#pipelinesnameclustersinit_scriptss3). + + * - `volumes` + - Map + - destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }`. See [\_](#pipelinesnameclustersinit_scriptsvolumes). + + * - `workspace` + - Map + - destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }`. See [\_](#pipelinesnameclustersinit_scriptsworkspace). + +### pipelines.\.clusters.init_scripts.abfss + +**`Type: Map`** + +:::list-table + +- - Key + - Type + - Description + - - `destination` - String - abfss destination, e.g. `abfss://@.dfs.core.windows.net/`. - + ::: - - + ### pipelines.\.clusters.init_scripts.dbfs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "dbfs" : { "destination" : "dbfs:/home/cluster_log" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - dbfs destination, e.g. `dbfs:/my/path` - + ::: - - + ### pipelines.\.clusters.init_scripts.file - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "file" : { "destination" : "file:/my/local/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - local file destination, e.g. `file:/my/local/file.sh` - + ::: - - + ### pipelines.\.clusters.init_scripts.gcs - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "gcs": { "destination": "gs://my-bucket/file.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - GCS destination/URI, e.g. `gs://my-bucket/some-prefix` - + ::: - - + ### pipelines.\.clusters.init_scripts.s3 - + **`Type: Map`** - + destination and either the region or endpoint need to be provided. e.g. `{ "s3": { "destination" : "s3://cluster_log_bucket/prefix", "region" : "us-west-2" } }` Cluster iam role is used to access s3, please make sure the cluster iam role in `instance_profile_arn` has permission to write data to the s3 destination. - - - + :::list-table - + - - Key - Type - Description - + - - `canned_acl` - String - (Optional) Set canned access control list for the logs, e.g. `bucket-owner-full-control`. If `canned_cal` is set, please make sure the cluster iam role has `s3:PutObjectAcl` permission on the destination bucket and prefix. The full list of possible canned acl can be found at http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl. Please also note that by default only the object owner gets full controls. If you are using cross account role for writing data, you may want to set `bucket-owner-full-control` to make bucket owner able to read the logs. - + - - `destination` - String - S3 destination, e.g. `s3://my-bucket/some-prefix` Note that logs will be delivered using cluster iam role, please make sure you set cluster iam role and the role has write access to the destination. Please also note that you cannot use AWS keys to deliver logs. - + - - `enable_encryption` - Boolean - (Optional) Flag to enable server side encryption, `false` by default. - + - - `encryption_type` - String - (Optional) The encryption type, it could be `sse-s3` or `sse-kms`. It will be used only when encryption is enabled and the default type is `sse-s3`. - + - - `endpoint` - String - S3 endpoint, e.g. `https://s3-us-west-2.amazonaws.com`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + - - `kms_key` - String - (Optional) Kms key which will be used if encryption is enabled and encryption type is set to `sse-kms`. - + - - `region` - String - S3 region, e.g. `us-west-2`. Either region or endpoint needs to be set. If both are set, endpoint will be used. - + ::: - - + ### pipelines.\.clusters.init_scripts.volumes - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "volumes" : { "destination" : "/Volumes/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - Unity Catalog Volumes file destination, e.g. `/Volumes/my-init.sh` - + ::: - - + ### pipelines.\.clusters.init_scripts.workspace - + **`Type: Map`** - + destination needs to be provided. e.g. `{ "workspace" : { "destination" : "/Users/user1@databricks.com/my-init.sh" } }` - - - + :::list-table - + - - Key - Type - Description - + - - `destination` - String - workspace files destination, e.g. `/Users/user1@databricks.com/my-init.sh` - + ::: - - + ### pipelines.\.deployment - + **`Type: Map`** - + Deployment type of this pipeline. - - - + :::list-table - + - - Key - Type - Description - + - - `kind` - String - The deployment method that manages the pipeline. - + - - `metadata_file_path` - String - The path to the file containing metadata about the deployment. - + ::: - - + ### pipelines.\.filters - + **`Type: Map`** - + Filters on which Pipeline packages to include in the deployed graph. - - - + :::list-table - + - - Key - Type - Description - + - - `exclude` - Sequence - Paths to exclude. - + - - `include` - Sequence - Paths to include. - + ::: - - + ### pipelines.\.gateway_definition - + **`Type: Map`** - + The definition of a gateway pipeline to support change data capture. - - - + :::list-table - + - - Key - Type - Description - + - - `connection_id` - String - [Deprecated, use connection_name instead] Immutable. The Unity Catalog connection that this gateway pipeline uses to communicate with the source. - + - - `connection_name` - String - Immutable. The Unity Catalog connection that this gateway pipeline uses to communicate with the source. - + - - `gateway_storage_catalog` - String - Required, Immutable. The name of the catalog for the gateway pipeline's storage location. - + - - `gateway_storage_name` - String - - Optional. The Unity Catalog-compatible name for the gateway storage location. This is the destination to use for the data that is extracted by the gateway. Delta Live Tables system will automatically create the storage location under the catalog and schema. - + - Optional. The Unity Catalog-compatible name for the gateway storage location. This is the destination to use for the data that is extracted by the gateway. Delta Live Tables system will automatically create the storage location under the catalog and schema. + - - `gateway_storage_schema` - String - Required, Immutable. The name of the schema for the gateway pipelines's storage location. - + ::: - - + ### pipelines.\.ingestion_definition - + **`Type: Map`** - + The configuration for a managed ingestion pipeline. These settings cannot be used with the 'libraries', 'target' or 'catalog' settings. - - - + :::list-table - + - - Key - Type - Description - + - - `connection_name` - String - Immutable. The Unity Catalog connection that this ingestion pipeline uses to communicate with the source. This is used with connectors for applications like Salesforce, Workday, and so on. - + - - `ingestion_gateway_id` - String - Immutable. Identifier for the gateway that is used by this ingestion pipeline to communicate with the source database. This is used with connectors to databases like SQL Server. - -- - `objects` - - Sequence - - Required. Settings specifying tables to replicate and the destination for the replicated tables. See [_](#pipelinesnameingestion_definitionobjects). - -- - `table_configuration` - - Map - - Configuration settings to control the ingestion of tables. These settings are applied to all tables in the pipeline. See [_](#pipelinesnameingestion_definitiontable_configuration). - -::: - - + + * - `objects` + - Sequence + - Required. Settings specifying tables to replicate and the destination for the replicated tables. See [\_](#pipelinesnameingestion_definitionobjects). + + * - `table_configuration` + - Map + - Configuration settings to control the ingestion of tables. These settings are applied to all tables in the pipeline. See [\_](#pipelinesnameingestion_definitiontable_configuration). + ### pipelines.\.ingestion_definition.objects - + **`Type: Sequence`** - + Required. Settings specifying tables to replicate and the destination for the replicated tables. - - - + :::list-table - + - - Key - Type - Description - -- - `report` - - Map - - Select a specific source report. See [_](#pipelinesnameingestion_definitionobjectsreport). - -- - `schema` - - Map - - Select all tables from a specific source schema. See [_](#pipelinesnameingestion_definitionobjectsschema). - -- - `table` - - Map - - Select a specific source table. See [_](#pipelinesnameingestion_definitionobjectstable). - -::: - - + + * - `report` + - Map + - Select a specific source report. See [\_](#pipelinesnameingestion_definitionobjectsreport). + + * - `schema` + - Map + - Select all tables from a specific source schema. See [\_](#pipelinesnameingestion_definitionobjectsschema). + + * - `table` + - Map + - Select a specific source table. See [\_](#pipelinesnameingestion_definitionobjectstable). + ### pipelines.\.ingestion_definition.objects.report - + **`Type: Map`** - + Select a specific source report. - - - + :::list-table - + - - Key - Type - Description - + - - `destination_catalog` - String - Required. Destination catalog to store table. - + - - `destination_schema` - String - Required. Destination schema to store table. - + - - `destination_table` - String - Required. Destination table name. The pipeline fails if a table with that name already exists. - + - - `source_url` - String - Required. Report URL in the source system. - -- - `table_configuration` - - Map - - Configuration settings to control the ingestion of tables. These settings override the table_configuration defined in the IngestionPipelineDefinition object. See [_](#pipelinesnameingestion_definitionobjectsreporttable_configuration). - -::: - - + + * - `table_configuration` + - Map + - Configuration settings to control the ingestion of tables. These settings override the table*configuration defined in the IngestionPipelineDefinition object. See [*](#pipelinesnameingestion_definitionobjectsreporttable_configuration). + ### pipelines.\.ingestion_definition.objects.report.table_configuration - + **`Type: Map`** - + Configuration settings to control the ingestion of tables. These settings override the table_configuration defined in the IngestionPipelineDefinition object. - - - + :::list-table - + - - Key - Type - Description - + - - `primary_keys` - Sequence - The primary key of the table used to apply changes. - + - - `salesforce_include_formula_fields` - Boolean - If true, formula fields defined in the table are included in the ingestion. This setting is only valid for the Salesforce connector - + - - `scd_type` - String - The SCD type to use to ingest the table. - + - - `sequence_by` - Sequence - The column names specifying the logical order of events in the source data. Delta Live Tables uses this sequencing to handle change events that arrive out of order. - + ::: - - + ### pipelines.\.ingestion_definition.objects.schema - + **`Type: Map`** - + Select all tables from a specific source schema. - - - + :::list-table - + - - Key - Type - Description - + - - `destination_catalog` - String - Required. Destination catalog to store tables. - + - - `destination_schema` - String - Required. Destination schema to store tables in. Tables with the same name as the source tables are created in this destination schema. The pipeline fails If a table with the same name already exists. - + - - `source_catalog` - String - The source catalog name. Might be optional depending on the type of source. - + - - `source_schema` - String - Required. Schema name in the source database. - -- - `table_configuration` - - Map - - Configuration settings to control the ingestion of tables. These settings are applied to all tables in this schema and override the table_configuration defined in the IngestionPipelineDefinition object. See [_](#pipelinesnameingestion_definitionobjectsschematable_configuration). - -::: - - + + * - `table_configuration` + - Map + - Configuration settings to control the ingestion of tables. These settings are applied to all tables in this schema and override the table*configuration defined in the IngestionPipelineDefinition object. See [*](#pipelinesnameingestion_definitionobjectsschematable_configuration). + ### pipelines.\.ingestion_definition.objects.schema.table_configuration - + **`Type: Map`** - + Configuration settings to control the ingestion of tables. These settings are applied to all tables in this schema and override the table_configuration defined in the IngestionPipelineDefinition object. - - - + :::list-table - + - - Key - Type - Description - + - - `primary_keys` - Sequence - The primary key of the table used to apply changes. - + - - `salesforce_include_formula_fields` - Boolean - If true, formula fields defined in the table are included in the ingestion. This setting is only valid for the Salesforce connector - + - - `scd_type` - String - The SCD type to use to ingest the table. - + - - `sequence_by` - Sequence - The column names specifying the logical order of events in the source data. Delta Live Tables uses this sequencing to handle change events that arrive out of order. - + ::: - - + ### pipelines.\.ingestion_definition.objects.table - + **`Type: Map`** - + Select a specific source table. - - - + :::list-table - + - - Key - Type - Description - + - - `destination_catalog` - String - Required. Destination catalog to store table. - + - - `destination_schema` - String - Required. Destination schema to store table. - + - - `destination_table` - String - Optional. Destination table name. The pipeline fails if a table with that name already exists. If not set, the source table name is used. - + - - `source_catalog` - String - Source catalog name. Might be optional depending on the type of source. - + - - `source_schema` - String - Schema name in the source database. Might be optional depending on the type of source. - + - - `source_table` - String - Required. Table name in the source database. - -- - `table_configuration` - - Map - - Configuration settings to control the ingestion of tables. These settings override the table_configuration defined in the IngestionPipelineDefinition object and the SchemaSpec. See [_](#pipelinesnameingestion_definitionobjectstabletable_configuration). - -::: - - + + * - `table_configuration` + - Map + - Configuration settings to control the ingestion of tables. These settings override the table*configuration defined in the IngestionPipelineDefinition object and the SchemaSpec. See [*](#pipelinesnameingestion_definitionobjectstabletable_configuration). + ### pipelines.\.ingestion_definition.objects.table.table_configuration - + **`Type: Map`** - + Configuration settings to control the ingestion of tables. These settings override the table_configuration defined in the IngestionPipelineDefinition object and the SchemaSpec. - - - + :::list-table - + - - Key - Type - Description - + - - `primary_keys` - Sequence - The primary key of the table used to apply changes. - + - - `salesforce_include_formula_fields` - Boolean - If true, formula fields defined in the table are included in the ingestion. This setting is only valid for the Salesforce connector - + - - `scd_type` - String - The SCD type to use to ingest the table. - + - - `sequence_by` - Sequence - The column names specifying the logical order of events in the source data. Delta Live Tables uses this sequencing to handle change events that arrive out of order. - + ::: - - + ### pipelines.\.ingestion_definition.table_configuration - + **`Type: Map`** - + Configuration settings to control the ingestion of tables. These settings are applied to all tables in the pipeline. - - - + :::list-table - + - - Key - Type - Description - + - - `primary_keys` - Sequence - The primary key of the table used to apply changes. - + - - `salesforce_include_formula_fields` - Boolean - If true, formula fields defined in the table are included in the ingestion. This setting is only valid for the Salesforce connector - + - - `scd_type` - String - The SCD type to use to ingest the table. - + - - `sequence_by` - Sequence - The column names specifying the logical order of events in the source data. Delta Live Tables uses this sequencing to handle change events that arrive out of order. - + ::: - - + ### pipelines.\.libraries - + **`Type: Sequence`** - + Libraries or code needed by this deployment. - - - + :::list-table - + - - Key - Type - Description - -- - `file` - - Map - - The path to a file that defines a pipeline and is stored in the Databricks Repos. . See [_](#pipelinesnamelibrariesfile). - + + * - `file` + - Map + - The path to a file that defines a pipeline and is stored in the Databricks Repos. . See [\_](#pipelinesnamelibrariesfile). + - - `jar` - String - - URI of the jar to be installed. Currently only DBFS is supported. - -- - `maven` - - Map - - Specification of a maven library to be installed. . See [_](#pipelinesnamelibrariesmaven). - -- - `notebook` - - Map - - The path to a notebook that defines a pipeline and is stored in the Databricks workspace. . See [_](#pipelinesnamelibrariesnotebook). - + - URI of the jar to be installed. Currently only DBFS is supported. + + * - `maven` + - Map + - Specification of a maven library to be installed. . See [\_](#pipelinesnamelibrariesmaven). + + * - `notebook` + - Map + - The path to a notebook that defines a pipeline and is stored in the Databricks workspace. . See [\_](#pipelinesnamelibrariesnotebook). + - - `whl` - String - URI of the whl to be installed. - + ::: - - + ### pipelines.\.libraries.file - + **`Type: Map`** - + The path to a file that defines a pipeline and is stored in the Databricks Repos. - - - :::list-table - + - - Key - Type - Description - + - - `path` - String - The absolute path of the file. - + ::: - - + ### pipelines.\.libraries.maven - + **`Type: Map`** - + Specification of a maven library to be installed. - - - :::list-table - + - - Key - Type - Description - + - - `coordinates` - String - Gradle-style maven coordinates. For example: "org.jsoup:jsoup:1.7.2". - + - - `exclusions` - Sequence - - List of dependences to exclude. For example: `["slf4j:slf4j", "*:hadoop-client"]`. Maven dependency exclusions: https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html. - + - List of dependences to exclude. For example: `["slf4j:slf4j", "*:hadoop-client"]`. Maven dependency exclusions: https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html. + - - `repo` - String - Maven repo to install the Maven package from. If omitted, both Maven Central Repository and Spark Packages are searched. - + ::: - - + ### pipelines.\.libraries.notebook - + **`Type: Map`** - + The path to a notebook that defines a pipeline and is stored in the Databricks workspace. - - - :::list-table - + - - Key - Type - Description - + - - `path` - String - The absolute path of the notebook. - + ::: - - + ### pipelines.\.notifications - + **`Type: Sequence`** - + List of notification settings for this pipeline. - - - + :::list-table - + - - Key - Type - Description - + - - `alerts` - Sequence - - A list of alerts that trigger the sending of notifications to the configured destinations. The supported alerts are: * `on-update-success`: A pipeline update completes successfully. * `on-update-failure`: Each time a pipeline update fails. * `on-update-fatal-failure`: A pipeline update fails with a non-retryable (fatal) error. * `on-flow-failure`: A single data flow fails. - + - A list of alerts that trigger the sending of notifications to the configured destinations. The supported alerts are: _ `on-update-success`: A pipeline update completes successfully. _ `on-update-failure`: Each time a pipeline update fails. _ `on-update-fatal-failure`: A pipeline update fails with a non-retryable (fatal) error. _ `on-flow-failure`: A single data flow fails. + - - `email_recipients` - Sequence - - A list of email addresses notified when a configured alert is triggered. - -::: - - -### pipelines.\.permissions - -**`Type: Sequence`** - + - A list of email addresses notified when a configured alert is triggered. + +::: + +### pipelines.\.permissions + +**`Type: Sequence`** - - - :::list-table - + - - Key - Type - Description - + - - `group_name` - String - The name of the group that has the permission set in level. - + - - `level` - String - The allowed permission for user, group, service principal defined for this permission. - + - - `service_principal_name` - String - The name of the service principal that has the permission set in level. - + - - `user_name` - String - The name of the user that has the permission set in level. - + ::: - - + ### pipelines.\.restart_window - + **`Type: Map`** - + Restart window of this pipeline. - - - + :::list-table - + - - Key - Type - Description - + - - `days_of_week` - Sequence - Days of week in which the restart is allowed to happen (within a five-hour window starting at start_hour). If not specified all days of the week will be used. - + - - `start_hour` - Integer - An integer between 0 and 23 denoting the start hour for the restart window in the 24-hour day. Continuous pipeline restart is triggered only within a five-hour window starting at this hour. - + - - `time_zone_id` - String - Time zone id of restart window. See https://docs.databricks.com/sql/language-manual/sql-ref-syntax-aux-conf-mgmt-set-timezone.html for details. If not specified, UTC will be used. - + ::: - - + ### pipelines.\.restart_window.days_of_week - + **`Type: Sequence`** - + Days of week in which the restart is allowed to happen (within a five-hour window starting at start_hour). If not specified all days of the week will be used. - - -### pipelines.\.trigger - + +### pipelines.\.run_as + **`Type: Map`** - -Which pipeline trigger to use. Deprecated: Use `continuous` instead. - - - -:::list-table - + +Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as. If not specified, the pipeline runs as the user who created the pipeline. + +Only `user_name` or `service_principal_name` can be specified. If both are specified, an error is thrown. + +.. list-table:: +:header-rows: 1 + - - Key - Type - Description - -- - `cron` - - Map - - See [_](#pipelinesnametriggercron). - + +- - `service_principal_name` + - String + - Application ID of an active service principal. Setting this field requires the `servicePrincipal/user` role. + +- - `user_name` + - String + - The email of an active workspace user. Users can only set this field to their own email. + +### pipelines.\.trigger + +**`Type: Map`** + +Which pipeline trigger to use. Deprecated: Use `continuous` instead. + +:::list-table + +- - Key + - Type + - Description + + * - `cron` + - Map + - See [\_](#pipelinesnametriggercron). + - - `manual` - Map - - - -::: - - -### pipelines.\.trigger.cron - -**`Type: Map`** - + - + +::: + +### pipelines.\.trigger.cron + +**`Type: Map`** - - - :::list-table - + - - Key - Type - Description - + - - `quartz_cron_schedule` - String - - - + - + - - `timezone_id` - String - - - -::: - - -### pipelines.\.trigger.manual - -**`Type: Map`** - + - + +::: + +### pipelines.\.trigger.manual - - -## quality_monitors - **`Type: Map`** - -The quality_monitor resource allows you to define a Unity Catalog [table monitor](/api/workspace/qualitymonitors/create). For information about monitors, see [_](/machine-learning/model-serving/monitor-diagnose-endpoints.md). - + +## quality_monitors + +**`Type: Map`** + +The quality*monitor resource allows you to define a Unity Catalog [table monitor](/api/workspace/qualitymonitors/create). For information about monitors, see [*](/machine-learning/model-serving/monitor-diagnose-endpoints.md). + ```yaml quality_monitors: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `assets_dir` - String - The directory to store monitoring assets (e.g. dashboard, metric tables). - + - - `baseline_table_name` - String - - Name of the baseline table from which drift metrics are computed from. Columns in the monitored table should also be present in the baseline table. - -- - `custom_metrics` - - Sequence - - Custom metrics to compute on the monitored table. These can be aggregate metrics, derived metrics (from already computed aggregate metrics), or drift metrics (comparing metrics across time windows). . See [_](#quality_monitorsnamecustom_metrics). - -- - `data_classification_config` - - Map - - The data classification config for the monitor. See [_](#quality_monitorsnamedata_classification_config). - -- - `inference_log` - - Map - - Configuration for monitoring inference logs. See [_](#quality_monitorsnameinference_log). - -- - `notifications` - - Map - - The notification settings for the monitor. See [_](#quality_monitorsnamenotifications). - + - Name of the baseline table from which drift metrics are computed from. Columns in the monitored table should also be present in the baseline table. + + * - `custom_metrics` + - Sequence + - Custom metrics to compute on the monitored table. These can be aggregate metrics, derived metrics (from already computed aggregate metrics), or drift metrics (comparing metrics across time windows). . See [\_](#quality_monitorsnamecustom_metrics). + + * - `data_classification_config` + - Map + - The data classification config for the monitor. See [\_](#quality_monitorsnamedata_classification_config). + + * - `inference_log` + - Map + - Configuration for monitoring inference logs. See [\_](#quality_monitorsnameinference_log). + + * - `notifications` + - Map + - The notification settings for the monitor. See [\_](#quality_monitorsnamenotifications). + - - `output_schema_name` - String - Schema where output metric tables are created. - -- - `schedule` - - Map - - The schedule for automatically updating and refreshing metric tables. See [_](#quality_monitorsnameschedule). - + + * - `schedule` + - Map + - The schedule for automatically updating and refreshing metric tables. See [\_](#quality_monitorsnameschedule). + - - `skip_builtin_dashboard` - Boolean - Whether to skip creating a default dashboard summarizing data quality metrics. - + - - `slicing_exprs` - Sequence - - List of column expressions to slice data with for targeted analysis. The data is grouped by each expression independently, resulting in a separate slice for each predicate and its complements. For high-cardinality columns, only the top 100 unique values by frequency will generate slices. - + - List of column expressions to slice data with for targeted analysis. The data is grouped by each expression independently, resulting in a separate slice for each predicate and its complements. For high-cardinality columns, only the top 100 unique values by frequency will generate slices. + - - `snapshot` - Map - Configuration for monitoring snapshot tables. - + - - `table_name` - String - - - -- - `time_series` - - Map - - Configuration for monitoring time series tables. See [_](#quality_monitorsnametime_series). - + - - - `time_series` + - Map + - Configuration for monitoring time series tables. See [\_](#quality_monitorsnametime_series). + - - `warehouse_id` - String - - Optional argument to specify the warehouse for dashboard creation. If not specified, the first running warehouse will be used. - + - Optional argument to specify the warehouse for dashboard creation. If not specified, the first running warehouse will be used. + ::: - - + **Example** - + The following example defines a quality monitor: ```yaml @@ -7890,381 +7099,344 @@ resources: quartz_cron_expression: 0 0 8 * * ? # Run Every day at 8am timezone_id: UTC ``` - + ### quality_monitors.\.custom_metrics - + **`Type: Sequence`** - + Custom metrics to compute on the monitored table. These can be aggregate metrics, derived metrics (from already computed aggregate metrics), or drift metrics (comparing metrics across time windows). - - - :::list-table - + - - Key - Type - Description - + - - `definition` - String - Jinja template for a SQL expression that specifies how to compute the metric. See [create metric definition](https://docs.databricks.com/en/lakehouse-monitoring/custom-metrics.html#create-definition). - + - - `input_columns` - Sequence - - A list of column names in the input table the metric should be computed for. Can use ``":table"`` to indicate that the metric needs information from multiple columns. - + - A list of column names in the input table the metric should be computed for. Can use `":table"` to indicate that the metric needs information from multiple columns. + - - `name` - String - Name of the metric in the output tables. - + - - `output_data_type` - String - The output type of the custom metric. - + - - `type` - String - - Can only be one of ``"CUSTOM_METRIC_TYPE_AGGREGATE"``, ``"CUSTOM_METRIC_TYPE_DERIVED"``, or ``"CUSTOM_METRIC_TYPE_DRIFT"``. The ``"CUSTOM_METRIC_TYPE_AGGREGATE"`` and ``"CUSTOM_METRIC_TYPE_DERIVED"`` metrics are computed on a single table, whereas the ``"CUSTOM_METRIC_TYPE_DRIFT"`` compare metrics across baseline and input table, or across the two consecutive time windows. - CUSTOM_METRIC_TYPE_AGGREGATE: only depend on the existing columns in your table - CUSTOM_METRIC_TYPE_DERIVED: depend on previously computed aggregate metrics - CUSTOM_METRIC_TYPE_DRIFT: depend on previously computed aggregate or derived metrics - + - Can only be one of `"CUSTOM_METRIC_TYPE_AGGREGATE"`, `"CUSTOM_METRIC_TYPE_DERIVED"`, or `"CUSTOM_METRIC_TYPE_DRIFT"`. The `"CUSTOM_METRIC_TYPE_AGGREGATE"` and `"CUSTOM_METRIC_TYPE_DERIVED"` metrics are computed on a single table, whereas the `"CUSTOM_METRIC_TYPE_DRIFT"` compare metrics across baseline and input table, or across the two consecutive time windows. - CUSTOM_METRIC_TYPE_AGGREGATE: only depend on the existing columns in your table - CUSTOM_METRIC_TYPE_DERIVED: depend on previously computed aggregate metrics - CUSTOM_METRIC_TYPE_DRIFT: depend on previously computed aggregate or derived metrics + ::: - - + ### quality_monitors.\.data_classification_config - + **`Type: Map`** - + The data classification config for the monitor. - - - + :::list-table - + - - Key - Type - Description - + - - `enabled` - Boolean - Whether data classification is enabled. - + ::: - - + ### quality_monitors.\.inference_log - + **`Type: Map`** - + Configuration for monitoring inference logs. - - - + :::list-table - + - - Key - Type - Description - + - - `granularities` - Sequence - - - + - + - - `label_col` - String - Optional column that contains the ground truth for the prediction. - + - - `model_id_col` - String - - Column that contains the id of the model generating the predictions. Metrics will be computed per model id by default, and also across all model ids. - + - Column that contains the id of the model generating the predictions. Metrics will be computed per model id by default, and also across all model ids. + - - `prediction_col` - String - Column that contains the output/prediction from the model. - + - - `prediction_proba_col` - String - - Optional column that contains the prediction probabilities for each class in a classification problem type. The values in this column should be a map, mapping each class label to the prediction probability for a given sample. The map should be of PySpark MapType(). - + - Optional column that contains the prediction probabilities for each class in a classification problem type. The values in this column should be a map, mapping each class label to the prediction probability for a given sample. The map should be of PySpark MapType(). + - - `problem_type` - String - Problem type the model aims to solve. Determines the type of model-quality metrics that will be computed. - + - - `timestamp_col` - String - - Column that contains the timestamps of requests. The column must be one of the following: - A ``TimestampType`` column - A column whose values can be converted to timestamps through the pyspark ``to_timestamp`` [function](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.to_timestamp.html). - + - Column that contains the timestamps of requests. The column must be one of the following: - A `TimestampType` column - A column whose values can be converted to timestamps through the pyspark `to_timestamp` [function](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.to_timestamp.html). + ::: - - + ### quality_monitors.\.notifications - + **`Type: Map`** - + The notification settings for the monitor. - - - + :::list-table - + - - Key - Type - Description - -- - `on_failure` - - Map - - Who to send notifications to on monitor failure. See [_](#quality_monitorsnamenotificationson_failure). - -- - `on_new_classification_tag_detected` - - Map - - Who to send notifications to when new data classification tags are detected. See [_](#quality_monitorsnamenotificationson_new_classification_tag_detected). - -::: - - + + * - `on_failure` + - Map + - Who to send notifications to on monitor failure. See [\_](#quality_monitorsnamenotificationson_failure). + + * - `on_new_classification_tag_detected` + - Map + - Who to send notifications to when new data classification tags are detected. See [\_](#quality_monitorsnamenotificationson_new_classification_tag_detected). + ### quality_monitors.\.notifications.on_failure - + **`Type: Map`** - + Who to send notifications to on monitor failure. - - - + :::list-table - + - - Key - Type - Description - + - - `email_addresses` - Sequence - The list of email addresses to send the notification to. A maximum of 5 email addresses is supported. - + ::: - - + ### quality_monitors.\.notifications.on_new_classification_tag_detected - + **`Type: Map`** - + Who to send notifications to when new data classification tags are detected. - - - + :::list-table - + - - Key - Type - Description - + - - `email_addresses` - Sequence - The list of email addresses to send the notification to. A maximum of 5 email addresses is supported. - + ::: - - + ### quality_monitors.\.schedule - + **`Type: Map`** - + The schedule for automatically updating and refreshing metric tables. - - - + :::list-table - + - - Key - Type - Description - + - - `pause_status` - String - Read only field that indicates whether a schedule is paused or not. - + - - `quartz_cron_expression` - String - - The expression that determines when to run the monitor. See [examples](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html). - + - The expression that determines when to run the monitor. See [examples](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html). + - - `timezone_id` - String - - The timezone id (e.g., ``"PST"``) in which to evaluate the quartz expression. - + - The timezone id (e.g., `"PST"`) in which to evaluate the quartz expression. + ::: - - + ### quality_monitors.\.snapshot - + **`Type: Map`** - + Configuration for monitoring snapshot tables. - - + ### quality_monitors.\.time_series - + **`Type: Map`** - + Configuration for monitoring time series tables. - - - + :::list-table - + - - Key - Type - Description - + - - `granularities` - Sequence - - - + - + - - `timestamp_col` - String - - Column that contains the timestamps of requests. The column must be one of the following: - A ``TimestampType`` column - A column whose values can be converted to timestamps through the pyspark ``to_timestamp`` [function](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.to_timestamp.html). - + - Column that contains the timestamps of requests. The column must be one of the following: - A `TimestampType` column - A column whose values can be converted to timestamps through the pyspark `to_timestamp` [function](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.to_timestamp.html). + ::: - - + ## registered_models - + **`Type: Map`** - -The registered model resource allows you to define models in Unity Catalog. For information about Unity Catalog [registered models](/api/workspace/registeredmodels/create), see [_](/machine-learning/manage-model-lifecycle/index.md). - + +The registered model resource allows you to define models in Unity Catalog. For information about Unity Catalog [registered models](/api/workspace/registeredmodels/create), see [\_](/machine-learning/manage-model-lifecycle/index.md). + ```yaml registered_models: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `catalog_name` - String - The name of the catalog where the schema and the registered model reside - + - - `comment` - String - The comment attached to the registered model - -- - `grants` - - Sequence - - See [_](#registered_modelsnamegrants). - + + * - `grants` + - Sequence + - See [\_](#registered_modelsnamegrants). + - - `name` - String - The name of the registered model - + - - `schema_name` - String - The name of the schema where the registered model resides - + - - `storage_location` - String - The storage location on the cloud under which model version data files are stored - + ::: - - + **Example** - + The following example defines a registered model in Unity Catalog: ```yaml resources: registered_models: - model: - name: my_model - catalog_name: ${bundle.target} - schema_name: mlops_schema - comment: Registered model in Unity Catalog for ${bundle.target} deployment target - grants: - - privileges: - - EXECUTE - principal: account users + model: + name: my_model + catalog_name: ${bundle.target} + schema_name: mlops_schema + comment: Registered model in Unity Catalog for ${bundle.target} deployment target + grants: + - privileges: + - EXECUTE + principal: account users ``` - -### registered_models.\.grants - -**`Type: Sequence`** - - - - +### registered_models.\.grants + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `principal` - String - The name of the principal that will be granted privileges - + - - `privileges` - Sequence - The privileges to grant to the specified entity - + ::: - - + ## schemas - + **`Type: Map`** - + The schema resource type allows you to define Unity Catalog [schemas](/api/workspace/schemas/create) for tables and other assets in your workflows and pipelines created as part of a bundle. A schema, different from other resource types, has the following limitations: - The owner of a schema resource is always the deployment user, and cannot be changed. If `run_as` is specified in the bundle, it will be ignored by operations on the schema. - Only fields supported by the corresponding [Schemas object create API](/api/workspace/schemas/create) are available for the schema resource. For example, `enable_predictive_optimization` is not supported as it is only available on the [update API](/api/workspace/schemas/update). - + ```yaml schemas: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `catalog_name` - String - Name of parent catalog. - + - - `comment` - String - User-provided free-form text description. - -- - `grants` - - Sequence - - See [_](#schemasnamegrants). - + + * - `grants` + - Sequence + - See [\_](#schemasnamegrants). + - - `name` - String - Name of schema, relative to parent catalog. - + - - `properties` - Map - - - + - + - - `storage_root` - String - Storage root URL for managed tables within schema. - + ::: - - + **Example** - + The following example defines a pipeline with the resource key `my_pipeline` that creates a Unity Catalog schema with the key `my_schema` as the target: ```yaml @@ -8286,7 +7458,7 @@ resources: comment: This schema was created by DABs. ``` -A top-level grants mapping is not supported by Databricks Asset Bundles, so if you want to set grants for a schema, define the grants for the schema within the `schemas` mapping. For more information about grants, see [_](/data-governance/unity-catalog/manage-privileges/index.md#grant). +A top-level grants mapping is not supported by Databricks Asset Bundles, so if you want to set grants for a schema, define the grants for the schema within the `schemas` mapping. For more information about grants, see [\_](/data-governance/unity-catalog/manage-privileges/index.md#grant). The following example defines a Unity Catalog schema with grants: @@ -8303,89 +7475,82 @@ resources: privileges: - CAN_READ catalog_name: main - ``` - -### schemas.\.grants - -**`Type: Sequence`** - +``` + +### schemas.\.grants + +**`Type: Sequence`** - - - :::list-table - + - - Key - Type - Description - + - - `principal` - String - The name of the principal that will be granted privileges - + - - `privileges` - Sequence - The privileges to grant to the specified entity - + ::: - - + ## volumes - + **`Type: Map`** - + The volume resource type allows you to define and create Unity Catalog [volumes](/api/workspace/volumes/create) as part of a bundle. When deploying a bundle with a volume defined, note that: - A volume cannot be referenced in the `artifact_path` for the bundle until it exists in the workspace. Hence, if you want to use Databricks Asset Bundles to create the volume, you must first define the volume in the bundle, deploy it to create the volume, then reference it in the `artifact_path` in subsequent deployments. -- Volumes in the bundle are not prepended with the `dev_${workspace.current_user.short_name}` prefix when the deployment target has `mode: development` configured. However, you can manually configure this prefix. See [_](/dev-tools/bundles/deployment-modes.md#custom-presets). - +- Volumes in the bundle are not prepended with the `dev_${workspace.current_user.short_name}` prefix when the deployment target has `mode: development` configured. However, you can manually configure this prefix. See [\_](/dev-tools/bundles/deployment-modes.md#custom-presets). + ```yaml volumes: : : ``` - - + :::list-table - + - - Key - Type - Description - + - - `catalog_name` - String - The name of the catalog where the schema and the volume are - + - - `comment` - String - The comment attached to the volume - -- - `grants` - - Sequence - - See [_](#volumesnamegrants). - + + * - `grants` + - Sequence + - See [\_](#volumesnamegrants). + - - `name` - String - The name of the volume - + - - `schema_name` - String - The name of the schema where the volume is - + - - `storage_location` - String - The storage location on the cloud - + - - `volume_type` - String - - - + - + ::: - - + **Example** - + The following example creates a Unity Catalog volume with the key `my_volume`: ```yaml @@ -8398,28 +7563,23 @@ resources: ``` For an example bundle that runs a job that writes to a file in Unity Catalog volume, see the [bundle-examples GitHub repository](https://github.com/databricks/bundle-examples/tree/main/knowledge_base/write_from_job_to_volume). - -### volumes.\.grants - -**`Type: Sequence`** - - - - +### volumes.\.grants + +**`Type: Sequence`** + :::list-table - + - - Key - Type - Description - + - - `principal` - String - The name of the principal that will be granted privileges - + - - `privileges` - Sequence - The privileges to grant to the specified entity - + ::: - \ No newline at end of file diff --git a/bundle/docsgen/refs.go b/bundle/docsgen/refs.go index ca45e6ab2..7a4451129 100644 --- a/bundle/docsgen/refs.go +++ b/bundle/docsgen/refs.go @@ -58,7 +58,7 @@ func resolveRefs(s *jsonschema.Schema, schemas map[string]*jsonschema.Schema) *j node := s description := s.Description markdownDescription := s.MarkdownDescription - examples := s.Examples + examples := getExamples(s.Examples) for node.Reference != nil { ref := getRefType(node) @@ -75,7 +75,7 @@ func resolveRefs(s *jsonschema.Schema, schemas map[string]*jsonschema.Schema) *j markdownDescription = newNode.MarkdownDescription } if len(examples) == 0 { - examples = newNode.Examples + examples = getExamples(newNode.Examples) } node = newNode @@ -89,6 +89,14 @@ func resolveRefs(s *jsonschema.Schema, schemas map[string]*jsonschema.Schema) *j return &newNode } +func getExamples(examples any) []string { + typedExamples, ok := examples.([]string) + if !ok { + return []string{} + } + return typedExamples +} + func getRefType(node *jsonschema.Schema) string { if node.Reference == nil { return "" diff --git a/bundle/docsgen/templates/reference.md b/bundle/docsgen/templates/reference.md index 6d99300a2..77708350f 100644 --- a/bundle/docsgen/templates/reference.md +++ b/bundle/docsgen/templates/reference.md @@ -1,11 +1,11 @@ --- -description: 'Configuration reference for databricks.yml' +description: "Configuration reference for databricks.yml" --- # Configuration reference -This article provides reference for keys supported by Databricks Asset Bundles configuration (YAML). See [_](/dev-tools/bundles/index.md). +This article provides reference for keys supported by Databricks Asset Bundles configuration (YAML). See [\_](/dev-tools/bundles/index.md). -For complete bundle examples, see [_](/dev-tools/bundles/resource-examples.md) and the [bundle-examples GitHub repository](https://github.com/databricks/bundle-examples). +For complete bundle examples, see [\_](/dev-tools/bundles/resource-examples.md) and the [bundle-examples GitHub repository](https://github.com/databricks/bundle-examples). diff --git a/bundle/docsgen/templates/resources.md b/bundle/docsgen/templates/resources.md index 71e3cf1b1..c6c18f9db 100644 --- a/bundle/docsgen/templates/resources.md +++ b/bundle/docsgen/templates/resources.md @@ -1,10 +1,10 @@ --- -description: 'Learn about resources supported by Databricks Asset Bundles and how to configure them.' +description: "Learn about resources supported by Databricks Asset Bundles and how to configure them." --- -# :re[DABS] resources +# resources :re[DABS] allows you to specify information about the :re[Databricks] resources used by the bundle in the `resources` mapping in the bundle configuration. See [resources mapping](settings.md#resources) and [resources key reference](reference.md#resources). diff --git a/bundle/docsgen/testdata/anchors.md b/bundle/docsgen/testdata/anchors.md new file mode 100644 index 000000000..0145d8cc9 --- /dev/null +++ b/bundle/docsgen/testdata/anchors.md @@ -0,0 +1,28 @@ +Header + +## some_field + +**`Type: Map`** + +This is a description + + + +.. list-table:: + :header-rows: 1 + + * - Key + - Type + - Description + + * - `my_attribute` + - Map + - Desc with link. See [_](#some_fieldnamemy_attribute). + + +### some_field.\.my_attribute + +**`Type: Boolean`** + +Another description + \ No newline at end of file diff --git a/bundle/internal/schema/annotations_openapi.yml b/bundle/internal/schema/annotations_openapi.yml index d5a9bf69e..74cd06c66 100644 --- a/bundle/internal/schema/annotations_openapi.yml +++ b/bundle/internal/schema/annotations_openapi.yml @@ -281,6 +281,9 @@ github.com/databricks/cli/bundle/config/resources.Job: "parameters": "description": |- Job-level parameter definitions + "performance_target": + "description": |- + PerformanceTarget defines how performant or cost efficient the execution of run on serverless should be. "queue": "description": |- The queue settings of the job. @@ -371,6 +374,9 @@ github.com/databricks/cli/bundle/config/resources.ModelServingEndpoint: "description": |- Tags to be attached to the serving endpoint and automatically propagated to billing logs. github.com/databricks/cli/bundle/config/resources.Pipeline: + "allow_duplicate_names": + "description": |- + If false, deployment will fail if name conflicts with that of another pipeline. "budget_policy_id": "description": |- Budget policy of this pipeline. @@ -395,6 +401,7 @@ github.com/databricks/cli/bundle/config/resources.Pipeline: "development": "description": |- Whether the pipeline is in Development mode. Defaults to false. + "dry_run": {} "edition": "description": |- Pipeline product edition. @@ -425,6 +432,7 @@ github.com/databricks/cli/bundle/config/resources.Pipeline: "restart_window": "description": |- Restart window of this pipeline. + "run_as": {} "schema": "description": |- The default schema (database) where tables are read from or published to. The presence of this field implies that the pipeline is in direct publishing mode. @@ -1813,6 +1821,17 @@ github.com/databricks/databricks-sdk-go/service/jobs.PauseStatus: UNPAUSED - |- PAUSED +github.com/databricks/databricks-sdk-go/service/jobs.PerformanceTarget: + "_": + "description": |- + PerformanceTarget defines how performant (lower latency) or cost efficient the execution of run on serverless compute should be. + The performance mode on the job or pipeline should map to a performance setting that is passed to Cluster Manager + (see cluster-common PerformanceTarget). + "enum": + - |- + PERFORMANCE_OPTIMIZED + - |- + COST_OPTIMIZED github.com/databricks/databricks-sdk-go/service/jobs.PeriodicTriggerConfiguration: "interval": "description": |- @@ -2624,6 +2643,18 @@ github.com/databricks/databricks-sdk-go/service/pipelines.RestartWindow: "description": |- Time zone id of restart window. See https://docs.databricks.com/sql/language-manual/sql-ref-syntax-aux-conf-mgmt-set-timezone.html for details. If not specified, UTC will be used. +github.com/databricks/databricks-sdk-go/service/pipelines.RunAs: + "_": + "description": |- + Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as. If not specified, the pipeline runs as the user who created the pipeline. + + Only `user_name` or `service_principal_name` can be specified. If both are specified, an error is thrown. + "service_principal_name": + "description": |- + Application ID of an active service principal. Setting this field requires the `servicePrincipal/user` role. + "user_name": + "description": |- + The email of an active workspace user. Users can only set this field to their own email. github.com/databricks/databricks-sdk-go/service/pipelines.SchemaSpec: "destination_catalog": "description": |- diff --git a/bundle/internal/schema/annotations_openapi_overrides.yml b/bundle/internal/schema/annotations_openapi_overrides.yml index 2cd8d4fd0..55ac4fdd4 100644 --- a/bundle/internal/schema/annotations_openapi_overrides.yml +++ b/bundle/internal/schema/annotations_openapi_overrides.yml @@ -60,7 +60,6 @@ github.com/databricks/cli/bundle/config/resources.Cluster: "_": "markdown_description": |- The cluster resource defines an [all-purpose cluster](/api/workspace/clusters/create). - "markdown_examples": |- The following example creates a cluster named `my_cluster` and sets that as the cluster to use to run the notebook in `my_job`: @@ -123,7 +122,6 @@ github.com/databricks/cli/bundle/config/resources.Dashboard: If you use the UI to modify the dashboard, modifications made through the UI are not applied to the dashboard JSON file in the local bundle unless you explicitly update it using `bundle generate`. You can use the `--watch` option to continuously poll and retrieve changes to the dashboard. See [_](/dev-tools/cli/bundle-commands.md#generate). In addition, if you attempt to deploy a bundle that contains a dashboard JSON file that is different than the one in the remote workspace, an error will occur. To force the deploy and overwrite the dashboard in the remote workspace with the local one, use the `--force` option. See [_](/dev-tools/cli/bundle-commands.md#deploy). - "embed_credentials": "description": |- PLACEHOLDER @@ -241,9 +239,15 @@ github.com/databricks/cli/bundle/config/resources.Pipeline: - notebook: path: ./pipeline.py ``` + "dry_run": + "description": |- + PLACEHOLDER "permissions": "description": |- PLACEHOLDER + "run_as": + "description": |- + PLACEHOLDER github.com/databricks/cli/bundle/config/resources.QualityMonitor: "_": "markdown_description": |- @@ -356,7 +360,6 @@ github.com/databricks/cli/bundle/config/resources.Volume: - A volume cannot be referenced in the `artifact_path` for the bundle until it exists in the workspace. Hence, if you want to use Databricks Asset Bundles to create the volume, you must first define the volume in the bundle, deploy it to create the volume, then reference it in the `artifact_path` in subsequent deployments. - Volumes in the bundle are not prepended with the `dev_${workspace.current_user.short_name}` prefix when the deployment target has `mode: development` configured. However, you can manually configure this prefix. See [_](/dev-tools/bundles/deployment-modes.md#custom-presets). - "markdown_examples": |- The following example creates a Unity Catalog volume with the key `my_volume`: @@ -376,6 +379,42 @@ github.com/databricks/cli/bundle/config/resources.Volume: "volume_type": "description": |- PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.AppDeployment: + "create_time": + "description": |- + PLACEHOLDER + "creator": + "description": |- + PLACEHOLDER + "deployment_artifacts": + "description": |- + PLACEHOLDER + "deployment_id": + "description": |- + PLACEHOLDER + "mode": + "description": |- + PLACEHOLDER + "source_code_path": + "description": |- + PLACEHOLDER + "status": + "description": |- + PLACEHOLDER + "update_time": + "description": |- + PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.AppDeploymentArtifacts: + "source_code_path": + "description": |- + PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.AppDeploymentStatus: + "message": + "description": |- + PLACEHOLDER + "state": + "description": |- + PLACEHOLDER github.com/databricks/databricks-sdk-go/service/apps.AppResource: "job": "description": |- @@ -389,6 +428,49 @@ github.com/databricks/databricks-sdk-go/service/apps.AppResource: "sql_warehouse": "description": |- PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.AppResourceJob: + "id": + "description": |- + PLACEHOLDER + "permission": + "description": |- + PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.AppResourceSecret: + "key": + "description": |- + PLACEHOLDER + "permission": + "description": |- + PLACEHOLDER + "scope": + "description": |- + PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.AppResourceServingEndpoint: + "name": + "description": |- + PLACEHOLDER + "permission": + "description": |- + PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.AppResourceSqlWarehouse: + "id": + "description": |- + PLACEHOLDER + "permission": + "description": |- + PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.ApplicationStatus: + "message": + "description": |- + PLACEHOLDER + "state": + "description": |- + PLACEHOLDER +github.com/databricks/databricks-sdk-go/service/apps.ComputeStatus: + "message": + "description": |- + PLACEHOLDER + "state": {} github.com/databricks/databricks-sdk-go/service/compute.AwsAttributes: "availability": "description": |- @@ -473,85 +555,6 @@ github.com/databricks/databricks-sdk-go/service/pipelines.PipelineTrigger: "manual": "description": |- PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.AppDeployment: - "create_time": - "description": |- - PLACEHOLDER - "creator": - "description": |- - PLACEHOLDER - "deployment_artifacts": - "description": |- - PLACEHOLDER - "deployment_id": - "description": |- - PLACEHOLDER - "mode": - "description": |- - PLACEHOLDER - "source_code_path": - "description": |- - PLACEHOLDER - "status": - "description": |- - PLACEHOLDER - "update_time": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.AppDeploymentArtifacts: - "source_code_path": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.AppDeploymentStatus: - "message": - "description": |- - PLACEHOLDER - "state": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.AppResourceJob: - "id": - "description": |- - PLACEHOLDER - "permission": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.AppResourceSecret: - "key": - "description": |- - PLACEHOLDER - "permission": - "description": |- - PLACEHOLDER - "scope": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.AppResourceServingEndpoint: - "name": - "description": |- - PLACEHOLDER - "permission": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.AppResourceSqlWarehouse: - "id": - "description": |- - PLACEHOLDER - "permission": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.ApplicationStatus: - "message": - "description": |- - PLACEHOLDER - "state": - "description": |- - PLACEHOLDER -github.com/databricks/databricks-sdk-go/service/apps.ComputeStatus: - "message": - "description": |- - PLACEHOLDER - "state": github.com/databricks/databricks-sdk-go/service/serving.ServedEntityInput: "entity_version": "description": |- diff --git a/bundle/internal/schema/main.go b/bundle/internal/schema/main.go index 38e099ece..2e0120e62 100644 --- a/bundle/internal/schema/main.go +++ b/bundle/internal/schema/main.go @@ -109,6 +109,20 @@ func removeJobsFields(typ reflect.Type, s jsonschema.Schema) jsonschema.Schema { return s } +func removePipelineFields(typ reflect.Type, s jsonschema.Schema) jsonschema.Schema { + switch typ { + case reflect.TypeOf(resources.Pipeline{}): + // Even though DABs supports this field, TF provider does not. Thus, we + // should not expose it to the user. + delete(s.Properties, "dry_run") + delete(s.Properties, "allow_duplicate_names") + default: + // Do nothing + } + + return s +} + // While volume_type is required in the volume create API, DABs automatically sets // it's value to "MANAGED" if it's not provided. Thus, we make it optional // in the bundle schema. @@ -168,6 +182,7 @@ func generateSchema(workdir, outputFile string) { // Generate the JSON schema from the bundle Go struct. s, err := jsonschema.FromType(reflect.TypeOf(config.Root{}), []func(reflect.Type, jsonschema.Schema) jsonschema.Schema{ removeJobsFields, + removePipelineFields, makeVolumeTypeOptional, a.addAnnotations, addInterpolationPatterns, diff --git a/bundle/internal/schema/main_test.go b/bundle/internal/schema/main_test.go index 051243c4d..620f1cb70 100644 --- a/bundle/internal/schema/main_test.go +++ b/bundle/internal/schema/main_test.go @@ -124,3 +124,23 @@ func getAnnotations(path string) (annotation.File, error) { err = yaml.Unmarshal(b, &data) return data, err } + +func TestNoDuplicatedAnnotations(t *testing.T) { + // Check for duplicated annotations in annotation files + files := []string{ + "annotations_openapi_overrides.yml", + "annotations.yml", + } + + annotations := map[string]bool{} + for _, file := range files { + annotationsFile, err := getAnnotations(file) + assert.NoError(t, err) + for k := range annotationsFile { + if _, ok := annotations[k]; ok { + t.Errorf("Annotation `%s` is duplicated in %s", k, file) + } + annotations[k] = true + } + } +} diff --git a/bundle/internal/schema/parser.go b/bundle/internal/schema/parser.go index 50e69e7c8..ca8c27d4c 100644 --- a/bundle/internal/schema/parser.go +++ b/bundle/internal/schema/parser.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/json" "fmt" "os" @@ -9,8 +10,9 @@ import ( "strings" "github.com/databricks/cli/bundle/internal/annotation" + "github.com/databricks/cli/libs/dyn/convert" + "github.com/databricks/cli/libs/dyn/yamlloader" "github.com/databricks/cli/libs/jsonschema" - "gopkg.in/yaml.v3" ) type Components struct { @@ -122,7 +124,11 @@ func (p *openapiParser) extractAnnotations(typ reflect.Type, outputPath, overrid if err != nil { return err } - err = yaml.Unmarshal(b, &overrides) + overridesDyn, err := yamlloader.LoadYAML(overridesPath, bytes.NewBuffer(b)) + if err != nil { + return err + } + err = convert.ToTyped(&overrides, overridesDyn) if err != nil { return err } diff --git a/bundle/internal/tf/codegen/README.md b/bundle/internal/tf/codegen/README.md index b1f8a33a8..968bf29ed 100644 --- a/bundle/internal/tf/codegen/README.md +++ b/bundle/internal/tf/codegen/README.md @@ -19,3 +19,6 @@ How to regenerate Go structs from an updated terraform provider? 2. Delete `./tmp` if it exists 3. Run `go run .` 4. Run `gofmt -s -w ../schema` +5. Go back to the root of the repo. +6. Update `/acceptance/terraform/main.tf` file to use new version of TF provider +7. Run `go test ./acceptance -v -update -run TestAccept/terraform` to update test output with a new version of TF provider diff --git a/bundle/internal/tf/codegen/schema/version.go b/bundle/internal/tf/codegen/schema/version.go index 393afd6ed..46548f3e8 100644 --- a/bundle/internal/tf/codegen/schema/version.go +++ b/bundle/internal/tf/codegen/schema/version.go @@ -1,3 +1,3 @@ package schema -const ProviderVersion = "1.64.1" +const ProviderVersion = "1.65.1" diff --git a/bundle/internal/tf/schema/data_source_catalog.go b/bundle/internal/tf/schema/data_source_catalog.go index 6f9237cfa..4b8c6df97 100644 --- a/bundle/internal/tf/schema/data_source_catalog.go +++ b/bundle/internal/tf/schema/data_source_catalog.go @@ -28,7 +28,6 @@ type DataSourceCatalogCatalogInfo struct { Owner string `json:"owner,omitempty"` Properties map[string]string `json:"properties,omitempty"` ProviderName string `json:"provider_name,omitempty"` - SecurableKind string `json:"securable_kind,omitempty"` SecurableType string `json:"securable_type,omitempty"` ShareName string `json:"share_name,omitempty"` StorageLocation string `json:"storage_location,omitempty"` diff --git a/bundle/internal/tf/schema/resource_aibi_dashboard_embedding_access_policy_setting.go b/bundle/internal/tf/schema/resource_aibi_dashboard_embedding_access_policy_setting.go new file mode 100644 index 000000000..d816b235d --- /dev/null +++ b/bundle/internal/tf/schema/resource_aibi_dashboard_embedding_access_policy_setting.go @@ -0,0 +1,14 @@ +// Generated from Databricks Terraform provider schema. DO NOT EDIT. + +package schema + +type ResourceAibiDashboardEmbeddingAccessPolicySettingAibiDashboardEmbeddingAccessPolicy struct { + AccessPolicyType string `json:"access_policy_type"` +} + +type ResourceAibiDashboardEmbeddingAccessPolicySetting struct { + Etag string `json:"etag,omitempty"` + Id string `json:"id,omitempty"` + SettingName string `json:"setting_name,omitempty"` + AibiDashboardEmbeddingAccessPolicy *ResourceAibiDashboardEmbeddingAccessPolicySettingAibiDashboardEmbeddingAccessPolicy `json:"aibi_dashboard_embedding_access_policy,omitempty"` +} diff --git a/bundle/internal/tf/schema/resource_aibi_dashboard_embedding_approved_domains_setting.go b/bundle/internal/tf/schema/resource_aibi_dashboard_embedding_approved_domains_setting.go new file mode 100644 index 000000000..690b334cd --- /dev/null +++ b/bundle/internal/tf/schema/resource_aibi_dashboard_embedding_approved_domains_setting.go @@ -0,0 +1,14 @@ +// Generated from Databricks Terraform provider schema. DO NOT EDIT. + +package schema + +type ResourceAibiDashboardEmbeddingApprovedDomainsSettingAibiDashboardEmbeddingApprovedDomains struct { + ApprovedDomains []string `json:"approved_domains"` +} + +type ResourceAibiDashboardEmbeddingApprovedDomainsSetting struct { + Etag string `json:"etag,omitempty"` + Id string `json:"id,omitempty"` + SettingName string `json:"setting_name,omitempty"` + AibiDashboardEmbeddingApprovedDomains *ResourceAibiDashboardEmbeddingApprovedDomainsSettingAibiDashboardEmbeddingApprovedDomains `json:"aibi_dashboard_embedding_approved_domains,omitempty"` +} diff --git a/bundle/internal/tf/schema/resource_custom_app_integration.go b/bundle/internal/tf/schema/resource_custom_app_integration.go index e89eb7fe5..0a964f6ab 100644 --- a/bundle/internal/tf/schema/resource_custom_app_integration.go +++ b/bundle/internal/tf/schema/resource_custom_app_integration.go @@ -8,16 +8,17 @@ type ResourceCustomAppIntegrationTokenAccessPolicy struct { } type ResourceCustomAppIntegration struct { - ClientId string `json:"client_id,omitempty"` - ClientSecret string `json:"client_secret,omitempty"` - Confidential bool `json:"confidential,omitempty"` - CreateTime string `json:"create_time,omitempty"` - CreatedBy int `json:"created_by,omitempty"` - CreatorUsername string `json:"creator_username,omitempty"` - Id string `json:"id,omitempty"` - IntegrationId string `json:"integration_id,omitempty"` - Name string `json:"name,omitempty"` - RedirectUrls []string `json:"redirect_urls,omitempty"` - Scopes []string `json:"scopes,omitempty"` - TokenAccessPolicy *ResourceCustomAppIntegrationTokenAccessPolicy `json:"token_access_policy,omitempty"` + ClientId string `json:"client_id,omitempty"` + ClientSecret string `json:"client_secret,omitempty"` + Confidential bool `json:"confidential,omitempty"` + CreateTime string `json:"create_time,omitempty"` + CreatedBy int `json:"created_by,omitempty"` + CreatorUsername string `json:"creator_username,omitempty"` + Id string `json:"id,omitempty"` + IntegrationId string `json:"integration_id,omitempty"` + Name string `json:"name,omitempty"` + RedirectUrls []string `json:"redirect_urls,omitempty"` + Scopes []string `json:"scopes,omitempty"` + UserAuthorizedScopes []string `json:"user_authorized_scopes,omitempty"` + TokenAccessPolicy *ResourceCustomAppIntegrationTokenAccessPolicy `json:"token_access_policy,omitempty"` } diff --git a/bundle/internal/tf/schema/resource_job.go b/bundle/internal/tf/schema/resource_job.go index da277b5c1..2c27f0be7 100644 --- a/bundle/internal/tf/schema/resource_job.go +++ b/bundle/internal/tf/schema/resource_job.go @@ -1489,6 +1489,7 @@ type ResourceJob struct { MaxRetries int `json:"max_retries,omitempty"` MinRetryIntervalMillis int `json:"min_retry_interval_millis,omitempty"` Name string `json:"name,omitempty"` + PerformanceTarget string `json:"performance_target,omitempty"` RetryOnTimeout bool `json:"retry_on_timeout,omitempty"` Tags map[string]string `json:"tags,omitempty"` TimeoutSeconds int `json:"timeout_seconds,omitempty"` diff --git a/bundle/internal/tf/schema/resource_pipeline.go b/bundle/internal/tf/schema/resource_pipeline.go index ebdb85027..8e260e65c 100644 --- a/bundle/internal/tf/schema/resource_pipeline.go +++ b/bundle/internal/tf/schema/resource_pipeline.go @@ -249,6 +249,11 @@ type ResourcePipelineRestartWindow struct { TimeZoneId string `json:"time_zone_id,omitempty"` } +type ResourcePipelineRunAs struct { + ServicePrincipalName string `json:"service_principal_name,omitempty"` + UserName string `json:"user_name,omitempty"` +} + type ResourcePipelineTriggerCron struct { QuartzCronSchedule string `json:"quartz_cron_schedule,omitempty"` TimezoneId string `json:"timezone_id,omitempty"` @@ -296,5 +301,6 @@ type ResourcePipeline struct { Library []ResourcePipelineLibrary `json:"library,omitempty"` Notification []ResourcePipelineNotification `json:"notification,omitempty"` RestartWindow *ResourcePipelineRestartWindow `json:"restart_window,omitempty"` + RunAs *ResourcePipelineRunAs `json:"run_as,omitempty"` Trigger *ResourcePipelineTrigger `json:"trigger,omitempty"` } diff --git a/bundle/internal/tf/schema/resources.go b/bundle/internal/tf/schema/resources.go index b57c2711a..c6eaa5b21 100644 --- a/bundle/internal/tf/schema/resources.go +++ b/bundle/internal/tf/schema/resources.go @@ -3,115 +3,119 @@ package schema type Resources struct { - AccessControlRuleSet map[string]any `json:"databricks_access_control_rule_set,omitempty"` - Alert map[string]any `json:"databricks_alert,omitempty"` - App map[string]any `json:"databricks_app,omitempty"` - ArtifactAllowlist map[string]any `json:"databricks_artifact_allowlist,omitempty"` - AutomaticClusterUpdateWorkspaceSetting map[string]any `json:"databricks_automatic_cluster_update_workspace_setting,omitempty"` - AwsS3Mount map[string]any `json:"databricks_aws_s3_mount,omitempty"` - AzureAdlsGen1Mount map[string]any `json:"databricks_azure_adls_gen1_mount,omitempty"` - AzureAdlsGen2Mount map[string]any `json:"databricks_azure_adls_gen2_mount,omitempty"` - AzureBlobMount map[string]any `json:"databricks_azure_blob_mount,omitempty"` - Budget map[string]any `json:"databricks_budget,omitempty"` - Catalog map[string]any `json:"databricks_catalog,omitempty"` - CatalogWorkspaceBinding map[string]any `json:"databricks_catalog_workspace_binding,omitempty"` - Cluster map[string]any `json:"databricks_cluster,omitempty"` - ClusterPolicy map[string]any `json:"databricks_cluster_policy,omitempty"` - ComplianceSecurityProfileWorkspaceSetting map[string]any `json:"databricks_compliance_security_profile_workspace_setting,omitempty"` - Connection map[string]any `json:"databricks_connection,omitempty"` - Credential map[string]any `json:"databricks_credential,omitempty"` - CustomAppIntegration map[string]any `json:"databricks_custom_app_integration,omitempty"` - Dashboard map[string]any `json:"databricks_dashboard,omitempty"` - DbfsFile map[string]any `json:"databricks_dbfs_file,omitempty"` - DefaultNamespaceSetting map[string]any `json:"databricks_default_namespace_setting,omitempty"` - Directory map[string]any `json:"databricks_directory,omitempty"` - EnhancedSecurityMonitoringWorkspaceSetting map[string]any `json:"databricks_enhanced_security_monitoring_workspace_setting,omitempty"` - Entitlements map[string]any `json:"databricks_entitlements,omitempty"` - ExternalLocation map[string]any `json:"databricks_external_location,omitempty"` - File map[string]any `json:"databricks_file,omitempty"` - GitCredential map[string]any `json:"databricks_git_credential,omitempty"` - GlobalInitScript map[string]any `json:"databricks_global_init_script,omitempty"` - Grant map[string]any `json:"databricks_grant,omitempty"` - Grants map[string]any `json:"databricks_grants,omitempty"` - Group map[string]any `json:"databricks_group,omitempty"` - GroupInstanceProfile map[string]any `json:"databricks_group_instance_profile,omitempty"` - GroupMember map[string]any `json:"databricks_group_member,omitempty"` - GroupRole map[string]any `json:"databricks_group_role,omitempty"` - InstancePool map[string]any `json:"databricks_instance_pool,omitempty"` - InstanceProfile map[string]any `json:"databricks_instance_profile,omitempty"` - IpAccessList map[string]any `json:"databricks_ip_access_list,omitempty"` - Job map[string]any `json:"databricks_job,omitempty"` - LakehouseMonitor map[string]any `json:"databricks_lakehouse_monitor,omitempty"` - Library map[string]any `json:"databricks_library,omitempty"` - Metastore map[string]any `json:"databricks_metastore,omitempty"` - MetastoreAssignment map[string]any `json:"databricks_metastore_assignment,omitempty"` - MetastoreDataAccess map[string]any `json:"databricks_metastore_data_access,omitempty"` - MlflowExperiment map[string]any `json:"databricks_mlflow_experiment,omitempty"` - MlflowModel map[string]any `json:"databricks_mlflow_model,omitempty"` - MlflowWebhook map[string]any `json:"databricks_mlflow_webhook,omitempty"` - ModelServing map[string]any `json:"databricks_model_serving,omitempty"` - Mount map[string]any `json:"databricks_mount,omitempty"` - MwsCredentials map[string]any `json:"databricks_mws_credentials,omitempty"` - MwsCustomerManagedKeys map[string]any `json:"databricks_mws_customer_managed_keys,omitempty"` - MwsLogDelivery map[string]any `json:"databricks_mws_log_delivery,omitempty"` - MwsNccBinding map[string]any `json:"databricks_mws_ncc_binding,omitempty"` - MwsNccPrivateEndpointRule map[string]any `json:"databricks_mws_ncc_private_endpoint_rule,omitempty"` - MwsNetworkConnectivityConfig map[string]any `json:"databricks_mws_network_connectivity_config,omitempty"` - MwsNetworks map[string]any `json:"databricks_mws_networks,omitempty"` - MwsPermissionAssignment map[string]any `json:"databricks_mws_permission_assignment,omitempty"` - MwsPrivateAccessSettings map[string]any `json:"databricks_mws_private_access_settings,omitempty"` - MwsStorageConfigurations map[string]any `json:"databricks_mws_storage_configurations,omitempty"` - MwsVpcEndpoint map[string]any `json:"databricks_mws_vpc_endpoint,omitempty"` - MwsWorkspaces map[string]any `json:"databricks_mws_workspaces,omitempty"` - Notebook map[string]any `json:"databricks_notebook,omitempty"` - NotificationDestination map[string]any `json:"databricks_notification_destination,omitempty"` - OboToken map[string]any `json:"databricks_obo_token,omitempty"` - OnlineTable map[string]any `json:"databricks_online_table,omitempty"` - PermissionAssignment map[string]any `json:"databricks_permission_assignment,omitempty"` - Permissions map[string]any `json:"databricks_permissions,omitempty"` - Pipeline map[string]any `json:"databricks_pipeline,omitempty"` - Provider map[string]any `json:"databricks_provider,omitempty"` - QualityMonitor map[string]any `json:"databricks_quality_monitor,omitempty"` - Query map[string]any `json:"databricks_query,omitempty"` - Recipient map[string]any `json:"databricks_recipient,omitempty"` - RegisteredModel map[string]any `json:"databricks_registered_model,omitempty"` - Repo map[string]any `json:"databricks_repo,omitempty"` - RestrictWorkspaceAdminsSetting map[string]any `json:"databricks_restrict_workspace_admins_setting,omitempty"` - Schema map[string]any `json:"databricks_schema,omitempty"` - Secret map[string]any `json:"databricks_secret,omitempty"` - SecretAcl map[string]any `json:"databricks_secret_acl,omitempty"` - SecretScope map[string]any `json:"databricks_secret_scope,omitempty"` - ServicePrincipal map[string]any `json:"databricks_service_principal,omitempty"` - ServicePrincipalRole map[string]any `json:"databricks_service_principal_role,omitempty"` - ServicePrincipalSecret map[string]any `json:"databricks_service_principal_secret,omitempty"` - Share map[string]any `json:"databricks_share,omitempty"` - SqlAlert map[string]any `json:"databricks_sql_alert,omitempty"` - SqlDashboard map[string]any `json:"databricks_sql_dashboard,omitempty"` - SqlEndpoint map[string]any `json:"databricks_sql_endpoint,omitempty"` - SqlGlobalConfig map[string]any `json:"databricks_sql_global_config,omitempty"` - SqlPermissions map[string]any `json:"databricks_sql_permissions,omitempty"` - SqlQuery map[string]any `json:"databricks_sql_query,omitempty"` - SqlTable map[string]any `json:"databricks_sql_table,omitempty"` - SqlVisualization map[string]any `json:"databricks_sql_visualization,omitempty"` - SqlWidget map[string]any `json:"databricks_sql_widget,omitempty"` - StorageCredential map[string]any `json:"databricks_storage_credential,omitempty"` - SystemSchema map[string]any `json:"databricks_system_schema,omitempty"` - Table map[string]any `json:"databricks_table,omitempty"` - Token map[string]any `json:"databricks_token,omitempty"` - User map[string]any `json:"databricks_user,omitempty"` - UserInstanceProfile map[string]any `json:"databricks_user_instance_profile,omitempty"` - UserRole map[string]any `json:"databricks_user_role,omitempty"` - VectorSearchEndpoint map[string]any `json:"databricks_vector_search_endpoint,omitempty"` - VectorSearchIndex map[string]any `json:"databricks_vector_search_index,omitempty"` - Volume map[string]any `json:"databricks_volume,omitempty"` - WorkspaceBinding map[string]any `json:"databricks_workspace_binding,omitempty"` - WorkspaceConf map[string]any `json:"databricks_workspace_conf,omitempty"` - WorkspaceFile map[string]any `json:"databricks_workspace_file,omitempty"` + AccessControlRuleSet map[string]any `json:"databricks_access_control_rule_set,omitempty"` + AibiDashboardEmbeddingAccessPolicySetting map[string]any `json:"databricks_aibi_dashboard_embedding_access_policy_setting,omitempty"` + AibiDashboardEmbeddingApprovedDomainsSetting map[string]any `json:"databricks_aibi_dashboard_embedding_approved_domains_setting,omitempty"` + Alert map[string]any `json:"databricks_alert,omitempty"` + App map[string]any `json:"databricks_app,omitempty"` + ArtifactAllowlist map[string]any `json:"databricks_artifact_allowlist,omitempty"` + AutomaticClusterUpdateWorkspaceSetting map[string]any `json:"databricks_automatic_cluster_update_workspace_setting,omitempty"` + AwsS3Mount map[string]any `json:"databricks_aws_s3_mount,omitempty"` + AzureAdlsGen1Mount map[string]any `json:"databricks_azure_adls_gen1_mount,omitempty"` + AzureAdlsGen2Mount map[string]any `json:"databricks_azure_adls_gen2_mount,omitempty"` + AzureBlobMount map[string]any `json:"databricks_azure_blob_mount,omitempty"` + Budget map[string]any `json:"databricks_budget,omitempty"` + Catalog map[string]any `json:"databricks_catalog,omitempty"` + CatalogWorkspaceBinding map[string]any `json:"databricks_catalog_workspace_binding,omitempty"` + Cluster map[string]any `json:"databricks_cluster,omitempty"` + ClusterPolicy map[string]any `json:"databricks_cluster_policy,omitempty"` + ComplianceSecurityProfileWorkspaceSetting map[string]any `json:"databricks_compliance_security_profile_workspace_setting,omitempty"` + Connection map[string]any `json:"databricks_connection,omitempty"` + Credential map[string]any `json:"databricks_credential,omitempty"` + CustomAppIntegration map[string]any `json:"databricks_custom_app_integration,omitempty"` + Dashboard map[string]any `json:"databricks_dashboard,omitempty"` + DbfsFile map[string]any `json:"databricks_dbfs_file,omitempty"` + DefaultNamespaceSetting map[string]any `json:"databricks_default_namespace_setting,omitempty"` + Directory map[string]any `json:"databricks_directory,omitempty"` + EnhancedSecurityMonitoringWorkspaceSetting map[string]any `json:"databricks_enhanced_security_monitoring_workspace_setting,omitempty"` + Entitlements map[string]any `json:"databricks_entitlements,omitempty"` + ExternalLocation map[string]any `json:"databricks_external_location,omitempty"` + File map[string]any `json:"databricks_file,omitempty"` + GitCredential map[string]any `json:"databricks_git_credential,omitempty"` + GlobalInitScript map[string]any `json:"databricks_global_init_script,omitempty"` + Grant map[string]any `json:"databricks_grant,omitempty"` + Grants map[string]any `json:"databricks_grants,omitempty"` + Group map[string]any `json:"databricks_group,omitempty"` + GroupInstanceProfile map[string]any `json:"databricks_group_instance_profile,omitempty"` + GroupMember map[string]any `json:"databricks_group_member,omitempty"` + GroupRole map[string]any `json:"databricks_group_role,omitempty"` + InstancePool map[string]any `json:"databricks_instance_pool,omitempty"` + InstanceProfile map[string]any `json:"databricks_instance_profile,omitempty"` + IpAccessList map[string]any `json:"databricks_ip_access_list,omitempty"` + Job map[string]any `json:"databricks_job,omitempty"` + LakehouseMonitor map[string]any `json:"databricks_lakehouse_monitor,omitempty"` + Library map[string]any `json:"databricks_library,omitempty"` + Metastore map[string]any `json:"databricks_metastore,omitempty"` + MetastoreAssignment map[string]any `json:"databricks_metastore_assignment,omitempty"` + MetastoreDataAccess map[string]any `json:"databricks_metastore_data_access,omitempty"` + MlflowExperiment map[string]any `json:"databricks_mlflow_experiment,omitempty"` + MlflowModel map[string]any `json:"databricks_mlflow_model,omitempty"` + MlflowWebhook map[string]any `json:"databricks_mlflow_webhook,omitempty"` + ModelServing map[string]any `json:"databricks_model_serving,omitempty"` + Mount map[string]any `json:"databricks_mount,omitempty"` + MwsCredentials map[string]any `json:"databricks_mws_credentials,omitempty"` + MwsCustomerManagedKeys map[string]any `json:"databricks_mws_customer_managed_keys,omitempty"` + MwsLogDelivery map[string]any `json:"databricks_mws_log_delivery,omitempty"` + MwsNccBinding map[string]any `json:"databricks_mws_ncc_binding,omitempty"` + MwsNccPrivateEndpointRule map[string]any `json:"databricks_mws_ncc_private_endpoint_rule,omitempty"` + MwsNetworkConnectivityConfig map[string]any `json:"databricks_mws_network_connectivity_config,omitempty"` + MwsNetworks map[string]any `json:"databricks_mws_networks,omitempty"` + MwsPermissionAssignment map[string]any `json:"databricks_mws_permission_assignment,omitempty"` + MwsPrivateAccessSettings map[string]any `json:"databricks_mws_private_access_settings,omitempty"` + MwsStorageConfigurations map[string]any `json:"databricks_mws_storage_configurations,omitempty"` + MwsVpcEndpoint map[string]any `json:"databricks_mws_vpc_endpoint,omitempty"` + MwsWorkspaces map[string]any `json:"databricks_mws_workspaces,omitempty"` + Notebook map[string]any `json:"databricks_notebook,omitempty"` + NotificationDestination map[string]any `json:"databricks_notification_destination,omitempty"` + OboToken map[string]any `json:"databricks_obo_token,omitempty"` + OnlineTable map[string]any `json:"databricks_online_table,omitempty"` + PermissionAssignment map[string]any `json:"databricks_permission_assignment,omitempty"` + Permissions map[string]any `json:"databricks_permissions,omitempty"` + Pipeline map[string]any `json:"databricks_pipeline,omitempty"` + Provider map[string]any `json:"databricks_provider,omitempty"` + QualityMonitor map[string]any `json:"databricks_quality_monitor,omitempty"` + Query map[string]any `json:"databricks_query,omitempty"` + Recipient map[string]any `json:"databricks_recipient,omitempty"` + RegisteredModel map[string]any `json:"databricks_registered_model,omitempty"` + Repo map[string]any `json:"databricks_repo,omitempty"` + RestrictWorkspaceAdminsSetting map[string]any `json:"databricks_restrict_workspace_admins_setting,omitempty"` + Schema map[string]any `json:"databricks_schema,omitempty"` + Secret map[string]any `json:"databricks_secret,omitempty"` + SecretAcl map[string]any `json:"databricks_secret_acl,omitempty"` + SecretScope map[string]any `json:"databricks_secret_scope,omitempty"` + ServicePrincipal map[string]any `json:"databricks_service_principal,omitempty"` + ServicePrincipalRole map[string]any `json:"databricks_service_principal_role,omitempty"` + ServicePrincipalSecret map[string]any `json:"databricks_service_principal_secret,omitempty"` + Share map[string]any `json:"databricks_share,omitempty"` + SqlAlert map[string]any `json:"databricks_sql_alert,omitempty"` + SqlDashboard map[string]any `json:"databricks_sql_dashboard,omitempty"` + SqlEndpoint map[string]any `json:"databricks_sql_endpoint,omitempty"` + SqlGlobalConfig map[string]any `json:"databricks_sql_global_config,omitempty"` + SqlPermissions map[string]any `json:"databricks_sql_permissions,omitempty"` + SqlQuery map[string]any `json:"databricks_sql_query,omitempty"` + SqlTable map[string]any `json:"databricks_sql_table,omitempty"` + SqlVisualization map[string]any `json:"databricks_sql_visualization,omitempty"` + SqlWidget map[string]any `json:"databricks_sql_widget,omitempty"` + StorageCredential map[string]any `json:"databricks_storage_credential,omitempty"` + SystemSchema map[string]any `json:"databricks_system_schema,omitempty"` + Table map[string]any `json:"databricks_table,omitempty"` + Token map[string]any `json:"databricks_token,omitempty"` + User map[string]any `json:"databricks_user,omitempty"` + UserInstanceProfile map[string]any `json:"databricks_user_instance_profile,omitempty"` + UserRole map[string]any `json:"databricks_user_role,omitempty"` + VectorSearchEndpoint map[string]any `json:"databricks_vector_search_endpoint,omitempty"` + VectorSearchIndex map[string]any `json:"databricks_vector_search_index,omitempty"` + Volume map[string]any `json:"databricks_volume,omitempty"` + WorkspaceBinding map[string]any `json:"databricks_workspace_binding,omitempty"` + WorkspaceConf map[string]any `json:"databricks_workspace_conf,omitempty"` + WorkspaceFile map[string]any `json:"databricks_workspace_file,omitempty"` } func NewResources() *Resources { return &Resources{ - AccessControlRuleSet: make(map[string]any), + AccessControlRuleSet: make(map[string]any), + AibiDashboardEmbeddingAccessPolicySetting: make(map[string]any), + AibiDashboardEmbeddingApprovedDomainsSetting: make(map[string]any), Alert: make(map[string]any), App: make(map[string]any), ArtifactAllowlist: make(map[string]any), diff --git a/bundle/internal/tf/schema/root.go b/bundle/internal/tf/schema/root.go index 2ac852355..816e8e6aa 100644 --- a/bundle/internal/tf/schema/root.go +++ b/bundle/internal/tf/schema/root.go @@ -21,7 +21,7 @@ type Root struct { const ProviderHost = "registry.terraform.io" const ProviderSource = "databricks/databricks" -const ProviderVersion = "1.64.1" +const ProviderVersion = "1.65.1" func NewRoot() *Root { return &Root{ diff --git a/bundle/mutator.go b/bundle/mutator.go index 6c9968aac..16ef79ee7 100644 --- a/bundle/mutator.go +++ b/bundle/mutator.go @@ -42,7 +42,7 @@ func Apply(ctx context.Context, b *Bundle, m Mutator) diag.Diagnostics { // such that they are not logged multiple times. // If this is done, we can omit this block. if err := diags.Error(); err != nil { - log.Errorf(ctx, "Error: %s", err) + log.Debugf(ctx, "Error: %s", err) } return diags diff --git a/bundle/mutator_read_only.go b/bundle/mutator_read_only.go index ee4e36e0f..700a90d8d 100644 --- a/bundle/mutator_read_only.go +++ b/bundle/mutator_read_only.go @@ -22,7 +22,7 @@ func ApplyReadOnly(ctx context.Context, rb ReadOnlyBundle, m ReadOnlyMutator) di log.Debugf(ctx, "ApplyReadOnly") diags := m.Apply(ctx, rb) if err := diags.Error(); err != nil { - log.Errorf(ctx, "Error: %s", err) + log.Debugf(ctx, "Error: %s", err) } return diags diff --git a/bundle/permissions/permission_diagnostics.go b/bundle/permissions/permission_diagnostics.go index d2c24fa01..3c76f3505 100644 --- a/bundle/permissions/permission_diagnostics.go +++ b/bundle/permissions/permission_diagnostics.go @@ -9,6 +9,7 @@ import ( "github.com/databricks/cli/bundle" "github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/dyn" + "github.com/databricks/cli/libs/iamutil" "github.com/databricks/cli/libs/set" ) @@ -33,9 +34,25 @@ func (m *permissionDiagnostics) Apply(ctx context.Context, b *bundle.Bundle) dia return nil } + me := b.Config.Workspace.CurrentUser.User + identityType := "user_name" + if iamutil.IsServicePrincipal(me) { + identityType = "service_principal_name" + } + return diag.Diagnostics{{ - Severity: diag.Warning, - Summary: fmt.Sprintf("permissions section should include %s or one of their groups with CAN_MANAGE permissions", b.Config.Workspace.CurrentUser.UserName), + Severity: diag.Recommendation, + Summary: fmt.Sprintf("permissions section should explicitly include the current deployment identity '%s' or one of its groups\n"+ + "If it is not included, CAN_MANAGE permissions are only applied if the present identity is used to deploy.\n\n"+ + "Consider using a adding a top-level permissions section such as the following:\n\n"+ + " permissions:\n"+ + " - %s: %s\n"+ + " level: CAN_MANAGE\n\n"+ + "See https://docs.databricks.com/dev-tools/bundles/permissions.html to learn more about permission configuration.", + b.Config.Workspace.CurrentUser.UserName, + identityType, + b.Config.Workspace.CurrentUser.UserName, + ), Locations: []dyn.Location{b.Config.GetLocation("permissions")}, ID: diag.PermissionNotIncluded, }} @@ -46,7 +63,7 @@ func (m *permissionDiagnostics) Apply(ctx context.Context, b *bundle.Bundle) dia // target workspace folder. // // Returns: -// - isManager: true if the current user is can manage the bundle resources. +// - canManageBundle: true if the current user or one of their groups can manage the bundle resources. // - assistance: advice on who to contact as to manage this project func analyzeBundlePermissions(b *bundle.Bundle) (bool, string) { canManageBundle := false diff --git a/bundle/permissions/permission_diagnostics_test.go b/bundle/permissions/permission_diagnostics_test.go index 6c55ab594..892f122de 100644 --- a/bundle/permissions/permission_diagnostics_test.go +++ b/bundle/permissions/permission_diagnostics_test.go @@ -18,7 +18,14 @@ func TestPermissionDiagnosticsApplySuccess(t *testing.T) { {Level: "CAN_MANAGE", UserName: "testuser@databricks.com"}, }) - diags := permissions.PermissionDiagnostics().Apply(context.Background(), b) + diags := bundle.Apply(context.Background(), b, permissions.PermissionDiagnostics()) + require.NoError(t, diags.Error()) +} + +func TestPermissionDiagnosticsEmpty(t *testing.T) { + b := mockBundle(nil) + + diags := bundle.Apply(context.Background(), b, permissions.PermissionDiagnostics()) require.NoError(t, diags.Error()) } @@ -27,9 +34,19 @@ func TestPermissionDiagnosticsApplyFail(t *testing.T) { {Level: "CAN_VIEW", UserName: "testuser@databricks.com"}, }) - diags := permissions.PermissionDiagnostics().Apply(context.Background(), b) - require.Equal(t, diag.Warning, diags[0].Severity) - require.Contains(t, diags[0].Summary, "permissions section should include testuser@databricks.com or one of their groups with CAN_MANAGE permissions") + diags := bundle.Apply(context.Background(), b, permissions.PermissionDiagnostics()) + require.Equal(t, diag.Recommendation, diags[0].Severity) + + expectedMsg := "permissions section should explicitly include the current deployment identity " + + "'testuser@databricks.com' or one of its groups\n" + + "If it is not included, CAN_MANAGE permissions are only applied if the present identity is used to deploy.\n\n" + + "Consider using a adding a top-level permissions section such as the following:\n\n" + + " permissions:\n" + + " - user_name: testuser@databricks.com\n" + + " level: CAN_MANAGE\n\n" + + "See https://docs.databricks.com/dev-tools/bundles/permissions.html to learn more about permission configuration." + + require.Contains(t, diags[0].Summary, expectedMsg) } func mockBundle(permissions []resources.Permission) *bundle.Bundle { diff --git a/bundle/permissions/workspace_root_test.go b/bundle/permissions/workspace_root_test.go index c48704a63..3e5f9c61b 100644 --- a/bundle/permissions/workspace_root_test.go +++ b/bundle/permissions/workspace_root_test.go @@ -38,8 +38,8 @@ func TestApplyWorkspaceRootPermissions(t *testing.T) { "job_2": {JobSettings: &jobs.JobSettings{Name: "job_2"}}, }, Pipelines: map[string]*resources.Pipeline{ - "pipeline_1": {PipelineSpec: &pipelines.PipelineSpec{}}, - "pipeline_2": {PipelineSpec: &pipelines.PipelineSpec{}}, + "pipeline_1": {CreatePipeline: &pipelines.CreatePipeline{}}, + "pipeline_2": {CreatePipeline: &pipelines.CreatePipeline{}}, }, Models: map[string]*resources.MlflowModel{ "model_1": {Model: &ml.Model{}}, @@ -98,8 +98,8 @@ func TestApplyWorkspaceRootPermissionsForAllPaths(t *testing.T) { "job_2": {JobSettings: &jobs.JobSettings{Name: "job_2"}}, }, Pipelines: map[string]*resources.Pipeline{ - "pipeline_1": {PipelineSpec: &pipelines.PipelineSpec{}}, - "pipeline_2": {PipelineSpec: &pipelines.PipelineSpec{}}, + "pipeline_1": {CreatePipeline: &pipelines.CreatePipeline{}}, + "pipeline_2": {CreatePipeline: &pipelines.CreatePipeline{}}, }, Models: map[string]*resources.MlflowModel{ "model_1": {Model: &ml.Model{}}, diff --git a/bundle/render/render_text_output_test.go b/bundle/render/render_text_output_test.go index 506756f70..d092e77c8 100644 --- a/bundle/render/render_text_output_test.go +++ b/bundle/render/render_text_output_test.go @@ -530,12 +530,12 @@ func TestRenderSummary(t *testing.T) { "pipeline2": { ID: "4", // no URL - PipelineSpec: &pipelines.PipelineSpec{Name: "pipeline2-name"}, + CreatePipeline: &pipelines.CreatePipeline{Name: "pipeline2-name"}, }, "pipeline1": { - ID: "3", - URL: "https://url3", - PipelineSpec: &pipelines.PipelineSpec{Name: "pipeline1-name"}, + ID: "3", + URL: "https://url3", + CreatePipeline: &pipelines.CreatePipeline{Name: "pipeline1-name"}, }, }, Schemas: map[string]*resources.Schema{ diff --git a/bundle/resources/completion_test.go b/bundle/resources/completion_test.go index 80412b6f1..56559f18c 100644 --- a/bundle/resources/completion_test.go +++ b/bundle/resources/completion_test.go @@ -25,7 +25,7 @@ func TestCompletions_SkipDuplicates(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "foo": { - PipelineSpec: &pipelines.PipelineSpec{}, + CreatePipeline: &pipelines.CreatePipeline{}, }, }, }, @@ -50,7 +50,7 @@ func TestCompletions_Filter(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "bar": { - PipelineSpec: &pipelines.PipelineSpec{}, + CreatePipeline: &pipelines.CreatePipeline{}, }, }, }, diff --git a/bundle/resources/lookup_test.go b/bundle/resources/lookup_test.go index 0ea5af7a2..d95da977a 100644 --- a/bundle/resources/lookup_test.go +++ b/bundle/resources/lookup_test.go @@ -56,7 +56,7 @@ func TestLookup_MultipleFound(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "foo": { - PipelineSpec: &pipelines.PipelineSpec{}, + CreatePipeline: &pipelines.CreatePipeline{}, }, }, }, @@ -107,7 +107,7 @@ func TestLookup_NominalWithFilters(t *testing.T) { }, Pipelines: map[string]*resources.Pipeline{ "bar": { - PipelineSpec: &pipelines.PipelineSpec{}, + CreatePipeline: &pipelines.CreatePipeline{}, }, }, }, diff --git a/bundle/run/pipeline.go b/bundle/run/pipeline.go index bdcf0f142..1cd6e8743 100644 --- a/bundle/run/pipeline.go +++ b/bundle/run/pipeline.go @@ -79,10 +79,10 @@ type pipelineRunner struct { } func (r *pipelineRunner) Name() string { - if r.pipeline == nil || r.pipeline.PipelineSpec == nil { + if r.pipeline == nil || r.pipeline.CreatePipeline == nil { return "" } - return r.pipeline.PipelineSpec.Name + return r.pipeline.CreatePipeline.Name } func (r *pipelineRunner) Run(ctx context.Context, opts *Options) (output.RunOutput, error) { diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index d827a181e..2cb2cd7b5 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -409,6 +409,10 @@ "description": "Job-level parameter definitions", "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/jobs.JobParameterDefinition" }, + "performance_target": { + "description": "PerformanceTarget defines how performant or cost efficient the execution of run on serverless should be.", + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/jobs.PerformanceTarget" + }, "permissions": { "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.Permission" }, @@ -703,6 +707,9 @@ "description": "Restart window of this pipeline.", "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/pipelines.RestartWindow" }, + "run_as": { + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/pipelines.RunAs" + }, "schema": { "description": "The default schema (database) where tables are read from or published to. The presence of this field implies that the pipeline is in direct publishing mode.", "$ref": "#/$defs/string" @@ -3895,6 +3902,22 @@ } ] }, + "jobs.PerformanceTarget": { + "oneOf": [ + { + "type": "string", + "description": "PerformanceTarget defines how performant (lower latency) or cost efficient the execution of run on serverless compute should be.\nThe performance mode on the job or pipeline should map to a performance setting that is passed to Cluster Manager\n(see cluster-common PerformanceTarget).", + "enum": [ + "PERFORMANCE_OPTIMIZED", + "COST_OPTIMIZED" + ] + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "jobs.PeriodicTriggerConfiguration": { "oneOf": [ { @@ -5379,6 +5402,29 @@ } ] }, + "pipelines.RunAs": { + "oneOf": [ + { + "type": "object", + "description": "Write-only setting, available only in Create/Update calls. Specifies the user or service principal that the pipeline runs as. If not specified, the pipeline runs as the user who created the pipeline.\n\nOnly `user_name` or `service_principal_name` can be specified. If both are specified, an error is thrown.", + "properties": { + "service_principal_name": { + "description": "Application ID of an active service principal. Setting this field requires the `servicePrincipal/user` role.", + "$ref": "#/$defs/string" + }, + "user_name": { + "description": "The email of an active workspace user. Users can only set this field to their own email.", + "$ref": "#/$defs/string" + } + }, + "additionalProperties": false + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "pipelines.SchemaSpec": { "oneOf": [ { diff --git a/bundle/tests/environment_git_test.go b/bundle/tests/environment_git_test.go index 848b972b1..901d2867b 100644 --- a/bundle/tests/environment_git_test.go +++ b/bundle/tests/environment_git_test.go @@ -13,7 +13,6 @@ import ( func TestGitAutoLoadWithEnvironment(t *testing.T) { b := load(t, "./environments_autoload_git") bundle.Apply(context.Background(), b, mutator.LoadGitDetails()) - assert.True(t, b.Config.Bundle.Git.Inferred) validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) } @@ -21,7 +20,6 @@ func TestGitAutoLoadWithEnvironment(t *testing.T) { func TestGitManuallySetBranchWithEnvironment(t *testing.T) { b := loadTarget(t, "./environments_autoload_git", "production") bundle.Apply(context.Background(), b, mutator.LoadGitDetails()) - assert.False(t, b.Config.Bundle.Git.Inferred) assert.Equal(t, "main", b.Config.Bundle.Git.Branch) validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) diff --git a/bundle/tests/git_test.go b/bundle/tests/git_test.go index 41293e450..dd79e26a4 100644 --- a/bundle/tests/git_test.go +++ b/bundle/tests/git_test.go @@ -14,7 +14,6 @@ import ( func TestGitAutoLoad(t *testing.T) { b := load(t, "./autoload_git") bundle.Apply(context.Background(), b, mutator.LoadGitDetails()) - assert.True(t, b.Config.Bundle.Git.Inferred) validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) } @@ -22,7 +21,6 @@ func TestGitAutoLoad(t *testing.T) { func TestGitManuallySetBranch(t *testing.T) { b := loadTarget(t, "./autoload_git", "production") bundle.Apply(context.Background(), b, mutator.LoadGitDetails()) - assert.False(t, b.Config.Bundle.Git.Inferred) assert.Equal(t, "main", b.Config.Bundle.Git.Branch) validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) @@ -36,7 +34,6 @@ func TestGitBundleBranchValidation(t *testing.T) { b := load(t, "./git_branch_validation") bundle.Apply(context.Background(), b, mutator.LoadGitDetails()) - assert.False(t, b.Config.Bundle.Git.Inferred) assert.Equal(t, "feature-a", b.Config.Bundle.Git.Branch) assert.Equal(t, "feature-b", b.Config.Bundle.Git.ActualBranch) diff --git a/cmd/account/budget-policy/budget-policy.go b/cmd/account/budget-policy/budget-policy.go new file mode 100755 index 000000000..28b14ea91 --- /dev/null +++ b/cmd/account/budget-policy/budget-policy.go @@ -0,0 +1,373 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package budget_policy + +import ( + "fmt" + + "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdio" + "github.com/databricks/cli/libs/flags" + "github.com/databricks/databricks-sdk-go/service/billing" + "github.com/spf13/cobra" +) + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var cmdOverrides []func(*cobra.Command) + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: "budget-policy", + Short: `A service serves REST API about Budget policies.`, + Long: `A service serves REST API about Budget policies`, + GroupID: "billing", + Annotations: map[string]string{ + "package": "billing", + }, + } + + // Add methods + cmd.AddCommand(newCreate()) + cmd.AddCommand(newDelete()) + cmd.AddCommand(newGet()) + cmd.AddCommand(newList()) + cmd.AddCommand(newUpdate()) + + // Apply optional overrides to this command. + for _, fn := range cmdOverrides { + fn(cmd) + } + + return cmd +} + +// start create command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var createOverrides []func( + *cobra.Command, + *billing.CreateBudgetPolicyRequest, +) + +func newCreate() *cobra.Command { + cmd := &cobra.Command{} + + var createReq billing.CreateBudgetPolicyRequest + var createJson flags.JsonFlag + + // TODO: short flags + cmd.Flags().Var(&createJson, "json", `either inline JSON string or @path/to/file.json with request body`) + + // TODO: array: custom_tags + cmd.Flags().StringVar(&createReq.PolicyName, "policy-name", createReq.PolicyName, `The name of the policy.`) + cmd.Flags().StringVar(&createReq.RequestId, "request-id", createReq.RequestId, `A unique identifier for this request.`) + + cmd.Use = "create" + cmd.Short = `Create a budget policy.` + cmd.Long = `Create a budget policy. + + Creates a new policy.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(0) + return check(cmd, args) + } + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + if cmd.Flags().Changed("json") { + diags := createJson.Unmarshal(&createReq) + if diags.HasError() { + return diags.Error() + } + if len(diags) > 0 { + err := cmdio.RenderDiagnosticsToErrorOut(ctx, diags) + if err != nil { + return err + } + } + } + + response, err := a.BudgetPolicy.Create(ctx, createReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range createOverrides { + fn(cmd, &createReq) + } + + return cmd +} + +// start delete command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var deleteOverrides []func( + *cobra.Command, + *billing.DeleteBudgetPolicyRequest, +) + +func newDelete() *cobra.Command { + cmd := &cobra.Command{} + + var deleteReq billing.DeleteBudgetPolicyRequest + + // TODO: short flags + + cmd.Use = "delete POLICY_ID" + cmd.Short = `Delete a budget policy.` + cmd.Long = `Delete a budget policy. + + Deletes a policy + + Arguments: + POLICY_ID: The Id of the policy.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(1) + return check(cmd, args) + } + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + deleteReq.PolicyId = args[0] + + err = a.BudgetPolicy.Delete(ctx, deleteReq) + if err != nil { + return err + } + return nil + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range deleteOverrides { + fn(cmd, &deleteReq) + } + + return cmd +} + +// start get command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var getOverrides []func( + *cobra.Command, + *billing.GetBudgetPolicyRequest, +) + +func newGet() *cobra.Command { + cmd := &cobra.Command{} + + var getReq billing.GetBudgetPolicyRequest + + // TODO: short flags + + cmd.Use = "get POLICY_ID" + cmd.Short = `Get a budget policy.` + cmd.Long = `Get a budget policy. + + Retrieves a policy by it's ID. + + Arguments: + POLICY_ID: The Id of the policy.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(1) + return check(cmd, args) + } + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + getReq.PolicyId = args[0] + + response, err := a.BudgetPolicy.Get(ctx, getReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range getOverrides { + fn(cmd, &getReq) + } + + return cmd +} + +// start list command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var listOverrides []func( + *cobra.Command, + *billing.ListBudgetPoliciesRequest, +) + +func newList() *cobra.Command { + cmd := &cobra.Command{} + + var listReq billing.ListBudgetPoliciesRequest + + // TODO: short flags + + // TODO: complex arg: filter_by + cmd.Flags().IntVar(&listReq.PageSize, "page-size", listReq.PageSize, `The maximum number of budget policies to return.`) + cmd.Flags().StringVar(&listReq.PageToken, "page-token", listReq.PageToken, `A page token, received from a previous ListServerlessPolicies call.`) + // TODO: complex arg: sort_spec + + cmd.Use = "list" + cmd.Short = `List policies.` + cmd.Long = `List policies. + + Lists all policies. Policies are returned in the alphabetically ascending + order of their names.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(0) + return check(cmd, args) + } + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + response := a.BudgetPolicy.List(ctx, listReq) + return cmdio.RenderIterator(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range listOverrides { + fn(cmd, &listReq) + } + + return cmd +} + +// start update command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var updateOverrides []func( + *cobra.Command, + *billing.UpdateBudgetPolicyRequest, +) + +func newUpdate() *cobra.Command { + cmd := &cobra.Command{} + + var updateReq billing.UpdateBudgetPolicyRequest + updateReq.Policy = &billing.BudgetPolicy{} + var updateJson flags.JsonFlag + + // TODO: short flags + cmd.Flags().Var(&updateJson, "json", `either inline JSON string or @path/to/file.json with request body`) + + // TODO: array: custom_tags + cmd.Flags().StringVar(&updateReq.Policy.PolicyName, "policy-name", updateReq.Policy.PolicyName, `The name of the policy.`) + + cmd.Use = "update POLICY_ID" + cmd.Short = `Update a budget policy.` + cmd.Long = `Update a budget policy. + + Updates a policy + + Arguments: + POLICY_ID: The Id of the policy. This field is generated by Databricks and globally + unique.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("json") { + err := root.ExactArgs(0)(cmd, args) + if err != nil { + return fmt.Errorf("when --json flag is specified, no positional arguments are required. Provide 'policy_id' in your JSON input") + } + return nil + } + check := root.ExactArgs(1) + return check(cmd, args) + } + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + if cmd.Flags().Changed("json") { + diags := updateJson.Unmarshal(&updateReq.Policy) + if diags.HasError() { + return diags.Error() + } + if len(diags) > 0 { + err := cmdio.RenderDiagnosticsToErrorOut(ctx, diags) + if err != nil { + return err + } + } + } + updateReq.PolicyId = args[0] + + response, err := a.BudgetPolicy.Update(ctx, updateReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range updateOverrides { + fn(cmd, &updateReq) + } + + return cmd +} + +// end service BudgetPolicy diff --git a/cmd/account/cmd.go b/cmd/account/cmd.go index f34966fd9..758e2af5e 100644 --- a/cmd/account/cmd.go +++ b/cmd/account/cmd.go @@ -7,6 +7,7 @@ import ( account_access_control "github.com/databricks/cli/cmd/account/access-control" billable_usage "github.com/databricks/cli/cmd/account/billable-usage" + budget_policy "github.com/databricks/cli/cmd/account/budget-policy" budgets "github.com/databricks/cli/cmd/account/budgets" credentials "github.com/databricks/cli/cmd/account/credentials" custom_app_integration "github.com/databricks/cli/cmd/account/custom-app-integration" @@ -43,6 +44,7 @@ func New() *cobra.Command { cmd.AddCommand(account_access_control.New()) cmd.AddCommand(billable_usage.New()) + cmd.AddCommand(budget_policy.New()) cmd.AddCommand(credentials.New()) cmd.AddCommand(custom_app_integration.New()) cmd.AddCommand(encryption_keys.New()) diff --git a/cmd/account/custom-app-integration/custom-app-integration.go b/cmd/account/custom-app-integration/custom-app-integration.go index 43e458bc6..61cfe0a09 100755 --- a/cmd/account/custom-app-integration/custom-app-integration.go +++ b/cmd/account/custom-app-integration/custom-app-integration.go @@ -65,6 +65,7 @@ func newCreate() *cobra.Command { // TODO: array: redirect_urls // TODO: array: scopes // TODO: complex arg: token_access_policy + // TODO: array: user_authorized_scopes cmd.Use = "create" cmd.Short = `Create Custom OAuth App Integration.` @@ -309,6 +310,7 @@ func newUpdate() *cobra.Command { // TODO: array: redirect_urls // TODO: array: scopes // TODO: complex arg: token_access_policy + // TODO: array: user_authorized_scopes cmd.Use = "update INTEGRATION_ID" cmd.Short = `Updates Custom OAuth App Integration.` diff --git a/cmd/account/enable-ip-access-lists/enable-ip-access-lists.go b/cmd/account/enable-ip-access-lists/enable-ip-access-lists.go new file mode 100755 index 000000000..24d30c9c6 --- /dev/null +++ b/cmd/account/enable-ip-access-lists/enable-ip-access-lists.go @@ -0,0 +1,218 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package enable_ip_access_lists + +import ( + "fmt" + + "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdio" + "github.com/databricks/cli/libs/flags" + "github.com/databricks/databricks-sdk-go/service/settings" + "github.com/spf13/cobra" +) + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var cmdOverrides []func(*cobra.Command) + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: "enable-ip-access-lists", + Short: `Controls the enforcement of IP access lists for accessing the account console.`, + Long: `Controls the enforcement of IP access lists for accessing the account console. + Allowing you to enable or disable restricted access based on IP addresses.`, + + // This service is being previewed; hide from help output. + Hidden: true, + } + + // Add methods + cmd.AddCommand(newDelete()) + cmd.AddCommand(newGet()) + cmd.AddCommand(newUpdate()) + + // Apply optional overrides to this command. + for _, fn := range cmdOverrides { + fn(cmd) + } + + return cmd +} + +// start delete command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var deleteOverrides []func( + *cobra.Command, + *settings.DeleteAccountIpAccessEnableRequest, +) + +func newDelete() *cobra.Command { + cmd := &cobra.Command{} + + var deleteReq settings.DeleteAccountIpAccessEnableRequest + + // TODO: short flags + + cmd.Flags().StringVar(&deleteReq.Etag, "etag", deleteReq.Etag, `etag used for versioning.`) + + cmd.Use = "delete" + cmd.Short = `Delete the account IP access toggle setting.` + cmd.Long = `Delete the account IP access toggle setting. + + Reverts the value of the account IP access toggle setting to default (ON)` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(0) + return check(cmd, args) + } + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + response, err := a.Settings.EnableIpAccessLists().Delete(ctx, deleteReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range deleteOverrides { + fn(cmd, &deleteReq) + } + + return cmd +} + +// start get command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var getOverrides []func( + *cobra.Command, + *settings.GetAccountIpAccessEnableRequest, +) + +func newGet() *cobra.Command { + cmd := &cobra.Command{} + + var getReq settings.GetAccountIpAccessEnableRequest + + // TODO: short flags + + cmd.Flags().StringVar(&getReq.Etag, "etag", getReq.Etag, `etag used for versioning.`) + + cmd.Use = "get" + cmd.Short = `Get the account IP access toggle setting.` + cmd.Long = `Get the account IP access toggle setting. + + Gets the value of the account IP access toggle setting.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(0) + return check(cmd, args) + } + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + response, err := a.Settings.EnableIpAccessLists().Get(ctx, getReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range getOverrides { + fn(cmd, &getReq) + } + + return cmd +} + +// start update command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var updateOverrides []func( + *cobra.Command, + *settings.UpdateAccountIpAccessEnableRequest, +) + +func newUpdate() *cobra.Command { + cmd := &cobra.Command{} + + var updateReq settings.UpdateAccountIpAccessEnableRequest + var updateJson flags.JsonFlag + + // TODO: short flags + cmd.Flags().Var(&updateJson, "json", `either inline JSON string or @path/to/file.json with request body`) + + cmd.Use = "update" + cmd.Short = `Update the account IP access toggle setting.` + cmd.Long = `Update the account IP access toggle setting. + + Updates the value of the account IP access toggle setting.` + + cmd.Annotations = make(map[string]string) + + cmd.PreRunE = root.MustAccountClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + a := root.AccountClient(ctx) + + if cmd.Flags().Changed("json") { + diags := updateJson.Unmarshal(&updateReq) + if diags.HasError() { + return diags.Error() + } + if len(diags) > 0 { + err := cmdio.RenderDiagnosticsToErrorOut(ctx, diags) + if err != nil { + return err + } + } + } else { + return fmt.Errorf("please provide command input in JSON format by specifying the --json flag") + } + + response, err := a.Settings.EnableIpAccessLists().Update(ctx, updateReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range updateOverrides { + fn(cmd, &updateReq) + } + + return cmd +} + +// end service EnableIpAccessLists diff --git a/cmd/account/federation-policy/federation-policy.go b/cmd/account/federation-policy/federation-policy.go index e47bf8324..ad45c0405 100755 --- a/cmd/account/federation-policy/federation-policy.go +++ b/cmd/account/federation-policy/federation-policy.go @@ -71,9 +71,6 @@ func New() *cobra.Command { Annotations: map[string]string{ "package": "oauth2", }, - - // This service is being previewed; hide from help output. - Hidden: true, } // Add methods diff --git a/cmd/account/service-principal-federation-policy/service-principal-federation-policy.go b/cmd/account/service-principal-federation-policy/service-principal-federation-policy.go index df36de239..451523b7e 100755 --- a/cmd/account/service-principal-federation-policy/service-principal-federation-policy.go +++ b/cmd/account/service-principal-federation-policy/service-principal-federation-policy.go @@ -78,9 +78,6 @@ func New() *cobra.Command { Annotations: map[string]string{ "package": "oauth2", }, - - // This service is being previewed; hide from help output. - Hidden: true, } // Add methods diff --git a/cmd/account/settings/settings.go b/cmd/account/settings/settings.go index 9a9cd44bf..cd30743f7 100755 --- a/cmd/account/settings/settings.go +++ b/cmd/account/settings/settings.go @@ -7,6 +7,7 @@ import ( csp_enablement_account "github.com/databricks/cli/cmd/account/csp-enablement-account" disable_legacy_features "github.com/databricks/cli/cmd/account/disable-legacy-features" + enable_ip_access_lists "github.com/databricks/cli/cmd/account/enable-ip-access-lists" esm_enablement_account "github.com/databricks/cli/cmd/account/esm-enablement-account" personal_compute "github.com/databricks/cli/cmd/account/personal-compute" ) @@ -29,6 +30,7 @@ func New() *cobra.Command { // Add subservices cmd.AddCommand(csp_enablement_account.New()) cmd.AddCommand(disable_legacy_features.New()) + cmd.AddCommand(enable_ip_access_lists.New()) cmd.AddCommand(esm_enablement_account.New()) cmd.AddCommand(personal_compute.New()) diff --git a/cmd/auth/token.go b/cmd/auth/token.go index fbf8b68f6..f3468df40 100644 --- a/cmd/auth/token.go +++ b/cmd/auth/token.go @@ -46,6 +46,10 @@ func newTokenCommand(persistentAuth *auth.PersistentAuth) *cobra.Command { cmd := &cobra.Command{ Use: "token [HOST]", Short: "Get authentication token", + Long: `Get authentication token from the local cache in ~/.databricks/token-cache.json. +Refresh the access token if it is expired. Note: This command only works with +U2M authentication (using the 'databricks auth login' command). M2M authentication +using a client ID and secret is not supported.`, } var tokenTimeout time.Duration diff --git a/cmd/bundle/generate/job.go b/cmd/bundle/generate/job.go index d97891cd5..438b235c9 100644 --- a/cmd/bundle/generate/job.go +++ b/cmd/bundle/generate/job.go @@ -50,10 +50,22 @@ func NewGenerateJobCommand() *cobra.Command { } downloader := newDownloader(w, sourceDir, configDir) - for _, task := range job.Settings.Tasks { - err := downloader.MarkTaskForDownload(ctx, &task) - if err != nil { - return err + + // Don't download files if the job is using Git source + // When Git source is used, the job will be using the files from the Git repository + // but specific tasks might override this behaviour by using `source: WORKSPACE` setting. + // In this case, we don't want to download the files as well for these specific tasks + // because it leads to confusion with relative paths between workspace and GIT files. + // Instead we keep these tasks as is and let the user handle the files manually. + // The configuration will be deployable as tasks paths for source: WORKSPACE tasks will be absolute workspace paths. + if job.Settings.GitSource != nil { + cmdio.LogString(ctx, "Job is using Git source, skipping downloading files") + } else { + for _, task := range job.Settings.Tasks { + err := downloader.MarkTaskForDownload(ctx, &task) + if err != nil { + return err + } } } diff --git a/cmd/bundle/generate/pipeline.go b/cmd/bundle/generate/pipeline.go index 1d2c345d6..9bf9e9947 100644 --- a/cmd/bundle/generate/pipeline.go +++ b/cmd/bundle/generate/pipeline.go @@ -92,7 +92,7 @@ func NewGeneratePipelineCommand() *cobra.Command { } saver := yamlsaver.NewSaverWithStyle( - // Including all PipelineSpec and nested fields which are map[string]string type + // Including all CreatePipeline and nested fields which are map[string]string type map[string]yaml.Style{ "spark_conf": yaml.DoubleQuotedStyle, "custom_tags": yaml.DoubleQuotedStyle, diff --git a/cmd/bundle/run.go b/cmd/bundle/run.go index df35d7222..ffb9c1b88 100644 --- a/cmd/bundle/run.go +++ b/cmd/bundle/run.go @@ -173,6 +173,7 @@ task or a Python wheel task, the second example applies. if err != nil { return err } + _, _ = cmd.OutOrStdout().Write([]byte{'\n'}) default: return fmt.Errorf("unknown output type %s", root.OutputType(cmd)) } diff --git a/cmd/bundle/summary.go b/cmd/bundle/summary.go index 7c669c845..2871c82ff 100644 --- a/cmd/bundle/summary.go +++ b/cmd/bundle/summary.go @@ -74,6 +74,7 @@ func newSummaryCommand() *cobra.Command { return err } _, _ = cmd.OutOrStdout().Write(buf) + _, _ = cmd.OutOrStdout().Write([]byte{'\n'}) default: return fmt.Errorf("unknown output type %s", root.OutputType(cmd)) } diff --git a/cmd/bundle/validate.go b/cmd/bundle/validate.go index 41fa87f30..c45453af6 100644 --- a/cmd/bundle/validate.go +++ b/cmd/bundle/validate.go @@ -20,7 +20,9 @@ func renderJsonOutput(cmd *cobra.Command, b *bundle.Bundle) error { if err != nil { return err } - _, _ = cmd.OutOrStdout().Write(buf) + out := cmd.OutOrStdout() + _, _ = out.Write(buf) + _, _ = out.Write([]byte{'\n'}) return nil } diff --git a/cmd/labs/CODEOWNERS b/cmd/labs/CODEOWNERS deleted file mode 100644 index cc93a75e6..000000000 --- a/cmd/labs/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @nfx diff --git a/cmd/labs/project/installer.go b/cmd/labs/project/installer.go index 05f7d68aa..2e42ce43d 100644 --- a/cmd/labs/project/installer.go +++ b/cmd/labs/project/installer.go @@ -32,6 +32,7 @@ type hook struct { RequireDatabricksConnect bool `yaml:"require_databricks_connect,omitempty"` MinRuntimeVersion string `yaml:"min_runtime_version,omitempty"` WarehouseTypes whTypes `yaml:"warehouse_types,omitempty"` + Extras string `yaml:"extras,omitempty"` } func (h *hook) RequireRunningCluster() bool { @@ -258,6 +259,10 @@ func (i *installer) setupPythonVirtualEnvironment(ctx context.Context, w *databr } } feedback <- "Installing Python library dependencies" + if i.Installer.Extras != "" { + // install main and optional dependencies + return i.installPythonDependencies(ctx, fmt.Sprintf(".[%s]", i.Installer.Extras)) + } return i.installPythonDependencies(ctx, ".") } diff --git a/cmd/labs/project/schema.json b/cmd/labs/project/schema.json index a779b15e4..7aa65813c 100644 --- a/cmd/labs/project/schema.json +++ b/cmd/labs/project/schema.json @@ -42,6 +42,11 @@ }, "warehouse_types": { "enum": [ "PRO", "CLASSIC", "TYPE_UNSPECIFIED" ] + }, + "extras": { + "type": "string", + "pattern": "^([^,]+)(,([^,]+))*$", + "default": "" } } }, diff --git a/cmd/labs/project/testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml b/cmd/labs/project/testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml index 0ac4bf826..b8a0e695e 100644 --- a/cmd/labs/project/testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml +++ b/cmd/labs/project/testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml @@ -8,6 +8,7 @@ install: warehouse_types: - PRO script: install.py + extras: "" entrypoint: main.py min_python: 3.9 commands: diff --git a/cmd/root/root.go b/cmd/root/root.go index 3b37d0176..d7adf47f4 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -114,10 +114,15 @@ func Execute(ctx context.Context, cmd *cobra.Command) error { if err == nil { logger.Info("completed execution", slog.String("exit_code", "0")) - } else { - logger.Error("failed execution", + } else if errors.Is(err, ErrAlreadyPrinted) { + logger.Debug("failed execution", slog.String("exit_code", "1"), - slog.String("error", err.Error())) + ) + } else { + logger.Info("failed execution", + slog.String("exit_code", "1"), + slog.String("error", err.Error()), + ) } } diff --git a/cmd/workspace/alerts/alerts.go b/cmd/workspace/alerts/alerts.go index fcf18652b..79467c405 100755 --- a/cmd/workspace/alerts/alerts.go +++ b/cmd/workspace/alerts/alerts.go @@ -335,10 +335,17 @@ func newUpdate() *cobra.Command { Arguments: ID: - UPDATE_MASK: Field mask is required to be passed into the PATCH request. Field mask - specifies which fields of the setting payload will be updated. The field - mask needs to be supplied as single string. To specify multiple fields in - the field mask, use comma as the separator (no space).` + UPDATE_MASK: The field mask must be a single string, with multiple fields separated by + commas (no spaces). The field path is relative to the resource object, + using a dot (.) to navigate sub-fields (e.g., author.given_name). + Specification of elements in sequence or map fields is not allowed, as + only the entire collection field can be specified. Field names must + exactly match the resource field names. + + A field mask of * indicates full replacement. It’s recommended to + always explicitly list the fields being updated and avoid using * + wildcards, as it can lead to unintended results if the API changes in the + future.` cmd.Annotations = make(map[string]string) diff --git a/cmd/workspace/catalogs/catalogs.go b/cmd/workspace/catalogs/catalogs.go index 9294c192b..ce37b6d54 100755 --- a/cmd/workspace/catalogs/catalogs.go +++ b/cmd/workspace/catalogs/catalogs.go @@ -342,6 +342,7 @@ func newUpdate() *cobra.Command { cmd.Flags().Var(&updateReq.EnablePredictiveOptimization, "enable-predictive-optimization", `Whether predictive optimization should be enabled for this object and objects under it. Supported values: [DISABLE, ENABLE, INHERIT]`) cmd.Flags().Var(&updateReq.IsolationMode, "isolation-mode", `Whether the current securable is accessible from all workspaces or a specific set of workspaces. Supported values: [ISOLATED, OPEN]`) cmd.Flags().StringVar(&updateReq.NewName, "new-name", updateReq.NewName, `New name for the catalog.`) + // TODO: map via StringToStringVar: options cmd.Flags().StringVar(&updateReq.Owner, "owner", updateReq.Owner, `Username of current owner of catalog.`) // TODO: map via StringToStringVar: properties diff --git a/cmd/workspace/clean-rooms/clean-rooms.go b/cmd/workspace/clean-rooms/clean-rooms.go index 053e41e8a..4fe61d56b 100755 --- a/cmd/workspace/clean-rooms/clean-rooms.go +++ b/cmd/workspace/clean-rooms/clean-rooms.go @@ -75,8 +75,9 @@ func newCreate() *cobra.Command { Create a new clean room with the specified collaborators. This method is asynchronous; the returned name field inside the clean_room field can be used to poll the clean room status, using the :method:cleanrooms/get method. When - this method returns, the cluster will be in a PROVISIONING state. The cluster - will be usable once it enters an ACTIVE state. + this method returns, the clean room will be in a PROVISIONING state, with only + name, owner, comment, created_at and status populated. The clean room will be + usable once it enters an ACTIVE state. The caller must be a metastore admin or have the **CREATE_CLEAN_ROOM** privilege on the metastore.` diff --git a/cmd/workspace/cmd.go b/cmd/workspace/cmd.go index c447bd736..2bd3c59a5 100755 --- a/cmd/workspace/cmd.go +++ b/cmd/workspace/cmd.go @@ -39,6 +39,7 @@ import ( ip_access_lists "github.com/databricks/cli/cmd/workspace/ip-access-lists" jobs "github.com/databricks/cli/cmd/workspace/jobs" lakeview "github.com/databricks/cli/cmd/workspace/lakeview" + lakeview_embedded "github.com/databricks/cli/cmd/workspace/lakeview-embedded" libraries "github.com/databricks/cli/cmd/workspace/libraries" metastores "github.com/databricks/cli/cmd/workspace/metastores" model_registry "github.com/databricks/cli/cmd/workspace/model-registry" @@ -62,11 +63,13 @@ import ( quality_monitors "github.com/databricks/cli/cmd/workspace/quality-monitors" queries "github.com/databricks/cli/cmd/workspace/queries" queries_legacy "github.com/databricks/cli/cmd/workspace/queries-legacy" + query_execution "github.com/databricks/cli/cmd/workspace/query-execution" query_history "github.com/databricks/cli/cmd/workspace/query-history" query_visualizations "github.com/databricks/cli/cmd/workspace/query-visualizations" query_visualizations_legacy "github.com/databricks/cli/cmd/workspace/query-visualizations-legacy" recipient_activation "github.com/databricks/cli/cmd/workspace/recipient-activation" recipients "github.com/databricks/cli/cmd/workspace/recipients" + redash_config "github.com/databricks/cli/cmd/workspace/redash-config" registered_models "github.com/databricks/cli/cmd/workspace/registered-models" repos "github.com/databricks/cli/cmd/workspace/repos" resource_quotas "github.com/databricks/cli/cmd/workspace/resource-quotas" @@ -133,6 +136,7 @@ func All() []*cobra.Command { out = append(out, ip_access_lists.New()) out = append(out, jobs.New()) out = append(out, lakeview.New()) + out = append(out, lakeview_embedded.New()) out = append(out, libraries.New()) out = append(out, metastores.New()) out = append(out, model_registry.New()) @@ -156,11 +160,13 @@ func All() []*cobra.Command { out = append(out, quality_monitors.New()) out = append(out, queries.New()) out = append(out, queries_legacy.New()) + out = append(out, query_execution.New()) out = append(out, query_history.New()) out = append(out, query_visualizations.New()) out = append(out, query_visualizations_legacy.New()) out = append(out, recipient_activation.New()) out = append(out, recipients.New()) + out = append(out, redash_config.New()) out = append(out, registered_models.New()) out = append(out, repos.New()) out = append(out, resource_quotas.New()) diff --git a/cmd/workspace/jobs/jobs.go b/cmd/workspace/jobs/jobs.go index 38a88f014..0f911d400 100755 --- a/cmd/workspace/jobs/jobs.go +++ b/cmd/workspace/jobs/jobs.go @@ -1354,6 +1354,7 @@ func newRunNow() *cobra.Command { // TODO: map via StringToStringVar: job_parameters // TODO: map via StringToStringVar: notebook_params // TODO: array: only + cmd.Flags().Var(&runNowReq.PerformanceTarget, "performance-target", `PerformanceTarget defines how performant or cost efficient the execution of run on serverless compute should be. Supported values: [COST_OPTIMIZED, PERFORMANCE_OPTIMIZED]`) // TODO: complex arg: pipeline_params // TODO: map via StringToStringVar: python_named_params // TODO: array: python_params diff --git a/cmd/workspace/lakeview-embedded/lakeview-embedded.go b/cmd/workspace/lakeview-embedded/lakeview-embedded.go new file mode 100755 index 000000000..ef04c2c13 --- /dev/null +++ b/cmd/workspace/lakeview-embedded/lakeview-embedded.go @@ -0,0 +1,98 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package lakeview_embedded + +import ( + "github.com/databricks/cli/cmd/root" + "github.com/databricks/databricks-sdk-go/service/dashboards" + "github.com/spf13/cobra" +) + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var cmdOverrides []func(*cobra.Command) + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: "lakeview-embedded", + Short: `Token-based Lakeview APIs for embedding dashboards in external applications.`, + Long: `Token-based Lakeview APIs for embedding dashboards in external applications.`, + GroupID: "dashboards", + Annotations: map[string]string{ + "package": "dashboards", + }, + } + + // Add methods + cmd.AddCommand(newGetPublishedDashboardEmbedded()) + + // Apply optional overrides to this command. + for _, fn := range cmdOverrides { + fn(cmd) + } + + return cmd +} + +// start get-published-dashboard-embedded command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var getPublishedDashboardEmbeddedOverrides []func( + *cobra.Command, + *dashboards.GetPublishedDashboardEmbeddedRequest, +) + +func newGetPublishedDashboardEmbedded() *cobra.Command { + cmd := &cobra.Command{} + + var getPublishedDashboardEmbeddedReq dashboards.GetPublishedDashboardEmbeddedRequest + + // TODO: short flags + + cmd.Use = "get-published-dashboard-embedded DASHBOARD_ID" + cmd.Short = `Read a published dashboard in an embedded ui.` + cmd.Long = `Read a published dashboard in an embedded ui. + + Get the current published dashboard within an embedded context. + + Arguments: + DASHBOARD_ID: UUID identifying the published dashboard.` + + // This command is being previewed; hide from help output. + cmd.Hidden = true + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(1) + return check(cmd, args) + } + + cmd.PreRunE = root.MustWorkspaceClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + w := root.WorkspaceClient(ctx) + + getPublishedDashboardEmbeddedReq.DashboardId = args[0] + + err = w.LakeviewEmbedded.GetPublishedDashboardEmbedded(ctx, getPublishedDashboardEmbeddedReq) + if err != nil { + return err + } + return nil + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range getPublishedDashboardEmbeddedOverrides { + fn(cmd, &getPublishedDashboardEmbeddedReq) + } + + return cmd +} + +// end service LakeviewEmbedded diff --git a/cmd/workspace/queries/queries.go b/cmd/workspace/queries/queries.go index 208f887da..bf74bb3f5 100755 --- a/cmd/workspace/queries/queries.go +++ b/cmd/workspace/queries/queries.go @@ -406,10 +406,17 @@ func newUpdate() *cobra.Command { Arguments: ID: - UPDATE_MASK: Field mask is required to be passed into the PATCH request. Field mask - specifies which fields of the setting payload will be updated. The field - mask needs to be supplied as single string. To specify multiple fields in - the field mask, use comma as the separator (no space).` + UPDATE_MASK: The field mask must be a single string, with multiple fields separated by + commas (no spaces). The field path is relative to the resource object, + using a dot (.) to navigate sub-fields (e.g., author.given_name). + Specification of elements in sequence or map fields is not allowed, as + only the entire collection field can be specified. Field names must + exactly match the resource field names. + + A field mask of * indicates full replacement. It’s recommended to + always explicitly list the fields being updated and avoid using * + wildcards, as it can lead to unintended results if the API changes in the + future.` cmd.Annotations = make(map[string]string) diff --git a/cmd/workspace/query-execution/query-execution.go b/cmd/workspace/query-execution/query-execution.go new file mode 100755 index 000000000..ebbb90f89 --- /dev/null +++ b/cmd/workspace/query-execution/query-execution.go @@ -0,0 +1,245 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package query_execution + +import ( + "fmt" + + "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdio" + "github.com/databricks/cli/libs/flags" + "github.com/databricks/databricks-sdk-go/service/dashboards" + "github.com/spf13/cobra" +) + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var cmdOverrides []func(*cobra.Command) + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: "query-execution", + Short: `Query execution APIs for AI / BI Dashboards.`, + Long: `Query execution APIs for AI / BI Dashboards`, + GroupID: "dashboards", + Annotations: map[string]string{ + "package": "dashboards", + }, + + // This service is being previewed; hide from help output. + Hidden: true, + } + + // Add methods + cmd.AddCommand(newCancelPublishedQueryExecution()) + cmd.AddCommand(newExecutePublishedDashboardQuery()) + cmd.AddCommand(newPollPublishedQueryStatus()) + + // Apply optional overrides to this command. + for _, fn := range cmdOverrides { + fn(cmd) + } + + return cmd +} + +// start cancel-published-query-execution command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var cancelPublishedQueryExecutionOverrides []func( + *cobra.Command, + *dashboards.CancelPublishedQueryExecutionRequest, +) + +func newCancelPublishedQueryExecution() *cobra.Command { + cmd := &cobra.Command{} + + var cancelPublishedQueryExecutionReq dashboards.CancelPublishedQueryExecutionRequest + + // TODO: short flags + + // TODO: array: tokens + + cmd.Use = "cancel-published-query-execution DASHBOARD_NAME DASHBOARD_REVISION_ID" + cmd.Short = `Cancel the results for the a query for a published, embedded dashboard.` + cmd.Long = `Cancel the results for the a query for a published, embedded dashboard.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(2) + return check(cmd, args) + } + + cmd.PreRunE = root.MustWorkspaceClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + w := root.WorkspaceClient(ctx) + + cancelPublishedQueryExecutionReq.DashboardName = args[0] + cancelPublishedQueryExecutionReq.DashboardRevisionId = args[1] + + response, err := w.QueryExecution.CancelPublishedQueryExecution(ctx, cancelPublishedQueryExecutionReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range cancelPublishedQueryExecutionOverrides { + fn(cmd, &cancelPublishedQueryExecutionReq) + } + + return cmd +} + +// start execute-published-dashboard-query command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var executePublishedDashboardQueryOverrides []func( + *cobra.Command, + *dashboards.ExecutePublishedDashboardQueryRequest, +) + +func newExecutePublishedDashboardQuery() *cobra.Command { + cmd := &cobra.Command{} + + var executePublishedDashboardQueryReq dashboards.ExecutePublishedDashboardQueryRequest + var executePublishedDashboardQueryJson flags.JsonFlag + + // TODO: short flags + cmd.Flags().Var(&executePublishedDashboardQueryJson, "json", `either inline JSON string or @path/to/file.json with request body`) + + cmd.Flags().StringVar(&executePublishedDashboardQueryReq.OverrideWarehouseId, "override-warehouse-id", executePublishedDashboardQueryReq.OverrideWarehouseId, `A dashboard schedule can override the warehouse used as compute for processing the published dashboard queries.`) + + cmd.Use = "execute-published-dashboard-query DASHBOARD_NAME DASHBOARD_REVISION_ID" + cmd.Short = `Execute a query for a published dashboard.` + cmd.Long = `Execute a query for a published dashboard. + + Arguments: + DASHBOARD_NAME: Dashboard name and revision_id is required to retrieve + PublishedDatasetDataModel which contains the list of datasets, + warehouse_id, and embedded_credentials + DASHBOARD_REVISION_ID: ` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("json") { + err := root.ExactArgs(0)(cmd, args) + if err != nil { + return fmt.Errorf("when --json flag is specified, no positional arguments are required. Provide 'dashboard_name', 'dashboard_revision_id' in your JSON input") + } + return nil + } + check := root.ExactArgs(2) + return check(cmd, args) + } + + cmd.PreRunE = root.MustWorkspaceClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + w := root.WorkspaceClient(ctx) + + if cmd.Flags().Changed("json") { + diags := executePublishedDashboardQueryJson.Unmarshal(&executePublishedDashboardQueryReq) + if diags.HasError() { + return diags.Error() + } + if len(diags) > 0 { + err := cmdio.RenderDiagnosticsToErrorOut(ctx, diags) + if err != nil { + return err + } + } + } + if !cmd.Flags().Changed("json") { + executePublishedDashboardQueryReq.DashboardName = args[0] + } + if !cmd.Flags().Changed("json") { + executePublishedDashboardQueryReq.DashboardRevisionId = args[1] + } + + err = w.QueryExecution.ExecutePublishedDashboardQuery(ctx, executePublishedDashboardQueryReq) + if err != nil { + return err + } + return nil + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range executePublishedDashboardQueryOverrides { + fn(cmd, &executePublishedDashboardQueryReq) + } + + return cmd +} + +// start poll-published-query-status command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var pollPublishedQueryStatusOverrides []func( + *cobra.Command, + *dashboards.PollPublishedQueryStatusRequest, +) + +func newPollPublishedQueryStatus() *cobra.Command { + cmd := &cobra.Command{} + + var pollPublishedQueryStatusReq dashboards.PollPublishedQueryStatusRequest + + // TODO: short flags + + // TODO: array: tokens + + cmd.Use = "poll-published-query-status DASHBOARD_NAME DASHBOARD_REVISION_ID" + cmd.Short = `Poll the results for the a query for a published, embedded dashboard.` + cmd.Long = `Poll the results for the a query for a published, embedded dashboard.` + + cmd.Annotations = make(map[string]string) + + cmd.Args = func(cmd *cobra.Command, args []string) error { + check := root.ExactArgs(2) + return check(cmd, args) + } + + cmd.PreRunE = root.MustWorkspaceClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + w := root.WorkspaceClient(ctx) + + pollPublishedQueryStatusReq.DashboardName = args[0] + pollPublishedQueryStatusReq.DashboardRevisionId = args[1] + + response, err := w.QueryExecution.PollPublishedQueryStatus(ctx, pollPublishedQueryStatusReq) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range pollPublishedQueryStatusOverrides { + fn(cmd, &pollPublishedQueryStatusReq) + } + + return cmd +} + +// end service QueryExecution diff --git a/cmd/workspace/query-visualizations/query-visualizations.go b/cmd/workspace/query-visualizations/query-visualizations.go index 621661952..2d50229ba 100755 --- a/cmd/workspace/query-visualizations/query-visualizations.go +++ b/cmd/workspace/query-visualizations/query-visualizations.go @@ -198,10 +198,17 @@ func newUpdate() *cobra.Command { Arguments: ID: - UPDATE_MASK: Field mask is required to be passed into the PATCH request. Field mask - specifies which fields of the setting payload will be updated. The field - mask needs to be supplied as single string. To specify multiple fields in - the field mask, use comma as the separator (no space).` + UPDATE_MASK: The field mask must be a single string, with multiple fields separated by + commas (no spaces). The field path is relative to the resource object, + using a dot (.) to navigate sub-fields (e.g., author.given_name). + Specification of elements in sequence or map fields is not allowed, as + only the entire collection field can be specified. Field names must + exactly match the resource field names. + + A field mask of * indicates full replacement. It’s recommended to + always explicitly list the fields being updated and avoid using * + wildcards, as it can lead to unintended results if the API changes in the + future.` cmd.Annotations = make(map[string]string) diff --git a/cmd/workspace/redash-config/redash-config.go b/cmd/workspace/redash-config/redash-config.go new file mode 100755 index 000000000..1a0f37759 --- /dev/null +++ b/cmd/workspace/redash-config/redash-config.go @@ -0,0 +1,80 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package redash_config + +import ( + "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdio" + "github.com/spf13/cobra" +) + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var cmdOverrides []func(*cobra.Command) + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: "redash-config", + Short: `Redash V2 service for workspace configurations (internal).`, + Long: `Redash V2 service for workspace configurations (internal)`, + GroupID: "sql", + Annotations: map[string]string{ + "package": "sql", + }, + + // This service is being previewed; hide from help output. + Hidden: true, + } + + // Add methods + cmd.AddCommand(newGetConfig()) + + // Apply optional overrides to this command. + for _, fn := range cmdOverrides { + fn(cmd) + } + + return cmd +} + +// start get-config command + +// Slice with functions to override default command behavior. +// Functions can be added from the `init()` function in manually curated files in this directory. +var getConfigOverrides []func( + *cobra.Command, +) + +func newGetConfig() *cobra.Command { + cmd := &cobra.Command{} + + cmd.Use = "get-config" + cmd.Short = `Read workspace configuration for Redash-v2.` + cmd.Long = `Read workspace configuration for Redash-v2.` + + cmd.Annotations = make(map[string]string) + + cmd.PreRunE = root.MustWorkspaceClient + cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { + ctx := cmd.Context() + w := root.WorkspaceClient(ctx) + response, err := w.RedashConfig.GetConfig(ctx) + if err != nil { + return err + } + return cmdio.Render(ctx, response) + } + + // Disable completions since they are not applicable. + // Can be overridden by manual implementation in `override.go`. + cmd.ValidArgsFunction = cobra.NoFileCompletions + + // Apply optional overrides to this command. + for _, fn := range getConfigOverrides { + fn(cmd) + } + + return cmd +} + +// end service RedashConfig diff --git a/cmd/workspace/serving-endpoints/serving-endpoints.go b/cmd/workspace/serving-endpoints/serving-endpoints.go index 034133623..645111646 100755 --- a/cmd/workspace/serving-endpoints/serving-endpoints.go +++ b/cmd/workspace/serving-endpoints/serving-endpoints.go @@ -642,7 +642,8 @@ func newHttpRequest() *cobra.Command { if err != nil { return err } - return cmdio.Render(ctx, response) + defer response.Contents.Close() + return cmdio.Render(ctx, response.Contents) } // Disable completions since they are not applicable. diff --git a/go.mod b/go.mod index bd8997190..b4157c61b 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,18 @@ go 1.23 toolchain go1.23.4 require ( + dario.cat/mergo v1.0.1 // BSD 3-Clause github.com/BurntSushi/toml v1.4.0 // MIT github.com/Masterminds/semver/v3 v3.3.1 // MIT github.com/briandowns/spinner v1.23.1 // Apache 2.0 - github.com/databricks/databricks-sdk-go v0.56.1 // Apache 2.0 + github.com/databricks/databricks-sdk-go v0.57.0 // Apache 2.0 github.com/fatih/color v1.18.0 // MIT github.com/google/uuid v1.6.0 // BSD-3-Clause + github.com/gorilla/mux v1.8.1 // BSD 3-Clause github.com/hashicorp/go-version v1.7.0 // MPL 2.0 github.com/hashicorp/hc-install v0.9.1 // MPL 2.0 - github.com/hashicorp/terraform-exec v0.21.0 // MPL 2.0 - github.com/hashicorp/terraform-json v0.23.0 // MPL 2.0 + github.com/hashicorp/terraform-exec v0.22.0 // MPL 2.0 + github.com/hashicorp/terraform-json v0.24.0 // MPL 2.0 github.com/hexops/gotextdiff v1.0.3 // BSD 3-Clause "New" or "Revised" License github.com/manifoldco/promptui v0.9.0 // BSD-3-Clause github.com/mattn/go-isatty v0.0.20 // MIT @@ -22,19 +24,21 @@ require ( github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // BSD-2-Clause github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // MIT github.com/spf13/cobra v1.8.1 // Apache 2.0 - github.com/spf13/pflag v1.0.5 // BSD-3-Clause + github.com/spf13/pflag v1.0.6 // BSD-3-Clause github.com/stretchr/testify v1.10.0 // MIT github.com/wI2L/jsondiff v0.6.1 // MIT golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 - golang.org/x/mod v0.22.0 - golang.org/x/oauth2 v0.25.0 - golang.org/x/sync v0.10.0 - golang.org/x/term v0.28.0 - golang.org/x/text v0.21.0 + golang.org/x/mod v0.23.0 + golang.org/x/oauth2 v0.26.0 + golang.org/x/sync v0.11.0 + golang.org/x/term v0.29.0 + golang.org/x/text v0.22.0 gopkg.in/ini.v1 v1.67.0 // Apache 2.0 gopkg.in/yaml.v3 v3.0.1 ) +require golang.org/x/sys v0.30.0 + require ( cloud.google.com/go/auth v0.4.2 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect @@ -62,7 +66,7 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/zclconf/go-cty v1.15.0 // indirect + github.com/zclconf/go-cty v1.16.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect @@ -70,7 +74,6 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.33.0 // indirect - golang.org/x/sys v0.29.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.182.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e // indirect diff --git a/go.sum b/go.sum index dec1d40b2..fbf942148 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,8 @@ cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKF cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= @@ -34,8 +34,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/databricks/databricks-sdk-go v0.56.1 h1:sgweTRvAQaI8EPrfDnVdAB0lNX6L5uTT720SlMMQI2U= -github.com/databricks/databricks-sdk-go v0.56.1/go.mod h1:JpLizplEs+up9/Z4Xf2x++o3sM9eTTWFGzIXAptKJzI= +github.com/databricks/databricks-sdk-go v0.57.0 h1:Vs3a+Zmg403er4+xpD7ZTQWm7e51d2q3yYEyIIgvtYw= +github.com/databricks/databricks-sdk-go v0.57.0/go.mod h1:JpLizplEs+up9/Z4Xf2x++o3sM9eTTWFGzIXAptKJzI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -97,6 +97,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= @@ -107,10 +109,10 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hc-install v0.9.1 h1:gkqTfE3vVbafGQo6VZXcy2v5yoz2bE0+nhZXruCuODQ= github.com/hashicorp/hc-install v0.9.1/go.mod h1:pWWvN/IrfeBK4XPeXXYkL6EjMufHkCK5DvwxeLKuBf0= -github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ= -github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg= -github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI= -github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c= +github.com/hashicorp/terraform-exec v0.22.0 h1:G5+4Sz6jYZfRYUCg6eQgDsqTzkNXV+fP8l+uRmZHj64= +github.com/hashicorp/terraform-exec v0.22.0/go.mod h1:bjVbsncaeh8jVdhttWYZuBGj21FcYw6Ia/XfHcNO7lQ= +github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q= +github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -147,8 +149,9 @@ github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0 github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -174,8 +177,8 @@ github.com/wI2L/jsondiff v0.6.1 h1:ISZb9oNWbP64LHnu4AUhsMF5W0FIj5Ok3Krip9Shqpw= github.com/wI2L/jsondiff v0.6.1/go.mod h1:KAEIojdQq66oJiHhDyQez2x+sRit0vIzC9KeK0yizxM= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= -github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.16.1 h1:a5TZEPzBFFR53udlIKApXzj8JIF4ZNQ6abH79z5R1S0= +github.com/zclconf/go-cty v1.16.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= @@ -198,8 +201,8 @@ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -209,13 +212,13 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= +golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -226,14 +229,14 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/integration/bundle/apps_test.go b/integration/bundle/apps_test.go index 01ab52e90..12bd2fcbf 100644 --- a/integration/bundle/apps_test.go +++ b/integration/bundle/apps_test.go @@ -98,6 +98,24 @@ func TestDeployBundleWithApp(t *testing.T) { - run env: - name: JOB_ID + value: "%d"`, job.JobId)) + + // Redeploy bundle with changed config env for app and confirm it's updated in app.yaml + deployBundleWithArgs(t, ctx, root, `--var="env_var_name=ANOTHER_JOB_ID"`, "--force-lock", "--auto-approve") + reader, err = wt.W.Workspace.Download(ctx, pathToAppYml) + require.NoError(t, err) + + data, err = io.ReadAll(reader) + require.NoError(t, err) + + content = string(data) + require.Contains(t, content, fmt.Sprintf(`command: + - flask + - --app + - app + - run +env: + - name: ANOTHER_JOB_ID value: "%d"`, job.JobId)) if testing.Short() { diff --git a/integration/bundle/basic_test.go b/integration/bundle/basic_test.go index 79301b850..53f8e3ef6 100644 --- a/integration/bundle/basic_test.go +++ b/integration/bundle/basic_test.go @@ -6,7 +6,9 @@ import ( "testing" "github.com/databricks/cli/integration/internal/acc" + "github.com/databricks/cli/internal/testcli" "github.com/databricks/cli/internal/testutil" + "github.com/databricks/cli/libs/testdiff" "github.com/google/uuid" "github.com/stretchr/testify/require" ) @@ -35,3 +37,40 @@ func TestBasicBundleDeployWithFailOnActiveRuns(t *testing.T) { // deploy empty bundle again deployBundleWithFlags(t, ctx, root, []string{"--fail-on-active-runs"}) } + +func TestBasicBundleDeployWithDoubleUnderscoreVariables(t *testing.T) { + ctx, wt := acc.WorkspaceTest(t) + + nodeTypeId := testutil.GetCloud(t).NodeTypeID() + uniqueId := uuid.New().String() + root := initTestTemplate(t, ctx, "basic_with_variables", map[string]any{ + "unique_id": uniqueId, + "node_type_id": nodeTypeId, + "spark_version": defaultSparkVersion, + }) + + currentUser, err := wt.W.CurrentUser.Me(ctx) + require.NoError(t, err) + + ctx, replacements := testdiff.WithReplacementsMap(ctx) + replacements.Set(uniqueId, "$UNIQUE_PRJ") + replacements.Set(currentUser.UserName, "$USERNAME") + + t.Cleanup(func() { + destroyBundle(t, ctx, root) + }) + + testutil.Chdir(t, root) + testcli.AssertOutput( + t, + ctx, + []string{"bundle", "validate"}, + testutil.TestData("testdata/basic_with_variables/bundle_validate.txt"), + ) + testcli.AssertOutput( + t, + ctx, + []string{"bundle", "deploy", "--force-lock", "--auto-approve"}, + testutil.TestData("testdata/basic_with_variables/bundle_deploy.txt"), + ) +} diff --git a/integration/bundle/bundles/apps/template/databricks.yml.tmpl b/integration/bundle/bundles/apps/template/databricks.yml.tmpl index 4d862a06f..e0937be71 100644 --- a/integration/bundle/bundles/apps/template/databricks.yml.tmpl +++ b/integration/bundle/bundles/apps/template/databricks.yml.tmpl @@ -4,6 +4,10 @@ bundle: workspace: root_path: "~/.bundle/{{.unique_id}}" +variables: + env_var_name: + default: "JOB_ID" + resources: apps: test_app: @@ -17,7 +21,7 @@ resources: - app - run env: - - name: JOB_ID + - name: ${var.env_var_name} value: ${resources.jobs.foo.id} resources: diff --git a/integration/bundle/bundles/basic_with_variables/databricks_template_schema.json b/integration/bundle/bundles/basic_with_variables/databricks_template_schema.json new file mode 100644 index 000000000..41a723b0f --- /dev/null +++ b/integration/bundle/bundles/basic_with_variables/databricks_template_schema.json @@ -0,0 +1,21 @@ +{ + "properties": { + "unique_id": { + "type": "string", + "description": "Unique ID for job name" + }, + "spark_version": { + "type": "string", + "description": "Spark version used for job cluster" + }, + "node_type_id": { + "type": "string", + "description": "Node type id for job cluster" + }, + "root_path": { + "type": "string", + "description": "Root path to deploy bundle to", + "default": "" + } + } +} diff --git a/integration/bundle/bundles/basic_with_variables/template/databricks.yml.tmpl b/integration/bundle/bundles/basic_with_variables/template/databricks.yml.tmpl new file mode 100644 index 000000000..cb02c9e2f --- /dev/null +++ b/integration/bundle/bundles/basic_with_variables/template/databricks.yml.tmpl @@ -0,0 +1,32 @@ +bundle: + name: basic + +workspace: + {{ if .root_path }} + root_path: "{{.root_path}}/.bundle/{{.unique_id}}" + {{ else }} + root_path: "~/.bundle/{{.unique_id}}" + {{ end }} + +variables: + task__key: # Note: the variable has double underscore + default: my_notebook_task + +resources: + jobs: + foo__bar: # Note: the resource has double underscore to check that TF provider can use such names + name: test-job-basic-{{.unique_id}} + tasks: + - task_key: ${var.task__key} + new_cluster: + num_workers: 1 + spark_version: "{{.spark_version}}" + node_type_id: "{{.node_type_id}}" + spark_python_task: + python_file: ./hello_world.py + foo: + name: test-job-basic-ref-{{.unique_id}} + tasks: + - task_key: job_task + run_job_task: + job_id: ${resources.jobs.foo__bar.id} diff --git a/integration/bundle/bundles/basic_with_variables/template/hello_world.py b/integration/bundle/bundles/basic_with_variables/template/hello_world.py new file mode 100644 index 000000000..f301245e2 --- /dev/null +++ b/integration/bundle/bundles/basic_with_variables/template/hello_world.py @@ -0,0 +1 @@ +print("Hello World!") diff --git a/integration/bundle/testdata/apps/bundle_deploy.txt b/integration/bundle/testdata/apps/bundle_deploy.txt index 211164174..437a55596 100644 --- a/integration/bundle/testdata/apps/bundle_deploy.txt +++ b/integration/bundle/testdata/apps/bundle_deploy.txt @@ -1,4 +1,4 @@ -Uploading bundle files to /Workspace/Users/$USERNAME/.bundle/$UNIQUE_PRJ/files... +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/$UNIQUE_PRJ/files... Deploying resources... Updating deployment state... Deployment complete! diff --git a/integration/bundle/testdata/apps/bundle_validate.txt b/integration/bundle/testdata/apps/bundle_validate.txt index dc9016a0f..567fafd24 100644 --- a/integration/bundle/testdata/apps/bundle_validate.txt +++ b/integration/bundle/testdata/apps/bundle_validate.txt @@ -1,7 +1,7 @@ Name: basic Target: default Workspace: - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/$UNIQUE_PRJ + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/$UNIQUE_PRJ Validation OK! diff --git a/integration/bundle/testdata/basic_with_variables/bundle_deploy.txt b/integration/bundle/testdata/basic_with_variables/bundle_deploy.txt new file mode 100644 index 000000000..211164174 --- /dev/null +++ b/integration/bundle/testdata/basic_with_variables/bundle_deploy.txt @@ -0,0 +1,4 @@ +Uploading bundle files to /Workspace/Users/$USERNAME/.bundle/$UNIQUE_PRJ/files... +Deploying resources... +Updating deployment state... +Deployment complete! diff --git a/integration/bundle/testdata/basic_with_variables/bundle_validate.txt b/integration/bundle/testdata/basic_with_variables/bundle_validate.txt new file mode 100644 index 000000000..dc9016a0f --- /dev/null +++ b/integration/bundle/testdata/basic_with_variables/bundle_validate.txt @@ -0,0 +1,7 @@ +Name: basic +Target: default +Workspace: + User: $USERNAME + Path: /Workspace/Users/$USERNAME/.bundle/$UNIQUE_PRJ + +Validation OK! diff --git a/integration/bundle/testdata/default_python/bundle_deploy.txt b/integration/bundle/testdata/default_python/bundle_deploy.txt index d7b8cede9..076e7618f 100644 --- a/integration/bundle/testdata/default_python/bundle_deploy.txt +++ b/integration/bundle/testdata/default_python/bundle_deploy.txt @@ -1,6 +1,6 @@ Building project_name_$UNIQUE_PRJ... Uploading project_name_$UNIQUE_PRJ-0.0.1+[NUMID].[NUMID]-py3-none-any.whl... -Uploading bundle files to /Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/files... +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/files... Deploying resources... Updating deployment state... Deployment complete! diff --git a/integration/bundle/testdata/default_python/bundle_init.txt b/integration/bundle/testdata/default_python/bundle_init.txt index c2917ea4e..6ea0801ad 100644 --- a/integration/bundle/testdata/default_python/bundle_init.txt +++ b/integration/bundle/testdata/default_python/bundle_init.txt @@ -1,6 +1,6 @@ Welcome to the default Python template for Databricks Asset Bundles! -Workspace to use (auto-detected, edit in 'project_name_$UNIQUE_PRJ/databricks.yml'): $DATABRICKS_URL +Workspace to use (auto-detected, edit in 'project_name_$UNIQUE_PRJ/databricks.yml'): [DATABRICKS_URL] ✨ Your new project has been created in the 'project_name_$UNIQUE_PRJ' directory! diff --git a/integration/bundle/testdata/default_python/bundle_summary.txt b/integration/bundle/testdata/default_python/bundle_summary.txt index 88ccdc496..450f01c46 100644 --- a/integration/bundle/testdata/default_python/bundle_summary.txt +++ b/integration/bundle/testdata/default_python/bundle_summary.txt @@ -7,8 +7,7 @@ "exec_path": "/tmp/.../terraform" }, "git": { - "bundle_root_path": ".", - "inferred": true + "bundle_root_path": "." }, "mode": "development", "deployment": { @@ -23,54 +22,54 @@ "resources/project_name_$UNIQUE_PRJ.pipeline.yml" ], "workspace": { - "host": "$DATABRICKS_URL", + "host": "[DATABRICKS_URL]", "current_user": { "active": true, - "displayName": "$USERNAME", + "displayName": "[USERNAME]", "emails": [ { "primary": true, "type": "work", - "value": "$USERNAME" + "value": "[USERNAME]" } ], "groups": [ { - "$ref": "Groups/$USER.Groups[0]", + "$ref": "Groups/[USERGROUP]", "display": "team.engineering", "type": "direct", - "value": "$USER.Groups[0]" + "value": "[USERGROUP]" } ], - "id": "$USER.Id", + "id": "[USERID]", "name": { - "familyName": "$USERNAME", - "givenName": "$USERNAME" + "familyName": "[USERNAME]", + "givenName": "[USERNAME]" }, "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:workspace:2.0:User" ], - "short_name": "$USERNAME", - "userName": "$USERNAME" + "short_name": "[USERNAME]", + "userName": "[USERNAME]" }, - "root_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev", - "file_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/files", - "resource_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/resources", - "artifact_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/artifacts", - "state_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/state" + "root_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev", + "file_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/files", + "resource_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/resources", + "artifact_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/artifacts", + "state_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/state" }, "resources": { "jobs": { "project_name_$UNIQUE_PRJ_job": { "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/state/metadata.json" }, "edit_mode": "UI_LOCKED", "email_notifications": { "on_failure": [ - "$USERNAME" + "[USERNAME]" ] }, "format": "MULTI_TASK", @@ -89,18 +88,18 @@ } ], "max_concurrent_runs": 4, - "name": "[dev $USERNAME] project_name_$UNIQUE_PRJ_job", + "name": "[dev [USERNAME]] project_name_$UNIQUE_PRJ_job", "queue": { "enabled": true }, "tags": { - "dev": "$USERNAME" + "dev": "[USERNAME]" }, "tasks": [ { "job_cluster_key": "job_cluster", "notebook_task": { - "notebook_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/files/src/notebook" + "notebook_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/files/src/notebook" }, "task_key": "notebook_task" }, @@ -141,31 +140,31 @@ "unit": "DAYS" } }, - "url": "$DATABRICKS_URL/jobs/[NUMID]?o=[NUMID]" + "url": "[DATABRICKS_URL]/jobs/[NUMID]?o=[NUMID]" } }, "pipelines": { "project_name_$UNIQUE_PRJ_pipeline": { "catalog": "main", "configuration": { - "bundle.sourcePath": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/files/src" + "bundle.sourcePath": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/files/src" }, "deployment": { "kind": "BUNDLE", - "metadata_file_path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/state/metadata.json" + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/state/metadata.json" }, "development": true, "id": "[UUID]", "libraries": [ { "notebook": { - "path": "/Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev/files/src/dlt_pipeline" + "path": "/Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev/files/src/dlt_pipeline" } } ], - "name": "[dev $USERNAME] project_name_$UNIQUE_PRJ_pipeline", + "name": "[dev [USERNAME]] project_name_$UNIQUE_PRJ_pipeline", "target": "project_name_$UNIQUE_PRJ_dev", - "url": "$DATABRICKS_URL/pipelines/[UUID]?o=[NUMID]" + "url": "[DATABRICKS_URL]/pipelines/[UUID]?o=[NUMID]" } } }, @@ -175,12 +174,12 @@ ] }, "presets": { - "name_prefix": "[dev $USERNAME] ", + "name_prefix": "[dev [USERNAME]] ", "pipelines_development": true, "trigger_pause_status": "PAUSED", "jobs_max_concurrent_runs": 4, "tags": { - "dev": "$USERNAME" + "dev": "[USERNAME]" } } -} +} \ No newline at end of file diff --git a/integration/bundle/testdata/default_python/bundle_validate.txt b/integration/bundle/testdata/default_python/bundle_validate.txt index 578fd6494..c5c62b521 100644 --- a/integration/bundle/testdata/default_python/bundle_validate.txt +++ b/integration/bundle/testdata/default_python/bundle_validate.txt @@ -1,8 +1,8 @@ Name: project_name_$UNIQUE_PRJ Target: dev Workspace: - Host: $DATABRICKS_URL - User: $USERNAME - Path: /Workspace/Users/$USERNAME/.bundle/project_name_$UNIQUE_PRJ/dev + Host: [DATABRICKS_URL] + User: [USERNAME] + Path: /Workspace/Users/[USERNAME]/.bundle/project_name_$UNIQUE_PRJ/dev Validation OK! diff --git a/integration/libs/telemetry/telemetry_test.go b/integration/libs/telemetry/telemetry_test.go new file mode 100644 index 000000000..d329c238e --- /dev/null +++ b/integration/libs/telemetry/telemetry_test.go @@ -0,0 +1,65 @@ +package telemetry + +import ( + "encoding/json" + "testing" + "time" + + "github.com/databricks/cli/integration/internal/acc" + "github.com/databricks/cli/libs/telemetry" + "github.com/databricks/cli/libs/telemetry/protos" + "github.com/databricks/databricks-sdk-go/client" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTelemetryEndpoint(t *testing.T) { + ctx, wt := acc.WorkspaceTest(t) + w := wt.W + + apiClient, err := client.New(w.Config) + require.NoError(t, err) + + logs := []protos.FrontendLog{ + { + FrontendLogEventID: uuid.New().String(), + Entry: protos.FrontendLogEntry{ + DatabricksCliLog: protos.DatabricksCliLog{ + CliTestEvent: &protos.CliTestEvent{Name: protos.DummyCliEnumValue1}, + }, + }, + }, + { + FrontendLogEventID: uuid.New().String(), + Entry: protos.FrontendLogEntry{ + DatabricksCliLog: protos.DatabricksCliLog{ + CliTestEvent: &protos.CliTestEvent{Name: protos.DummyCliEnumValue2}, + }, + }, + }, + } + + protoLogs := make([]string, len(logs)) + for i, log := range logs { + b, err := json.Marshal(log) + require.NoError(t, err) + protoLogs[i] = string(b) + } + + reqB := telemetry.RequestBody{ + UploadTime: time.Now().UnixMilli(), + Items: []string{}, + ProtoLogs: protoLogs, + } + + respB := telemetry.ResponseBody{} + + err = apiClient.Do(ctx, "POST", "/telemetry-ext", nil, nil, reqB, &respB) + require.NoError(t, err) + + assert.Equal(t, telemetry.ResponseBody{ + Errors: []telemetry.LogError{}, + NumProtoSuccess: int64(2), + }, respB) +} diff --git a/libs/daemon/daemon.go b/libs/daemon/daemon.go new file mode 100644 index 000000000..91914477b --- /dev/null +++ b/libs/daemon/daemon.go @@ -0,0 +1,120 @@ +package daemon + +import ( + "fmt" + "io" + "os" + "os/exec" + "strconv" +) + +const DatabricksCliParentPid = "DATABRICKS_CLI_PARENT_PID" + +type Daemon struct { + // If provided, the child process's pid will be written in the file at this + // path. + PidFilePath string + + // Environment variables to set in the child process. + Env []string + + // Path to executable to run. If empty, the current executable is used. + Executable string + + // Arguments to pass to the child process. + Args []string + + // Log file to write the child process's output to. + LogFile string + + logFile *os.File + cmd *exec.Cmd + stdin io.WriteCloser +} + +func (d *Daemon) Start() error { + cli, err := os.Executable() + if err != nil { + return err + } + + executable := d.Executable + if executable == "" { + executable = cli + } + + d.cmd = exec.Command(executable, d.Args...) + + // Set environment variable so that the child process knows its parent's PID. + // In unix systems orphaned processes are automatically re-parented to init (pid 1) + // so we cannot rely on os.Getppid() to get the original parent's pid. + d.Env = append(d.Env, fmt.Sprintf("%s=%d", DatabricksCliParentPid, os.Getpid())) + d.cmd.Env = d.Env + + d.cmd.SysProcAttr = sysProcAttr() + + // By default redirect stdout and stderr to /dev/null. + d.cmd.Stdout = nil + d.cmd.Stderr = nil + + // If a log file is provided, redirect stdout and stderr to the log file. + if d.LogFile != "" { + d.logFile, err = os.OpenFile(d.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) + if err != nil { + return fmt.Errorf("failed to open log file: %w", err) + } + + d.cmd.Stdout = d.logFile + d.cmd.Stderr = d.logFile + } + + d.stdin, err = d.cmd.StdinPipe() + if err != nil { + return fmt.Errorf("failed to get stdin pipe: %w", err) + } + + err = d.cmd.Start() + if err != nil { + return err + } + + if d.PidFilePath != "" { + err = os.WriteFile(d.PidFilePath, []byte(strconv.Itoa(d.cmd.Process.Pid)), 0o644) + if err != nil { + return fmt.Errorf("failed to write pid file: %w", err) + } + } + + return nil +} + +func (d *Daemon) WriteInput(b []byte) error { + _, err := d.stdin.Write(b) + return err +} + +func (d *Daemon) Release() error { + if d.stdin != nil { + err := d.stdin.Close() + if err != nil { + return fmt.Errorf("failed to close stdin: %w", err) + } + } + + // Note that the child process will stream it's output directly to the log file. + // So it's safe to close this file handle even if the child process is still running. + if d.logFile != nil { + err := d.logFile.Close() + if err != nil { + return fmt.Errorf("failed to close log file: %w", err) + } + } + + if d.cmd == nil { + return nil + } + + // The docs for [os.Process.Release] recommend calling Release if Wait is not called. + // It's probably not necessary but we call it just to be safe. + return d.cmd.Process.Release() +} diff --git a/libs/daemon/daemon_test.go b/libs/daemon/daemon_test.go new file mode 100644 index 000000000..ee9d92baa --- /dev/null +++ b/libs/daemon/daemon_test.go @@ -0,0 +1,51 @@ +package daemon + +import ( + "io" + "net/http" + "os" + "os/exec" + "path/filepath" + "strconv" + "testing" + "time" + + "github.com/databricks/cli/internal/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDaemon(t *testing.T) { + tmpDir := t.TempDir() + cmd := exec.Command("go", "run", "internal/parent_process/main.go", tmpDir) + + // cmd.Run() will block until the parent process exits. + err := cmd.Run() + require.NoError(t, err) + + // Assert that a PID file was created for the child process. + assert.FileExists(t, filepath.Join(tmpDir, "child.pid")) + + // Wait 10 seconds for the server to start and to write the port number to + // a file. + portFilePath := filepath.Join(tmpDir, "port.txt") + assert.Eventually(t, func() bool { + _, err := os.Stat(portFilePath) + return err == nil + }, 10*time.Second, 100*time.Millisecond) + + port, err := strconv.Atoi(testutil.ReadFile(t, portFilePath)) + require.NoError(t, err) + + // Query the local server, which should be alive even after the parent process + // has exited. + r, err := http.Get("http://localhost:" + strconv.Itoa(port)) + require.NoError(t, err) + defer r.Body.Close() + + // The server should respond with "child says hi". + assert.Equal(t, http.StatusOK, r.StatusCode) + b, err := io.ReadAll(r.Body) + require.NoError(t, err) + assert.Equal(t, "child says hi", string(b)) +} diff --git a/libs/daemon/daemon_unix.go b/libs/daemon/daemon_unix.go new file mode 100644 index 000000000..b9a7023a7 --- /dev/null +++ b/libs/daemon/daemon_unix.go @@ -0,0 +1,17 @@ +//go:build linux || darwin + +package daemon + +import "syscall" + +// References: +// 1. linux: https://go.dev/src/syscall/exec_linux.go +// 2. macos (arm): https://go.dev/src/syscall/exec_libc2.go +func sysProcAttr() *syscall.SysProcAttr { + return &syscall.SysProcAttr{ + // Create a new session for the child process. This ensures that the daemon + // is not terminated when the parent session is closed. This can happen + // for example when a ssh session is terminated. + Setsid: true, + } +} diff --git a/libs/daemon/daemon_windows.go b/libs/daemon/daemon_windows.go new file mode 100644 index 000000000..bccf22e4b --- /dev/null +++ b/libs/daemon/daemon_windows.go @@ -0,0 +1,16 @@ +//go:build windows + +package daemon + +import ( + "syscall" + + "golang.org/x/sys/windows" +) + +func sysProcAttr() *syscall.SysProcAttr { + return &syscall.SysProcAttr{ + HideWindow: true, + CreationFlags: windows.CREATE_NEW_PROCESS_GROUP | windows.DETACHED_PROCESS, + } +} diff --git a/libs/daemon/internal/parent_process/main.go b/libs/daemon/internal/parent_process/main.go new file mode 100644 index 000000000..87c1bdda2 --- /dev/null +++ b/libs/daemon/internal/parent_process/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "os" + "path/filepath" + + "github.com/databricks/cli/libs/daemon" +) + +func main() { + tmpDir := os.Args[1] + + d := daemon.Daemon{ + PidFilePath: filepath.Join(tmpDir, "child.pid"), + Executable: "python3", + // The server script writes the port number the server is listening on + // to the specified file. + Args: []string{"./internal/parent_process/server.py", filepath.Join(tmpDir, "port.txt")}, + } + + err := d.Start() + if err != nil { + panic(err) + } + + err = d.Release() + if err != nil { + panic(err) + } +} diff --git a/libs/daemon/internal/parent_process/server.py b/libs/daemon/internal/parent_process/server.py new file mode 100644 index 000000000..ad341f992 --- /dev/null +++ b/libs/daemon/internal/parent_process/server.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +import sys +from http.server import BaseHTTPRequestHandler, HTTPServer + +if len(sys.argv) < 2: + print("Usage: python script.py ") + sys.exit(1) + +port_file_path = sys.argv[1] + + +class SimpleHandler(BaseHTTPRequestHandler): + def do_GET(self): + # Send HTTP 200 response with plain text content + self.send_response(200) + self.send_header("Content-type", "text/plain") + self.end_headers() + self.wfile.write(b"child says hi") + + +# Bind to localhost on port 0 to let the OS pick an available port. +server_address = ("localhost", 0) +httpd = HTTPServer(server_address, SimpleHandler) + +# Retrieve the assigned port. +assigned_port = httpd.server_address[1] + +# Write the port number to the provided file path. +with open(port_file_path, "w") as f: + f.write(str(assigned_port)) + +try: + # Automatically shut down the server after 2 minutes. This is a precaution to + # prevent the server from running indefinitely incase the GET API is never called. + httpd.timeout = 120 + + # This server will exit after one request. + httpd.handle_request() +except KeyboardInterrupt: + print("\nServer is shutting down.") diff --git a/libs/dyn/drop_keys.go b/libs/dyn/drop_keys.go new file mode 100644 index 000000000..494f9b9cd --- /dev/null +++ b/libs/dyn/drop_keys.go @@ -0,0 +1,27 @@ +package dyn + +func DropKeys(v Value, drop []string) (Value, error) { + var err error + nv, err := Walk(v, func(p Path, v Value) (Value, error) { + if len(p) == 0 { + return v, nil + } + + // Check if this key should be dropped. + for _, key := range drop { + if p[0].Key() != key { + continue + } + + return InvalidValue, ErrDrop + } + + // Pass through all other values. + return v, ErrSkip + }) + if err != nil { + return InvalidValue, err + } + + return nv, nil +} diff --git a/libs/dyn/drop_keys_test.go b/libs/dyn/drop_keys_test.go new file mode 100644 index 000000000..83a9744ca --- /dev/null +++ b/libs/dyn/drop_keys_test.go @@ -0,0 +1,24 @@ +package dyn + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDropKeysTest(t *testing.T) { + v := V(map[string]Value{ + "key1": V("value1"), + "key2": V("value2"), + "key3": V("value3"), + }) + + vout, err := DropKeys(v, []string{"key1", "key3"}) + require.NoError(t, err) + + mv := vout.MustMap() + require.Equal(t, 1, mv.Len()) + v, ok := mv.GetByString("key2") + require.True(t, ok) + require.Equal(t, "value2", v.MustString()) +} diff --git a/libs/dyn/dynvar/ref.go b/libs/dyn/dynvar/ref.go index a28938823..ba397267a 100644 --- a/libs/dyn/dynvar/ref.go +++ b/libs/dyn/dynvar/ref.go @@ -1,12 +1,16 @@ package dynvar import ( + "fmt" "regexp" "github.com/databricks/cli/libs/dyn" ) -var re = regexp.MustCompile(`\$\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\[[0-9]+\])*)*(\[[0-9]+\])*)\}`) +var ( + baseVarDef = `[a-zA-Z]+([-_]*[a-zA-Z0-9]+)*` + re = regexp.MustCompile(fmt.Sprintf(`\$\{(%s(\.%s(\[[0-9]+\])*)*(\[[0-9]+\])*)\}`, baseVarDef, baseVarDef)) +) // ref represents a variable reference. // It is a string [dyn.Value] contained in a larger [dyn.Value]. diff --git a/libs/dyn/dynvar/ref_test.go b/libs/dyn/dynvar/ref_test.go index 4110732f8..637ecb98e 100644 --- a/libs/dyn/dynvar/ref_test.go +++ b/libs/dyn/dynvar/ref_test.go @@ -15,9 +15,13 @@ func TestNewRefNoString(t *testing.T) { func TestNewRefValidPattern(t *testing.T) { for in, refs := range map[string][]string{ - "${hello_world.world_world}": {"hello_world.world_world"}, - "${helloworld.world-world}": {"helloworld.world-world"}, - "${hello-world.world-world}": {"hello-world.world-world"}, + "${hello_world.world_world}": {"hello_world.world_world"}, + "${helloworld.world-world}": {"helloworld.world-world"}, + "${hello-world.world-world}": {"hello-world.world-world"}, + "${hello_world.world__world}": {"hello_world.world__world"}, + "${hello_world.world--world}": {"hello_world.world--world"}, + "${hello_world.world-_world}": {"hello_world.world-_world"}, + "${hello_world.world_-world}": {"hello_world.world_-world"}, } { ref, ok := newRef(dyn.V(in)) require.True(t, ok, "should match valid pattern: %s", in) @@ -36,8 +40,6 @@ func TestNewRefInvalidPattern(t *testing.T) { "${_-_._-_.id}", // cannot use _- in sequence "${0helloworld.world-world}", // interpolated first section shouldn't start with number "${helloworld.9world-world}", // interpolated second section shouldn't start with number - "${a-a.a-_a-a.id}", // fails because of -_ in the second segment - "${a-a.a--a-a.id}", // fails because of -- in the second segment } for _, v := range invalid { _, ok := newRef(dyn.V(v)) diff --git a/libs/dyn/yamlsaver/utils.go b/libs/dyn/yamlsaver/utils.go index a162bf31f..c1b60b1b5 100644 --- a/libs/dyn/yamlsaver/utils.go +++ b/libs/dyn/yamlsaver/utils.go @@ -22,9 +22,50 @@ func ConvertToMapValue(strct any, order *Order, skipFields []string, dst map[str return dyn.InvalidValue, fmt.Errorf("expected map, got %s", mv.Kind()) } + mv, err = sortMapAlphabetically(mv) + if err != nil { + return dyn.InvalidValue, err + } + return skipAndOrder(mv, order, skipFields, dst) } +// Sort the map alphabetically by keys. This is used to produce stable output for generated YAML files. +func sortMapAlphabetically(mv dyn.Value) (dyn.Value, error) { + sortedMap := dyn.NewMapping() + mapV := mv.MustMap() + keys := mapV.Keys() + slices.SortStableFunc(keys, func(i, j dyn.Value) int { + iKey := i.MustString() + jKey := j.MustString() + if iKey < jKey { + return -1 + } + + if iKey > jKey { + return 1 + } + return 0 + }) + + for _, key := range keys { + value, _ := mapV.Get(key) + var err error + if value.Kind() == dyn.KindMap { + value, err = sortMapAlphabetically(value) + if err != nil { + return dyn.InvalidValue, err + } + } + err = sortedMap.Set(key, value) + if err != nil { + return dyn.InvalidValue, err + } + } + + return dyn.V(sortedMap), nil +} + func skipAndOrder(mv dyn.Value, order *Order, skipFields []string, dst map[string]dyn.Value) (dyn.Value, error) { for _, pair := range mv.MustMap().Pairs() { k := pair.Key.MustString() @@ -44,7 +85,11 @@ func skipAndOrder(mv dyn.Value, order *Order, skipFields []string, dst map[strin continue } - dst[k] = dyn.NewValue(v.Value(), []dyn.Location{{Line: order.Get(k)}}) + if order == nil { + dst[k] = v + } else { + dst[k] = dyn.NewValue(v.Value(), []dyn.Location{{Line: order.Get(k)}}) + } } return dyn.V(dst), nil diff --git a/libs/dyn/yamlsaver/utils_test.go b/libs/dyn/yamlsaver/utils_test.go index 1afab601a..f7ea3c96c 100644 --- a/libs/dyn/yamlsaver/utils_test.go +++ b/libs/dyn/yamlsaver/utils_test.go @@ -7,6 +7,54 @@ import ( assert "github.com/databricks/cli/libs/dyn/dynassert" ) +func TestConvertToMap(t *testing.T) { + type test struct { + Name string `json:"name"` + Map map[string]string `json:"map"` + List []string `json:"list"` + LongNameField string `json:"long_name_field"` + ForceSendFields []string `json:"-"` + Format string `json:"format"` + } + + v := &test{ + Name: "test", + Map: map[string]string{ + "key2": "value2", + "key1": "value1", + }, + List: []string{"a", "b", "c"}, + ForceSendFields: []string{ + "Name", + }, + LongNameField: "long name goes here", + } + result, err := ConvertToMapValue(v, nil, []string{"format"}, map[string]dyn.Value{}) + assert.NoError(t, err) + assert.Equal(t, dyn.V(map[string]dyn.Value{ + "list": dyn.NewValue( + []dyn.Value{ + dyn.V("a"), + dyn.V("b"), + dyn.V("c"), + }, + []dyn.Location{}, + ), + "long_name_field": dyn.NewValue("long name goes here", []dyn.Location{}), + "map": dyn.NewValue( + map[string]dyn.Value{ + "key1": dyn.V("value1"), + "key2": dyn.V("value2"), + }, + []dyn.Location{}, + ), + "name": dyn.NewValue( + "test", + []dyn.Location{}, + ), + }), result) +} + func TestConvertToMapValueWithOrder(t *testing.T) { type test struct { Name string `json:"name"` diff --git a/libs/flags/log_level_flag.go b/libs/flags/log_level_flag.go index 836d84b70..82e2abc4c 100644 --- a/libs/flags/log_level_flag.go +++ b/libs/flags/log_level_flag.go @@ -25,7 +25,7 @@ type LogLevelFlag struct { func NewLogLevelFlag() LogLevelFlag { return LogLevelFlag{ - l: log.LevelDisabled, + l: log.LevelWarn, } } diff --git a/libs/flags/log_level_flag_test.go b/libs/flags/log_level_flag_test.go index 11a50bc45..c81f90d18 100644 --- a/libs/flags/log_level_flag_test.go +++ b/libs/flags/log_level_flag_test.go @@ -10,8 +10,8 @@ import ( func TestLogLevelFlagDefault(t *testing.T) { f := NewLogLevelFlag() - assert.Equal(t, log.LevelDisabled, f.Level()) - assert.Equal(t, "disabled", f.String()) + assert.Equal(t, log.LevelWarn, f.Level()) + assert.Equal(t, "warn", f.String()) } func TestLogLevelFlagSetValid(t *testing.T) { diff --git a/libs/jsonschema/schema.go b/libs/jsonschema/schema.go index 5028bb0d7..85f6a0328 100644 --- a/libs/jsonschema/schema.go +++ b/libs/jsonschema/schema.go @@ -79,7 +79,7 @@ type Schema struct { // Examples of the value for properties in the schema. // https://json-schema.org/understanding-json-schema/reference/annotations - Examples []any `json:"examples,omitempty"` + Examples any `json:"examples,omitempty"` } // Default value defined in a JSON Schema, represented as a string. diff --git a/libs/log/handler/friendly.go b/libs/log/handler/friendly.go index 33b88a9e2..5c60eb13d 100644 --- a/libs/log/handler/friendly.go +++ b/libs/log/handler/friendly.go @@ -53,11 +53,11 @@ func NewFriendlyHandler(out io.Writer, opts *Options) slog.Handler { // Cache (colorized) level strings. // The colors to use for each level are configured in `colors.go`. - h.levelTrace = h.sprintf(ttyColorLevelTrace, "%5s", "TRACE") - h.levelDebug = h.sprintf(ttyColorLevelDebug, "%5s", "DEBUG") - h.levelInfo = h.sprintf(ttyColorLevelInfo, "%5s", "INFO") - h.levelWarn = h.sprintf(ttyColorLevelWarn, "%5s", "WARN") - h.levelError = h.sprintf(ttyColorLevelError, "%5s", "ERROR") + h.levelTrace = h.sprintf(ttyColorLevelTrace, "%s", "Trace:") + h.levelDebug = h.sprintf(ttyColorLevelDebug, "%s", "Debug:") + h.levelInfo = h.sprintf(ttyColorLevelInfo, "%s", "Info:") + h.levelWarn = h.sprintf(ttyColorLevelWarn, "%s", "Warn:") + h.levelError = h.sprintf(ttyColorLevelError, "%s", "Error:") return h } @@ -185,33 +185,41 @@ func (s *handleState) appendAttr(a slog.Attr) { // Handle implements slog.Handler. func (h *friendlyHandler) Handle(ctx context.Context, r slog.Record) error { state := h.handleState() - state.append(h.sprintf(ttyColorTime, "%02d:%02d:%02d ", r.Time.Hour(), r.Time.Minute(), r.Time.Second())) + + if h.opts.Level.Level() <= slog.LevelDebug { + state.append(h.sprintf(ttyColorTime, "%02d:%02d:%02d ", r.Time.Hour(), r.Time.Minute(), r.Time.Second())) + } + state.appendf("%s ", h.coloredLevel(r)) state.append(h.sprint(ttyColorMessage, r.Message)) - // Handle state from WithGroup and WithAttrs. - goas := h.goas - if r.NumAttrs() == 0 { - // If the record has no Attrs, remove groups at the end of the list; they are empty. - for len(goas) > 0 && goas[len(goas)-1].group != "" { - goas = goas[:len(goas)-1] - } - } - for _, goa := range goas { - if goa.group != "" { - state.openGroup(goa.group) - } else { - for _, a := range goa.attrs { - state.appendAttr(a) + if h.opts.Level.Level() <= slog.LevelDebug { + + // Handle state from WithGroup and WithAttrs. + goas := h.goas + if r.NumAttrs() == 0 { + // If the record has no Attrs, remove groups at the end of the list; they are empty. + for len(goas) > 0 && goas[len(goas)-1].group != "" { + goas = goas[:len(goas)-1] + } + } + for _, goa := range goas { + if goa.group != "" { + state.openGroup(goa.group) + } else { + for _, a := range goa.attrs { + state.appendAttr(a) + } } } - } - // Add attributes from the record. - r.Attrs(func(a slog.Attr) bool { - state.appendAttr(a) - return true - }) + // Add attributes from the record. + r.Attrs(func(a slog.Attr) bool { + state.appendAttr(a) + return true + }) + + } // Add newline. state.append("\n") diff --git a/libs/template/templates/dbt-sql/template/{{.project_name}}/databricks.yml.tmpl b/libs/template/templates/dbt-sql/template/{{.project_name}}/databricks.yml.tmpl index ba336f6a1..d991c06ff 100644 --- a/libs/template/templates/dbt-sql/template/{{.project_name}}/databricks.yml.tmpl +++ b/libs/template/templates/dbt-sql/template/{{.project_name}}/databricks.yml.tmpl @@ -12,12 +12,12 @@ include: # The default schema, catalog, etc. for dbt are defined in dbt_profiles/profiles.yml targets: dev: - default: true # The default target uses 'mode: development' to create a development copy. # - Deployed resources get prefixed with '[dev my_user_name]' # - Any job schedules and triggers are paused by default. # See also https://docs.databricks.com/dev-tools/bundles/deployment-modes.html. mode: development + default: true workspace: host: {{workspace_host}} @@ -25,10 +25,8 @@ targets: mode: production workspace: host: {{workspace_host}} - # We explicitly specify /Workspace/Users/{{user_name}} to make sure we only have a single copy. + # We explicitly deploy to /Workspace/Users/{{user_name}} to make sure we only have a single copy. root_path: /Workspace/Users/{{user_name}}/.bundle/${bundle.name}/${bundle.target} permissions: - {{if is_service_principal}}service_principal{{else}}user{{end}}_name: {{user_name}} level: CAN_MANAGE - run_as: - {{if is_service_principal}}service_principal{{else}}user{{end}}_name: {{user_name}} diff --git a/libs/template/templates/default-python/template/{{.project_name}}/README.md.tmpl b/libs/template/templates/default-python/template/{{.project_name}}/README.md.tmpl index 53847a9c9..b8811fa3e 100644 --- a/libs/template/templates/default-python/template/{{.project_name}}/README.md.tmpl +++ b/libs/template/templates/default-python/template/{{.project_name}}/README.md.tmpl @@ -38,10 +38,16 @@ The '{{.project_name}}' project was generated by using the default-python templa $ databricks bundle run ``` +{{- if (eq .include_python "no") }} 6. Optionally, install developer tools such as the Databricks extension for Visual Studio Code from https://docs.databricks.com/dev-tools/vscode-ext.html. -{{- if (eq .include_python "yes") }} Or read the "getting started" documentation for - **Databricks Connect** for instructions on running the included Python code from a different IDE. +{{- else }} +6. Optionally, install the Databricks extension for Visual Studio code for local development from + https://docs.databricks.com/dev-tools/vscode-ext.html. It can configure your + virtual environment and setup Databricks Connect for running unit tests locally. + When not using these tools, consult your development environment's documentation + and/or the documentation for Databricks Connect for manually setting up your environment + (https://docs.databricks.com/en/dev-tools/databricks-connect/python/index.html). {{- end}} 7. For documentation on the Databricks asset bundles format used diff --git a/libs/template/templates/default-python/template/{{.project_name}}/databricks.yml.tmpl b/libs/template/templates/default-python/template/{{.project_name}}/databricks.yml.tmpl index 4d052e38e..04d22a764 100644 --- a/libs/template/templates/default-python/template/{{.project_name}}/databricks.yml.tmpl +++ b/libs/template/templates/default-python/template/{{.project_name}}/databricks.yml.tmpl @@ -22,10 +22,8 @@ targets: mode: production workspace: host: {{workspace_host}} - # We explicitly specify /Workspace/Users/{{user_name}} to make sure we only have a single copy. + # We explicitly deploy to /Workspace/Users/{{user_name}} to make sure we only have a single copy. root_path: /Workspace/Users/{{user_name}}/.bundle/${bundle.name}/${bundle.target} permissions: - {{if is_service_principal}}service_principal{{else}}user{{end}}_name: {{user_name}} level: CAN_MANAGE - run_as: - {{if is_service_principal}}service_principal{{else}}user{{end}}_name: {{user_name}} diff --git a/libs/template/templates/default-sql/template/{{.project_name}}/databricks.yml.tmpl b/libs/template/templates/default-sql/template/{{.project_name}}/databricks.yml.tmpl index 84e07df17..6acdf40e7 100644 --- a/libs/template/templates/default-sql/template/{{.project_name}}/databricks.yml.tmpl +++ b/libs/template/templates/default-sql/template/{{.project_name}}/databricks.yml.tmpl @@ -42,7 +42,7 @@ targets: mode: production workspace: host: {{workspace_host}} - # We explicitly specify /Workspace/Users/{{user_name}} to make sure we only have a single copy. + # We explicitly deploy to /Workspace/Users/{{user_name}} to make sure we only have a single copy. root_path: /Workspace/Users/{{user_name}}/.bundle/${bundle.name}/${bundle.target} variables: warehouse_id: {{index ((regexp "[^/]+$").FindStringSubmatch .http_path) 0}} @@ -51,5 +51,3 @@ targets: permissions: - {{if is_service_principal}}service_principal{{else}}user{{end}}_name: {{user_name}} level: CAN_MANAGE - run_as: - {{if is_service_principal}}service_principal{{else}}user{{end}}_name: {{user_name}} diff --git a/libs/testdiff/replacement.go b/libs/testdiff/replacement.go index 7077e611b..d4d5eb27b 100644 --- a/libs/testdiff/replacement.go +++ b/libs/testdiff/replacement.go @@ -2,7 +2,6 @@ package testdiff import ( "encoding/json" - "fmt" "path/filepath" "regexp" "runtime" @@ -13,10 +12,11 @@ import ( "github.com/databricks/cli/libs/iamutil" "github.com/databricks/databricks-sdk-go" "github.com/databricks/databricks-sdk-go/service/iam" + "golang.org/x/mod/semver" ) const ( - testerName = "$USERNAME" + testerName = "[USERNAME]" ) var ( @@ -140,25 +140,25 @@ func PrepareReplacementsWorkspaceClient(t testutil.TestingT, r *ReplacementsCont t.Helper() // in some clouds (gcp) w.Config.Host includes "https://" prefix in others it's really just a host (azure) host := strings.TrimPrefix(strings.TrimPrefix(w.Config.Host, "http://"), "https://") - r.Set("https://"+host, "$DATABRICKS_URL") - r.Set("http://"+host, "$DATABRICKS_URL") - r.Set(host, "$DATABRICKS_HOST") - r.Set(w.Config.ClusterID, "$DATABRICKS_CLUSTER_ID") - r.Set(w.Config.WarehouseID, "$DATABRICKS_WAREHOUSE_ID") - r.Set(w.Config.ServerlessComputeID, "$DATABRICKS_SERVERLESS_COMPUTE_ID") - r.Set(w.Config.AccountID, "$DATABRICKS_ACCOUNT_ID") - r.Set(w.Config.Username, "$DATABRICKS_USERNAME") - r.SetPath(w.Config.Profile, "$DATABRICKS_CONFIG_PROFILE") - r.Set(w.Config.ConfigFile, "$DATABRICKS_CONFIG_FILE") - r.Set(w.Config.GoogleServiceAccount, "$DATABRICKS_GOOGLE_SERVICE_ACCOUNT") - r.Set(w.Config.AzureResourceID, "$DATABRICKS_AZURE_RESOURCE_ID") + r.Set("https://"+host, "[DATABRICKS_URL]") + r.Set("http://"+host, "[DATABRICKS_URL]") + r.Set(host, "[DATABRICKS_HOST]") + r.Set(w.Config.ClusterID, "[DATABRICKS_CLUSTER_ID]") + r.Set(w.Config.WarehouseID, "[DATABRICKS_WAREHOUSE_ID]") + r.Set(w.Config.ServerlessComputeID, "[DATABRICKS_SERVERLESS_COMPUTE_ID]") + r.Set(w.Config.AccountID, "[DATABRICKS_ACCOUNT_ID]") + r.Set(w.Config.Username, "[DATABRICKS_USERNAME]") + r.SetPath(w.Config.Profile, "[DATABRICKS_CONFIG_PROFILE]") + r.Set(w.Config.ConfigFile, "[DATABRICKS_CONFIG_FILE]") + r.Set(w.Config.GoogleServiceAccount, "[DATABRICKS_GOOGLE_SERVICE_ACCOUNT]") + r.Set(w.Config.AzureResourceID, "[DATABRICKS_AZURE_RESOURCE_ID]") r.Set(w.Config.AzureClientID, testerName) - r.Set(w.Config.AzureTenantID, "$ARM_TENANT_ID") - r.Set(w.Config.AzureEnvironment, "$ARM_ENVIRONMENT") - r.Set(w.Config.ClientID, "$DATABRICKS_CLIENT_ID") - r.SetPath(w.Config.DatabricksCliPath, "$DATABRICKS_CLI_PATH") + r.Set(w.Config.AzureTenantID, "[ARM_TENANT_ID]") + r.Set(w.Config.AzureEnvironment, "[ARM_ENVIRONMENT]") + r.Set(w.Config.ClientID, "[DATABRICKS_CLIENT_ID]") + r.SetPath(w.Config.DatabricksCliPath, "[DATABRICKS_CLI_PATH]") // This is set to words like "path" that happen too frequently - // r.Set(w.Config.AuthType, "$DATABRICKS_AUTH_TYPE") + // r.Set(w.Config.AuthType, "[DATABRICKS_AUTH_TYPE]") } func PrepareReplacementsUser(t testutil.TestingT, r *ReplacementsContext, u iam.User) { @@ -179,14 +179,14 @@ func PrepareReplacementsUser(t testutil.TestingT, r *ReplacementsContext, u iam. r.Set(iamutil.GetShortUserName(&u), testerName) - for ind, val := range u.Groups { - r.Set(val.Value, fmt.Sprintf("$USER.Groups[%d]", ind)) + for _, val := range u.Groups { + r.Set(val.Value, "[USERGROUP]") } - r.Set(u.Id, "$USER.Id") + r.Set(u.Id, "[USERID]") - for ind, val := range u.Roles { - r.Set(val.Value, fmt.Sprintf("$USER.Roles[%d]", ind)) + for _, val := range u.Roles { + r.Set(val.Value, "[USERROLE]") } } @@ -207,5 +207,22 @@ func PrepareReplacementsTemporaryDirectory(t testutil.TestingT, r *ReplacementsC func PrepareReplacementsDevVersion(t testutil.TestingT, r *ReplacementsContext) { t.Helper() - r.append(devVersionRegex, "$$DEV_VERSION") + r.append(devVersionRegex, "[DEV_VERSION]") +} + +func PrepareReplacementSdkVersion(t testutil.TestingT, r *ReplacementsContext) { + t.Helper() + r.Set(databricks.Version(), "[SDK_VERSION]") +} + +func goVersion() string { + gv := runtime.Version() + ssv := strings.ReplaceAll(gv, "go", "v") + sv := semver.Canonical(ssv) + return strings.TrimPrefix(sv, "v") +} + +func PrepareReplacementsGoVersion(t testutil.TestingT, r *ReplacementsContext) { + t.Helper() + r.Set(goVersion(), "[GO_VERSION]") } diff --git a/libs/testserver/fake_workspace.go b/libs/testserver/fake_workspace.go new file mode 100644 index 000000000..4e943f828 --- /dev/null +++ b/libs/testserver/fake_workspace.go @@ -0,0 +1,175 @@ +package testserver + +import ( + "bytes" + "encoding/json" + "fmt" + "sort" + "strconv" + "strings" + + "github.com/databricks/databricks-sdk-go/service/jobs" + "github.com/databricks/databricks-sdk-go/service/workspace" +) + +// FakeWorkspace holds a state of a workspace for acceptance tests. +type FakeWorkspace struct { + directories map[string]bool + files map[string][]byte + // normally, ids are not sequential, but we make them sequential for deterministic diff + nextJobId int64 + jobs map[int64]jobs.Job +} + +func NewFakeWorkspace() *FakeWorkspace { + return &FakeWorkspace{ + directories: map[string]bool{ + "/Workspace": true, + }, + files: map[string][]byte{}, + jobs: map[int64]jobs.Job{}, + nextJobId: 1, + } +} + +func (s *FakeWorkspace) WorkspaceGetStatus(path string) Response { + if s.directories[path] { + return Response{ + Body: &workspace.ObjectInfo{ + ObjectType: "DIRECTORY", + Path: path, + }, + } + } else if _, ok := s.files[path]; ok { + return Response{ + Body: &workspace.ObjectInfo{ + ObjectType: "FILE", + Path: path, + Language: "SCALA", + }, + } + } else { + return Response{ + StatusCode: 404, + Body: map[string]string{"message": "Workspace path not found"}, + } + } +} + +func (s *FakeWorkspace) WorkspaceMkdirs(request workspace.Mkdirs) { + s.directories[request.Path] = true +} + +func (s *FakeWorkspace) WorkspaceExport(path string) []byte { + return s.files[path] +} + +func (s *FakeWorkspace) WorkspaceDelete(path string, recursive bool) { + if !recursive { + s.files[path] = nil + } else { + for key := range s.files { + if strings.HasPrefix(key, path) { + s.files[key] = nil + } + } + } +} + +func (s *FakeWorkspace) WorkspaceFilesImportFile(path string, body []byte) { + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + s.files[path] = body +} + +func (s *FakeWorkspace) JobsCreate(request jobs.CreateJob) Response { + jobId := s.nextJobId + s.nextJobId++ + + jobSettings := jobs.JobSettings{} + err := jsonConvert(request, &jobSettings) + if err != nil { + return Response{ + StatusCode: 400, + Body: fmt.Sprintf("Cannot convert request to jobSettings: %s", err), + } + } + + s.jobs[jobId] = jobs.Job{ + JobId: jobId, + Settings: &jobSettings, + } + + return Response{ + Body: jobs.CreateResponse{JobId: jobId}, + } +} + +func (s *FakeWorkspace) JobsGet(jobId string) Response { + id := jobId + + jobIdInt, err := strconv.ParseInt(id, 10, 64) + if err != nil { + return Response{ + StatusCode: 400, + Body: fmt.Sprintf("Failed to parse job id: %s: %v", err, id), + } + } + + job, ok := s.jobs[jobIdInt] + if !ok { + return Response{ + StatusCode: 404, + } + } + + return Response{ + Body: job, + } +} + +func (s *FakeWorkspace) JobsList() Response { + list := make([]jobs.BaseJob, 0, len(s.jobs)) + for _, job := range s.jobs { + baseJob := jobs.BaseJob{} + err := jsonConvert(job, &baseJob) + if err != nil { + return Response{ + StatusCode: 400, + Body: fmt.Sprintf("failed to convert job to base job: %s", err), + } + } + + list = append(list, baseJob) + } + + // sort to have less non-determinism in tests + sort.Slice(list, func(i, j int) bool { + return list[i].JobId < list[j].JobId + }) + + return Response{ + Body: jobs.ListJobsResponse{ + Jobs: list, + }, + } +} + +// jsonConvert saves input to a value pointed by output +func jsonConvert(input, output any) error { + writer := new(bytes.Buffer) + encoder := json.NewEncoder(writer) + err := encoder.Encode(input) + if err != nil { + return fmt.Errorf("failed to encode: %w", err) + } + + decoder := json.NewDecoder(writer) + err = decoder.Decode(output) + if err != nil { + return fmt.Errorf("failed to decode: %w", err) + } + + return nil +} diff --git a/libs/testserver/server.go b/libs/testserver/server.go index 10269af8f..a10ddf4d8 100644 --- a/libs/testserver/server.go +++ b/libs/testserver/server.go @@ -2,62 +2,296 @@ package testserver import ( "encoding/json" + "io" "net/http" "net/http/httptest" + "net/url" + "reflect" + "strings" + "sync" + + "github.com/gorilla/mux" "github.com/databricks/cli/internal/testutil" + "github.com/databricks/databricks-sdk-go/apierr" ) type Server struct { *httptest.Server - Mux *http.ServeMux + Router *mux.Router t testutil.TestingT + + fakeWorkspaces map[string]*FakeWorkspace + mu *sync.Mutex + + RecordRequestsCallback func(request *Request) } -func New(t testutil.TestingT) *Server { - mux := http.NewServeMux() - server := httptest.NewServer(mux) +type Request struct { + Method string + URL *url.URL + Headers http.Header + Body []byte + Vars map[string]string + Workspace *FakeWorkspace +} - return &Server{ - Server: server, - Mux: mux, - t: t, +type Response struct { + StatusCode int + Headers http.Header + Body any +} + +type encodedResponse struct { + StatusCode int + Headers http.Header + Body []byte +} + +func NewRequest(t testutil.TestingT, r *http.Request, fakeWorkspace *FakeWorkspace) Request { + body, err := io.ReadAll(r.Body) + if err != nil { + t.Fatalf("Failed to read request body: %s", err) + } + + return Request{ + Method: r.Method, + URL: r.URL, + Headers: r.Header, + Body: body, + Vars: mux.Vars(r), + Workspace: fakeWorkspace, } } -type HandlerFunc func(req *http.Request) (resp any, err error) - -func (s *Server) Close() { - s.Server.Close() +func normalizeResponse(t testutil.TestingT, resp any) encodedResponse { + result := normalizeResponseBody(t, resp) + if result.StatusCode == 0 { + result.StatusCode = 200 + } + return result } -func (s *Server) Handle(pattern string, handler HandlerFunc) { - s.Mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { - resp, err := handler(r) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return +func normalizeResponseBody(t testutil.TestingT, resp any) encodedResponse { + if isNil(resp) { + t.Errorf("Handler must not return nil") + return encodedResponse{StatusCode: 500} + } + + respBytes, ok := resp.([]byte) + if ok { + return encodedResponse{ + Body: respBytes, + Headers: getHeaders(respBytes), } + } - w.Header().Set("Content-Type", "application/json") + respString, ok := resp.(string) + if ok { + return encodedResponse{ + Body: []byte(respString), + Headers: getHeaders([]byte(respString)), + } + } - var respBytes []byte - - respString, ok := resp.(string) - if ok { - respBytes = []byte(respString) - } else { - respBytes, err = json.MarshalIndent(resp, "", " ") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return + respStruct, ok := resp.(Response) + if ok { + if isNil(respStruct.Body) { + return encodedResponse{ + StatusCode: respStruct.StatusCode, + Headers: respStruct.Headers, + Body: []byte{}, } } + bytesVal, isBytes := respStruct.Body.([]byte) + if isBytes { + return encodedResponse{ + StatusCode: respStruct.StatusCode, + Headers: respStruct.Headers, + Body: bytesVal, + } + } + + stringVal, isString := respStruct.Body.(string) + if isString { + return encodedResponse{ + StatusCode: respStruct.StatusCode, + Headers: respStruct.Headers, + Body: []byte(stringVal), + } + } + + respBytes, err := json.MarshalIndent(respStruct.Body, "", " ") + if err != nil { + t.Errorf("JSON encoding error: %s", err) + return encodedResponse{ + StatusCode: 500, + Body: []byte("internal error"), + } + } + + headers := respStruct.Headers + if headers == nil { + headers = getJsonHeaders() + } + + return encodedResponse{ + StatusCode: respStruct.StatusCode, + Headers: headers, + Body: respBytes, + } + } + + respBytes, err := json.MarshalIndent(resp, "", " ") + if err != nil { + t.Errorf("JSON encoding error: %s", err) + return encodedResponse{ + StatusCode: 500, + Body: []byte("internal error"), + } + } + + return encodedResponse{ + Body: respBytes, + Headers: getJsonHeaders(), + } +} + +func getJsonHeaders() http.Header { + return map[string][]string{ + "Content-Type": {"application/json"}, + } +} + +func getHeaders(value []byte) http.Header { + if json.Valid(value) { + return getJsonHeaders() + } else { + return map[string][]string{ + "Content-Type": {"text/plain"}, + } + } +} + +func New(t testutil.TestingT) *Server { + router := mux.NewRouter() + server := httptest.NewServer(router) + t.Cleanup(server.Close) + + s := &Server{ + Server: server, + Router: router, + t: t, + mu: &sync.Mutex{}, + fakeWorkspaces: map[string]*FakeWorkspace{}, + } + + // Set up the not found handler as fallback + router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + pattern := r.Method + " " + r.URL.Path + + t.Errorf(` + +---------------------------------------- +No stub found for pattern: %s + +To stub a response for this request, you can add +the following to test.toml: +[[Server]] +Pattern = %q +Response.Body = ''' + +''' +Response.StatusCode = +---------------------------------------- + + +`, pattern, pattern) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotImplemented) + + resp := apierr.APIError{ + Message: "No stub found for pattern: " + pattern, + } + + respBytes, err := json.Marshal(resp) + if err != nil { + t.Errorf("JSON encoding error: %s", err) + respBytes = []byte("{\"message\": \"JSON encoding error\"}") + } + if _, err := w.Write(respBytes); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return + t.Errorf("Response write error: %s", err) } }) + + return s +} + +type HandlerFunc func(req Request) any + +func (s *Server) Handle(method, path string, handler HandlerFunc) { + s.Router.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + // For simplicity we process requests sequentially. It's fast enough because + // we don't do any IO except reading and writing request/response bodies. + s.mu.Lock() + defer s.mu.Unlock() + + // Each test uses unique DATABRICKS_TOKEN, we simulate each token having + // it's own fake fakeWorkspace to avoid interference between tests. + var fakeWorkspace *FakeWorkspace = nil + token := getToken(r) + if token != "" { + if _, ok := s.fakeWorkspaces[token]; !ok { + s.fakeWorkspaces[token] = NewFakeWorkspace() + } + + fakeWorkspace = s.fakeWorkspaces[token] + } + + request := NewRequest(s.t, r, fakeWorkspace) + if s.RecordRequestsCallback != nil { + s.RecordRequestsCallback(&request) + } + respAny := handler(request) + resp := normalizeResponse(s.t, respAny) + + for k, v := range resp.Headers { + w.Header()[k] = v + } + + w.WriteHeader(resp.StatusCode) + + if _, err := w.Write(resp.Body); err != nil { + s.t.Errorf("Failed to write response: %s", err) + return + } + }).Methods(method) +} + +func getToken(r *http.Request) string { + header := r.Header.Get("Authorization") + prefix := "Bearer " + + if !strings.HasPrefix(header, prefix) { + return "" + } + + return header[len(prefix):] +} + +func isNil(i any) bool { + if i == nil { + return true + } + v := reflect.ValueOf(i) + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice: + return v.IsNil() + default: + return false + } } diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 000000000..802a3ca67 --- /dev/null +++ b/ruff.toml @@ -0,0 +1 @@ +line-length = 150