diff --git a/.nextchanges/bundles/4630.md b/.nextchanges/bundles/4630.md new file mode 100644 index 00000000000..73d60dfceb6 --- /dev/null +++ b/.nextchanges/bundles/4630.md @@ -0,0 +1 @@ +* Add `lifecycle.bind` to resources to bring an existing workspace resource under bundle management at deploy time instead of creating a new one. The first deploy adopts the resource (`bind`) and applies the configuration if it differs (`bind_and_update`); while the block is present, deploys cannot recreate the resource, and `bundle destroy` still deletes it. ([#4630](https://github.com/databricks/cli/pull/4630), [#7321](https://github.com/databricks/cli/pull/7321)) diff --git a/acceptance/bundle/deploy/bind/basic/databricks.yml b/acceptance/bundle/deploy/bind/basic/databricks.yml new file mode 100644 index 00000000000..5a33ba1ced8 --- /dev/null +++ b/acceptance/bundle/deploy/bind/basic/databricks.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-basic-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/basic/hello.py b/acceptance/bundle/deploy/bind/basic/hello.py new file mode 100644 index 00000000000..11b15b1a458 --- /dev/null +++ b/acceptance/bundle/deploy/bind/basic/hello.py @@ -0,0 +1 @@ +print("hello") diff --git a/acceptance/bundle/deploy/bind/basic/out.test.toml b/acceptance/bundle/deploy/bind/basic/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/basic/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/basic/output.txt b/acceptance/bundle/deploy/bind/basic/output.txt new file mode 100644 index 00000000000..4bbb8bff679 --- /dev/null +++ b/acceptance/bundle/deploy/bind/basic/output.txt @@ -0,0 +1,65 @@ + +>>> [CLI] bundle plan +bind_and_update jobs.foo (id: [NEW_JOB_ID]) + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-basic-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Files: 2 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +>>> [CLI] bundle plan +Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged + +>>> print_state.py +{ + "state_version": 3, + "cli_version": "[CLI_VERSION]", + "lineage": "[UUID]", + "serial": 1, + "state": { + "resources.jobs.foo": { + "__id__": "[NEW_JOB_ID]", + "state": { + "deployment": { + "kind": "BUNDLE", + "metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/test-bind-basic-[UNIQUE_NAME]/default/state/metadata.json" + }, + "edit_mode": "UI_LOCKED", + "environments": [ + { + "environment_key": "default", + "spec": { + "client": "1" + } + } + ], + "format": "MULTI_TASK", + "max_concurrent_runs": 1, + "name": "test-bind-job", + "queue": { + "enabled": true + }, + "tasks": [ + { + "environment_key": "default", + "spark_python_task": { + "python_file": "/Workspace/Users/[USERNAME]/.bundle/test-bind-basic-[UNIQUE_NAME]/default/files/hello.py" + }, + "task_key": "my_task" + } + ] + } + } + } +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-basic-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/basic/script b/acceptance/bundle/deploy/bind/basic/script new file mode 100644 index 00000000000..557be0c9b33 --- /dev/null +++ b/acceptance/bundle/deploy/bind/basic/script @@ -0,0 +1,25 @@ +# Bundle names carry $UNIQUE_NAME so concurrent runs on the same workspace do not share +# a root path and its deployment lock. +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-import-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID + +# Update the databricks.yml with the actual job ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +# Run plan - should show import action +trace $CLI bundle plan + +# Deploy with auto-approve +trace $CLI bundle deploy --auto-approve + +# Plan again - should show no changes (skip) +trace $CLI bundle plan + +# Verify state file contains the imported ID +trace print_state.py | contains.py "$NEW_JOB_ID" + +# Cleanup: destroy is allowed even with an active bind block +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/bind-and-resize/databricks.yml.tmpl b/acceptance/bundle/deploy/bind/bind-and-resize/databricks.yml.tmpl new file mode 100644 index 00000000000..6332e9f172d --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-resize/databricks.yml.tmpl @@ -0,0 +1,16 @@ +bundle: + name: test-bind-resize + +workspace: + root_path: ~/.bundle/$UNIQUE_NAME + +resources: + clusters: + test_cluster: + cluster_name: test-cluster-$UNIQUE_NAME + spark_version: $DEFAULT_SPARK_VERSION + instance_pool_id: $TEST_INSTANCE_POOL_ID + num_workers: 3 + lifecycle: + bind: + id: "PLACEHOLDER_CLUSTER_ID" diff --git a/acceptance/bundle/deploy/bind/bind-and-resize/out.test.toml b/acceptance/bundle/deploy/bind/bind-and-resize/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-resize/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/bind-and-resize/output.txt b/acceptance/bundle/deploy/bind/bind-and-resize/output.txt new file mode 100644 index 00000000000..5e7ecc9f876 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-resize/output.txt @@ -0,0 +1,37 @@ + +>>> [CLI] bundle plan +bind_and_update clusters.test_cluster (id: [CLUSTER_ID]) + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/[UNIQUE_NAME]/files... +Bound and updated clusters.test_cluster +Files: 2 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +>>> print_requests.py //clusters/resize //clusters/edit +{ + "method": "POST", + "path": "/api/2.1/clusters/resize", + "body": { + "cluster_id": "[CLUSTER_ID]", + "num_workers": 3 + } +} + +=== Cluster should have new num_workers + +>>> [CLI] clusters get [CLUSTER_ID] +{ + "cluster_name": "test-cluster-[UNIQUE_NAME]", + "num_workers": 3 +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.clusters.test_cluster + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/[UNIQUE_NAME] + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/bind-and-resize/script b/acceptance/bundle/deploy/bind/bind-and-resize/script new file mode 100644 index 00000000000..271eaf9d447 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-resize/script @@ -0,0 +1,26 @@ +envsubst < databricks.yml.tmpl > databricks.yml + +# Create a cluster out-of-band, then bring it to RUNNING so that a num_workers +# change is planned as a resize rather than an edit. The cluster uses an instance +# pool only: the API rejects node_type_id together with instance_pool_id. +CLUSTER_ID=$($CLI clusters create --json "{\"cluster_name\": \"test-cluster-$UNIQUE_NAME\", \"spark_version\": \"$DEFAULT_SPARK_VERSION\", \"instance_pool_id\": \"$TEST_INSTANCE_POOL_ID\", \"num_workers\": 2, \"autotermination_minutes\": 60}" | jq -r .cluster_id) +add_repl.py "$CLUSTER_ID" CLUSTER_ID +update_file.py databricks.yml 'PLACEHOLDER_CLUSTER_ID' "$CLUSTER_ID" + +# Transition PENDING -> RUNNING (ClustersGet promotes the state). +$CLI clusters get "$CLUSTER_ID" > /dev/null + +# Plan: config differs only in num_workers, so the bound running cluster is +# planned as bind_and_update backed by a resize. +trace $CLI bundle plan + +# Deploy: bind_and_update must go through the resize API, not clusters/edit. +trace $CLI bundle deploy --auto-approve +trace print_requests.py //clusters/resize //clusters/edit + +title "Cluster should have new num_workers\n" +trace $CLI clusters get "$CLUSTER_ID" | jq '{cluster_name,num_workers}' + +# Cleanup +trace $CLI bundle destroy --auto-approve +rm -f out.requests.txt diff --git a/acceptance/bundle/deploy/bind/bind-and-resize/test.toml b/acceptance/bundle/deploy/bind/bind-and-resize/test.toml new file mode 100644 index 00000000000..e7593c38d40 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-resize/test.toml @@ -0,0 +1,3 @@ +RecordRequests = true + +Ignore = [".databricks", "databricks.yml"] diff --git a/acceptance/bundle/deploy/bind/bind-and-update/databricks.yml b/acceptance/bundle/deploy/bind/bind-and-update/databricks.yml new file mode 100644 index 00000000000..0c5a6a9fa9e --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-update/databricks.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-update-UNIQUE_NAME + +resources: + jobs: + foo: + name: updated-job-name + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/bind-and-update/hello.py b/acceptance/bundle/deploy/bind/bind-and-update/hello.py new file mode 100644 index 00000000000..11b15b1a458 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-update/hello.py @@ -0,0 +1 @@ +print("hello") diff --git a/acceptance/bundle/deploy/bind/bind-and-update/out.test.toml b/acceptance/bundle/deploy/bind/bind-and-update/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-update/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/bind-and-update/output.txt b/acceptance/bundle/deploy/bind/bind-and-update/output.txt new file mode 100644 index 00000000000..202baea71d5 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-update/output.txt @@ -0,0 +1,36 @@ + +>>> [CLI] bundle plan +bind_and_update jobs.foo (id: [NEW_JOB_ID]) + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-update-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Files: 2 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +>>> [CLI] jobs get [NEW_JOB_ID] +updated-job-name + +>>> [CLI] bundle plan +update jobs.foo + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-update-[UNIQUE_NAME]/default/files... +Updated jobs.foo +Files: 1 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged + +>>> [CLI] jobs get [NEW_JOB_ID] +second-update-name + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-update-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/bind-and-update/script b/acceptance/bundle/deploy/bind/bind-and-update/script new file mode 100644 index 00000000000..60a64f29814 --- /dev/null +++ b/acceptance/bundle/deploy/bind/bind-and-update/script @@ -0,0 +1,30 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace with a different name +NEW_JOB_ID=$($CLI jobs create --json '{"name": "original-job-name", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID + +# Update the databricks.yml with the actual job ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +# Run plan - should show bind action (name differs from config) +trace $CLI bundle plan + +# Deploy with auto-approve +trace $CLI bundle deploy --auto-approve + +# Verify the job was updated +trace $CLI jobs get $NEW_JOB_ID | jq -r .settings.name + +# Now update the job name again in the config and deploy again. +# This time the action should be "update", not "bind", since the resource +# is already bound in state. +update_file.py databricks.yml 'updated-job-name' 'second-update-name' +trace $CLI bundle plan +trace $CLI bundle deploy --auto-approve + +# Verify the job was updated with the second name +trace $CLI jobs get $NEW_JOB_ID | jq -r .settings.name + +# Cleanup: destroy is allowed even with an active bind block +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/block-removed/databricks.yml b/acceptance/bundle/deploy/bind/block-removed/databricks.yml new file mode 100644 index 00000000000..cb7b2234af8 --- /dev/null +++ b/acceptance/bundle/deploy/bind/block-removed/databricks.yml @@ -0,0 +1,14 @@ +bundle: + name: test-bind-block-removed-UNIQUE_NAME + +resources: + pipelines: + foo: + name: test-pipeline + storage: /old/storage/path + libraries: + - notebook: + path: ./nb.sql + lifecycle: + bind: + id: "PLACEHOLDER_PIPELINE_ID" diff --git a/acceptance/bundle/deploy/bind/block-removed/databricks_unbound.yml b/acceptance/bundle/deploy/bind/block-removed/databricks_unbound.yml new file mode 100644 index 00000000000..1632bfce959 --- /dev/null +++ b/acceptance/bundle/deploy/bind/block-removed/databricks_unbound.yml @@ -0,0 +1,11 @@ +bundle: + name: test-bind-block-removed-UNIQUE_NAME + +resources: + pipelines: + foo: + name: test-pipeline + storage: /new/storage/path + libraries: + - notebook: + path: ./nb.sql diff --git a/acceptance/bundle/deploy/bind/block-removed/nb.sql b/acceptance/bundle/deploy/bind/block-removed/nb.sql new file mode 100644 index 00000000000..199ff507884 --- /dev/null +++ b/acceptance/bundle/deploy/bind/block-removed/nb.sql @@ -0,0 +1,2 @@ +-- Databricks notebook source +select 1 diff --git a/acceptance/bundle/deploy/bind/block-removed/out.test.toml b/acceptance/bundle/deploy/bind/block-removed/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/block-removed/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/block-removed/output.txt b/acceptance/bundle/deploy/bind/block-removed/output.txt new file mode 100644 index 00000000000..33cba18f69d --- /dev/null +++ b/acceptance/bundle/deploy/bind/block-removed/output.txt @@ -0,0 +1,24 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-block-removed-[UNIQUE_NAME]/default/files... +Bound and updated pipelines.foo +Files: 3 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +=== Removing the bind block is the opt-out: with it gone, the same storage change plans a recreate +>>> [CLI] bundle plan +recreate pipelines.foo + +Plan: 1 to add, 0 to change, 1 to delete, 0 unchanged + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.pipelines.foo + +This action will result in the deletion of the following Lakeflow Spark Declarative Pipelines along with the +Streaming Tables (STs) and Materialized Views (MVs) managed by them. Set 'cascade_on_destroy: false' on a pipeline to retain datasets on pipeline deletion: + delete resources.pipelines.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-block-removed-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/block-removed/script b/acceptance/bundle/deploy/bind/block-removed/script new file mode 100644 index 00000000000..4b75a1748be --- /dev/null +++ b/acceptance/bundle/deploy/bind/block-removed/script @@ -0,0 +1,16 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" +update_file.py databricks_unbound.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a pipeline whose storage matches the config and bind it +NEW_PIPELINE_ID=$($CLI pipelines create --json '{"name": "test-pipeline", "storage": "/old/storage/path", "allow_duplicate_names": true, "libraries": [{"notebook": {"path": "/Workspace/test"}}]}' | jq -r .pipeline_id) +add_repl.py $NEW_PIPELINE_ID NEW_PIPELINE_ID +update_file.py databricks.yml 'PLACEHOLDER_PIPELINE_ID' "$NEW_PIPELINE_ID" + +trace $CLI bundle deploy --auto-approve + +title "Removing the bind block is the opt-out: with it gone, the same storage change plans a recreate" +cp databricks_unbound.yml databricks.yml +trace $CLI bundle plan + +# Cleanup +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/block-removed/test.toml b/acceptance/bundle/deploy/bind/block-removed/test.toml new file mode 100644 index 00000000000..a65df196368 --- /dev/null +++ b/acceptance/bundle/deploy/bind/block-removed/test.toml @@ -0,0 +1 @@ +Ignore = [".databricks", "databricks_unbound.yml"] diff --git a/acceptance/bundle/deploy/bind/delete-and-bind-conflict/databricks.yml b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/databricks.yml new file mode 100644 index 00000000000..ae172299eed --- /dev/null +++ b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/databricks.yml @@ -0,0 +1,16 @@ +bundle: + name: test-bind-delete-conflict-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-delete-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py diff --git a/acceptance/bundle/deploy/bind/delete-and-bind-conflict/databricks_conflict.yml b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/databricks_conflict.yml new file mode 100644 index 00000000000..0232d1f092b --- /dev/null +++ b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/databricks_conflict.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-delete-conflict-UNIQUE_NAME + +resources: + jobs: + bar: + name: test-bind-delete-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/delete-and-bind-conflict/hello.py b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/hello.py new file mode 100644 index 00000000000..11b15b1a458 --- /dev/null +++ b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/hello.py @@ -0,0 +1 @@ +print("hello") diff --git a/acceptance/bundle/deploy/bind/delete-and-bind-conflict/out.test.toml b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/delete-and-bind-conflict/output.txt b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/output.txt new file mode 100644 index 00000000000..065a7f6cbc7 --- /dev/null +++ b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/output.txt @@ -0,0 +1,22 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-delete-conflict-[UNIQUE_NAME]/default/files... +Created jobs.foo +Files: 3 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +>>> musterr [CLI] bundle plan +Error: resources.jobs.bar has the same lifecycle.bind ID "[FOO_ID]" as existing resource "resources.jobs.foo"; remove lifecycle.bind or the conflicting resource + at resources.jobs.bar.lifecycle.bind.id + in databricks.yml:19:15 + +Error: bind validation failed + + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-delete-conflict-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/delete-and-bind-conflict/script b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/script new file mode 100644 index 00000000000..df869e60a36 --- /dev/null +++ b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/script @@ -0,0 +1,21 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" +update_file.py databricks_conflict.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Deploy foo to create it in state +trace $CLI bundle deploy --auto-approve + +# Get the job ID from state +JOB_ID=$(read_id.py foo) + +# Switch to a config that renames foo->bar and adds a bind block for bar +# with the same job ID. This creates a conflict: foo is being deleted +# (still in state) while bar is being bound with the same ID. +cp databricks.yml databricks.yml.bak +cp databricks_conflict.yml databricks.yml +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$JOB_ID" + +trace musterr $CLI bundle plan + +# Cleanup: restore original config and destroy +cp databricks.yml.bak databricks.yml +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/delete-and-bind-conflict/test.toml b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/test.toml new file mode 100644 index 00000000000..a07a7675610 --- /dev/null +++ b/acceptance/bundle/deploy/bind/delete-and-bind-conflict/test.toml @@ -0,0 +1 @@ +Ignore = [".databricks", "databricks.yml.bak", "databricks_conflict.yml"] diff --git a/acceptance/bundle/deploy/bind/destroy-allowed/databricks.yml b/acceptance/bundle/deploy/bind/destroy-allowed/databricks.yml new file mode 100644 index 00000000000..59f39207f6a --- /dev/null +++ b/acceptance/bundle/deploy/bind/destroy-allowed/databricks.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-destroy-allowed-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/destroy-allowed/hello.py b/acceptance/bundle/deploy/bind/destroy-allowed/hello.py new file mode 100644 index 00000000000..11b15b1a458 --- /dev/null +++ b/acceptance/bundle/deploy/bind/destroy-allowed/hello.py @@ -0,0 +1 @@ +print("hello") diff --git a/acceptance/bundle/deploy/bind/destroy-allowed/out.test.toml b/acceptance/bundle/deploy/bind/destroy-allowed/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/destroy-allowed/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/destroy-allowed/output.txt b/acceptance/bundle/deploy/bind/destroy-allowed/output.txt new file mode 100644 index 00000000000..88283729e0a --- /dev/null +++ b/acceptance/bundle/deploy/bind/destroy-allowed/output.txt @@ -0,0 +1,14 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-destroy-allowed-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Files: 2 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-destroy-allowed-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/destroy-allowed/script b/acceptance/bundle/deploy/bind/destroy-allowed/script new file mode 100644 index 00000000000..2ca53089a89 --- /dev/null +++ b/acceptance/bundle/deploy/bind/destroy-allowed/script @@ -0,0 +1,15 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID + +# Update the databricks.yml with the actual job ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +# Deploy to bind the resource into state +trace $CLI bundle deploy --auto-approve + +# Destroy is allowed even with an active bind block: naming destroy explicitly +# captures the intent to tear the deployment down. +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/dev-mode/databricks.yml b/acceptance/bundle/deploy/bind/dev-mode/databricks.yml new file mode 100644 index 00000000000..723742f381a --- /dev/null +++ b/acceptance/bundle/deploy/bind/dev-mode/databricks.yml @@ -0,0 +1,26 @@ +bundle: + name: test-bind-dev-mode + +resources: + jobs: + foo: + name: test-bind-job + schedule: + quartz_cron_expression: "0 0 12 * * ?" + timezone_id: UTC + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" + +targets: + default: + mode: development diff --git a/acceptance/bundle/deploy/bind/dev-mode/out.test.toml b/acceptance/bundle/deploy/bind/dev-mode/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/dev-mode/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/dev-mode/output.txt b/acceptance/bundle/deploy/bind/dev-mode/output.txt new file mode 100644 index 00000000000..0cd894c31d8 --- /dev/null +++ b/acceptance/bundle/deploy/bind/dev-mode/output.txt @@ -0,0 +1,10 @@ + +>>> [CLI] bundle plan +bind_and_update jobs.foo (id: [NEW_JOB_ID]) + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind + +>>> [CLI] bundle plan -o json +json.plan.resources.jobs.foo.changes.name.new = "[dev [USERNAME]] test-bind-job"; +json.plan.resources.jobs.foo.changes.schedule.pause_status.new = "PAUSED"; +json.plan.resources.jobs.foo.changes.tags.new.dev = "[USERNAME]"; diff --git a/acceptance/bundle/deploy/bind/dev-mode/script b/acceptance/bundle/deploy/bind/dev-mode/script new file mode 100644 index 00000000000..63f6344a41c --- /dev/null +++ b/acceptance/bundle/deploy/bind/dev-mode/script @@ -0,0 +1,11 @@ +# Binding in development mode applies the mode's transformations to the adopted +# resource: it is renamed with the [dev ] prefix, its schedule is paused and +# it is tagged. The plan is the only place that shows this before it happens. +# Only the new values are listed: the remote side differs between the test server +# and a real workspace (which reports pause_status: UNPAUSED). +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "schedule": {"quartz_cron_expression": "0 0 12 * * ?", "timezone_id": "UTC"}, "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle plan +trace $CLI bundle plan -o json | gron.py | grep -E 'changes\.(name|schedule|tags)\S*\.new' diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id-config/databricks.yml b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/databricks.yml new file mode 100644 index 00000000000..3820ee5551e --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/databricks.yml @@ -0,0 +1,33 @@ +bundle: + name: test-bind-duplicate-id-config + +resources: + jobs: + foo: + name: test-bind-dup-config-foo + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "12345" + bar: + name: test-bind-dup-config-bar + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "12345" diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id-config/hello.py b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/hello.py new file mode 100644 index 00000000000..11b15b1a458 --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/hello.py @@ -0,0 +1 @@ +print("hello") diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id-config/out.test.toml b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id-config/output.txt b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/output.txt new file mode 100644 index 00000000000..6f22c9a60cb --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/output.txt @@ -0,0 +1,12 @@ + +>>> musterr [CLI] bundle plan +Error: resources.jobs.bar has the same lifecycle.bind ID "12345" as resources.jobs.foo; each workspace resource can only be bound once + at resources.jobs.bar.lifecycle.bind.id + in databricks.yml:33:15 + +Error: resources.jobs.foo has the same lifecycle.bind ID "12345" as resources.jobs.bar; each workspace resource can only be bound once + at resources.jobs.foo.lifecycle.bind.id + in databricks.yml:19:15 + +Error: bind validation failed + diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id-config/script b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/script new file mode 100644 index 00000000000..6c1284521fe --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id-config/script @@ -0,0 +1,3 @@ +# Two first-time bind blocks pointing at the same workspace ID must be rejected; +# otherwise both would create state entries managing one remote resource. +trace musterr $CLI bundle plan diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id/databricks.yml b/acceptance/bundle/deploy/bind/duplicate-bind-id/databricks.yml new file mode 100644 index 00000000000..6db6bc7d2ed --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id/databricks.yml @@ -0,0 +1,16 @@ +bundle: + name: test-bind-duplicate-id-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-dup-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id/databricks_with_bind.yml b/acceptance/bundle/deploy/bind/duplicate-bind-id/databricks_with_bind.yml new file mode 100644 index 00000000000..234b22fd66b --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id/databricks_with_bind.yml @@ -0,0 +1,30 @@ +bundle: + name: test-bind-duplicate-id-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-dup-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + bar: + name: test-bind-dup-bar + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id/hello.py b/acceptance/bundle/deploy/bind/duplicate-bind-id/hello.py new file mode 100644 index 00000000000..11b15b1a458 --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id/hello.py @@ -0,0 +1 @@ +print("hello") diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id/out.test.toml b/acceptance/bundle/deploy/bind/duplicate-bind-id/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id/output.txt b/acceptance/bundle/deploy/bind/duplicate-bind-id/output.txt new file mode 100644 index 00000000000..744bb060309 --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id/output.txt @@ -0,0 +1,22 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-duplicate-id-[UNIQUE_NAME]/default/files... +Created jobs.foo +Files: 3 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +>>> musterr [CLI] bundle plan +Error: resources.jobs.bar has the same lifecycle.bind ID "[FOO_ID]" as existing resource "resources.jobs.foo"; remove lifecycle.bind or the conflicting resource + at resources.jobs.bar.lifecycle.bind.id + in databricks.yml:30:15 + +Error: bind validation failed + + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-duplicate-id-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id/script b/acceptance/bundle/deploy/bind/duplicate-bind-id/script new file mode 100644 index 00000000000..4ca237bffb0 --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id/script @@ -0,0 +1,21 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" +update_file.py databricks_with_bind.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Deploy foo to create it in state +trace $CLI bundle deploy --auto-approve + +# Get foo's job ID from state +JOB_ID=$(read_id.py foo) + +# Switch to a config that keeps foo AND adds bar with a bind block +# pointing to foo's ID. This is a conflict: foo is still managed in +# state and bar tries to bind the same resource ID. +cp databricks.yml databricks.yml.bak +cp databricks_with_bind.yml databricks.yml +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$JOB_ID" + +trace musterr $CLI bundle plan + +# Cleanup +cp databricks.yml.bak databricks.yml +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/duplicate-bind-id/test.toml b/acceptance/bundle/deploy/bind/duplicate-bind-id/test.toml new file mode 100644 index 00000000000..f70b5c78fff --- /dev/null +++ b/acceptance/bundle/deploy/bind/duplicate-bind-id/test.toml @@ -0,0 +1 @@ +Ignore = [".databricks", "databricks.yml.bak", "databricks_with_bind.yml"] diff --git a/acceptance/bundle/deploy/bind/gone-in-state/databricks.yml b/acceptance/bundle/deploy/bind/gone-in-state/databricks.yml new file mode 100644 index 00000000000..297233c545e --- /dev/null +++ b/acceptance/bundle/deploy/bind/gone-in-state/databricks.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-gone-in-state-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/gone-in-state/out.test.toml b/acceptance/bundle/deploy/bind/gone-in-state/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/gone-in-state/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/gone-in-state/output.txt b/acceptance/bundle/deploy/bind/gone-in-state/output.txt new file mode 100644 index 00000000000..bfebd09896d --- /dev/null +++ b/acceptance/bundle/deploy/bind/gone-in-state/output.txt @@ -0,0 +1,28 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-gone-in-state-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Files: 1 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +=== Delete the bound job out-of-band: the bind block pins that ID, so the deploy must not create a replacement +>>> [CLI] jobs delete [NEW_JOB_ID] + +>>> musterr [CLI] bundle plan +Error: cannot plan resources.jobs.foo: bound resource with ID "[NEW_JOB_ID]" no longer exists in the workspace; remove lifecycle.bind to create a new resource + +Error: planning failed + + +>>> musterr [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-gone-in-state-[UNIQUE_NAME]/default/files... +Error: cannot plan resources.jobs.foo: bound resource with ID "[NEW_JOB_ID]" no longer exists in the workspace; remove lifecycle.bind to create a new resource + +Error: planning failed + +Files: 0 uploaded, 0 deleted + +>>> [CLI] bundle destroy --auto-approve +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-gone-in-state-[UNIQUE_NAME]/default + +Destroy: 0 deleted diff --git a/acceptance/bundle/deploy/bind/gone-in-state/script b/acceptance/bundle/deploy/bind/gone-in-state/script new file mode 100644 index 00000000000..049e1cce043 --- /dev/null +++ b/acceptance/bundle/deploy/bind/gone-in-state/script @@ -0,0 +1,16 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace and bind it +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle deploy --auto-approve + +title "Delete the bound job out-of-band: the bind block pins that ID, so the deploy must not create a replacement" +trace $CLI jobs delete $NEW_JOB_ID +trace musterr $CLI bundle plan +trace musterr $CLI bundle deploy --auto-approve + +# Cleanup: the job is already gone, destroy only drops the state entry +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/id-collision-different-type/databricks.yml b/acceptance/bundle/deploy/bind/id-collision-different-type/databricks.yml new file mode 100644 index 00000000000..8e5f17f4c89 --- /dev/null +++ b/acceptance/bundle/deploy/bind/id-collision-different-type/databricks.yml @@ -0,0 +1,16 @@ +bundle: + name: test-bind-id-collision-type-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-collision-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py diff --git a/acceptance/bundle/deploy/bind/id-collision-different-type/databricks_with_bind.yml b/acceptance/bundle/deploy/bind/id-collision-different-type/databricks_with_bind.yml new file mode 100644 index 00000000000..06987427d19 --- /dev/null +++ b/acceptance/bundle/deploy/bind/id-collision-different-type/databricks_with_bind.yml @@ -0,0 +1,22 @@ +bundle: + name: test-bind-id-collision-type-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-collision-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + experiments: + exp: + name: /Shared/test-bind-collision-exp + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/id-collision-different-type/out.test.toml b/acceptance/bundle/deploy/bind/id-collision-different-type/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/id-collision-different-type/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/id-collision-different-type/output.txt b/acceptance/bundle/deploy/bind/id-collision-different-type/output.txt new file mode 100644 index 00000000000..4ef65c527d3 --- /dev/null +++ b/acceptance/bundle/deploy/bind/id-collision-different-type/output.txt @@ -0,0 +1,20 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-id-collision-type-[UNIQUE_NAME]/default/files... +Created jobs.foo +Files: 2 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +>>> musterr [CLI] bundle plan +Error: cannot bind resources.experiments.exp: resource with ID "[FOO_ID]" does not exist in workspace + +Error: planning failed + + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-id-collision-type-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/id-collision-different-type/script b/acceptance/bundle/deploy/bind/id-collision-different-type/script new file mode 100644 index 00000000000..ca4191ec385 --- /dev/null +++ b/acceptance/bundle/deploy/bind/id-collision-different-type/script @@ -0,0 +1,19 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" +update_file.py databricks_with_bind.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Deploy foo to create it in state +trace $CLI bundle deploy --auto-approve + +JOB_ID=$(read_id.py foo) + +# Bind an experiment whose ID happens to equal the job's ID. IDs are only unique +# per resource type, so this is not a collision with jobs.foo; the bind proceeds and +# fails only because no experiment with that ID exists. +cp databricks.yml databricks.yml.bak +cp databricks_with_bind.yml databricks.yml +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$JOB_ID" +trace musterr $CLI bundle plan + +# Cleanup +cp databricks.yml.bak databricks.yml +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/id-collision-different-type/test.toml b/acceptance/bundle/deploy/bind/id-collision-different-type/test.toml new file mode 100644 index 00000000000..f70b5c78fff --- /dev/null +++ b/acceptance/bundle/deploy/bind/id-collision-different-type/test.toml @@ -0,0 +1 @@ +Ignore = [".databricks", "databricks.yml.bak", "databricks_with_bind.yml"] diff --git a/acceptance/bundle/deploy/bind/int-id/databricks.yml b/acceptance/bundle/deploy/bind/int-id/databricks.yml new file mode 100644 index 00000000000..b8d623b657c --- /dev/null +++ b/acceptance/bundle/deploy/bind/int-id/databricks.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-int-id + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: PLACEHOLDER_JOB_ID diff --git a/acceptance/bundle/deploy/bind/int-id/out.test.toml b/acceptance/bundle/deploy/bind/int-id/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/int-id/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/int-id/output.txt b/acceptance/bundle/deploy/bind/int-id/output.txt new file mode 100644 index 00000000000..06ee8a67f28 --- /dev/null +++ b/acceptance/bundle/deploy/bind/int-id/output.txt @@ -0,0 +1,5 @@ + +>>> [CLI] bundle plan +bind_and_update jobs.foo (id: [NEW_JOB_ID]) + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind diff --git a/acceptance/bundle/deploy/bind/int-id/script b/acceptance/bundle/deploy/bind/int-id/script new file mode 100644 index 00000000000..b1c6700e046 --- /dev/null +++ b/acceptance/bundle/deploy/bind/int-id/script @@ -0,0 +1,6 @@ +# An unquoted ID is parsed by YAML as an integer and must normalize to the string ID. +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle plan diff --git a/acceptance/bundle/deploy/bind/pure-bind/databricks.yml b/acceptance/bundle/deploy/bind/pure-bind/databricks.yml new file mode 100644 index 00000000000..1dc0f3557c2 --- /dev/null +++ b/acceptance/bundle/deploy/bind/pure-bind/databricks.yml @@ -0,0 +1,22 @@ +bundle: + name: test-bind-pure-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + permissions: + - group_name: users + level: CAN_VIEW + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/pure-bind/out.test.toml b/acceptance/bundle/deploy/bind/pure-bind/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/pure-bind/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/pure-bind/output.txt b/acceptance/bundle/deploy/bind/pure-bind/output.txt new file mode 100644 index 00000000000..6ad11bb2f42 --- /dev/null +++ b/acceptance/bundle/deploy/bind/pure-bind/output.txt @@ -0,0 +1,54 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-pure-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Created jobs.foo.permissions +Files: 1 uploaded, 0 deleted +Resources: 1 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +=== Unbind the job. The bind block is still in config, so the next deploy re-binds it +>>> [CLI] bundle deployment unbind foo +Warning: resources.jobs.foo.lifecycle.bind re-binds the resource on the next deploy; remove it to keep the resource unbound + at resources.jobs.foo.lifecycle.bind + in databricks.yml:22:11 + + +=== The job now matches the config, so this is a pure bind +>>> [CLI] bundle plan +bind jobs.foo (id: [NEW_JOB_ID]) +create jobs.foo.permissions + +Plan: 1 to add, 0 to change, 0 to delete, 0 unchanged, 1 to bind + +>>> [CLI] bundle plan -o json +json.plan.resources.jobs.foo.bind_id = "[NEW_JOB_ID]"; +json.plan.resources.jobs.foo.action = "bind"; + +>>> print_requests.py --get --oneline //jobs/get +{"method": "GET", "path": "/api/2.2/jobs/get", "q": {"job_id": "[NEW_JOB_ID]"}} +{"method": "GET", "path": "/api/2.2/jobs/get", "q": {"job_id": "[NEW_JOB_ID]"}} +{"method": "GET", "path": "/api/2.2/jobs/get", "q": {"job_id": "[NEW_JOB_ID]"}} +{"method": "GET", "path": "/api/2.2/jobs/get", "q": {"job_id": "[NEW_JOB_ID]"}} + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-pure-[UNIQUE_NAME]/default/files... +Bound jobs.foo +Created jobs.foo.permissions +Files: 0 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged, 1 bound + +=== The re-bind deploy reads the job once, at plan time +>>> print_requests.py --get --oneline //jobs/get +{"method": "GET", "path": "/api/2.2/jobs/get", "q": {"job_id": "[NEW_JOB_ID]"}} + +>>> print_state.py +json.state.resources.jobs.foo.__id__ = "[NEW_JOB_ID]"; +json.state.resources.jobs.foo.permissions.__id__ = "/jobs/[NEW_JOB_ID]"; + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-pure-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/pure-bind/script b/acceptance/bundle/deploy/bind/pure-bind/script new file mode 100644 index 00000000000..45a1f4a056b --- /dev/null +++ b/acceptance/bundle/deploy/bind/pure-bind/script @@ -0,0 +1,27 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace and bind it; the first deploy is a bind_and_update +# because the bundle sets fields such as deployment and edit_mode on every job. +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle deploy --auto-approve + +title "Unbind the job. The bind block is still in config, so the next deploy re-binds it" +trace $CLI bundle deployment unbind foo + +title "The job now matches the config, so this is a pure bind" +trace $CLI bundle plan +trace $CLI bundle plan -o json | gron.py | grep -E 'jobs\.foo\.(action|bind_id)' + +trace print_requests.py --get --oneline //jobs/get +trace $CLI bundle deploy --auto-approve + +title "The re-bind deploy reads the job once, at plan time" +trace print_requests.py --get --oneline //jobs/get +trace print_state.py | gron.py | grep __id__ + +# Cleanup +trace $CLI bundle destroy --auto-approve +rm -f out.requests.txt diff --git a/acceptance/bundle/deploy/bind/pure-bind/test.toml b/acceptance/bundle/deploy/bind/pure-bind/test.toml new file mode 100644 index 00000000000..159efe02696 --- /dev/null +++ b/acceptance/bundle/deploy/bind/pure-bind/test.toml @@ -0,0 +1 @@ +RecordRequests = true diff --git a/acceptance/bundle/deploy/bind/rebind-different-id/databricks.yml b/acceptance/bundle/deploy/bind/rebind-different-id/databricks.yml new file mode 100644 index 00000000000..34c1ecf3a82 --- /dev/null +++ b/acceptance/bundle/deploy/bind/rebind-different-id/databricks.yml @@ -0,0 +1,16 @@ +bundle: + name: test-bind-rebind-different-id-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py diff --git a/acceptance/bundle/deploy/bind/rebind-different-id/databricks_with_bind.yml b/acceptance/bundle/deploy/bind/rebind-different-id/databricks_with_bind.yml new file mode 100644 index 00000000000..40e85d37a0e --- /dev/null +++ b/acceptance/bundle/deploy/bind/rebind-different-id/databricks_with_bind.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-rebind-different-id-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: "999999999" diff --git a/acceptance/bundle/deploy/bind/rebind-different-id/out.test.toml b/acceptance/bundle/deploy/bind/rebind-different-id/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/rebind-different-id/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/rebind-different-id/output.txt b/acceptance/bundle/deploy/bind/rebind-different-id/output.txt new file mode 100644 index 00000000000..1bbd0c4cc7b --- /dev/null +++ b/acceptance/bundle/deploy/bind/rebind-different-id/output.txt @@ -0,0 +1,23 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-rebind-different-id-[UNIQUE_NAME]/default/files... +Created jobs.foo +Files: 2 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +=== A bind block for a resource already in state must carry the state ID; a different ID is not a re-point +>>> musterr [CLI] bundle plan +Error: resources.jobs.foo: resource already bound to ID "[FOO_ID]", cannot bind as "999999999"; remove lifecycle.bind or unbind the existing resource + at resources.jobs.foo.lifecycle.bind.id + in databricks.yml:19:15 + +Error: bind validation failed + + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-rebind-different-id-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/rebind-different-id/script b/acceptance/bundle/deploy/bind/rebind-different-id/script new file mode 100644 index 00000000000..c5d08c6a07c --- /dev/null +++ b/acceptance/bundle/deploy/bind/rebind-different-id/script @@ -0,0 +1,15 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" +update_file.py databricks_with_bind.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Deploy foo to create it in state +trace $CLI bundle deploy --auto-approve +JOB_ID=$(read_id.py foo) + +title "A bind block for a resource already in state must carry the state ID; a different ID is not a re-point" +cp databricks.yml databricks.yml.bak +cp databricks_with_bind.yml databricks.yml +trace musterr $CLI bundle plan + +# Cleanup +cp databricks.yml.bak databricks.yml +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/rebind-different-id/test.toml b/acceptance/bundle/deploy/bind/rebind-different-id/test.toml new file mode 100644 index 00000000000..f70b5c78fff --- /dev/null +++ b/acceptance/bundle/deploy/bind/rebind-different-id/test.toml @@ -0,0 +1 @@ +Ignore = [".databricks", "databricks.yml.bak", "databricks_with_bind.yml"] diff --git a/acceptance/bundle/deploy/bind/recreate-blocked-in-state/databricks.yml b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/databricks.yml new file mode 100644 index 00000000000..9bec38b6a6b --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/databricks.yml @@ -0,0 +1,14 @@ +bundle: + name: test-bind-recreate-in-state-UNIQUE_NAME + +resources: + pipelines: + foo: + name: test-pipeline + storage: /old/storage/path + libraries: + - notebook: + path: ./nb.sql + lifecycle: + bind: + id: "PLACEHOLDER_PIPELINE_ID" diff --git a/acceptance/bundle/deploy/bind/recreate-blocked-in-state/nb.sql b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/nb.sql new file mode 100644 index 00000000000..199ff507884 --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/nb.sql @@ -0,0 +1,2 @@ +-- Databricks notebook source +select 1 diff --git a/acceptance/bundle/deploy/bind/recreate-blocked-in-state/out.test.toml b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/recreate-blocked-in-state/output.txt b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/output.txt new file mode 100644 index 00000000000..69a32ffc21c --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/output.txt @@ -0,0 +1,49 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-recreate-in-state-[UNIQUE_NAME]/default/files... +Bound and updated pipelines.foo +Files: 2 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +>>> musterr [CLI] bundle plan +Error: cannot plan resources.pipelines.foo: lifecycle.bind prevents recreating the bound resource + +This would destroy and recreate the bound workspace resource, changing its ID. + +The following fields cannot be modified because they require resource recreation: + - storage (immutable) + +To resolve this issue, you have two options: + +1. Revert the problematic fields in your configuration to keep the bound resource as it is: + + resources: + pipelines: + foo: + # Remove or comment out these fields: + # storage: ... + +2. Remove lifecycle.bind if you want to allow the resource to be recreated/updated: + + resources: + pipelines: + foo: + lifecycle: + # Remove the bind block: + # bind: + # id: + +Error: planning failed + + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.pipelines.foo + +This action will result in the deletion of the following Lakeflow Spark Declarative Pipelines along with the +Streaming Tables (STs) and Materialized Views (MVs) managed by them. Set 'cascade_on_destroy: false' on a pipeline to retain datasets on pipeline deletion: + delete resources.pipelines.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-recreate-in-state-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/recreate-blocked-in-state/script b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/script new file mode 100644 index 00000000000..e770f80d3cf --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked-in-state/script @@ -0,0 +1,22 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a pipeline whose storage matches the config, so the first deploy binds +# it cleanly (no recreate). +NEW_PIPELINE_ID=$($CLI pipelines create --json '{"name": "test-pipeline", "storage": "/old/storage/path", "allow_duplicate_names": true, "libraries": [{"notebook": {"path": "/Workspace/test"}}]}' | jq -r .pipeline_id) +add_repl.py $NEW_PIPELINE_ID NEW_PIPELINE_ID + +# Update the databricks.yml with the actual pipeline ID +update_file.py databricks.yml 'PLACEHOLDER_PIPELINE_ID' "$NEW_PIPELINE_ID" + +# Deploy to bind the resource into state +trace $CLI bundle deploy --auto-approve + +# Change storage (immutable) while the bind block is still defined. The bind +# block must keep guarding against recreate even after the resource is in state. +# No leading slash in the arguments: Git Bash on Windows would rewrite it as a path. +update_file.py databricks.yml 'old/storage/path' 'new/storage/path' +trace musterr $CLI bundle plan + +# Cleanup +update_file.py databricks.yml 'new/storage/path' 'old/storage/path' +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/recreate-blocked/databricks.yml b/acceptance/bundle/deploy/bind/recreate-blocked/databricks.yml new file mode 100644 index 00000000000..7afeed66ed2 --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked/databricks.yml @@ -0,0 +1,14 @@ +bundle: + name: test-bind-recreate + +resources: + pipelines: + foo: + name: test-pipeline + storage: /new/storage/path + libraries: + - notebook: + path: ./nb.sql + lifecycle: + bind: + id: "PLACEHOLDER_PIPELINE_ID" diff --git a/acceptance/bundle/deploy/bind/recreate-blocked/nb.sql b/acceptance/bundle/deploy/bind/recreate-blocked/nb.sql new file mode 100644 index 00000000000..199ff507884 --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked/nb.sql @@ -0,0 +1,2 @@ +-- Databricks notebook source +select 1 diff --git a/acceptance/bundle/deploy/bind/recreate-blocked/out.test.toml b/acceptance/bundle/deploy/bind/recreate-blocked/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/recreate-blocked/output.txt b/acceptance/bundle/deploy/bind/recreate-blocked/output.txt new file mode 100644 index 00000000000..51588345908 --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked/output.txt @@ -0,0 +1,31 @@ + +>>> musterr [CLI] bundle plan +Error: cannot bind resources.pipelines.foo: cannot recreate resource with lifecycle.bind + +This would destroy and recreate the existing workspace resource, changing its ID. + +The following fields cannot be modified because they require resource recreation: + - storage (immutable) + +To resolve this issue, you have two options: + +1. Remove the problematic fields from your configuration to make this a bind-only operation: + + resources: + pipelines: + foo: + # Remove or comment out these fields: + # storage: ... + +2. Remove lifecycle.bind if you want to allow the resource to be recreated/updated: + + resources: + pipelines: + foo: + lifecycle: + # Remove the bind block: + # bind: + # id: + +Error: planning failed + diff --git a/acceptance/bundle/deploy/bind/recreate-blocked/script b/acceptance/bundle/deploy/bind/recreate-blocked/script new file mode 100644 index 00000000000..f28f6b94ac8 --- /dev/null +++ b/acceptance/bundle/deploy/bind/recreate-blocked/script @@ -0,0 +1,9 @@ +# Create a pipeline with a different storage path +NEW_PIPELINE_ID=$($CLI pipelines create --json '{"name": "test-pipeline", "storage": "/old/storage/path", "allow_duplicate_names": true, "libraries": [{"notebook": {"path": "/Workspace/test"}}]}' | jq -r .pipeline_id) +add_repl.py $NEW_PIPELINE_ID NEW_PIPELINE_ID + +# Update the databricks.yml with the actual pipeline ID +update_file.py databricks.yml 'PLACEHOLDER_PIPELINE_ID' "$NEW_PIPELINE_ID" + +# Run plan - should fail because changing storage requires recreate which is blocked for binds +trace musterr $CLI bundle plan diff --git a/acceptance/bundle/deploy/bind/ref-to-bound/databricks.yml b/acceptance/bundle/deploy/bind/ref-to-bound/databricks.yml new file mode 100644 index 00000000000..5218a0c2a62 --- /dev/null +++ b/acceptance/bundle/deploy/bind/ref-to-bound/databricks.yml @@ -0,0 +1,25 @@ +bundle: + name: test-bind-ref-to-bound-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" + bar: + name: test-bind-runner + tasks: + - task_key: run_foo + run_job_task: + job_id: ${resources.jobs.foo.id} diff --git a/acceptance/bundle/deploy/bind/ref-to-bound/out.test.toml b/acceptance/bundle/deploy/bind/ref-to-bound/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/ref-to-bound/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/ref-to-bound/output.txt b/acceptance/bundle/deploy/bind/ref-to-bound/output.txt new file mode 100644 index 00000000000..10dcb40bbcb --- /dev/null +++ b/acceptance/bundle/deploy/bind/ref-to-bound/output.txt @@ -0,0 +1,29 @@ + +>>> [CLI] bundle plan +create jobs.bar +bind_and_update jobs.foo (id: [NEW_JOB_ID]) + +Plan: 1 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind + +=== The bound ID is known at plan time, so the reference is already resolved in the plan +>>> [CLI] bundle plan -o json +json.plan.resources.jobs.bar.new_state.value.tasks[0].run_job_task.job_id = [NEW_JOB_ID]; + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-ref-to-bound-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Created jobs.bar +Files: 1 uploaded, 0 deleted +Resources: 1 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +>>> [CLI] jobs get [BAR_ID] +[NEW_JOB_ID] + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.bar + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-ref-to-bound-[UNIQUE_NAME]/default + +Destroy: 2 deleted diff --git a/acceptance/bundle/deploy/bind/ref-to-bound/script b/acceptance/bundle/deploy/bind/ref-to-bound/script new file mode 100644 index 00000000000..e033312fe5e --- /dev/null +++ b/acceptance/bundle/deploy/bind/ref-to-bound/script @@ -0,0 +1,18 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace; bar refers to it through ${resources.jobs.foo.id} +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle plan + +title "The bound ID is known at plan time, so the reference is already resolved in the plan" +trace $CLI bundle plan -o json | gron.py | grep run_job_task + +trace $CLI bundle deploy --auto-approve +BAR_ID=$(read_id.py bar) +trace $CLI jobs get $BAR_ID | jq '.settings.tasks[0].run_job_task.job_id' + +# Cleanup +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/removed-from-config/databricks.yml b/acceptance/bundle/deploy/bind/removed-from-config/databricks.yml new file mode 100644 index 00000000000..b9058bbe0c6 --- /dev/null +++ b/acceptance/bundle/deploy/bind/removed-from-config/databricks.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-removed-from-config-UNIQUE_NAME + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/removed-from-config/databricks_nores.yml b/acceptance/bundle/deploy/bind/removed-from-config/databricks_nores.yml new file mode 100644 index 00000000000..9b759d9f81f --- /dev/null +++ b/acceptance/bundle/deploy/bind/removed-from-config/databricks_nores.yml @@ -0,0 +1,2 @@ +bundle: + name: test-bind-removed-from-config-UNIQUE_NAME diff --git a/acceptance/bundle/deploy/bind/removed-from-config/out.test.toml b/acceptance/bundle/deploy/bind/removed-from-config/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/removed-from-config/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/removed-from-config/output.txt b/acceptance/bundle/deploy/bind/removed-from-config/output.txt new file mode 100644 index 00000000000..c7e97a1b674 --- /dev/null +++ b/acceptance/bundle/deploy/bind/removed-from-config/output.txt @@ -0,0 +1,26 @@ + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-removed-from-config-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Files: 2 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +=== Remove the resource from config. Its lifecycle.bind goes with it, so, as with prevent_destroy, the protection ends and the deploy deletes the job +>>> [CLI] bundle plan +delete jobs.foo + +Plan: 0 to add, 0 to change, 1 to delete, 0 unchanged + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-removed-from-config-[UNIQUE_NAME]/default/files... +Deleted jobs.foo +Files: 1 uploaded, 0 deleted +Resources: 0 created, 0 changed, 1 deleted, 0 unchanged + +>>> musterr [CLI] jobs get [NEW_JOB_ID] +Error: Job [NEW_JOB_ID] does not exist. + +>>> [CLI] bundle destroy --auto-approve +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-removed-from-config-[UNIQUE_NAME]/default + +Destroy: 0 deleted diff --git a/acceptance/bundle/deploy/bind/removed-from-config/script b/acceptance/bundle/deploy/bind/removed-from-config/script new file mode 100644 index 00000000000..082c5fa089f --- /dev/null +++ b/acceptance/bundle/deploy/bind/removed-from-config/script @@ -0,0 +1,18 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" +update_file.py databricks_nores.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace and bind it +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle deploy --auto-approve + +title "Remove the resource from config. Its lifecycle.bind goes with it, so, as with prevent_destroy, the protection ends and the deploy deletes the job" +cp databricks_nores.yml databricks.yml +trace $CLI bundle plan +trace $CLI bundle deploy --auto-approve +trace musterr $CLI jobs get $NEW_JOB_ID + +# Cleanup +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/deploy/bind/removed-from-config/test.toml b/acceptance/bundle/deploy/bind/removed-from-config/test.toml new file mode 100644 index 00000000000..4c1cffe2567 --- /dev/null +++ b/acceptance/bundle/deploy/bind/removed-from-config/test.toml @@ -0,0 +1 @@ +Ignore = [".databricks", "databricks_nores.yml"] diff --git a/acceptance/bundle/deploy/bind/resource-not-found/databricks.yml b/acceptance/bundle/deploy/bind/resource-not-found/databricks.yml new file mode 100644 index 00000000000..02196311478 --- /dev/null +++ b/acceptance/bundle/deploy/bind/resource-not-found/databricks.yml @@ -0,0 +1,19 @@ +bundle: + name: test-bind-not-found + +resources: + jobs: + foo: + name: test-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: ./hello.py + lifecycle: + bind: + id: "999999999" diff --git a/acceptance/bundle/deploy/bind/resource-not-found/hello.py b/acceptance/bundle/deploy/bind/resource-not-found/hello.py new file mode 100644 index 00000000000..11b15b1a458 --- /dev/null +++ b/acceptance/bundle/deploy/bind/resource-not-found/hello.py @@ -0,0 +1 @@ +print("hello") diff --git a/acceptance/bundle/deploy/bind/resource-not-found/out.test.toml b/acceptance/bundle/deploy/bind/resource-not-found/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/resource-not-found/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/resource-not-found/output.txt b/acceptance/bundle/deploy/bind/resource-not-found/output.txt new file mode 100644 index 00000000000..bf1e85e7591 --- /dev/null +++ b/acceptance/bundle/deploy/bind/resource-not-found/output.txt @@ -0,0 +1,6 @@ + +>>> musterr [CLI] bundle plan +Error: cannot bind resources.jobs.foo: resource with ID "999999999" does not exist in workspace + +Error: planning failed + diff --git a/acceptance/bundle/deploy/bind/resource-not-found/script b/acceptance/bundle/deploy/bind/resource-not-found/script new file mode 100644 index 00000000000..6226cb85916 --- /dev/null +++ b/acceptance/bundle/deploy/bind/resource-not-found/script @@ -0,0 +1,2 @@ +# Try to plan with a non-existent job ID - should fail +trace musterr $CLI bundle plan diff --git a/acceptance/bundle/deploy/bind/target-override/databricks.yml b/acceptance/bundle/deploy/bind/target-override/databricks.yml new file mode 100644 index 00000000000..f8012429493 --- /dev/null +++ b/acceptance/bundle/deploy/bind/target-override/databricks.yml @@ -0,0 +1,28 @@ +bundle: + name: test-bind-target-override + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: "999999999" + +targets: + default: + resources: + jobs: + foo: + lifecycle: + bind: + id: "PLACEHOLDER_JOB_ID" diff --git a/acceptance/bundle/deploy/bind/target-override/out.test.toml b/acceptance/bundle/deploy/bind/target-override/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/target-override/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/target-override/output.txt b/acceptance/bundle/deploy/bind/target-override/output.txt new file mode 100644 index 00000000000..01b1ecff408 --- /dev/null +++ b/acceptance/bundle/deploy/bind/target-override/output.txt @@ -0,0 +1,12 @@ + +>>> [CLI] bundle validate -o json +{ + "bind": { + "id": "[NEW_JOB_ID]" + } +} + +>>> [CLI] bundle plan +bind_and_update jobs.foo (id: [NEW_JOB_ID]) + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind diff --git a/acceptance/bundle/deploy/bind/target-override/script b/acceptance/bundle/deploy/bind/target-override/script new file mode 100644 index 00000000000..f1bf38e0aba --- /dev/null +++ b/acceptance/bundle/deploy/bind/target-override/script @@ -0,0 +1,8 @@ +# The ID of the resource to adopt differs per target, so it is set through the usual +# target override of the resource; the root value is a placeholder here. +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle validate -o json | jq '.resources.jobs.foo.lifecycle' +trace $CLI bundle plan diff --git a/acceptance/bundle/deploy/bind/test.toml b/acceptance/bundle/deploy/bind/test.toml new file mode 100644 index 00000000000..f59fefe3e02 --- /dev/null +++ b/acceptance/bundle/deploy/bind/test.toml @@ -0,0 +1,2 @@ +Cloud = true +Ignore = [".databricks"] diff --git a/acceptance/bundle/deploy/bind/variable-id/databricks.yml b/acceptance/bundle/deploy/bind/variable-id/databricks.yml new file mode 100644 index 00000000000..f266dec8262 --- /dev/null +++ b/acceptance/bundle/deploy/bind/variable-id/databricks.yml @@ -0,0 +1,24 @@ +bundle: + name: test-bind-variable-id-UNIQUE_NAME + +variables: + job_id: + description: ID of the existing job to bind + default: "PLACEHOLDER_JOB_ID" + +resources: + jobs: + foo: + name: test-bind-job + environments: + - environment_key: default + spec: + client: "1" + tasks: + - task_key: my_task + environment_key: default + spark_python_task: + python_file: /Workspace/test.py + lifecycle: + bind: + id: ${var.job_id} diff --git a/acceptance/bundle/deploy/bind/variable-id/out.test.toml b/acceptance/bundle/deploy/bind/variable-id/out.test.toml new file mode 100644 index 00000000000..0f167effef1 --- /dev/null +++ b/acceptance/bundle/deploy/bind/variable-id/out.test.toml @@ -0,0 +1,2 @@ +Cloud = true +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/deploy/bind/variable-id/output.txt b/acceptance/bundle/deploy/bind/variable-id/output.txt new file mode 100644 index 00000000000..99a13d92977 --- /dev/null +++ b/acceptance/bundle/deploy/bind/variable-id/output.txt @@ -0,0 +1,22 @@ + +>>> [CLI] bundle plan +bind_and_update jobs.foo (id: [NEW_JOB_ID]) + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged, 1 to bind + +>>> [CLI] bundle deploy --auto-approve +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bind-variable-id-[UNIQUE_NAME]/default/files... +Bound and updated jobs.foo +Files: 1 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged, 1 bound + +>>> print_state.py +json.state.resources.jobs.foo.__id__ = "[NEW_JOB_ID]"; + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.jobs.foo + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bind-variable-id-[UNIQUE_NAME]/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/deploy/bind/variable-id/script b/acceptance/bundle/deploy/bind/variable-id/script new file mode 100644 index 00000000000..0e9a511a8e2 --- /dev/null +++ b/acceptance/bundle/deploy/bind/variable-id/script @@ -0,0 +1,13 @@ +update_file.py databricks.yml 'UNIQUE_NAME' "$UNIQUE_NAME" + +# Create a job in the workspace; its ID reaches the bind block through a variable +NEW_JOB_ID=$($CLI jobs create --json '{"name": "test-bind-job", "environments": [{"environment_key": "default", "spec": {"client": "1"}}], "tasks": [{"task_key": "my_task", "environment_key": "default", "spark_python_task": {"python_file": "/Workspace/test.py"}}]}' | jq -r .job_id) +add_repl.py $NEW_JOB_ID NEW_JOB_ID +update_file.py databricks.yml 'PLACEHOLDER_JOB_ID' "$NEW_JOB_ID" + +trace $CLI bundle plan +trace $CLI bundle deploy --auto-approve +trace print_state.py | gron.py | grep __id__ + +# Cleanup +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/refschema/output/alerts.txt b/acceptance/bundle/refschema/output/alerts.txt index 566299e11cd..518dcb5369c 100644 --- a/acceptance/bundle/refschema/output/alerts.txt +++ b/acceptance/bundle/refschema/output/alerts.txt @@ -34,6 +34,8 @@ resources.alerts.*.evaluation.threshold.value.string_value string ALL resources.alerts.*.file_path string INPUT resources.alerts.*.id string ALL resources.alerts.*.lifecycle resources.Lifecycle INPUT +resources.alerts.*.lifecycle.bind *resources.Bind INPUT +resources.alerts.*.lifecycle.bind.id string INPUT resources.alerts.*.lifecycle.depends_on []resources.DependsOn INPUT resources.alerts.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.alerts.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/apps.txt b/acceptance/bundle/refschema/output/apps.txt index 3e1f91151f1..3087fafd5c0 100644 --- a/acceptance/bundle/refschema/output/apps.txt +++ b/acceptance/bundle/refschema/output/apps.txt @@ -91,6 +91,8 @@ resources.apps.*.id string ALL resources.apps.*.lifecycle *dresources.StateLifecycle REMOTE STATE resources.apps.*.lifecycle *resources.LifecycleWithStarted INPUT resources.apps.*.lifecycle resources.Lifecycle INPUT +resources.apps.*.lifecycle.bind *resources.Bind INPUT +resources.apps.*.lifecycle.bind.id string INPUT resources.apps.*.lifecycle.depends_on []resources.DependsOn INPUT resources.apps.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.apps.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/catalogs.txt b/acceptance/bundle/refschema/output/catalogs.txt index feaee00d2ca..e2c0a061582 100644 --- a/acceptance/bundle/refschema/output/catalogs.txt +++ b/acceptance/bundle/refschema/output/catalogs.txt @@ -14,6 +14,8 @@ resources.catalogs.*.full_name string REMOTE resources.catalogs.*.id string INPUT resources.catalogs.*.isolation_mode catalog.CatalogIsolationMode REMOTE resources.catalogs.*.lifecycle resources.Lifecycle INPUT +resources.catalogs.*.lifecycle.bind *resources.Bind INPUT +resources.catalogs.*.lifecycle.bind.id string INPUT resources.catalogs.*.lifecycle.depends_on []resources.DependsOn INPUT resources.catalogs.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.catalogs.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/cluster_policies.txt b/acceptance/bundle/refschema/output/cluster_policies.txt index da5be2b6b9b..bb8f08ad455 100644 --- a/acceptance/bundle/refschema/output/cluster_policies.txt +++ b/acceptance/bundle/refschema/output/cluster_policies.txt @@ -23,6 +23,8 @@ resources.cluster_policies.*.libraries[*].pypi.repo string ALL resources.cluster_policies.*.libraries[*].requirements string ALL resources.cluster_policies.*.libraries[*].whl string ALL resources.cluster_policies.*.lifecycle resources.Lifecycle INPUT +resources.cluster_policies.*.lifecycle.bind *resources.Bind INPUT +resources.cluster_policies.*.lifecycle.bind.id string INPUT resources.cluster_policies.*.lifecycle.depends_on []resources.DependsOn INPUT resources.cluster_policies.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.cluster_policies.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/clusters.txt b/acceptance/bundle/refschema/output/clusters.txt index ad9c1e333a5..e672cb77771 100644 --- a/acceptance/bundle/refschema/output/clusters.txt +++ b/acceptance/bundle/refschema/output/clusters.txt @@ -140,6 +140,8 @@ resources.clusters.*.libraries[*].whl string ALL resources.clusters.*.lifecycle *dresources.StateLifecycle REMOTE STATE resources.clusters.*.lifecycle *resources.LifecycleWithStarted INPUT resources.clusters.*.lifecycle resources.Lifecycle INPUT +resources.clusters.*.lifecycle.bind *resources.Bind INPUT +resources.clusters.*.lifecycle.bind.id string INPUT resources.clusters.*.lifecycle.depends_on []resources.DependsOn INPUT resources.clusters.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.clusters.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/dashboards.txt b/acceptance/bundle/refschema/output/dashboards.txt index 300a7d9c3a7..6a5a1356938 100644 --- a/acceptance/bundle/refschema/output/dashboards.txt +++ b/acceptance/bundle/refschema/output/dashboards.txt @@ -8,6 +8,8 @@ resources.dashboards.*.etag string ALL resources.dashboards.*.file_path string INPUT resources.dashboards.*.id string INPUT resources.dashboards.*.lifecycle resources.Lifecycle INPUT +resources.dashboards.*.lifecycle.bind *resources.Bind INPUT +resources.dashboards.*.lifecycle.bind.id string INPUT resources.dashboards.*.lifecycle.depends_on []resources.DependsOn INPUT resources.dashboards.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.dashboards.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/database_catalogs.txt b/acceptance/bundle/refschema/output/database_catalogs.txt index e23c5246e31..f36b1a79eb5 100644 --- a/acceptance/bundle/refschema/output/database_catalogs.txt +++ b/acceptance/bundle/refschema/output/database_catalogs.txt @@ -3,6 +3,8 @@ resources.database_catalogs.*.database_instance_name string ALL resources.database_catalogs.*.database_name string ALL resources.database_catalogs.*.id string INPUT resources.database_catalogs.*.lifecycle resources.Lifecycle INPUT +resources.database_catalogs.*.lifecycle.bind *resources.Bind INPUT +resources.database_catalogs.*.lifecycle.bind.id string INPUT resources.database_catalogs.*.lifecycle.depends_on []resources.DependsOn INPUT resources.database_catalogs.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.database_catalogs.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/database_instances.txt b/acceptance/bundle/refschema/output/database_instances.txt index d09ebf65dc2..ad4308b7245 100644 --- a/acceptance/bundle/refschema/output/database_instances.txt +++ b/acceptance/bundle/refschema/output/database_instances.txt @@ -27,6 +27,8 @@ resources.database_instances.*.enable_pg_native_login bool ALL resources.database_instances.*.enable_readable_secondaries bool ALL resources.database_instances.*.id string INPUT resources.database_instances.*.lifecycle resources.Lifecycle INPUT +resources.database_instances.*.lifecycle.bind *resources.Bind INPUT +resources.database_instances.*.lifecycle.bind.id string INPUT resources.database_instances.*.lifecycle.depends_on []resources.DependsOn INPUT resources.database_instances.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.database_instances.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/experiments.txt b/acceptance/bundle/refschema/output/experiments.txt index a85aafdd5d0..85384fd3e5f 100644 --- a/acceptance/bundle/refschema/output/experiments.txt +++ b/acceptance/bundle/refschema/output/experiments.txt @@ -4,6 +4,8 @@ resources.experiments.*.experiment_id string REMOTE resources.experiments.*.id string INPUT resources.experiments.*.last_update_time int64 REMOTE resources.experiments.*.lifecycle resources.Lifecycle INPUT +resources.experiments.*.lifecycle.bind *resources.Bind INPUT +resources.experiments.*.lifecycle.bind.id string INPUT resources.experiments.*.lifecycle.depends_on []resources.DependsOn INPUT resources.experiments.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.experiments.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/external_locations.txt b/acceptance/bundle/refschema/output/external_locations.txt index 4e058354db2..5950751b3e8 100644 --- a/acceptance/bundle/refschema/output/external_locations.txt +++ b/acceptance/bundle/refschema/output/external_locations.txt @@ -60,6 +60,8 @@ resources.external_locations.*.file_event_queue.provided_sqs.queue_url string AL resources.external_locations.*.id string INPUT resources.external_locations.*.isolation_mode catalog.IsolationMode REMOTE resources.external_locations.*.lifecycle resources.Lifecycle INPUT +resources.external_locations.*.lifecycle.bind *resources.Bind INPUT +resources.external_locations.*.lifecycle.bind.id string INPUT resources.external_locations.*.lifecycle.depends_on []resources.DependsOn INPUT resources.external_locations.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.external_locations.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/features.txt b/acceptance/bundle/refschema/output/features.txt index c06246cee3d..907f26be1b2 100644 --- a/acceptance/bundle/refschema/output/features.txt +++ b/acceptance/bundle/refschema/output/features.txt @@ -89,6 +89,8 @@ resources.features.*.id string INPUT resources.features.*.inputs []string ALL resources.features.*.inputs[*] string ALL resources.features.*.lifecycle resources.Lifecycle INPUT +resources.features.*.lifecycle.bind *resources.Bind INPUT +resources.features.*.lifecycle.bind.id string INPUT resources.features.*.lifecycle.depends_on []resources.DependsOn INPUT resources.features.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.features.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/genie_spaces.txt b/acceptance/bundle/refschema/output/genie_spaces.txt index 40dbd2b70ba..2bad6604528 100644 --- a/acceptance/bundle/refschema/output/genie_spaces.txt +++ b/acceptance/bundle/refschema/output/genie_spaces.txt @@ -3,6 +3,8 @@ resources.genie_spaces.*.etag string ALL resources.genie_spaces.*.file_path string INPUT resources.genie_spaces.*.id string INPUT resources.genie_spaces.*.lifecycle resources.Lifecycle INPUT +resources.genie_spaces.*.lifecycle.bind *resources.Bind INPUT +resources.genie_spaces.*.lifecycle.bind.id string INPUT resources.genie_spaces.*.lifecycle.depends_on []resources.DependsOn INPUT resources.genie_spaces.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.genie_spaces.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/instance_pools.txt b/acceptance/bundle/refschema/output/instance_pools.txt index 71991cd0733..8c7263f8a3e 100644 --- a/acceptance/bundle/refschema/output/instance_pools.txt +++ b/acceptance/bundle/refschema/output/instance_pools.txt @@ -29,6 +29,8 @@ resources.instance_pools.*.idle_instance_autotermination_minutes int ALL resources.instance_pools.*.instance_pool_id string REMOTE resources.instance_pools.*.instance_pool_name string ALL resources.instance_pools.*.lifecycle resources.Lifecycle INPUT +resources.instance_pools.*.lifecycle.bind *resources.Bind INPUT +resources.instance_pools.*.lifecycle.bind.id string INPUT resources.instance_pools.*.lifecycle.depends_on []resources.DependsOn INPUT resources.instance_pools.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.instance_pools.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/job_runs.txt b/acceptance/bundle/refschema/output/job_runs.txt index c613f750f7b..406b7093897 100644 --- a/acceptance/bundle/refschema/output/job_runs.txt +++ b/acceptance/bundle/refschema/output/job_runs.txt @@ -11,6 +11,8 @@ resources.job_runs.*.job_parameters.* string ALL resources.job_runs.*.lifecycle *dresources.JobRunLifecycleState STATE resources.job_runs.*.lifecycle *resources.JobRunLifecycle INPUT resources.job_runs.*.lifecycle resources.Lifecycle INPUT +resources.job_runs.*.lifecycle.bind *resources.Bind INPUT +resources.job_runs.*.lifecycle.bind.id string INPUT resources.job_runs.*.lifecycle.depends_on []resources.DependsOn INPUT resources.job_runs.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.job_runs.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/jobs.txt b/acceptance/bundle/refschema/output/jobs.txt index 06a058987fd..099ceeb7df9 100644 --- a/acceptance/bundle/refschema/output/jobs.txt +++ b/acceptance/bundle/refschema/output/jobs.txt @@ -198,6 +198,8 @@ resources.jobs.*.job_clusters[*].serverless_compute.policy_id string ALL resources.jobs.*.job_clusters[*].serverless_compute_id string ALL resources.jobs.*.job_id int64 REMOTE resources.jobs.*.lifecycle resources.Lifecycle INPUT +resources.jobs.*.lifecycle.bind *resources.Bind INPUT +resources.jobs.*.lifecycle.bind.id string INPUT resources.jobs.*.lifecycle.depends_on []resources.DependsOn INPUT resources.jobs.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.jobs.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/mcp_services.txt b/acceptance/bundle/refschema/output/mcp_services.txt index 578b2636d79..403db38c3d9 100644 --- a/acceptance/bundle/refschema/output/mcp_services.txt +++ b/acceptance/bundle/refschema/output/mcp_services.txt @@ -16,6 +16,8 @@ resources.mcp_services.*.config.source_connection.options map[string]string ALL resources.mcp_services.*.config.source_connection.options.* string ALL resources.mcp_services.*.id string INPUT resources.mcp_services.*.lifecycle resources.Lifecycle INPUT +resources.mcp_services.*.lifecycle.bind *resources.Bind INPUT +resources.mcp_services.*.lifecycle.bind.id string INPUT resources.mcp_services.*.lifecycle.depends_on []resources.DependsOn INPUT resources.mcp_services.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.mcp_services.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/model_provider_services.txt b/acceptance/bundle/refschema/output/model_provider_services.txt index 0d5e76e1a7f..c228aa54904 100644 --- a/acceptance/bundle/refschema/output/model_provider_services.txt +++ b/acceptance/bundle/refschema/output/model_provider_services.txt @@ -119,6 +119,8 @@ resources.model_provider_services.*.config.targets[*].native_api_types []string resources.model_provider_services.*.config.targets[*].native_api_types[*] string ALL resources.model_provider_services.*.id string INPUT resources.model_provider_services.*.lifecycle resources.Lifecycle INPUT +resources.model_provider_services.*.lifecycle.bind *resources.Bind INPUT +resources.model_provider_services.*.lifecycle.bind.id string INPUT resources.model_provider_services.*.lifecycle.depends_on []resources.DependsOn INPUT resources.model_provider_services.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.model_provider_services.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/model_services.txt b/acceptance/bundle/refschema/output/model_services.txt index a13287e468b..8a43df8baa8 100644 --- a/acceptance/bundle/refschema/output/model_services.txt +++ b/acceptance/bundle/refschema/output/model_services.txt @@ -52,6 +52,8 @@ resources.model_services.*.config.routing.fallback.destinations[*].provisioned_t resources.model_services.*.config.routing.fallback.destinations[*].traffic_percentage int ALL resources.model_services.*.id string INPUT resources.model_services.*.lifecycle resources.Lifecycle INPUT +resources.model_services.*.lifecycle.bind *resources.Bind INPUT +resources.model_services.*.lifecycle.bind.id string INPUT resources.model_services.*.lifecycle.depends_on []resources.DependsOn INPUT resources.model_services.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.model_services.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/model_serving_endpoints.txt b/acceptance/bundle/refschema/output/model_serving_endpoints.txt index 95a3adcf440..796a84a3d7d 100644 --- a/acceptance/bundle/refschema/output/model_serving_endpoints.txt +++ b/acceptance/bundle/refschema/output/model_serving_endpoints.txt @@ -461,6 +461,8 @@ resources.model_serving_endpoints.*.endpoint_details.telemetry_config.telemetry_ resources.model_serving_endpoints.*.endpoint_id string REMOTE resources.model_serving_endpoints.*.id string INPUT resources.model_serving_endpoints.*.lifecycle resources.Lifecycle INPUT +resources.model_serving_endpoints.*.lifecycle.bind *resources.Bind INPUT +resources.model_serving_endpoints.*.lifecycle.bind.id string INPUT resources.model_serving_endpoints.*.lifecycle.depends_on []resources.DependsOn INPUT resources.model_serving_endpoints.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.model_serving_endpoints.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/models.txt b/acceptance/bundle/refschema/output/models.txt index 3570dd6fb58..7886abda59d 100644 --- a/acceptance/bundle/refschema/output/models.txt +++ b/acceptance/bundle/refschema/output/models.txt @@ -21,6 +21,8 @@ resources.models.*.latest_versions[*].tags[*].value string REMOTE resources.models.*.latest_versions[*].user_id string REMOTE resources.models.*.latest_versions[*].version string REMOTE resources.models.*.lifecycle resources.Lifecycle INPUT +resources.models.*.lifecycle.bind *resources.Bind INPUT +resources.models.*.lifecycle.bind.id string INPUT resources.models.*.lifecycle.depends_on []resources.DependsOn INPUT resources.models.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.models.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/pipelines.txt b/acceptance/bundle/refschema/output/pipelines.txt index c8bc57f512c..e15ec9f418a 100644 --- a/acceptance/bundle/refschema/output/pipelines.txt +++ b/acceptance/bundle/refschema/output/pipelines.txt @@ -831,6 +831,8 @@ resources.pipelines.*.libraries[*].notebook *pipelines.NotebookLibrary ALL resources.pipelines.*.libraries[*].notebook.path string ALL resources.pipelines.*.libraries[*].whl string ALL resources.pipelines.*.lifecycle resources.Lifecycle INPUT +resources.pipelines.*.lifecycle.bind *resources.Bind INPUT +resources.pipelines.*.lifecycle.bind.id string INPUT resources.pipelines.*.lifecycle.depends_on []resources.DependsOn INPUT resources.pipelines.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.pipelines.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_branches.txt b/acceptance/bundle/refschema/output/postgres_branches.txt index 85248e7a93a..e7db507827a 100644 --- a/acceptance/bundle/refschema/output/postgres_branches.txt +++ b/acceptance/bundle/refschema/output/postgres_branches.txt @@ -4,6 +4,8 @@ resources.postgres_branches.*.expire_time *time.Time ALL resources.postgres_branches.*.id string INPUT resources.postgres_branches.*.is_protected bool ALL resources.postgres_branches.*.lifecycle resources.Lifecycle INPUT +resources.postgres_branches.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_branches.*.lifecycle.bind.id string INPUT resources.postgres_branches.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_branches.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_branches.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_catalogs.txt b/acceptance/bundle/refschema/output/postgres_catalogs.txt index 3cefc681b99..30f13150c6f 100644 --- a/acceptance/bundle/refschema/output/postgres_catalogs.txt +++ b/acceptance/bundle/refschema/output/postgres_catalogs.txt @@ -4,6 +4,8 @@ resources.postgres_catalogs.*.create_database_if_missing bool ALL resources.postgres_catalogs.*.create_time *time.Time REMOTE resources.postgres_catalogs.*.id string INPUT resources.postgres_catalogs.*.lifecycle resources.Lifecycle INPUT +resources.postgres_catalogs.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_catalogs.*.lifecycle.bind.id string INPUT resources.postgres_catalogs.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_catalogs.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_catalogs.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_databases.txt b/acceptance/bundle/refschema/output/postgres_databases.txt index 2ccb3ba2b68..505bc9cf551 100644 --- a/acceptance/bundle/refschema/output/postgres_databases.txt +++ b/acceptance/bundle/refschema/output/postgres_databases.txt @@ -2,6 +2,8 @@ resources.postgres_databases.*.create_time *time.Time REMOTE resources.postgres_databases.*.database_id string ALL resources.postgres_databases.*.id string INPUT resources.postgres_databases.*.lifecycle resources.Lifecycle INPUT +resources.postgres_databases.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_databases.*.lifecycle.bind.id string INPUT resources.postgres_databases.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_databases.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_databases.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_endpoints.txt b/acceptance/bundle/refschema/output/postgres_endpoints.txt index 32f2395228b..ab1280898bf 100644 --- a/acceptance/bundle/refschema/output/postgres_endpoints.txt +++ b/acceptance/bundle/refschema/output/postgres_endpoints.txt @@ -10,6 +10,8 @@ resources.postgres_endpoints.*.group.max int ALL resources.postgres_endpoints.*.group.min int ALL resources.postgres_endpoints.*.id string INPUT resources.postgres_endpoints.*.lifecycle resources.Lifecycle INPUT +resources.postgres_endpoints.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_endpoints.*.lifecycle.bind.id string INPUT resources.postgres_endpoints.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_endpoints.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_endpoints.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_projects.txt b/acceptance/bundle/refschema/output/postgres_projects.txt index 575b12db52d..f9727d43730 100644 --- a/acceptance/bundle/refschema/output/postgres_projects.txt +++ b/acceptance/bundle/refschema/output/postgres_projects.txt @@ -27,6 +27,8 @@ resources.postgres_projects.*.initial_endpoint_spec.group.min int REMOTE resources.postgres_projects.*.initial_endpoint_spec.no_suspension bool REMOTE resources.postgres_projects.*.initial_endpoint_spec.suspend_timeout_duration *duration.Duration REMOTE resources.postgres_projects.*.lifecycle resources.Lifecycle INPUT +resources.postgres_projects.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_projects.*.lifecycle.bind.id string INPUT resources.postgres_projects.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_projects.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_projects.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_roles.txt b/acceptance/bundle/refschema/output/postgres_roles.txt index b77c3258488..cba2e3ae34d 100644 --- a/acceptance/bundle/refschema/output/postgres_roles.txt +++ b/acceptance/bundle/refschema/output/postgres_roles.txt @@ -7,6 +7,8 @@ resources.postgres_roles.*.create_time *time.Time REMOTE resources.postgres_roles.*.id string INPUT resources.postgres_roles.*.identity_type postgres.RoleIdentityType ALL resources.postgres_roles.*.lifecycle resources.Lifecycle INPUT +resources.postgres_roles.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_roles.*.lifecycle.bind.id string INPUT resources.postgres_roles.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_roles.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_roles.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_snapshot_schedules.txt b/acceptance/bundle/refschema/output/postgres_snapshot_schedules.txt index ae44e6072ca..12046615c49 100644 --- a/acceptance/bundle/refschema/output/postgres_snapshot_schedules.txt +++ b/acceptance/bundle/refschema/output/postgres_snapshot_schedules.txt @@ -1,6 +1,8 @@ resources.postgres_snapshot_schedules.*.branch string ALL resources.postgres_snapshot_schedules.*.id string INPUT resources.postgres_snapshot_schedules.*.lifecycle resources.Lifecycle INPUT +resources.postgres_snapshot_schedules.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_snapshot_schedules.*.lifecycle.bind.id string INPUT resources.postgres_snapshot_schedules.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_snapshot_schedules.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_snapshot_schedules.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/postgres_synced_tables.txt b/acceptance/bundle/refschema/output/postgres_synced_tables.txt index 78be11c8847..0da83f70495 100644 --- a/acceptance/bundle/refschema/output/postgres_synced_tables.txt +++ b/acceptance/bundle/refschema/output/postgres_synced_tables.txt @@ -11,6 +11,8 @@ resources.postgres_synced_tables.*.extra_columns[*].compute string ALL resources.postgres_synced_tables.*.extra_columns[*].maintenance postgres.SyncedTableSyncedTableSpecExtraColumnMaintenance ALL resources.postgres_synced_tables.*.id string INPUT resources.postgres_synced_tables.*.lifecycle resources.Lifecycle INPUT +resources.postgres_synced_tables.*.lifecycle.bind *resources.Bind INPUT +resources.postgres_synced_tables.*.lifecycle.bind.id string INPUT resources.postgres_synced_tables.*.lifecycle.depends_on []resources.DependsOn INPUT resources.postgres_synced_tables.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.postgres_synced_tables.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/quality_monitors.txt b/acceptance/bundle/refschema/output/quality_monitors.txt index 5bd3f952fbd..e51d38e3eaa 100644 --- a/acceptance/bundle/refschema/output/quality_monitors.txt +++ b/acceptance/bundle/refschema/output/quality_monitors.txt @@ -24,6 +24,8 @@ resources.quality_monitors.*.inference_log.problem_type catalog.MonitorInference resources.quality_monitors.*.inference_log.timestamp_col string ALL resources.quality_monitors.*.latest_monitor_failure_msg string ALL resources.quality_monitors.*.lifecycle resources.Lifecycle INPUT +resources.quality_monitors.*.lifecycle.bind *resources.Bind INPUT +resources.quality_monitors.*.lifecycle.bind.id string INPUT resources.quality_monitors.*.lifecycle.depends_on []resources.DependsOn INPUT resources.quality_monitors.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.quality_monitors.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/registered_models.txt b/acceptance/bundle/refschema/output/registered_models.txt index 7c3d1db0860..efc40ad54bb 100644 --- a/acceptance/bundle/refschema/output/registered_models.txt +++ b/acceptance/bundle/refschema/output/registered_models.txt @@ -14,6 +14,8 @@ resources.registered_models.*.created_by string ALL resources.registered_models.*.full_name string ALL resources.registered_models.*.id string INPUT resources.registered_models.*.lifecycle resources.Lifecycle INPUT +resources.registered_models.*.lifecycle.bind *resources.Bind INPUT +resources.registered_models.*.lifecycle.bind.id string INPUT resources.registered_models.*.lifecycle.depends_on []resources.DependsOn INPUT resources.registered_models.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.registered_models.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/schemas.txt b/acceptance/bundle/refschema/output/schemas.txt index 694d59c6211..70983f86e00 100644 --- a/acceptance/bundle/refschema/output/schemas.txt +++ b/acceptance/bundle/refschema/output/schemas.txt @@ -13,6 +13,8 @@ resources.schemas.*.enable_predictive_optimization catalog.EnablePredictiveOptim resources.schemas.*.full_name string REMOTE resources.schemas.*.id string INPUT resources.schemas.*.lifecycle resources.Lifecycle INPUT +resources.schemas.*.lifecycle.bind *resources.Bind INPUT +resources.schemas.*.lifecycle.bind.id string INPUT resources.schemas.*.lifecycle.depends_on []resources.DependsOn INPUT resources.schemas.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.schemas.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/secret_scopes.txt b/acceptance/bundle/refschema/output/secret_scopes.txt index 832a476d47a..793e8591de9 100644 --- a/acceptance/bundle/refschema/output/secret_scopes.txt +++ b/acceptance/bundle/refschema/output/secret_scopes.txt @@ -8,6 +8,8 @@ resources.secret_scopes.*.keyvault_metadata *workspace.AzureKeyVaultSecretScopeM resources.secret_scopes.*.keyvault_metadata.dns_name string INPUT resources.secret_scopes.*.keyvault_metadata.resource_id string INPUT resources.secret_scopes.*.lifecycle resources.Lifecycle INPUT +resources.secret_scopes.*.lifecycle.bind *resources.Bind INPUT +resources.secret_scopes.*.lifecycle.bind.id string INPUT resources.secret_scopes.*.lifecycle.depends_on []resources.DependsOn INPUT resources.secret_scopes.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.secret_scopes.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/secrets.txt b/acceptance/bundle/refschema/output/secrets.txt index f0c4b2b213a..29f5e5f454f 100644 --- a/acceptance/bundle/refschema/output/secrets.txt +++ b/acceptance/bundle/refschema/output/secrets.txt @@ -8,6 +8,8 @@ resources.secrets.*.expire_time *time.Time ALL resources.secrets.*.full_name string ALL resources.secrets.*.id string INPUT resources.secrets.*.lifecycle resources.Lifecycle INPUT +resources.secrets.*.lifecycle.bind *resources.Bind INPUT +resources.secrets.*.lifecycle.bind.id string INPUT resources.secrets.*.lifecycle.depends_on []resources.DependsOn INPUT resources.secrets.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.secrets.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/sql_warehouses.txt b/acceptance/bundle/refschema/output/sql_warehouses.txt index a642c226ac9..f7c11cb8caf 100644 --- a/acceptance/bundle/refschema/output/sql_warehouses.txt +++ b/acceptance/bundle/refschema/output/sql_warehouses.txt @@ -23,6 +23,8 @@ resources.sql_warehouses.*.jdbc_url string REMOTE resources.sql_warehouses.*.lifecycle *dresources.StateLifecycle REMOTE STATE resources.sql_warehouses.*.lifecycle *resources.LifecycleWithStarted INPUT resources.sql_warehouses.*.lifecycle resources.Lifecycle INPUT +resources.sql_warehouses.*.lifecycle.bind *resources.Bind INPUT +resources.sql_warehouses.*.lifecycle.bind.id string INPUT resources.sql_warehouses.*.lifecycle.depends_on []resources.DependsOn INPUT resources.sql_warehouses.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.sql_warehouses.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/synced_database_tables.txt b/acceptance/bundle/refschema/output/synced_database_tables.txt index 7836f00bb8b..7cc0ca860a4 100644 --- a/acceptance/bundle/refschema/output/synced_database_tables.txt +++ b/acceptance/bundle/refschema/output/synced_database_tables.txt @@ -44,6 +44,8 @@ resources.synced_database_tables.*.effective_database_instance_name string ALL resources.synced_database_tables.*.effective_logical_database_name string ALL resources.synced_database_tables.*.id string INPUT resources.synced_database_tables.*.lifecycle resources.Lifecycle INPUT +resources.synced_database_tables.*.lifecycle.bind *resources.Bind INPUT +resources.synced_database_tables.*.lifecycle.bind.id string INPUT resources.synced_database_tables.*.lifecycle.depends_on []resources.DependsOn INPUT resources.synced_database_tables.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.synced_database_tables.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/vector_search_endpoints.txt b/acceptance/bundle/refschema/output/vector_search_endpoints.txt index 7fddb5b8e05..48947c4302f 100644 --- a/acceptance/bundle/refschema/output/vector_search_endpoints.txt +++ b/acceptance/bundle/refschema/output/vector_search_endpoints.txt @@ -15,6 +15,8 @@ resources.vector_search_endpoints.*.id string INPUT REMOTE resources.vector_search_endpoints.*.last_updated_timestamp int64 REMOTE resources.vector_search_endpoints.*.last_updated_user string REMOTE resources.vector_search_endpoints.*.lifecycle resources.Lifecycle INPUT +resources.vector_search_endpoints.*.lifecycle.bind *resources.Bind INPUT +resources.vector_search_endpoints.*.lifecycle.bind.id string INPUT resources.vector_search_endpoints.*.lifecycle.depends_on []resources.DependsOn INPUT resources.vector_search_endpoints.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.vector_search_endpoints.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/vector_search_indexes.txt b/acceptance/bundle/refschema/output/vector_search_indexes.txt index 6246bf1fdc7..24a5807f541 100644 --- a/acceptance/bundle/refschema/output/vector_search_indexes.txt +++ b/acceptance/bundle/refschema/output/vector_search_indexes.txt @@ -36,6 +36,8 @@ resources.vector_search_indexes.*.id string INPUT resources.vector_search_indexes.*.index_subtype vectorsearch.IndexSubtype ALL resources.vector_search_indexes.*.index_type vectorsearch.VectorIndexType ALL resources.vector_search_indexes.*.lifecycle resources.Lifecycle INPUT +resources.vector_search_indexes.*.lifecycle.bind *resources.Bind INPUT +resources.vector_search_indexes.*.lifecycle.bind.id string INPUT resources.vector_search_indexes.*.lifecycle.depends_on []resources.DependsOn INPUT resources.vector_search_indexes.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.vector_search_indexes.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/bundle/refschema/output/volumes.txt b/acceptance/bundle/refschema/output/volumes.txt index 1c573ed1931..c34d267fbd7 100644 --- a/acceptance/bundle/refschema/output/volumes.txt +++ b/acceptance/bundle/refschema/output/volumes.txt @@ -11,6 +11,8 @@ resources.volumes.*.encryption_details.sse_encryption_details.aws_kms_key_arn st resources.volumes.*.full_name string REMOTE resources.volumes.*.id string INPUT resources.volumes.*.lifecycle resources.Lifecycle INPUT +resources.volumes.*.lifecycle.bind *resources.Bind INPUT +resources.volumes.*.lifecycle.bind.id string INPUT resources.volumes.*.lifecycle.depends_on []resources.DependsOn INPUT resources.volumes.*.lifecycle.depends_on[*] resources.DependsOn INPUT resources.volumes.*.lifecycle.depends_on[*].resource string INPUT diff --git a/acceptance/test.toml b/acceptance/test.toml index 6e18a40e78a..593f9961c60 100644 --- a/acceptance/test.toml +++ b/acceptance/test.toml @@ -23,7 +23,7 @@ Env.PYTHONUTF8 = "1" # applied in parallel, so the order of these lines is not deterministic. Sort each run of # them before comparing, so tests pin which resources were applied, not the order. # A test that needs the raw order sets SortLinesOn.deploy_actions = false. -SortLines.deploy_actions = '^(Created|Updated|Deleted|Recreated|Resized) \S+$' +SortLines.deploy_actions = '^(Created|Updated|Deleted|Recreated|Resized|Bound|Bound and updated) \S+$' # Retries are timing dependent, so their warnings would make output flaky. They go to the # test log instead. A test that injects errors deterministically and asserts the warning diff --git a/bundle/config/resources/lifecycle.go b/bundle/config/resources/lifecycle.go index ec93ba5af06..90e849ba8cd 100644 --- a/bundle/config/resources/lifecycle.go +++ b/bundle/config/resources/lifecycle.go @@ -4,6 +4,7 @@ package resources type LifecycleConfig interface { HasPreventDestroy() bool GetDependsOn() []DependsOn + GetBind() *Bind } // Lifecycle contains base lifecycle settings supported by all resources. @@ -19,6 +20,9 @@ type Lifecycle struct { // Resources that must be deployed before this resource and deleted after it. DependsOn []DependsOn `json:"depends_on,omitempty"` + + // Existing workspace resource to bring under bundle management instead of creating one. + Bind *Bind `json:"bind,omitempty"` } // DependsOn is a single lifecycle.depends_on entry. @@ -27,6 +31,15 @@ type DependsOn struct { Resource string `json:"resource"` } +// Bind is the lifecycle.bind block: the deploy adopts the workspace resource with this +// ID into the deployment state instead of creating a new one. Nothing is recorded in +// state about the adoption; the block guards the resource against being recreated for +// as long as it is present in the configuration. +type Bind struct { + // ID of the existing workspace resource, as used by its API. + ID string `json:"id"` +} + // HasPreventDestroy returns true if prevent_destroy is set. func (l Lifecycle) HasPreventDestroy() bool { return l.PreventDestroy @@ -37,6 +50,11 @@ func (l Lifecycle) GetDependsOn() []DependsOn { return l.DependsOn } +// GetBind returns the lifecycle.bind block, or nil when the resource is not bound. +func (l Lifecycle) GetBind() *Bind { + return l.Bind +} + // LifecycleWithStarted contains lifecycle settings for resources that support lifecycle.started. // It is used by apps, clusters, and sql_warehouses. type LifecycleWithStarted struct { diff --git a/bundle/deployplan/action.go b/bundle/deployplan/action.go index e53ef0d84bd..e85a5b63df6 100644 --- a/bundle/deployplan/action.go +++ b/bundle/deployplan/action.go @@ -43,36 +43,45 @@ type ActionType string // If case of several options, action with highest severity wins. // Note, Create/Delete are handled explicitly and never compared. const ( - Undefined ActionType = "" - Skip ActionType = "skip" - Resize ActionType = "resize" - Update ActionType = "update" - UpdateWithID ActionType = "update_id" - Create ActionType = "create" - Recreate ActionType = "recreate" - Delete ActionType = "delete" + Undefined ActionType = "" + Skip ActionType = "skip" + Resize ActionType = "resize" + Update ActionType = "update" + UpdateWithID ActionType = "update_id" + Bind ActionType = "bind" + BindAndUpdate ActionType = "bind_and_update" + Create ActionType = "create" + Recreate ActionType = "recreate" + Delete ActionType = "delete" ) var actionOrder = map[ActionType]int{ - Undefined: 0, - Skip: 1, - Resize: 2, - Update: 3, - UpdateWithID: 4, - Create: 5, - Recreate: 6, - Delete: 7, + Undefined: 0, + Skip: 1, + Resize: 2, + Update: 3, + UpdateWithID: 4, + Bind: 5, + BindAndUpdate: 6, + Create: 7, + Recreate: 8, + Delete: 9, } func (a ActionType) KeepsID() bool { switch a { - case Create, UpdateWithID, Recreate, Delete: + case Create, UpdateWithID, Recreate, Delete, Bind, BindAndUpdate: return false default: return true } } +// IsBind returns true if the action is a bind action. +func (a ActionType) IsBind() bool { + return a == Bind || a == BindAndUpdate +} + // StringShort short version of action string, without suffix func (a ActionType) StringShort() string { items := strings.SplitN(string(a), "_", 2) @@ -85,8 +94,17 @@ func (a ActionType) StringShort() string { // sentence case of other output. "bundle plan" keeps the lower-case present tense, // so the two are still distinguishable at a glance. func AppliedLine(resourceKey string, action ActionType) string { - verb := action.StringShort() + "d" - return strings.ToUpper(verb[:1]) + verb[1:] + " " + strings.TrimPrefix(resourceKey, "resources.") + key := strings.TrimPrefix(resourceKey, "resources.") + // "bind" does not follow the "+d" rule, and bind_and_update names both halves. + switch action { + case Bind: + return "Bound " + key + case BindAndUpdate: + return "Bound and updated " + key + default: + verb := action.StringShort() + "d" + return strings.ToUpper(verb[:1]) + verb[1:] + " " + key + } } // GetHigherAction returns the action with higher severity between a and b. diff --git a/bundle/deployplan/plan.go b/bundle/deployplan/plan.go index 8446b200b12..1591ac2d770 100644 --- a/bundle/deployplan/plan.go +++ b/bundle/deployplan/plan.go @@ -49,6 +49,9 @@ type ActionCounts struct { Change int Delete int Unchanged int + // Bind counts bind and bind_and_update actions; a bind_and_update also + // counts as a change, since it applies config to the adopted resource. + Bind int } // CountActions tallies the plan's actions by category. Order is irrelevant to a @@ -74,6 +77,11 @@ func (p *Plan) CountActions() ActionCounts { // A recreate counts as both a delete and a create. c.Delete++ c.Create++ + case Bind: + c.Bind++ + case BindAndUpdate: + c.Bind++ + c.Change++ case Skip, Undefined: c.Unchanged++ } @@ -120,6 +128,7 @@ func LoadPlanFromFile(path string) (*Plan, error) { type PlanEntry struct { ID string `json:"id,omitempty"` + BindID string `json:"bind_id,omitempty"` DependsOn []DependsOnEntry `json:"depends_on,omitempty"` Action ActionType `json:"action,omitempty"` // Gone is set on Delete entries when planning confirmed the resource no longer diff --git a/bundle/direct/apply.go b/bundle/direct/apply.go index 9cdd5a4f505..9e95c4cebc0 100644 --- a/bundle/direct/apply.go +++ b/bundle/direct/apply.go @@ -36,8 +36,15 @@ func (d *DeploymentUnit) Destroy(ctx context.Context, db *dstate.DeploymentState func (d *DeploymentUnit) Deploy(ctx context.Context, db *dstate.DeploymentState, newState any, actionType deployplan.ActionType, planEntry *deployplan.PlanEntry) error { ctx = log.WithPrefix(ctx, "deploying "+d.ResourceKey) ctx = d.withResourceKey(ctx) - if actionType == deployplan.Create { + switch actionType { + case deployplan.Create: return d.Create(ctx, db, newState) + case deployplan.Bind: + return d.Bind(ctx, db, planEntry.BindID, newState, planEntry) + case deployplan.BindAndUpdate: + return d.BindAndUpdate(ctx, db, planEntry.BindID, newState, planEntry) + default: + // The remaining actions operate on the ID recorded in state. } oldID := db.GetResourceID(d.ResourceKey) @@ -59,6 +66,49 @@ func (d *DeploymentUnit) Deploy(ctx context.Context, db *dstate.DeploymentState, } } +// Bind brings an existing workspace resource under bundle management by persisting +// its ID to state, without modifying the remote resource. +func (d *DeploymentUnit) Bind(ctx context.Context, db *dstate.DeploymentState, id string, newState any, planEntry *deployplan.PlanEntry) error { + // The remote resource was read during planning and is unchanged by a pure bind; + // reuse it so dependents (permissions, grants) do not trigger a second read. + err := d.SetRemoteState(planEntry.RemoteState) + if err != nil { + return err + } + + err = db.SaveState(ctx, d.ResourceKey, id, newState, d.DependsOn) + if err != nil { + return fmt.Errorf("saving state id=%s: %w", id, err) + } + + log.Infof(ctx, "Bound %s id=%s", d.ResourceKey, id) + return nil +} + +// BindAndUpdate binds an existing workspace resource and applies the configured +// field changes to it. It dispatches on the planned action so the change goes +// through the same path a normal deploy would: Resize for running-cluster +// worker/autoscale drift, Update otherwise. Recreate / UpdateWithID are rejected +// at plan time, so only Update and Resize can reach here. +func (d *DeploymentUnit) BindAndUpdate(ctx context.Context, db *dstate.DeploymentState, id string, newState any, planEntry *deployplan.PlanEntry) error { + action := getMaxAction(planEntry.Changes) + switch action { + case deployplan.Resize: + if err := d.Resize(ctx, db, id, newState, planEntry); err != nil { + return err + } + case deployplan.Update: + if err := d.Update(ctx, db, id, newState, planEntry); err != nil { + return err + } + default: + return fmt.Errorf("internal error: unexpected action %q during bind_and_update", action) + } + + log.Infof(ctx, "Bound and updated %s id=%s", d.ResourceKey, id) + return nil +} + // Create creates the resource and records its state. func (d *DeploymentUnit) Create(ctx context.Context, db *dstate.DeploymentState, newState any) error { var newID string diff --git a/bundle/direct/bundle_plan.go b/bundle/direct/bundle_plan.go index 8f8336beaa5..2a1321c2fab 100644 --- a/bundle/direct/bundle_plan.go +++ b/bundle/direct/bundle_plan.go @@ -161,6 +161,9 @@ func (b *DeploymentBundle) StampDeploymentIdForFirstVersion(deploymentID string) // CalculatePlan computes the deployment plan by comparing local config against remote state. // StateDB must already be open for read before calling this function. +// +// Resources with lifecycle.bind that are not yet in state are planned as Bind / +// BindAndUpdate instead of Create; a nil configRoot (destroy) binds nothing. func (b *DeploymentBundle) CalculatePlan(ctx context.Context, client *databricks.WorkspaceClient, configRoot *config.Root) (*deployplan.Plan, error) { b.StateDB.AssertOpenedForRead() @@ -181,6 +184,14 @@ func (b *DeploymentBundle) CalculatePlan(ctx context.Context, client *databricks b.Plan = plan + // Validate bind blocks against the state before walking the graph; the per-resource + // planning below selects Bind / BindAndUpdate for resources being bound for the + // first time and guards the ones already bound. + bindIDByKey := lifecycleBindIDs(configRoot) + if len(bindIDByKey) > 0 && !b.validateBindConfig(ctx, configRoot, bindIDByKey) { + return nil, errors.New("bind validation failed") + } + g, err := makeGraph(plan) if err != nil { return nil, err @@ -275,6 +286,13 @@ func (b *DeploymentBundle) CalculatePlan(ctx context.Context, client *databricks // state files may still carry a malformed entry). Treat as missing // and let the resource be re-created on this plan. if !hasEntry || dbentry.ID == "" { + // A resource that is not in state but carries a bind block is imported + // rather than created: read the remote resource under the bound ID and + // plan a Bind / BindAndUpdate instead of a Create. + if bindID, ok := bindIDByKey[resourceKey]; ok { + entry.BindID = bindID + return b.handleBindPlan(ctx, resourceKey, entry, adapter) + } entry.Action = deployplan.Create return true } @@ -370,7 +388,15 @@ func (b *DeploymentBundle) CalculatePlan(ctx context.Context, client *databricks return false } + _, bound := bindIDByKey[resourceKey] if remoteState == nil { + // A bind block pins the resource to one ID. Creating a replacement would + // re-point the state at a new ID behind the user's back and leave the + // block mismatched on every later plan, so report the deletion instead. + if bound { + logdiag.LogError(ctx, fmt.Errorf("%s: bound resource with ID %q no longer exists in the workspace; remove lifecycle.bind to create a new resource", errorPrefix, dbentry.ID)) + return false + } // Even if local action is "recreate" which is higher than "create", we should still pick "create" here // because we know remote does not exist. action = deployplan.Create @@ -382,6 +408,15 @@ func (b *DeploymentBundle) CalculatePlan(ctx context.Context, client *databricks // it can be used for variable resolution depends on several factors, see canReadRemoteCache in LookupReferencePreDeploy b.RemoteStateCache.Store(resourceKey, remoteState) + // An active bind block guards its resource against recreation for as long as + // it is defined, not just during the first bind. Once the resource is in + // state, a config change that would recreate or re-ID it still surfaces as an + // error so the bind block behaves as a persistent guard (see handleBindPlan). + if bound && (action == deployplan.Recreate || action == deployplan.UpdateWithID) { + logdiag.LogError(ctx, buildBindConflictError(resourceKey, action, entry.Changes, false)) + return false + } + // Validate that resources without DoUpdate don't have update actions if action == deployplan.Update && !adapter.HasDoUpdate() { logdiag.LogError(ctx, fmt.Errorf("%s: resource does not support update action but plan produced update", errorPrefix)) @@ -991,6 +1026,11 @@ func (b *DeploymentBundle) LookupReferencePreDeploy(ctx context.Context, path *s } return id, nil } + // A bind adopts the resource under the ID from the bind block; it is known + // before deployment even though the state has no entry yet. + if targetEntry.BindID != "" { + return targetEntry.BindID, nil + } // id may change after deployment, this needs to be done later return nil, errDelayed } diff --git a/bundle/direct/bundle_plan_bind.go b/bundle/direct/bundle_plan_bind.go new file mode 100644 index 00000000000..11f26c5f1b4 --- /dev/null +++ b/bundle/direct/bundle_plan_bind.go @@ -0,0 +1,300 @@ +package direct + +import ( + "context" + "errors" + "fmt" + "maps" + "slices" + "strings" + + "github.com/databricks/cli/bundle/config" + "github.com/databricks/cli/bundle/deployplan" + "github.com/databricks/cli/bundle/direct/dresources" + "github.com/databricks/cli/libs/diag" + "github.com/databricks/cli/libs/logdiag" + "github.com/databricks/cli/libs/retry" + "github.com/databricks/cli/libs/structs/structdiff" + "github.com/databricks/cli/libs/structs/structpath" + "github.com/databricks/databricks-sdk-go/apierr" +) + +// lifecycleBindIDs collects lifecycle.bind IDs by resource key. A nil configRoot +// (destroy) has no bind blocks. +func lifecycleBindIDs(configRoot *config.Root) map[string]string { + result := map[string]string{} + if configRoot == nil { + return result + } + for _, group := range configRoot.Resources.AllResources() { + for name, resource := range group.Resources { + bind := resource.GetLifecycle().GetBind() + if bind == nil { + continue + } + result["resources."+group.Description.PluralName+"."+name] = bind.ID + } + } + return result +} + +// bindIDPath returns the config path of a resource's lifecycle.bind.id, used to point +// diagnostics at the offending entry. +func bindIDPath(resourceKey string) *structpath.PathNode { + resourceType, resourceName := splitResourceKey(resourceKey) + return structpath.NewPath(nil, "resources", resourceType, resourceName, "lifecycle", "bind", "id") +} + +func (b *DeploymentBundle) logBindError(ctx context.Context, configRoot *config.Root, resourceKey, summary string) { + path := bindIDPath(resourceKey) + logdiag.LogDiag(ctx, diag.Diagnostic{ + Severity: diag.Error, + Summary: summary, + Locations: configRoot.GetLocationsOf(path), + Paths: []*structpath.PathNode{path}, + }) +} + +// validateBindConfig logs diagnostics for lifecycle.bind entries that conflict with the +// state. Returns false if any errors were logged. +func (b *DeploymentBundle) validateBindConfig(ctx context.Context, configRoot *config.Root, bindIDByKey map[string]string) bool { + hasError := false + keys := slices.Sorted(maps.Keys(bindIDByKey)) + + // A resource that is already in state cannot be re-bound to a different ID: + // lifecycle.bind adopts a resource for the first time. When the IDs match the bind + // is a no-op and the resource just deploys normally. + for _, key := range keys { + bindID := bindIDByKey[key] + dbentry, hasEntry := b.StateDB.GetResourceEntry(key) + if !hasEntry || dbentry.ID == "" || dbentry.ID == bindID { + continue + } + b.logBindError(ctx, configRoot, key, fmt.Sprintf("%s: resource already bound to ID %q, cannot bind as %q; remove lifecycle.bind or unbind the existing resource", key, dbentry.ID, bindID)) + hasError = true + } + + // Two resources must not bind the same workspace ID. Otherwise both would be + // adopted and two state entries would manage one remote resource. IDs are only + // unique within a resource type (a job and an experiment can share a numeric ID), + // so only resources of the same type can collide. + keysByTypeAndID := map[string][]string{} + for _, key := range keys { + keysByTypeAndID[typeAndID(key, bindIDByKey[key])] = append(keysByTypeAndID[typeAndID(key, bindIDByKey[key])], key) + } + for _, key := range keys { + bindID := bindIDByKey[key] + others := slices.DeleteFunc(slices.Clone(keysByTypeAndID[typeAndID(key, bindID)]), func(k string) bool { return k == key }) + if len(others) == 0 { + continue + } + b.logBindError(ctx, configRoot, key, fmt.Sprintf("%s has the same lifecycle.bind ID %q as %s; each workspace resource can only be bound once", key, bindID, strings.Join(others, ", "))) + hasError = true + } + + // A bind ID must not collide with another resource's ID in state. Such a collision + // would let a bind silently redirect a delete/recreate/update_id at a resource the + // user is also trying to import; reject it instead of choosing one over the other. + stateKeys := slices.Sorted(maps.Keys(b.StateDB.Data.State)) + for _, key := range keys { + bindID := bindIDByKey[key] + for _, stateKey := range stateKeys { + if stateKey == key || b.StateDB.Data.State[stateKey].ID != bindID || typeAndID(stateKey, bindID) != typeAndID(key, bindID) { + continue + } + b.logBindError(ctx, configRoot, key, fmt.Sprintf("%s has the same lifecycle.bind ID %q as existing resource %q; remove lifecycle.bind or the conflicting resource", key, bindID, stateKey)) + hasError = true + } + } + + return !hasError +} + +// typeAndID keys a bind by resource type and workspace ID, the scope within which IDs +// are unique. +func typeAndID(resourceKey, bindID string) string { + resourceType, _ := splitResourceKey(resourceKey) + return resourceType + ":" + bindID +} + +// handleBindPlan reads the remote resource for a resource that is being bound for +// the first time, computes the change set against the local config, and selects +// either Bind (no changes) or BindAndUpdate (config drift can be applied). +// +// Recreate / UpdateWithID actions imply destroying or replacing the workspace +// resource — incompatible with bind — so they surface as actionable errors. +// Returns false if an error was logged. +func (b *DeploymentBundle) handleBindPlan(ctx context.Context, resourceKey string, entry *deployplan.PlanEntry, adapter *dresources.Adapter) bool { + bindID := entry.BindID + errorPrefix := "cannot bind " + resourceKey + + remoteState, err := retry.With(ctx, retry.IsTransientRead, func() (any, error) { + return adapter.DoRead(ctx, bindID) + }) + if err != nil { + if apierr.IsMissing(err) { + logdiag.LogError(ctx, fmt.Errorf("%s: resource with ID %q does not exist in workspace", errorPrefix, bindID)) + } else { + logdiag.LogError(ctx, fmt.Errorf("%s: reading remote resource id=%q: %w", errorPrefix, bindID, err)) + } + return false + } + + entry.RemoteState = remoteState + b.RemoteStateCache.Store(resourceKey, remoteState) + + sv, ok := b.StateCache.Load(resourceKey) + if !ok { + logdiag.LogError(ctx, fmt.Errorf("%s: internal error: no state cache entry", errorPrefix)) + return false + } + + remoteStateComparable, err := adapter.RemapState(remoteState) + if err != nil { + logdiag.LogError(ctx, fmt.Errorf("%s: interpreting remote state: %w", errorPrefix, err)) + return false + } + + // Compact both sides on the same fields, so a hashed_fields field is a hash on + // both sides of the diff. sv.Value keeps the full contents for the deploy. + remoteStateComparable, err = dresources.CompactState(adapter.ResourceConfig(), remoteStateComparable) + if err != nil { + logdiag.LogError(ctx, fmt.Errorf("%s: compacting remote state: %w", errorPrefix, err)) + return false + } + localState, err := dresources.CompactState(adapter.ResourceConfig(), sv.Value) + if err != nil { + logdiag.LogError(ctx, fmt.Errorf("%s: compacting local state: %w", errorPrefix, err)) + return false + } + + remoteDiff, err := structdiff.GetStructDiff(remoteStateComparable, localState, adapter.KeyedSlices()) + if err != nil { + logdiag.LogError(ctx, fmt.Errorf("%s: diffing remote state: %w", errorPrefix, err)) + return false + } + + // No "saved state" exists for a first-time bind; the diff is purely remote vs. config. + entry.Changes, err = prepareChanges(ctx, adapter, nil, remoteDiff, nil, remoteStateComparable) + if err != nil { + logdiag.LogError(ctx, fmt.Errorf("%s: %w", errorPrefix, err)) + return false + } + + err = addPerFieldActions(ctx, adapter, entry.Changes, sv.Value, remoteState) + if err != nil { + logdiag.LogError(ctx, fmt.Errorf("%s: classifying changes: %w", errorPrefix, err)) + return false + } + + switch maxAction := getMaxAction(entry.Changes); maxAction { + case deployplan.Skip, deployplan.Undefined: + entry.Action = deployplan.Bind + case deployplan.Update, deployplan.Resize: + // Same guard as the in-state path: an update can only be applied if the + // resource implements DoUpdate. + if maxAction == deployplan.Update && !adapter.HasDoUpdate() { + logdiag.LogError(ctx, fmt.Errorf("%s: resource does not support update action but plan produced update", errorPrefix)) + return false + } + entry.Action = deployplan.BindAndUpdate + case deployplan.Recreate, deployplan.UpdateWithID: + logdiag.LogError(ctx, buildBindConflictError(resourceKey, maxAction, entry.Changes, true)) + return false + default: + logdiag.LogError(ctx, fmt.Errorf("%s: internal error: unexpected action %q during bind planning", errorPrefix, maxAction)) + return false + } + return true +} + +// buildBindConflictError formats a multi-line message that names the fields whose +// changes forced an incompatible action (Recreate / UpdateWithID) and shows the two +// concrete resolutions: drop the offending fields, or drop lifecycle.bind. firstBind +// tells a resource being adopted apart from one that is already bound in state. +func buildBindConflictError(resourceKey string, action deployplan.ActionType, changes deployplan.Changes, firstBind bool) error { + problematicFields := make([]string, 0, len(changes)) + for fieldPath, change := range changes { + if change.Action == action { + problematicFields = append(problematicFields, fieldPath) + } + } + // Stable order so the YAML examples are deterministic across runs. + slices.Sort(problematicFields) + + resourceType, resourceName := splitResourceKey(resourceKey) + + var headline, effect, option1 string + // buildBindConflictError is only invoked for Recreate / UpdateWithID; other + // action types are guarded by the caller. + switch { //nolint:exhaustive + case action == deployplan.Recreate && firstBind: + headline = "cannot bind " + resourceKey + ": cannot recreate resource with lifecycle.bind" + effect = "This would destroy and recreate the existing workspace resource, changing its ID." + case action == deployplan.Recreate: + headline = "cannot plan " + resourceKey + ": lifecycle.bind prevents recreating the bound resource" + effect = "This would destroy and recreate the bound workspace resource, changing its ID." + case action == deployplan.UpdateWithID && firstBind: + headline = "cannot bind " + resourceKey + ": cannot update resource ID with lifecycle.bind" + effect = "This would replace the existing workspace resource with a new ID." + case action == deployplan.UpdateWithID: + headline = "cannot plan " + resourceKey + ": lifecycle.bind prevents changing the ID of the bound resource" + effect = "This would replace the bound workspace resource with a new ID." + } + if firstBind { + option1 = "Remove the problematic fields from your configuration to make this a bind-only operation:" + } else { + option1 = "Revert the problematic fields in your configuration to keep the bound resource as it is:" + } + + var msg strings.Builder + msg.WriteString(headline + "\n\n") + msg.WriteString(effect + "\n\n") + + msg.WriteString("The following fields cannot be modified because they require ") + if action == deployplan.Recreate { + msg.WriteString("resource recreation:\n") + } else { + msg.WriteString("ID changes:\n") + } + for _, field := range problematicFields { + if reason := changes[field].Reason; reason != "" { + fmt.Fprintf(&msg, " - %s (%s)\n", field, reason) + } else { + fmt.Fprintf(&msg, " - %s\n", field) + } + } + msg.WriteString("\n") + + msg.WriteString("To resolve this issue, you have two options:\n\n") + msg.WriteString("1. " + option1 + "\n\n") + msg.WriteString(" resources:\n") + fmt.Fprintf(&msg, " %s:\n", resourceType) + fmt.Fprintf(&msg, " %s:\n", resourceName) + msg.WriteString(" # Remove or comment out these fields:\n") + for _, field := range problematicFields { + fmt.Fprintf(&msg, " # %s: ...\n", field) + } + msg.WriteString("\n") + msg.WriteString("2. Remove lifecycle.bind if you want to allow the resource to be recreated/updated:\n\n") + msg.WriteString(" resources:\n") + fmt.Fprintf(&msg, " %s:\n", resourceType) + fmt.Fprintf(&msg, " %s:\n", resourceName) + msg.WriteString(" lifecycle:\n") + msg.WriteString(" # Remove the bind block:\n") + msg.WriteString(" # bind:\n") + // No trailing newline: error strings must not end with one. + msg.WriteString(" # id: ") + + return errors.New(msg.String()) +} + +// splitResourceKey extracts the resource type and name from a key like +// "resources.jobs.foo" → ("jobs", "foo"). +func splitResourceKey(resourceKey string) (resourceType, resourceName string) { + parts := strings.SplitN(resourceKey, ".", 3) + if len(parts) < 3 { + return "", "" + } + return parts[1], parts[2] +} diff --git a/bundle/direct/dresources/type_test.go b/bundle/direct/dresources/type_test.go index d7515ae55a8..38b758b9625 100644 --- a/bundle/direct/dresources/type_test.go +++ b/bundle/direct/dresources/type_test.go @@ -83,19 +83,23 @@ var knownMissingInStateType = map[string][]string{ "apps": { "lifecycle.prevent_destroy", "lifecycle.depends_on", + "lifecycle.bind", }, "clusters": { "lifecycle.prevent_destroy", "lifecycle.depends_on", + "lifecycle.bind", }, "sql_warehouses": { "lifecycle.prevent_destroy", "lifecycle.depends_on", + "lifecycle.bind", }, "job_runs": { // State stores trigger fingerprints, not the config trigger list / prevent_destroy. "lifecycle.prevent_destroy", "lifecycle.depends_on", + "lifecycle.bind", "lifecycle.triggers", }, "dashboards": { diff --git a/bundle/internal/schema/annotations.yml b/bundle/internal/schema/annotations.yml index d4885599805..26c729583a4 100644 --- a/bundle/internal/schema/annotations.yml +++ b/bundle/internal/schema/annotations.yml @@ -629,6 +629,9 @@ resources: "description": |- Settings that control the deployment lifecycle of the resource, such as preventing it from being destroyed. "$fields": + "bind": + "description": |- + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. "depends_on": "description": |- Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -1087,6 +1090,9 @@ resources: "description": |- Settings that control the deployment lifecycle of the resource, such as preventing it from being destroyed and when the run re-fires. "$fields": + "bind": + "description": |- + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. "depends_on": "description": |- Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -1170,6 +1176,13 @@ resources: "description": |- Settings that control the deployment lifecycle of the resource, such as preventing it from being destroyed. "$fields": + "bind": + "description": |- + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + "$fields": + "id": + "description": |- + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. "depends_on": "description": |- Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/bundle/internal/validation/generated/required_fields.go b/bundle/internal/validation/generated/required_fields.go index 8d40e0255f6..38d395d9a29 100644 --- a/bundle/internal/validation/generated/required_fields.go +++ b/bundle/internal/validation/generated/required_fields.go @@ -15,6 +15,7 @@ var RequiredFields = map[string][]string{ "resources.alerts.*.evaluation": {"comparison_operator", "source"}, "resources.alerts.*.evaluation.source": {"name"}, "resources.alerts.*.evaluation.threshold.column": {"name"}, + "resources.alerts.*.lifecycle.bind": {"id"}, "resources.alerts.*.lifecycle.depends_on[*]": {"resource"}, "resources.alerts.*.parameters[*]": {"name"}, "resources.alerts.*.permissions[*]": {"level"}, @@ -26,6 +27,7 @@ var RequiredFields = map[string][]string{ "resources.apps.*.default_git_source.git_repository": {"provider", "url"}, "resources.apps.*.git_repository": {"provider", "url"}, "resources.apps.*.git_source.git_repository": {"provider", "url"}, + "resources.apps.*.lifecycle.bind": {"id"}, "resources.apps.*.lifecycle.depends_on[*]": {"resource"}, "resources.apps.*.pending_deployment.git_source.git_repository": {"provider", "url"}, "resources.apps.*.permissions[*]": {"level"}, @@ -41,12 +43,14 @@ var RequiredFields = map[string][]string{ "resources.apps.*.telemetry_export_destinations[*].unity_catalog": {"logs_table", "metrics_table", "traces_table"}, "resources.catalogs.*": {"name"}, + "resources.catalogs.*.lifecycle.bind": {"id"}, "resources.catalogs.*.lifecycle.depends_on[*]": {"resource"}, "resources.catalogs.*.managed_encryption_settings.azure_encryption_settings": {"azure_tenant_id"}, "resources.cluster_policies.*.libraries[*].cran": {"package"}, "resources.cluster_policies.*.libraries[*].maven": {"coordinates"}, "resources.cluster_policies.*.libraries[*].pypi": {"package"}, + "resources.cluster_policies.*.lifecycle.bind": {"id"}, "resources.cluster_policies.*.lifecycle.depends_on[*]": {"resource"}, "resources.cluster_policies.*.permissions[*]": {"level"}, @@ -63,26 +67,32 @@ var RequiredFields = map[string][]string{ "resources.clusters.*.libraries[*].cran": {"package"}, "resources.clusters.*.libraries[*].maven": {"coordinates"}, "resources.clusters.*.libraries[*].pypi": {"package"}, + "resources.clusters.*.lifecycle.bind": {"id"}, "resources.clusters.*.lifecycle.depends_on[*]": {"resource"}, "resources.clusters.*.permissions[*]": {"level"}, "resources.clusters.*.workload_type": {"clients"}, + "resources.dashboards.*.lifecycle.bind": {"id"}, "resources.dashboards.*.lifecycle.depends_on[*]": {"resource"}, "resources.dashboards.*.permissions[*]": {"level"}, "resources.database_catalogs.*": {"database_instance_name", "database_name", "name"}, + "resources.database_catalogs.*.lifecycle.bind": {"id"}, "resources.database_catalogs.*.lifecycle.depends_on[*]": {"resource"}, "resources.database_instances.*": {"name"}, + "resources.database_instances.*.lifecycle.bind": {"id"}, "resources.database_instances.*.lifecycle.depends_on[*]": {"resource"}, "resources.database_instances.*.permissions[*]": {"level"}, "resources.experiments.*": {"name"}, + "resources.experiments.*.lifecycle.bind": {"id"}, "resources.experiments.*.lifecycle.depends_on[*]": {"resource"}, "resources.experiments.*.permissions[*]": {"level"}, "resources.experiments.*.trace_location.uc_trace_location": {"catalog", "schema"}, "resources.external_locations.*": {"credential_name", "name", "url"}, + "resources.external_locations.*.lifecycle.bind": {"id"}, "resources.external_locations.*.lifecycle.depends_on[*]": {"resource"}, "resources.features.*": {"full_name", "function", "source"}, @@ -111,6 +121,7 @@ var RequiredFields = map[string][]string{ "resources.features.*.function.custom_udf": {"function_path"}, "resources.features.*.function.custom_udf.input_bindings[*]": {"column", "parameter"}, "resources.features.*.function.extra_parameters[*]": {"key", "value"}, + "resources.features.*.lifecycle.bind": {"id"}, "resources.features.*.lifecycle.depends_on[*]": {"resource"}, "resources.features.*.source.delta_table_source": {"full_name"}, "resources.features.*.source.feature_view_source.feature_references[*]": {"feature"}, @@ -125,14 +136,17 @@ var RequiredFields = map[string][]string{ "resources.features.*.time_window.tumbling": {"window_duration"}, "resources.features.*.timeseries_column": {"name"}, + "resources.genie_spaces.*.lifecycle.bind": {"id"}, "resources.genie_spaces.*.lifecycle.depends_on[*]": {"resource"}, "resources.genie_spaces.*.permissions[*]": {"level"}, "resources.instance_pools.*": {"instance_pool_name", "node_type_id"}, + "resources.instance_pools.*.lifecycle.bind": {"id"}, "resources.instance_pools.*.lifecycle.depends_on[*]": {"resource"}, "resources.instance_pools.*.permissions[*]": {"level"}, "resources.job_runs.*": {"job_id"}, + "resources.job_runs.*.lifecycle.bind": {"id"}, "resources.job_runs.*.lifecycle.depends_on[*]": {"resource"}, "resources.job_runs.*.queue": {"enabled"}, @@ -155,6 +169,7 @@ var RequiredFields = map[string][]string{ "resources.jobs.*.job_clusters[*].new_cluster.init_scripts[*].volumes": {"destination"}, "resources.jobs.*.job_clusters[*].new_cluster.init_scripts[*].workspace": {"destination"}, "resources.jobs.*.job_clusters[*].new_cluster.workload_type": {"clients"}, + "resources.jobs.*.lifecycle.bind": {"id"}, "resources.jobs.*.lifecycle.depends_on[*]": {"resource"}, "resources.jobs.*.parameters[*]": {"default", "name"}, "resources.jobs.*.permissions[*]": {"level"}, @@ -294,6 +309,7 @@ var RequiredFields = map[string][]string{ "resources.mcp_services.*": {"parent", "mcp_service_id"}, "resources.mcp_services.*.config.rate_limits[*]": {"key", "renewal_period"}, "resources.mcp_services.*.config.source_connection": {"name"}, + "resources.mcp_services.*.lifecycle.bind": {"id"}, "resources.mcp_services.*.lifecycle.depends_on[*]": {"resource"}, "resources.model_provider_services.*": {"parent", "model_provider_service_id"}, @@ -316,6 +332,7 @@ var RequiredFields = map[string][]string{ "resources.model_provider_services.*.config.openai.direct.api_key.secret_reference": {"name"}, "resources.model_provider_services.*.config.rate_limits[*]": {"key", "renewal_period"}, "resources.model_provider_services.*.config.targets[*]": {"model"}, + "resources.model_provider_services.*.lifecycle.bind": {"id"}, "resources.model_provider_services.*.lifecycle.depends_on[*]": {"resource"}, "resources.model_services.*": {"parent", "model_service_id"}, @@ -331,6 +348,7 @@ var RequiredFields = map[string][]string{ "resources.model_services.*.config.routing.fallback.destinations[*].external_model_config.target": {"model"}, "resources.model_services.*.config.routing.fallback.destinations[*].pay_per_token_config": {"model"}, "resources.model_services.*.config.routing.fallback.destinations[*].provisioned_throughput_config": {"model_serving_endpoint"}, + "resources.model_services.*.lifecycle.bind": {"id"}, "resources.model_services.*.lifecycle.depends_on[*]": {"resource"}, "resources.model_serving_endpoints.*": {"name"}, @@ -344,12 +362,14 @@ var RequiredFields = map[string][]string{ "resources.model_serving_endpoints.*.config.served_entities[*].external_model.google_cloud_vertex_ai_config": {"project_id", "region"}, "resources.model_serving_endpoints.*.config.served_models[*]": {"model_name", "model_version", "scale_to_zero_enabled"}, "resources.model_serving_endpoints.*.config.traffic_config.routes[*]": {"traffic_percentage"}, + "resources.model_serving_endpoints.*.lifecycle.bind": {"id"}, "resources.model_serving_endpoints.*.lifecycle.depends_on[*]": {"resource"}, "resources.model_serving_endpoints.*.permissions[*]": {"level"}, "resources.model_serving_endpoints.*.rate_limits[*]": {"calls", "renewal_period"}, "resources.model_serving_endpoints.*.tags[*]": {"key"}, "resources.models.*": {"name"}, + "resources.models.*.lifecycle.bind": {"id"}, "resources.models.*.lifecycle.depends_on[*]": {"resource"}, "resources.models.*.permissions[*]": {"level"}, @@ -384,31 +404,39 @@ var RequiredFields = map[string][]string{ "resources.pipelines.*.ingestion_definition.objects[*].table.table_configuration.auto_full_refresh_policy": {"enabled"}, "resources.pipelines.*.ingestion_definition.table_configuration.auto_full_refresh_policy": {"enabled"}, "resources.pipelines.*.libraries[*].maven": {"coordinates"}, + "resources.pipelines.*.lifecycle.bind": {"id"}, "resources.pipelines.*.lifecycle.depends_on[*]": {"resource"}, "resources.pipelines.*.permissions[*]": {"level"}, "resources.pipelines.*.restart_window": {"start_hour"}, "resources.postgres_branches.*": {"branch_id", "parent"}, + "resources.postgres_branches.*.lifecycle.bind": {"id"}, "resources.postgres_branches.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_catalogs.*": {"postgres_database", "catalog_id"}, + "resources.postgres_catalogs.*.lifecycle.bind": {"id"}, "resources.postgres_catalogs.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_databases.*": {"role", "database_id", "parent"}, + "resources.postgres_databases.*.lifecycle.bind": {"id"}, "resources.postgres_databases.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_endpoints.*": {"endpoint_type", "endpoint_id", "parent"}, "resources.postgres_endpoints.*.group": {"max", "min"}, + "resources.postgres_endpoints.*.lifecycle.bind": {"id"}, "resources.postgres_endpoints.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_projects.*": {"project_id"}, + "resources.postgres_projects.*.lifecycle.bind": {"id"}, "resources.postgres_projects.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_projects.*.permissions[*]": {"level"}, "resources.postgres_roles.*": {"role_id", "parent"}, + "resources.postgres_roles.*.lifecycle.bind": {"id"}, "resources.postgres_roles.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_snapshot_schedules.*": {"branch"}, + "resources.postgres_snapshot_schedules.*.lifecycle.bind": {"id"}, "resources.postgres_snapshot_schedules.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_snapshot_schedules.*.schedule[*]": {"retention"}, "resources.postgres_snapshot_schedules.*.schedule[*].monthly_schedule": {"day"}, @@ -416,44 +444,55 @@ var RequiredFields = map[string][]string{ "resources.postgres_synced_tables.*": {"synced_table_id"}, "resources.postgres_synced_tables.*.extra_columns[*]": {"column_name", "column_type"}, + "resources.postgres_synced_tables.*.lifecycle.bind": {"id"}, "resources.postgres_synced_tables.*.lifecycle.depends_on[*]": {"resource"}, "resources.postgres_synced_tables.*.type_overrides[*]": {"column_name", "pg_type"}, "resources.quality_monitors.*": {"assets_dir", "output_schema_name", "table_name"}, "resources.quality_monitors.*.custom_metrics[*]": {"definition", "input_columns", "name", "output_data_type", "type"}, "resources.quality_monitors.*.inference_log": {"granularities", "model_id_col", "prediction_col", "problem_type", "timestamp_col"}, + "resources.quality_monitors.*.lifecycle.bind": {"id"}, "resources.quality_monitors.*.lifecycle.depends_on[*]": {"resource"}, "resources.quality_monitors.*.schedule": {"quartz_cron_expression", "timezone_id"}, "resources.quality_monitors.*.time_series": {"granularities", "timestamp_col"}, + "resources.registered_models.*.lifecycle.bind": {"id"}, "resources.registered_models.*.lifecycle.depends_on[*]": {"resource"}, "resources.schemas.*": {"catalog_name", "name"}, + "resources.schemas.*.lifecycle.bind": {"id"}, "resources.schemas.*.lifecycle.depends_on[*]": {"resource"}, "resources.secret_scopes.*": {"name"}, "resources.secret_scopes.*.keyvault_metadata": {"dns_name", "resource_id"}, + "resources.secret_scopes.*.lifecycle.bind": {"id"}, "resources.secret_scopes.*.lifecycle.depends_on[*]": {"resource"}, "resources.secret_scopes.*.permissions[*]": {"level"}, "resources.secrets.*": {"catalog_name", "name", "schema_name", "value"}, + "resources.secrets.*.lifecycle.bind": {"id"}, "resources.secrets.*.lifecycle.depends_on[*]": {"resource"}, + "resources.sql_warehouses.*.lifecycle.bind": {"id"}, "resources.sql_warehouses.*.lifecycle.depends_on[*]": {"resource"}, "resources.sql_warehouses.*.permissions[*]": {"level"}, "resources.synced_database_tables.*": {"name"}, + "resources.synced_database_tables.*.lifecycle.bind": {"id"}, "resources.synced_database_tables.*.lifecycle.depends_on[*]": {"resource"}, "resources.synced_database_tables.*.spec.type_overrides[*]": {"column_name", "pg_type"}, "resources.vector_search_endpoints.*": {"endpoint_type", "name"}, + "resources.vector_search_endpoints.*.lifecycle.bind": {"id"}, "resources.vector_search_endpoints.*.lifecycle.depends_on[*]": {"resource"}, "resources.vector_search_endpoints.*.permissions[*]": {"level"}, "resources.vector_search_indexes.*": {"endpoint_name", "index_type", "name", "primary_key"}, + "resources.vector_search_indexes.*.lifecycle.bind": {"id"}, "resources.vector_search_indexes.*.lifecycle.depends_on[*]": {"resource"}, "resources.volumes.*": {"catalog_name", "name", "schema_name", "volume_type"}, + "resources.volumes.*.lifecycle.bind": {"id"}, "resources.volumes.*.lifecycle.depends_on[*]": {"resource"}, "scripts.*": {"content"}, diff --git a/bundle/phases/bind.go b/bundle/phases/bind.go index 36c4fcf56b4..18e7cf91ea7 100644 --- a/bundle/phases/bind.go +++ b/bundle/phases/bind.go @@ -15,8 +15,10 @@ import ( "github.com/databricks/cli/bundle/statemgmt" "github.com/databricks/cli/libs/agent" "github.com/databricks/cli/libs/cmdio" + "github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/log" "github.com/databricks/cli/libs/logdiag" + "github.com/databricks/cli/libs/structs/structpath" ) type BindOptions struct { @@ -142,4 +144,17 @@ func Unbind(ctx context.Context, b *bundle.Bundle, group, resourceKey string, en } statemgmt.PushResourcesState(ctx, b) + + // Bind is state-less: nothing records that the resource was just unbound, so a + // lifecycle.bind block still in config re-adopts it on the next deploy. + resource, _, err := b.Config.Resources.ResolveKey(group + "." + resourceKey) + if err == nil && resource.GetLifecycle().GetBind() != nil { + bindPath := structpath.NewPath(nil, "resources", group, resourceKey, "lifecycle", "bind") + logdiag.LogDiag(ctx, diag.Diagnostic{ + Severity: diag.Warning, + Summary: fullResourceKey + ".lifecycle.bind re-binds the resource on the next deploy; remove it to keep the resource unbound", + Locations: b.Config.GetLocationsOf(bindPath), + Paths: []*structpath.PathNode{bindPath}, + }) + } } diff --git a/bundle/phases/deploy.go b/bundle/phases/deploy.go index cffeb8e9cd6..11491b00de1 100644 --- a/bundle/phases/deploy.go +++ b/bundle/phases/deploy.go @@ -130,6 +130,9 @@ func logDeploySummary(ctx context.Context, b *bundle.Bundle, plan *deployplan.Pl counts := plan.CountActions() summary := fmt.Sprintf("Resources: %d created, %d changed, %d deleted, %d unchanged", counts.Create, counts.Change, counts.Delete, counts.Unchanged) + if counts.Bind > 0 { + summary += fmt.Sprintf(", %d bound", counts.Bind) + } // Gate on the plan's own NotSelected (not b.Select) so the suffix survives a // deploy from a --plan file, where --select was applied at plan time and // b.Select is empty here. NotSelected is only ever set by FilterToSelected. diff --git a/bundle/phases/destroy.go b/bundle/phases/destroy.go index cfac15e5930..d98a82298e9 100644 --- a/bundle/phases/destroy.go +++ b/bundle/phases/destroy.go @@ -321,6 +321,9 @@ func Destroy(ctx context.Context, b *bundle.Bundle) { bundle.ApplyContext(ctx, b, lock.Release(lock.GoalDestroy)) }() + // Planned without config, so lifecycle.bind plays no role: naming destroy explicitly + // captures the intent to tear the deployment down, bound resources included. The + // block only guards against a recreate during a normal deploy. plan, err := b.DeploymentBundle.CalculatePlan(ctx, b.WorkspaceClient(ctx), nil) if err != nil { logdiag.LogError(ctx, err) diff --git a/bundle/phases/dms.go b/bundle/phases/dms.go index 38210913ce8..3b13bb14ee8 100644 --- a/bundle/phases/dms.go +++ b/bundle/phases/dms.go @@ -63,6 +63,10 @@ func actionToSDK(a deployplan.ActionType) (bundledeployments.OperationActionType return bundledeployments.OperationActionTypeOperationActionTypeResize, nil case deployplan.Delete: return bundledeployments.OperationActionTypeOperationActionTypeDelete, nil + case deployplan.Bind: + return bundledeployments.OperationActionTypeOperationActionTypeBind, nil + case deployplan.BindAndUpdate: + return bundledeployments.OperationActionTypeOperationActionTypeBindAndUpdate, nil default: return "", fmt.Errorf("cannot record operation: unsupported action %q", a) } diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index 8742c086217..63c13d2a7ad 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -350,6 +350,27 @@ } ] }, + "resources.Bind": { + "oneOf": [ + { + "type": "object", + "properties": { + "id": { + "description": "The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved.", + "$ref": "#/$defs/string" + } + }, + "additionalProperties": false, + "required": [ + "id" + ] + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\._*\\p{L}+([-_]*[\\p{L}\\p{N}]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "resources.Catalog": { "oneOf": [ { @@ -1631,6 +1652,10 @@ { "type": "object", "properties": { + "bind": { + "description": "Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption.", + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Bind" + }, "depends_on": { "description": "Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering.", "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.DependsOn" @@ -1679,6 +1704,10 @@ { "type": "object", "properties": { + "bind": { + "description": "Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption.", + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Bind" + }, "depends_on": { "description": "Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering.", "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.DependsOn" @@ -1701,6 +1730,10 @@ { "type": "object", "properties": { + "bind": { + "description": "Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption.", + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Bind" + }, "depends_on": { "description": "Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering.", "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.DependsOn" diff --git a/cmd/bundle/plan.go b/cmd/bundle/plan.go index 1132834bc4d..f7294a6e2a9 100644 --- a/cmd/bundle/plan.go +++ b/cmd/bundle/plan.go @@ -82,7 +82,7 @@ It is useful for previewing changes before running 'bundle deploy'.`, switch root.OutputType(cmd) { case flags.OutputText: // Print summary line and actions to stdout - totalChanges := counts.Create + counts.Change + counts.Delete + totalChanges := counts.Create + counts.Change + counts.Delete + counts.Bind if totalChanges > 0 && bundle.QuietLevel(quiet) < bundle.QuietSummary { // Print all actions in the order they were processed for _, action := range plan.GetActions() { @@ -95,7 +95,14 @@ It is useful for previewing changes before running 'bundle deploy'.`, continue } key := strings.TrimPrefix(action.ResourceKey, "resources.") - fmt.Fprintf(out, "%s %s\n", action.ActionType.StringShort(), key) + if action.ActionType.IsBind() { + // Print the full action string (not StringShort) so bind and + // bind_and_update are distinguishable in the text plan. + entry := plan.Plan[action.ResourceKey] + fmt.Fprintf(out, "%s %s (id: %s)\n", action.ActionType, key, entry.BindID) + } else { + fmt.Fprintf(out, "%s %s\n", action.ActionType.StringShort(), key) + } } fmt.Fprintln(out) } @@ -104,6 +111,9 @@ It is useful for previewing changes before running 'bundle deploy'.`, } // Note, this string should not be changed, "bundle deployment migrate" depends on this format: fmt.Fprintf(out, "Plan: %d to add, %d to change, %d to delete, %d unchanged", counts.Create, counts.Change, counts.Delete, counts.Unchanged) + if counts.Bind > 0 { + fmt.Fprintf(out, ", %d to bind", counts.Bind) + } if len(selectResources) > 0 { fmt.Fprintf(out, ", %d not selected", plan.NotSelected) } diff --git a/python/databricks/bundles/alerts/__init__.py b/python/databricks/bundles/alerts/__init__.py index edc2e7294d9..4785eeb3caa 100644 --- a/python/databricks/bundles/alerts/__init__.py +++ b/python/databricks/bundles/alerts/__init__.py @@ -32,6 +32,9 @@ "AlertV2Subscription", "AlertV2SubscriptionDict", "AlertV2SubscriptionParam", + "Bind", + "BindDict", + "BindParam", "ComparisonOperator", "ComparisonOperatorParam", "CronSchedule", @@ -101,6 +104,7 @@ AlertV2SubscriptionDict, AlertV2SubscriptionParam, ) +from databricks.bundles.alerts._models.bind import Bind, BindDict, BindParam from databricks.bundles.alerts._models.comparison_operator import ( ComparisonOperator, ComparisonOperatorParam, diff --git a/python/databricks/bundles/alerts/_models/alert.py b/python/databricks/bundles/alerts/_models/alert.py index e6dbf9d8448..1924b0f035a 100644 --- a/python/databricks/bundles/alerts/_models/alert.py +++ b/python/databricks/bundles/alerts/_models/alert.py @@ -23,10 +23,7 @@ CustomTemplateFormat, CustomTemplateFormatParam, ) -from databricks.bundles.alerts._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.alerts._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.alerts._models.permission import Permission, PermissionParam from databricks.bundles.core._resource import Resource from databricks.bundles.core._transform import _transform diff --git a/python/databricks/bundles/alerts/_models/bind.py b/python/databricks/bundles/alerts/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/alerts/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/alerts/_models/lifecycle.py b/python/databricks/bundles/alerts/_models/lifecycle.py index 3f8bb9dec50..3e0828f5e69 100644 --- a/python/databricks/bundles/alerts/_models/lifecycle.py +++ b/python/databricks/bundles/alerts/_models/lifecycle.py @@ -3,6 +3,7 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict +from databricks.bundles.alerts._models.bind import Bind, BindParam from databricks.bundles.alerts._models.depends_on import DependsOn, DependsOnParam from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value @@ -16,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -37,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/apps/__init__.py b/python/databricks/bundles/apps/__init__.py index 944c7424fd5..4d1c18730cb 100644 --- a/python/databricks/bundles/apps/__init__.py +++ b/python/databricks/bundles/apps/__init__.py @@ -70,6 +70,9 @@ "AppResourceUcSecurableUcSecurablePermissionParam", "AppResourceUcSecurableUcSecurableType", "AppResourceUcSecurableUcSecurableTypeParam", + "Bind", + "BindDict", + "BindParam", "ComputeSize", "ComputeSizeParam", "DependsOn", @@ -212,6 +215,7 @@ AppResourceUcSecurableUcSecurableType, AppResourceUcSecurableUcSecurableTypeParam, ) +from databricks.bundles.apps._models.bind import Bind, BindDict, BindParam from databricks.bundles.apps._models.compute_size import ComputeSize, ComputeSizeParam from databricks.bundles.apps._models.depends_on import ( DependsOn, diff --git a/python/databricks/bundles/apps/_models/bind.py b/python/databricks/bundles/apps/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/apps/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/apps/_models/lifecycle_with_started.py b/python/databricks/bundles/apps/_models/lifecycle_with_started.py index 0784bf0e2e7..cefac435c97 100644 --- a/python/databricks/bundles/apps/_models/lifecycle_with_started.py +++ b/python/databricks/bundles/apps/_models/lifecycle_with_started.py @@ -3,10 +3,8 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict -from databricks.bundles.apps._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.apps._models.bind import Bind, BindParam +from databricks.bundles.apps._models.depends_on import DependsOn, DependsOnParam from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional @@ -19,6 +17,11 @@ class LifecycleWithStarted: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -45,6 +48,11 @@ def as_dict(self) -> "LifecycleWithStartedDict": class LifecycleWithStartedDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/catalogs/__init__.py b/python/databricks/bundles/catalogs/__init__.py index fced08f1bb2..da17929ec74 100644 --- a/python/databricks/bundles/catalogs/__init__.py +++ b/python/databricks/bundles/catalogs/__init__.py @@ -4,6 +4,9 @@ "AzureEncryptionSettings", "AzureEncryptionSettingsDict", "AzureEncryptionSettingsParam", + "Bind", + "BindDict", + "BindParam", "Catalog", "CatalogDict", "CatalogGrant", @@ -34,6 +37,7 @@ AzureEncryptionSettingsDict, AzureEncryptionSettingsParam, ) +from databricks.bundles.catalogs._models.bind import Bind, BindDict, BindParam from databricks.bundles.catalogs._models.catalog import ( Catalog, CatalogDict, diff --git a/python/databricks/bundles/catalogs/_models/bind.py b/python/databricks/bundles/catalogs/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/catalogs/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/catalogs/_models/catalog.py b/python/databricks/bundles/catalogs/_models/catalog.py index 1f8f3e95b7a..bdb397b0cb0 100644 --- a/python/databricks/bundles/catalogs/_models/catalog.py +++ b/python/databricks/bundles/catalogs/_models/catalog.py @@ -7,10 +7,7 @@ EncryptionSettings, EncryptionSettingsParam, ) -from databricks.bundles.catalogs._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.catalogs._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.catalogs._models.privilege_assignment import ( PrivilegeAssignment, PrivilegeAssignmentParam, diff --git a/python/databricks/bundles/catalogs/_models/lifecycle.py b/python/databricks/bundles/catalogs/_models/lifecycle.py index 0a9985c5b30..067d2787d96 100644 --- a/python/databricks/bundles/catalogs/_models/lifecycle.py +++ b/python/databricks/bundles/catalogs/_models/lifecycle.py @@ -3,7 +3,11 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict -from databricks.bundles.catalogs._models.depends_on import DependsOn, DependsOnParam +from databricks.bundles.catalogs._models.bind import Bind, BindParam +from databricks.bundles.catalogs._models.depends_on import ( + DependsOn, + DependsOnParam, +) from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional @@ -16,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -37,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/cluster_policies/__init__.py b/python/databricks/bundles/cluster_policies/__init__.py index 5f5790166f7..92e19472d4d 100644 --- a/python/databricks/bundles/cluster_policies/__init__.py +++ b/python/databricks/bundles/cluster_policies/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "ClusterPolicy", "ClusterPolicyDict", "ClusterPolicyParam", @@ -30,6 +33,7 @@ ] +from databricks.bundles.cluster_policies._models.bind import Bind, BindDict, BindParam from databricks.bundles.cluster_policies._models.cluster_policy import ( ClusterPolicy, ClusterPolicyDict, diff --git a/python/databricks/bundles/cluster_policies/_models/bind.py b/python/databricks/bundles/cluster_policies/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/cluster_policies/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/cluster_policies/_models/lifecycle.py b/python/databricks/bundles/cluster_policies/_models/lifecycle.py index ccec29db600..e38185faedf 100644 --- a/python/databricks/bundles/cluster_policies/_models/lifecycle.py +++ b/python/databricks/bundles/cluster_policies/_models/lifecycle.py @@ -3,6 +3,7 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict +from databricks.bundles.cluster_policies._models.bind import Bind, BindParam from databricks.bundles.cluster_policies._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/clusters/__init__.py b/python/databricks/bundles/clusters/__init__.py index feaa262198f..3796dee5368 100644 --- a/python/databricks/bundles/clusters/__init__.py +++ b/python/databricks/bundles/clusters/__init__.py @@ -17,6 +17,9 @@ "AzureAttributesParam", "AzureAvailability", "AzureAvailabilityParam", + "Bind", + "BindDict", + "BindParam", "ClientsTypes", "ClientsTypesDict", "ClientsTypesParam", @@ -133,6 +136,7 @@ AzureAvailability, AzureAvailabilityParam, ) +from databricks.bundles.clusters._models.bind import Bind, BindDict, BindParam from databricks.bundles.clusters._models.clients_types import ( ClientsTypes, ClientsTypesDict, diff --git a/python/databricks/bundles/clusters/_models/bind.py b/python/databricks/bundles/clusters/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/clusters/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/clusters/_models/lifecycle_with_started.py b/python/databricks/bundles/clusters/_models/lifecycle_with_started.py index 68aa5088083..7a932c06d88 100644 --- a/python/databricks/bundles/clusters/_models/lifecycle_with_started.py +++ b/python/databricks/bundles/clusters/_models/lifecycle_with_started.py @@ -3,10 +3,8 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict -from databricks.bundles.clusters._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.clusters._models.bind import Bind, BindParam +from databricks.bundles.clusters._models.depends_on import DependsOn, DependsOnParam from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional @@ -19,6 +17,11 @@ class LifecycleWithStarted: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -45,6 +48,11 @@ def as_dict(self) -> "LifecycleWithStartedDict": class LifecycleWithStartedDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/dashboards/__init__.py b/python/databricks/bundles/dashboards/__init__.py index 7e383631fb2..233b0015ffc 100644 --- a/python/databricks/bundles/dashboards/__init__.py +++ b/python/databricks/bundles/dashboards/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "Dashboard", "DashboardDict", "DashboardParam", @@ -20,6 +23,7 @@ ] +from databricks.bundles.dashboards._models.bind import Bind, BindDict, BindParam from databricks.bundles.dashboards._models.dashboard import ( Dashboard, DashboardDict, diff --git a/python/databricks/bundles/dashboards/_models/bind.py b/python/databricks/bundles/dashboards/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/dashboards/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/dashboards/_models/dashboard.py b/python/databricks/bundles/dashboards/_models/dashboard.py index d7efbdf814f..2a3e5f03364 100644 --- a/python/databricks/bundles/dashboards/_models/dashboard.py +++ b/python/databricks/bundles/dashboards/_models/dashboard.py @@ -7,10 +7,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.dashboards._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.dashboards._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.dashboards._models.lifecycle_state import ( LifecycleState, LifecycleStateParam, diff --git a/python/databricks/bundles/dashboards/_models/lifecycle.py b/python/databricks/bundles/dashboards/_models/lifecycle.py index fa61e0279a4..39198b5521e 100644 --- a/python/databricks/bundles/dashboards/_models/lifecycle.py +++ b/python/databricks/bundles/dashboards/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.dashboards._models.bind import Bind, BindParam from databricks.bundles.dashboards._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/database_catalogs/__init__.py b/python/databricks/bundles/database_catalogs/__init__.py index a02e6710b39..633b373d88d 100644 --- a/python/databricks/bundles/database_catalogs/__init__.py +++ b/python/databricks/bundles/database_catalogs/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DatabaseCatalog", "DatabaseCatalogDict", "DatabaseCatalogParam", @@ -13,6 +16,7 @@ ] +from databricks.bundles.database_catalogs._models.bind import Bind, BindDict, BindParam from databricks.bundles.database_catalogs._models.database_catalog import ( DatabaseCatalog, DatabaseCatalogDict, diff --git a/python/databricks/bundles/database_catalogs/_models/bind.py b/python/databricks/bundles/database_catalogs/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/database_catalogs/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/database_catalogs/_models/lifecycle.py b/python/databricks/bundles/database_catalogs/_models/lifecycle.py index 098d125a985..021237f4da7 100644 --- a/python/databricks/bundles/database_catalogs/_models/lifecycle.py +++ b/python/databricks/bundles/database_catalogs/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.database_catalogs._models.bind import Bind, BindParam from databricks.bundles.database_catalogs._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/database_instances/__init__.py b/python/databricks/bundles/database_instances/__init__.py index f6b05ef2765..f92fd55c82c 100644 --- a/python/databricks/bundles/database_instances/__init__.py +++ b/python/databricks/bundles/database_instances/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "CustomTag", "CustomTagDict", "CustomTagParam", @@ -24,6 +27,7 @@ ] +from databricks.bundles.database_instances._models.bind import Bind, BindDict, BindParam from databricks.bundles.database_instances._models.custom_tag import ( CustomTag, CustomTagDict, diff --git a/python/databricks/bundles/database_instances/_models/bind.py b/python/databricks/bundles/database_instances/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/database_instances/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/database_instances/_models/lifecycle.py b/python/databricks/bundles/database_instances/_models/lifecycle.py index 2e81c847cc6..f74e28445d1 100644 --- a/python/databricks/bundles/database_instances/_models/lifecycle.py +++ b/python/databricks/bundles/database_instances/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.database_instances._models.bind import Bind, BindParam from databricks.bundles.database_instances._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/experiments/__init__.py b/python/databricks/bundles/experiments/__init__.py index 78726dd8002..e6b01f08927 100644 --- a/python/databricks/bundles/experiments/__init__.py +++ b/python/databricks/bundles/experiments/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -27,6 +30,7 @@ ] +from databricks.bundles.experiments._models.bind import Bind, BindDict, BindParam from databricks.bundles.experiments._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/experiments/_models/bind.py b/python/databricks/bundles/experiments/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/experiments/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/experiments/_models/lifecycle.py b/python/databricks/bundles/experiments/_models/lifecycle.py index f2b82bf9aa2..c70097e927b 100644 --- a/python/databricks/bundles/experiments/_models/lifecycle.py +++ b/python/databricks/bundles/experiments/_models/lifecycle.py @@ -6,10 +6,8 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.experiments._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.experiments._models.bind import Bind, BindParam +from databricks.bundles.experiments._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: from typing_extensions import Self @@ -19,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/experiments/_models/mlflow_experiment.py b/python/databricks/bundles/experiments/_models/mlflow_experiment.py index bafe167f2f8..8a9d5368e99 100644 --- a/python/databricks/bundles/experiments/_models/mlflow_experiment.py +++ b/python/databricks/bundles/experiments/_models/mlflow_experiment.py @@ -19,7 +19,10 @@ ExperimentTraceLocation, ExperimentTraceLocationParam, ) -from databricks.bundles.experiments._models.lifecycle import Lifecycle, LifecycleParam +from databricks.bundles.experiments._models.lifecycle import ( + Lifecycle, + LifecycleParam, +) from databricks.bundles.experiments._models.mlflow_experiment_permission import ( MlflowExperimentPermission, MlflowExperimentPermissionParam, diff --git a/python/databricks/bundles/external_locations/__init__.py b/python/databricks/bundles/external_locations/__init__.py index 18f867345b2..32ba39ab02f 100644 --- a/python/databricks/bundles/external_locations/__init__.py +++ b/python/databricks/bundles/external_locations/__init__.py @@ -7,6 +7,9 @@ "AzureQueueStorage", "AzureQueueStorageDict", "AzureQueueStorageParam", + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -48,6 +51,7 @@ AzureQueueStorageDict, AzureQueueStorageParam, ) +from databricks.bundles.external_locations._models.bind import Bind, BindDict, BindParam from databricks.bundles.external_locations._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/external_locations/_models/bind.py b/python/databricks/bundles/external_locations/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/external_locations/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/external_locations/_models/lifecycle.py b/python/databricks/bundles/external_locations/_models/lifecycle.py index ace07eb75a1..2b82a5ca4ac 100644 --- a/python/databricks/bundles/external_locations/_models/lifecycle.py +++ b/python/databricks/bundles/external_locations/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.external_locations._models.bind import Bind, BindParam from databricks.bundles.external_locations._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/features/__init__.py b/python/databricks/bundles/features/__init__.py index 28b95182245..fc9843349c8 100644 --- a/python/databricks/bundles/features/__init__.py +++ b/python/databricks/bundles/features/__init__.py @@ -13,6 +13,9 @@ "AvgFunction", "AvgFunctionDict", "AvgFunctionParam", + "Bind", + "BindDict", + "BindParam", "ColumnSelection", "ColumnSelectionDict", "ColumnSelectionParam", @@ -161,6 +164,7 @@ AvgFunctionDict, AvgFunctionParam, ) +from databricks.bundles.features._models.bind import Bind, BindDict, BindParam from databricks.bundles.features._models.column_selection import ( ColumnSelection, ColumnSelectionDict, diff --git a/python/databricks/bundles/features/_models/bind.py b/python/databricks/bundles/features/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/features/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/features/_models/feature.py b/python/databricks/bundles/features/_models/feature.py index b489a756bcc..d00ed799f92 100644 --- a/python/databricks/bundles/features/_models/feature.py +++ b/python/databricks/bundles/features/_models/feature.py @@ -23,7 +23,10 @@ Function, FunctionParam, ) -from databricks.bundles.features._models.lifecycle import Lifecycle, LifecycleParam +from databricks.bundles.features._models.lifecycle import ( + Lifecycle, + LifecycleParam, +) from databricks.bundles.features._models.lineage_context import ( LineageContext, LineageContextParam, diff --git a/python/databricks/bundles/features/_models/lifecycle.py b/python/databricks/bundles/features/_models/lifecycle.py index 53c3a4b38b9..088937d751a 100644 --- a/python/databricks/bundles/features/_models/lifecycle.py +++ b/python/databricks/bundles/features/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.features._models.bind import Bind, BindParam from databricks.bundles.features._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: @@ -16,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -37,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/genie_spaces/__init__.py b/python/databricks/bundles/genie_spaces/__init__.py index 960dd98014d..5dd9ef0f56e 100644 --- a/python/databricks/bundles/genie_spaces/__init__.py +++ b/python/databricks/bundles/genie_spaces/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -18,6 +21,7 @@ ] +from databricks.bundles.genie_spaces._models.bind import Bind, BindDict, BindParam from databricks.bundles.genie_spaces._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/genie_spaces/_models/bind.py b/python/databricks/bundles/genie_spaces/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/genie_spaces/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/genie_spaces/_models/genie_space.py b/python/databricks/bundles/genie_spaces/_models/genie_space.py index 6b7cd0532d4..bb1ec94c8df 100644 --- a/python/databricks/bundles/genie_spaces/_models/genie_space.py +++ b/python/databricks/bundles/genie_spaces/_models/genie_space.py @@ -7,10 +7,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.genie_spaces._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.genie_spaces._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.genie_spaces._models.permission import ( Permission, PermissionParam, diff --git a/python/databricks/bundles/genie_spaces/_models/lifecycle.py b/python/databricks/bundles/genie_spaces/_models/lifecycle.py index 8e740937885..8fb76376854 100644 --- a/python/databricks/bundles/genie_spaces/_models/lifecycle.py +++ b/python/databricks/bundles/genie_spaces/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.genie_spaces._models.bind import Bind, BindParam from databricks.bundles.genie_spaces._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: @@ -16,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -37,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/instance_pools/__init__.py b/python/databricks/bundles/instance_pools/__init__.py index 782be8340a5..8a842a373a5 100644 --- a/python/databricks/bundles/instance_pools/__init__.py +++ b/python/databricks/bundles/instance_pools/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -52,6 +55,7 @@ ] +from databricks.bundles.instance_pools._models.bind import Bind, BindDict, BindParam from databricks.bundles.instance_pools._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/instance_pools/_models/bind.py b/python/databricks/bundles/instance_pools/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/instance_pools/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/instance_pools/_models/lifecycle.py b/python/databricks/bundles/instance_pools/_models/lifecycle.py index 182c0682172..7378572c2a3 100644 --- a/python/databricks/bundles/instance_pools/_models/lifecycle.py +++ b/python/databricks/bundles/instance_pools/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.instance_pools._models.bind import Bind, BindParam from databricks.bundles.instance_pools._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/job_runs/__init__.py b/python/databricks/bundles/job_runs/__init__.py index 4b83903777d..9a71d0b3290 100644 --- a/python/databricks/bundles/job_runs/__init__.py +++ b/python/databricks/bundles/job_runs/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -24,6 +27,7 @@ ] +from databricks.bundles.job_runs._models.bind import Bind, BindDict, BindParam from databricks.bundles.job_runs._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/job_runs/_models/bind.py b/python/databricks/bundles/job_runs/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/job_runs/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/job_runs/_models/job_run_lifecycle.py b/python/databricks/bundles/job_runs/_models/job_run_lifecycle.py index 01d44e54ad3..7a012daddd5 100644 --- a/python/databricks/bundles/job_runs/_models/job_run_lifecycle.py +++ b/python/databricks/bundles/job_runs/_models/job_run_lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.job_runs._models.bind import Bind, BindParam from databricks.bundles.job_runs._models.depends_on import DependsOn, DependsOnParam from databricks.bundles.job_runs._models.job_run_trigger import ( JobRunTrigger, @@ -20,6 +21,11 @@ class JobRunLifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -46,6 +52,11 @@ def as_dict(self) -> "JobRunLifecycleDict": class JobRunLifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/jobs/__init__.py b/python/databricks/bundles/jobs/__init__.py index d75e2474de1..ef42f2f8dbe 100644 --- a/python/databricks/bundles/jobs/__init__.py +++ b/python/databricks/bundles/jobs/__init__.py @@ -52,6 +52,9 @@ "AzureAttributesParam", "AzureAvailability", "AzureAvailabilityParam", + "Bind", + "BindDict", + "BindParam", "CleanRoomsNotebookTask", "CleanRoomsNotebookTaskDict", "CleanRoomsNotebookTaskParam", @@ -494,6 +497,7 @@ AzureAvailability, AzureAvailabilityParam, ) +from databricks.bundles.jobs._models.bind import Bind, BindDict, BindParam from databricks.bundles.jobs._models.clean_rooms_notebook_task import ( CleanRoomsNotebookTask, CleanRoomsNotebookTaskDict, diff --git a/python/databricks/bundles/jobs/_models/bind.py b/python/databricks/bundles/jobs/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/jobs/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/jobs/_models/lifecycle.py b/python/databricks/bundles/jobs/_models/lifecycle.py index 254663c54d0..6124d357626 100644 --- a/python/databricks/bundles/jobs/_models/lifecycle.py +++ b/python/databricks/bundles/jobs/_models/lifecycle.py @@ -6,10 +6,8 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.jobs._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.jobs._models.bind import Bind, BindParam +from databricks.bundles.jobs._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: from typing_extensions import Self @@ -19,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/mcp_services/__init__.py b/python/databricks/bundles/mcp_services/__init__.py index 981e709bff8..af10858d3be 100644 --- a/python/databricks/bundles/mcp_services/__init__.py +++ b/python/databricks/bundles/mcp_services/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -31,6 +34,7 @@ ] +from databricks.bundles.mcp_services._models.bind import Bind, BindDict, BindParam from databricks.bundles.mcp_services._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/mcp_services/_models/bind.py b/python/databricks/bundles/mcp_services/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/mcp_services/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/mcp_services/_models/lifecycle.py b/python/databricks/bundles/mcp_services/_models/lifecycle.py index eca16a56d15..49ede7eecd0 100644 --- a/python/databricks/bundles/mcp_services/_models/lifecycle.py +++ b/python/databricks/bundles/mcp_services/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.mcp_services._models.bind import Bind, BindParam from databricks.bundles.mcp_services._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: @@ -16,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -37,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/mcp_services/_models/mcp_service.py b/python/databricks/bundles/mcp_services/_models/mcp_service.py index 129935ea097..1050e5153f4 100644 --- a/python/databricks/bundles/mcp_services/_models/mcp_service.py +++ b/python/databricks/bundles/mcp_services/_models/mcp_service.py @@ -11,7 +11,10 @@ VariableOrList, VariableOrOptional, ) -from databricks.bundles.mcp_services._models.lifecycle import Lifecycle, LifecycleParam +from databricks.bundles.mcp_services._models.lifecycle import ( + Lifecycle, + LifecycleParam, +) from databricks.bundles.mcp_services._models.mcp_service_config import ( McpServiceConfig, McpServiceConfigParam, diff --git a/python/databricks/bundles/model_provider_services/__init__.py b/python/databricks/bundles/model_provider_services/__init__.py index 57b9bb80463..ed93a148814 100644 --- a/python/databricks/bundles/model_provider_services/__init__.py +++ b/python/databricks/bundles/model_provider_services/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -102,6 +105,11 @@ ] +from databricks.bundles.model_provider_services._models.bind import ( + Bind, + BindDict, + BindParam, +) from databricks.bundles.model_provider_services._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/model_provider_services/_models/bind.py b/python/databricks/bundles/model_provider_services/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/model_provider_services/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/model_provider_services/_models/lifecycle.py b/python/databricks/bundles/model_provider_services/_models/lifecycle.py index 2837780438d..4ec7f31cd03 100644 --- a/python/databricks/bundles/model_provider_services/_models/lifecycle.py +++ b/python/databricks/bundles/model_provider_services/_models/lifecycle.py @@ -6,6 +6,10 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.model_provider_services._models.bind import ( + Bind, + BindParam, +) from databricks.bundles.model_provider_services._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +23,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +49,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/model_services/__init__.py b/python/databricks/bundles/model_services/__init__.py index 2e40ce88cb2..157f633fa01 100644 --- a/python/databricks/bundles/model_services/__init__.py +++ b/python/databricks/bundles/model_services/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -54,6 +57,7 @@ ] +from databricks.bundles.model_services._models.bind import Bind, BindDict, BindParam from databricks.bundles.model_services._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/model_services/_models/bind.py b/python/databricks/bundles/model_services/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/model_services/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/model_services/_models/lifecycle.py b/python/databricks/bundles/model_services/_models/lifecycle.py index fa15d53667c..55690e15c89 100644 --- a/python/databricks/bundles/model_services/_models/lifecycle.py +++ b/python/databricks/bundles/model_services/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.model_services._models.bind import Bind, BindParam from databricks.bundles.model_services._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/model_serving_endpoints/__init__.py b/python/databricks/bundles/model_serving_endpoints/__init__.py index be47098b53e..ef7fb7b1015 100644 --- a/python/databricks/bundles/model_serving_endpoints/__init__.py +++ b/python/databricks/bundles/model_serving_endpoints/__init__.py @@ -48,6 +48,9 @@ "BearerTokenAuth", "BearerTokenAuthDict", "BearerTokenAuthParam", + "Bind", + "BindDict", + "BindParam", "CohereConfig", "CohereConfigDict", "CohereConfigParam", @@ -215,6 +218,11 @@ BearerTokenAuthDict, BearerTokenAuthParam, ) +from databricks.bundles.model_serving_endpoints._models.bind import ( + Bind, + BindDict, + BindParam, +) from databricks.bundles.model_serving_endpoints._models.cohere_config import ( CohereConfig, CohereConfigDict, diff --git a/python/databricks/bundles/model_serving_endpoints/_models/bind.py b/python/databricks/bundles/model_serving_endpoints/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/model_serving_endpoints/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/model_serving_endpoints/_models/lifecycle.py b/python/databricks/bundles/model_serving_endpoints/_models/lifecycle.py index f6e3412eb9a..4690fd5eb02 100644 --- a/python/databricks/bundles/model_serving_endpoints/_models/lifecycle.py +++ b/python/databricks/bundles/model_serving_endpoints/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.model_serving_endpoints._models.bind import Bind, BindParam from databricks.bundles.model_serving_endpoints._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/models/__init__.py b/python/databricks/bundles/models/__init__.py index fa9922454b7..e040ceeb807 100644 --- a/python/databricks/bundles/models/__init__.py +++ b/python/databricks/bundles/models/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -21,6 +24,7 @@ ] +from databricks.bundles.models._models.bind import Bind, BindDict, BindParam from databricks.bundles.models._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/models/_models/bind.py b/python/databricks/bundles/models/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/models/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/models/_models/lifecycle.py b/python/databricks/bundles/models/_models/lifecycle.py index ed360157ba8..ae1b6916991 100644 --- a/python/databricks/bundles/models/_models/lifecycle.py +++ b/python/databricks/bundles/models/_models/lifecycle.py @@ -6,10 +6,8 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.models._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.models._models.bind import Bind, BindParam +from databricks.bundles.models._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: from typing_extensions import Self @@ -19,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/models/_models/mlflow_model.py b/python/databricks/bundles/models/_models/mlflow_model.py index 97c21186983..390f1155f2c 100644 --- a/python/databricks/bundles/models/_models/mlflow_model.py +++ b/python/databricks/bundles/models/_models/mlflow_model.py @@ -11,10 +11,7 @@ VariableOrList, VariableOrOptional, ) -from databricks.bundles.models._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.models._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.models._models.mlflow_model_permission import ( MlflowModelPermission, MlflowModelPermissionParam, diff --git a/python/databricks/bundles/pipelines/__init__.py b/python/databricks/bundles/pipelines/__init__.py index 412cbfa59b3..00f1b49a432 100644 --- a/python/databricks/bundles/pipelines/__init__.py +++ b/python/databricks/bundles/pipelines/__init__.py @@ -26,6 +26,9 @@ "AzureAttributesParam", "AzureAvailability", "AzureAvailabilityParam", + "Bind", + "BindDict", + "BindParam", "ClusterLogConf", "ClusterLogConfDict", "ClusterLogConfParam", @@ -338,6 +341,7 @@ AzureAvailability, AzureAvailabilityParam, ) +from databricks.bundles.pipelines._models.bind import Bind, BindDict, BindParam from databricks.bundles.pipelines._models.cluster_log_conf import ( ClusterLogConf, ClusterLogConfDict, diff --git a/python/databricks/bundles/pipelines/_models/bind.py b/python/databricks/bundles/pipelines/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/pipelines/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/pipelines/_models/lifecycle.py b/python/databricks/bundles/pipelines/_models/lifecycle.py index a8f228e0e0a..cdbc755571f 100644 --- a/python/databricks/bundles/pipelines/_models/lifecycle.py +++ b/python/databricks/bundles/pipelines/_models/lifecycle.py @@ -6,10 +6,8 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.pipelines._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.pipelines._models.bind import Bind, BindParam +from databricks.bundles.pipelines._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: from typing_extensions import Self @@ -19,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/pipelines/_models/pipeline.py b/python/databricks/bundles/pipelines/_models/pipeline.py index 070e813ef34..5e4b04bb726 100644 --- a/python/databricks/bundles/pipelines/_models/pipeline.py +++ b/python/databricks/bundles/pipelines/_models/pipeline.py @@ -27,10 +27,7 @@ IngestionPipelineDefinition, IngestionPipelineDefinitionParam, ) -from databricks.bundles.pipelines._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.pipelines._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.pipelines._models.notifications import ( Notifications, NotificationsParam, diff --git a/python/databricks/bundles/quality_monitors/__init__.py b/python/databricks/bundles/quality_monitors/__init__.py index 806df764ade..e281999b695 100644 --- a/python/databricks/bundles/quality_monitors/__init__.py +++ b/python/databricks/bundles/quality_monitors/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -43,6 +46,7 @@ ] +from databricks.bundles.quality_monitors._models.bind import Bind, BindDict, BindParam from databricks.bundles.quality_monitors._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/quality_monitors/_models/bind.py b/python/databricks/bundles/quality_monitors/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/quality_monitors/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/quality_monitors/_models/lifecycle.py b/python/databricks/bundles/quality_monitors/_models/lifecycle.py index 53ba2aafd3d..e7dafdb464e 100644 --- a/python/databricks/bundles/quality_monitors/_models/lifecycle.py +++ b/python/databricks/bundles/quality_monitors/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.quality_monitors._models.bind import Bind, BindParam from databricks.bundles.quality_monitors._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/registered_models/__init__.py b/python/databricks/bundles/registered_models/__init__.py index e193f063599..932c5bd5b4d 100644 --- a/python/databricks/bundles/registered_models/__init__.py +++ b/python/databricks/bundles/registered_models/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -21,6 +24,7 @@ ] +from databricks.bundles.registered_models._models.bind import Bind, BindDict, BindParam from databricks.bundles.registered_models._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/registered_models/_models/bind.py b/python/databricks/bundles/registered_models/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/registered_models/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/registered_models/_models/lifecycle.py b/python/databricks/bundles/registered_models/_models/lifecycle.py index b8642305131..9a42fa739e1 100644 --- a/python/databricks/bundles/registered_models/_models/lifecycle.py +++ b/python/databricks/bundles/registered_models/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.registered_models._models.bind import Bind, BindParam from databricks.bundles.registered_models._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/schemas/__init__.py b/python/databricks/bundles/schemas/__init__.py index 60ce398bd97..4ba569f4670 100644 --- a/python/databricks/bundles/schemas/__init__.py +++ b/python/databricks/bundles/schemas/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -23,6 +26,7 @@ ] +from databricks.bundles.schemas._models.bind import Bind, BindDict, BindParam from databricks.bundles.schemas._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/schemas/_models/bind.py b/python/databricks/bundles/schemas/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/schemas/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/schemas/_models/lifecycle.py b/python/databricks/bundles/schemas/_models/lifecycle.py index c8467b44428..d1fb0845e76 100644 --- a/python/databricks/bundles/schemas/_models/lifecycle.py +++ b/python/databricks/bundles/schemas/_models/lifecycle.py @@ -6,10 +6,8 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.schemas._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.schemas._models.bind import Bind, BindParam +from databricks.bundles.schemas._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: from typing_extensions import Self @@ -19,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/schemas/_models/schema.py b/python/databricks/bundles/schemas/_models/schema.py index eaa1f023cf9..32ff22c8227 100644 --- a/python/databricks/bundles/schemas/_models/schema.py +++ b/python/databricks/bundles/schemas/_models/schema.py @@ -12,10 +12,7 @@ VariableOrList, VariableOrOptional, ) -from databricks.bundles.schemas._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.schemas._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.schemas._models.privilege_assignment import ( PrivilegeAssignment, PrivilegeAssignmentParam, diff --git a/python/databricks/bundles/secret_scopes/__init__.py b/python/databricks/bundles/secret_scopes/__init__.py index d85f347bbba..9a6109b9375 100644 --- a/python/databricks/bundles/secret_scopes/__init__.py +++ b/python/databricks/bundles/secret_scopes/__init__.py @@ -4,6 +4,9 @@ "AzureKeyVaultSecretScopeMetadata", "AzureKeyVaultSecretScopeMetadataDict", "AzureKeyVaultSecretScopeMetadataParam", + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -28,6 +31,7 @@ AzureKeyVaultSecretScopeMetadataDict, AzureKeyVaultSecretScopeMetadataParam, ) +from databricks.bundles.secret_scopes._models.bind import Bind, BindDict, BindParam from databricks.bundles.secret_scopes._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/secret_scopes/_models/bind.py b/python/databricks/bundles/secret_scopes/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/secret_scopes/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/secret_scopes/_models/lifecycle.py b/python/databricks/bundles/secret_scopes/_models/lifecycle.py index 7f1b17140e0..0e7190c3414 100644 --- a/python/databricks/bundles/secret_scopes/_models/lifecycle.py +++ b/python/databricks/bundles/secret_scopes/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.secret_scopes._models.bind import Bind, BindParam from databricks.bundles.secret_scopes._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/secret_scopes/_models/secret_scope.py b/python/databricks/bundles/secret_scopes/_models/secret_scope.py index 022aaafb82d..5e436f1d247 100644 --- a/python/databricks/bundles/secret_scopes/_models/secret_scope.py +++ b/python/databricks/bundles/secret_scopes/_models/secret_scope.py @@ -15,10 +15,7 @@ AzureKeyVaultSecretScopeMetadata, AzureKeyVaultSecretScopeMetadataParam, ) -from databricks.bundles.secret_scopes._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.secret_scopes._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.secret_scopes._models.scope_backend_type import ( ScopeBackendType, ScopeBackendTypeParam, diff --git a/python/databricks/bundles/secrets/__init__.py b/python/databricks/bundles/secrets/__init__.py index 138d56de11b..5698fdad304 100644 --- a/python/databricks/bundles/secrets/__init__.py +++ b/python/databricks/bundles/secrets/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -18,6 +21,7 @@ ] +from databricks.bundles.secrets._models.bind import Bind, BindDict, BindParam from databricks.bundles.secrets._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/secrets/_models/bind.py b/python/databricks/bundles/secrets/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/secrets/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/secrets/_models/lifecycle.py b/python/databricks/bundles/secrets/_models/lifecycle.py index 1bd7bc1189a..25247266ed5 100644 --- a/python/databricks/bundles/secrets/_models/lifecycle.py +++ b/python/databricks/bundles/secrets/_models/lifecycle.py @@ -6,10 +6,8 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.secrets._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.secrets._models.bind import Bind, BindParam +from databricks.bundles.secrets._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: from typing_extensions import Self @@ -19,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/secrets/_models/secret.py b/python/databricks/bundles/secrets/_models/secret.py index d6af914a045..b0db4c03ada 100644 --- a/python/databricks/bundles/secrets/_models/secret.py +++ b/python/databricks/bundles/secrets/_models/secret.py @@ -11,10 +11,7 @@ VariableOrList, VariableOrOptional, ) -from databricks.bundles.secrets._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.secrets._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.secrets._models.privilege_assignment import ( PrivilegeAssignment, PrivilegeAssignmentParam, diff --git a/python/databricks/bundles/sql_warehouses/__init__.py b/python/databricks/bundles/sql_warehouses/__init__.py index 3f19eb82205..375f91f8b5d 100644 --- a/python/databricks/bundles/sql_warehouses/__init__.py +++ b/python/databricks/bundles/sql_warehouses/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "Channel", "ChannelDict", "ChannelName", @@ -33,6 +36,7 @@ ] +from databricks.bundles.sql_warehouses._models.bind import Bind, BindDict, BindParam from databricks.bundles.sql_warehouses._models.channel import ( Channel, ChannelDict, diff --git a/python/databricks/bundles/sql_warehouses/_models/bind.py b/python/databricks/bundles/sql_warehouses/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/sql_warehouses/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/sql_warehouses/_models/lifecycle_with_started.py b/python/databricks/bundles/sql_warehouses/_models/lifecycle_with_started.py index 54f0d97ae5a..c62c481c96b 100644 --- a/python/databricks/bundles/sql_warehouses/_models/lifecycle_with_started.py +++ b/python/databricks/bundles/sql_warehouses/_models/lifecycle_with_started.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.sql_warehouses._models.bind import Bind, BindParam from databricks.bundles.sql_warehouses._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class LifecycleWithStarted: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -45,6 +51,11 @@ def as_dict(self) -> "LifecycleWithStartedDict": class LifecycleWithStartedDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/synced_database_tables/__init__.py b/python/databricks/bundles/synced_database_tables/__init__.py index c626e16396c..dfa5563d2c0 100644 --- a/python/databricks/bundles/synced_database_tables/__init__.py +++ b/python/databricks/bundles/synced_database_tables/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -26,6 +29,11 @@ ] +from databricks.bundles.synced_database_tables._models.bind import ( + Bind, + BindDict, + BindParam, +) from databricks.bundles.synced_database_tables._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/synced_database_tables/_models/bind.py b/python/databricks/bundles/synced_database_tables/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/synced_database_tables/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/synced_database_tables/_models/lifecycle.py b/python/databricks/bundles/synced_database_tables/_models/lifecycle.py index 6145aa8ac96..dc61dd1ea9d 100644 --- a/python/databricks/bundles/synced_database_tables/_models/lifecycle.py +++ b/python/databricks/bundles/synced_database_tables/_models/lifecycle.py @@ -6,6 +6,10 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.synced_database_tables._models.bind import ( + Bind, + BindParam, +) from databricks.bundles.synced_database_tables._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +23,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +49,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/vector_search_endpoints/__init__.py b/python/databricks/bundles/vector_search_endpoints/__init__.py index ad58a72b996..c33e2dcd6af 100644 --- a/python/databricks/bundles/vector_search_endpoints/__init__.py +++ b/python/databricks/bundles/vector_search_endpoints/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -20,6 +23,11 @@ ] +from databricks.bundles.vector_search_endpoints._models.bind import ( + Bind, + BindDict, + BindParam, +) from databricks.bundles.vector_search_endpoints._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/vector_search_endpoints/_models/bind.py b/python/databricks/bundles/vector_search_endpoints/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/vector_search_endpoints/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/vector_search_endpoints/_models/lifecycle.py b/python/databricks/bundles/vector_search_endpoints/_models/lifecycle.py index 45f1d1427b3..2f54e82b59a 100644 --- a/python/databricks/bundles/vector_search_endpoints/_models/lifecycle.py +++ b/python/databricks/bundles/vector_search_endpoints/_models/lifecycle.py @@ -6,6 +6,7 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.vector_search_endpoints._models.bind import Bind, BindParam from databricks.bundles.vector_search_endpoints._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +20,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +46,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/vector_search_indexes/__init__.py b/python/databricks/bundles/vector_search_indexes/__init__.py index 8a23b46be42..bcf11f12f55 100644 --- a/python/databricks/bundles/vector_search_indexes/__init__.py +++ b/python/databricks/bundles/vector_search_indexes/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DeltaSyncVectorIndexSpecRequest", "DeltaSyncVectorIndexSpecRequestDict", "DeltaSyncVectorIndexSpecRequestParam", @@ -36,6 +39,11 @@ ] +from databricks.bundles.vector_search_indexes._models.bind import ( + Bind, + BindDict, + BindParam, +) from databricks.bundles.vector_search_indexes._models.delta_sync_vector_index_spec_request import ( DeltaSyncVectorIndexSpecRequest, DeltaSyncVectorIndexSpecRequestDict, diff --git a/python/databricks/bundles/vector_search_indexes/_models/bind.py b/python/databricks/bundles/vector_search_indexes/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/vector_search_indexes/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/vector_search_indexes/_models/lifecycle.py b/python/databricks/bundles/vector_search_indexes/_models/lifecycle.py index b03f75d8f6e..efc70d6ac85 100644 --- a/python/databricks/bundles/vector_search_indexes/_models/lifecycle.py +++ b/python/databricks/bundles/vector_search_indexes/_models/lifecycle.py @@ -6,6 +6,10 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.vector_search_indexes._models.bind import ( + Bind, + BindParam, +) from databricks.bundles.vector_search_indexes._models.depends_on import ( DependsOn, DependsOnParam, @@ -19,6 +23,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +49,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/volumes/__init__.py b/python/databricks/bundles/volumes/__init__.py index 3fdd871e124..3432bbb9a1f 100644 --- a/python/databricks/bundles/volumes/__init__.py +++ b/python/databricks/bundles/volumes/__init__.py @@ -1,6 +1,9 @@ # Code generated by pydabs-codegen. DO NOT EDIT. __all__ = [ + "Bind", + "BindDict", + "BindParam", "DependsOn", "DependsOnDict", "DependsOnParam", @@ -25,6 +28,7 @@ ] +from databricks.bundles.volumes._models.bind import Bind, BindDict, BindParam from databricks.bundles.volumes._models.depends_on import ( DependsOn, DependsOnDict, diff --git a/python/databricks/bundles/volumes/_models/bind.py b/python/databricks/bundles/volumes/_models/bind.py new file mode 100644 index 00000000000..35f09d15949 --- /dev/null +++ b/python/databricks/bundles/volumes/_models/bind.py @@ -0,0 +1,40 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOr + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class Bind: + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + @classmethod + def from_dict(cls, value: "BindDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "BindDict": + return _transform_to_json_value(self) # type:ignore + + +class BindDict(TypedDict, total=False): + """""" + + id: VariableOr[str] + """ + The ID of the existing workspace resource, as used by its API (for example a job ID, or the full name of a schema or volume). Set it per target through a target override of the resource; variable references are resolved. + """ + + +BindParam = BindDict | Bind diff --git a/python/databricks/bundles/volumes/_models/lifecycle.py b/python/databricks/bundles/volumes/_models/lifecycle.py index 818b3d25108..c7013db6ce7 100644 --- a/python/databricks/bundles/volumes/_models/lifecycle.py +++ b/python/databricks/bundles/volumes/_models/lifecycle.py @@ -6,10 +6,8 @@ from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value from databricks.bundles.core._variable import VariableOrList, VariableOrOptional -from databricks.bundles.volumes._models.depends_on import ( - DependsOn, - DependsOnParam, -) +from databricks.bundles.volumes._models.bind import Bind, BindParam +from databricks.bundles.volumes._models.depends_on import DependsOn, DependsOnParam if TYPE_CHECKING: from typing_extensions import Self @@ -19,6 +17,11 @@ class Lifecycle: """""" + bind: VariableOrOptional[Bind] = None + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOn] = field(default_factory=list) """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. @@ -40,6 +43,11 @@ def as_dict(self) -> "LifecycleDict": class LifecycleDict(TypedDict, total=False): """""" + bind: VariableOrOptional[BindParam] + """ + Existing workspace resource to adopt into the deployment state instead of creating a new one. The first deploy binds it (`bind`) and applies the configuration if it differs (`bind_and_update`), including target settings such as `mode: development`. While the block is present the resource cannot be recreated; removing the resource or the block ends that protection, and `bundle destroy` deletes bound resources like any other. Nothing is recorded in the state about the adoption. + """ + depends_on: VariableOrList[DependsOnParam] """ Resources that must be deployed before this resource and deleted after it. Unlike variable references, this only affects ordering. diff --git a/python/databricks/bundles/volumes/_models/volume.py b/python/databricks/bundles/volumes/_models/volume.py index fb6f2462d0c..db248fbba94 100644 --- a/python/databricks/bundles/volumes/_models/volume.py +++ b/python/databricks/bundles/volumes/_models/volume.py @@ -11,10 +11,7 @@ VariableOrList, VariableOrOptional, ) -from databricks.bundles.volumes._models.lifecycle import ( - Lifecycle, - LifecycleParam, -) +from databricks.bundles.volumes._models.lifecycle import Lifecycle, LifecycleParam from databricks.bundles.volumes._models.privilege_assignment import ( PrivilegeAssignment, PrivilegeAssignmentParam,