Repository navigation
Support selecting resources for deletion with bundle deploy --select #7023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
880a3c1
8f1cc5d
1c8d42e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| * Support selecting resources for deletion with `bundle deploy --select`. ([#7023](https://github.com/databricks/cli/pull/7023)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| bundle: | ||
| name: select-del-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| jobs: | ||
| keep: | ||
| name: keep-$UNIQUE_NAME |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| bundle: | ||
| name: select-del-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| jobs: | ||
| keep: | ||
| name: keep-$UNIQUE_NAME | ||
|
|
||
| gone: | ||
| name: gone-$UNIQUE_NAME |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Cloud = true | ||
| EnvMatrix.DMS = ["", "true"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
|
|
||
| === Initial deploy | ||
|
|
||
| >>> [CLI] bundle deploy | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-del-[UNIQUE_NAME]/default/files... | ||
| Created jobs.gone | ||
| Created jobs.keep | ||
| Files: 3 uploaded, 0 deleted | ||
| Resources: 2 created, 0 changed, 0 deleted, 0 unchanged | ||
|
|
||
| >>> [CLI] bundle plan --select jobs.gone | ||
| delete jobs.gone | ||
|
|
||
| Plan: 0 to add, 0 to change, 1 to delete, 0 unchanged, 1 not selected | ||
|
|
||
| === bundle deploy --select jobs.gone | ||
|
|
||
| >>> [CLI] bundle deploy --select jobs.gone | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-del-[UNIQUE_NAME]/default/files... | ||
| Deleted jobs.gone | ||
| Files: 1 uploaded, 0 deleted | ||
| Resources: 0 created, 0 changed, 1 deleted, 0 unchanged, 1 not selected | ||
|
|
||
| >>> print_requests.py --sort //jobs/delete | ||
| { | ||
| "method": "POST", | ||
| "path": "/api/2.2/jobs/delete", | ||
| "body": { | ||
| "job_id": [GONE_ID] | ||
| } | ||
| } | ||
|
|
||
| >>> [CLI] bundle plan | ||
| Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged | ||
|
|
||
| === Redeploy gone, then select it by unqualified name | ||
|
|
||
| >>> [CLI] bundle deploy | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-del-[UNIQUE_NAME]/default/files... | ||
| Created jobs.gone | ||
| Files: 1 uploaded, 0 deleted | ||
| Resources: 1 created, 0 changed, 0 deleted, 1 unchanged | ||
|
|
||
| >>> [CLI] bundle plan --select gone | ||
| delete jobs.gone | ||
|
|
||
| Plan: 0 to add, 0 to change, 1 to delete, 0 unchanged, 1 not selected | ||
|
|
||
| === bundle deploy --select gone | ||
|
|
||
| >>> [CLI] bundle deploy --select gone | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-del-[UNIQUE_NAME]/default/files... | ||
| Deleted jobs.gone | ||
| Files: 1 uploaded, 0 deleted | ||
| Resources: 0 created, 0 changed, 1 deleted, 0 unchanged, 1 not selected | ||
|
|
||
| >>> print_requests.py --sort //jobs/delete | ||
| { | ||
| "method": "POST", | ||
| "path": "/api/2.2/jobs/delete", | ||
| "body": { | ||
| "job_id": [GONE_ID_2] | ||
| } | ||
| } | ||
|
|
||
| >>> [CLI] bundle plan | ||
| Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged | ||
|
|
||
| === Destroy | ||
| >>> [CLI] bundle destroy --auto-approve | ||
| The following resources will be deleted: | ||
| delete resources.jobs.keep | ||
|
|
||
| All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/select-del-[UNIQUE_NAME]/default | ||
|
|
||
| Destroy: 1 deleted |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| envsubst '$UNIQUE_NAME' < databricks.yml.tmpl > databricks.yml | ||
|
|
||
| cleanup() { | ||
| title "Destroy" | ||
| trace $CLI bundle destroy --auto-approve | ||
| rm -f "$OUT_REQUESTS" | ||
| } | ||
| trap cleanup EXIT | ||
|
|
||
| # Deploy both jobs. | ||
| title "Initial deploy\n" | ||
| trace $CLI bundle deploy | ||
| # Register [KEEP_ID]/[GONE_ID] from state while both still exist, so the delete | ||
| # request body below is masked deterministically. | ||
| replace_ids.py | ||
|
|
||
| # Remove 'gone' from config. It is now orphaned in state and planned for deletion. | ||
| envsubst '$UNIQUE_NAME' < databricks.yml.after.tmpl > databricks.yml | ||
|
|
||
| # A resource removed from config is selectable by name, like any created or updated | ||
| # one. The plan is filtered to just its deletion. | ||
| trace $CLI bundle plan --select jobs.gone | ||
|
|
||
| title "bundle deploy --select jobs.gone\n" | ||
| trace $CLI bundle deploy --select jobs.gone | ||
|
|
||
| # The delete call targeted 'gone' only. | ||
| trace print_requests.py --sort //jobs/delete | ||
|
|
||
| # A full plan now has nothing to delete and 'keep' is unchanged. | ||
| trace $CLI bundle plan | ||
|
|
||
| # The same works with an unqualified name. Deploy 'gone' again, then remove it from | ||
| # config so it is once more orphaned in state. | ||
| title "Redeploy gone, then select it by unqualified name\n" | ||
| envsubst '$UNIQUE_NAME' < databricks.yml.tmpl > databricks.yml | ||
| trace $CLI bundle deploy | ||
| replace_ids.py | ||
| envsubst '$UNIQUE_NAME' < databricks.yml.after.tmpl > databricks.yml | ||
|
|
||
| trace $CLI bundle plan --select gone | ||
|
|
||
| title "bundle deploy --select gone\n" | ||
| trace $CLI bundle deploy --select gone | ||
|
|
||
| trace print_requests.py --sort //jobs/delete | ||
|
|
||
| trace $CLI bundle plan | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Cloud = true | ||
| RecordRequests = true | ||
| # databricks.yml is generated at runtime from the committed templates. | ||
| Ignore = [".databricks", ".gitignore", "databricks.yml"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| bundle: | ||
| name: select-deldep-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| jobs: | ||
| keep: | ||
| name: keep-$UNIQUE_NAME |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| bundle: | ||
| name: select-deldep-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| jobs: | ||
| keep: | ||
| name: keep-$UNIQUE_NAME | ||
|
|
||
| consumer: | ||
| name: consumer-$UNIQUE_NAME | ||
| tasks: | ||
| - task_key: run_producer | ||
| run_job_task: | ||
| job_id: ${resources.jobs.producer.id} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| bundle: | ||
| name: select-deldep-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| jobs: | ||
| keep: | ||
| name: keep-$UNIQUE_NAME | ||
|
|
||
| producer: | ||
| name: producer-$UNIQUE_NAME | ||
|
|
||
| consumer: | ||
| name: consumer-$UNIQUE_NAME | ||
| tasks: | ||
| - task_key: run_producer | ||
| run_job_task: | ||
| job_id: ${resources.jobs.producer.id} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Cloud = true | ||
| EnvMatrix.DMS = ["", "true"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
|
|
||
| === Initial deploy | ||
|
|
||
| >>> [CLI] bundle deploy | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-deldep-[UNIQUE_NAME]/default/files... | ||
| Created jobs.consumer | ||
| Created jobs.keep | ||
| Created jobs.producer | ||
| Files: 4 uploaded, 0 deleted | ||
| Resources: 3 created, 0 changed, 0 deleted, 0 unchanged | ||
|
|
||
| >>> [CLI] bundle plan --select jobs.producer | ||
| Error: cannot delete jobs.producer: jobs.consumer still references it; remove the reference or also remove jobs.consumer from the config | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should not this configuration fail even without --select? There is a reference to a missing resource, the whole config is not valid.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's invalid, but validate passes and a plain deploy deletes producer and then fails midway without --select. This PR makes --select fail cleanly before deleting anything, should we do the same without --select as separate PR? |
||
|
|
||
|
|
||
| >>> [CLI] bundle deploy --select jobs.producer | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-deldep-[UNIQUE_NAME]/default/files... | ||
| Error: cannot delete jobs.producer: jobs.consumer still references it; remove the reference or also remove jobs.consumer from the config | ||
|
|
||
| Files: 1 uploaded, 0 deleted | ||
|
|
||
| >>> print_requests.py --sort //jobs/delete --keep | ||
|
|
||
| >>> [CLI] bundle plan | ||
| update jobs.consumer | ||
| delete jobs.producer | ||
|
|
||
| Plan: 0 to add, 1 to change, 1 to delete, 1 unchanged | ||
|
|
||
| >>> [CLI] bundle plan --select jobs.producer | ||
| delete jobs.consumer | ||
| delete jobs.producer | ||
|
|
||
| Plan: 0 to add, 0 to change, 2 to delete, 0 unchanged, 1 not selected | ||
|
|
||
| === bundle deploy --select jobs.producer | ||
|
|
||
| >>> [CLI] bundle deploy --select jobs.producer | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-deldep-[UNIQUE_NAME]/default/files... | ||
| Deleted jobs.consumer | ||
| Deleted jobs.producer | ||
| Files: 1 uploaded, 0 deleted | ||
| Resources: 0 created, 0 changed, 2 deleted, 0 unchanged, 1 not selected | ||
|
|
||
| >>> print_requests.py //jobs/delete | ||
| { | ||
| "method": "POST", | ||
| "path": "/api/2.2/jobs/delete", | ||
| "body": { | ||
| "job_id": [CONSUMER_ID] | ||
| } | ||
| } | ||
| { | ||
| "method": "POST", | ||
| "path": "/api/2.2/jobs/delete", | ||
| "body": { | ||
| "job_id": [PRODUCER_ID] | ||
| } | ||
| } | ||
|
|
||
| >>> [CLI] bundle plan | ||
| Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged | ||
|
|
||
| === Destroy | ||
| >>> [CLI] bundle destroy --auto-approve | ||
| The following resources will be deleted: | ||
| delete resources.jobs.keep | ||
|
|
||
| All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/select-deldep-[UNIQUE_NAME]/default | ||
|
|
||
| Destroy: 1 deleted | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| envsubst '$UNIQUE_NAME' < databricks.yml.tmpl > databricks.yml | ||
|
|
||
| cleanup() { | ||
| title "Destroy" | ||
| trace $CLI bundle destroy --auto-approve | ||
| rm -f "$OUT_REQUESTS" | ||
| } | ||
| trap cleanup EXIT | ||
|
|
||
| # Deploy three jobs; consumer references producer, so state records consumer's | ||
| # dependency on producer. | ||
| title "Initial deploy\n" | ||
| trace $CLI bundle deploy | ||
| replace_ids.py | ||
|
|
||
| # --- error case: consumer is still live and references producer --- | ||
| # Remove only producer from config; consumer stays with its reference intact. | ||
| # Selecting producer for deletion must error: it would leave consumer broken. | ||
| envsubst '$UNIQUE_NAME' < databricks.yml.live_consumer.tmpl > databricks.yml | ||
|
|
||
| musterr trace $CLI bundle plan --select jobs.producer | ||
|
|
||
| # bundle deploy --select also errors before sending any delete request. | ||
| musterr trace $CLI bundle deploy --select jobs.producer | ||
|
|
||
| # No delete request was sent by either command. | ||
| trace print_requests.py --sort //jobs/delete --keep | ||
|
|
||
| # A full plan still works and shows producer as a pending delete. | ||
| trace $CLI bundle plan | ||
|
|
||
| # --- success case: both producer and consumer are removed from config --- | ||
| # Remove producer and consumer from config; both are now planned for deletion. | ||
| envsubst '$UNIQUE_NAME' < databricks.yml.after.tmpl > databricks.yml | ||
|
|
||
| # Selecting the depended-upon producer for deletion also deletes its dependent | ||
| # consumer (which would otherwise be left referencing a deleted job). 'keep' is | ||
| # untouched. The dependency direction is reversed for deletes. | ||
| trace $CLI bundle plan --select jobs.producer | ||
|
|
||
| title "bundle deploy --select jobs.producer\n" | ||
| trace $CLI bundle deploy --select jobs.producer | ||
|
|
||
| # Both producer and consumer were deleted, dependent first; keep was not. Not sorted: | ||
| # --sort orders by the raw job ID, which is random on a real workspace. | ||
| trace print_requests.py //jobs/delete | ||
|
|
||
| # A full plan now has nothing to delete and 'keep' is unchanged. | ||
| trace $CLI bundle plan |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Cloud = true | ||
| RecordRequests = true | ||
| # databricks.yml is generated at runtime from the committed templates. | ||
| Ignore = [".databricks", ".gitignore", "databricks.yml"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| bundle: | ||
| name: select-del-plan-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| jobs: | ||
| keep: | ||
| name: keep-$UNIQUE_NAME |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| bundle: | ||
| name: select-del-plan-$UNIQUE_NAME | ||
|
|
||
| resources: | ||
| jobs: | ||
| keep: | ||
| name: keep-$UNIQUE_NAME | ||
|
|
||
| gone: | ||
| name: gone-$UNIQUE_NAME |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Cloud = true | ||
| EnvMatrix.DMS = ["", "true"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
|
|
||
| === Initial deploy | ||
|
|
||
| >>> [CLI] bundle deploy | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-del-plan-[UNIQUE_NAME]/default/files... | ||
| Created jobs.gone | ||
| Created jobs.keep | ||
| Files: 3 uploaded, 0 deleted | ||
| Resources: 2 created, 0 changed, 0 deleted, 0 unchanged | ||
|
|
||
| === bundle deploy --plan (no --select) | ||
|
|
||
| >>> [CLI] bundle deploy --plan plan.json | ||
| Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/select-del-plan-[UNIQUE_NAME]/default/files... | ||
| Deleted jobs.gone | ||
| Files: 2 uploaded, 0 deleted | ||
| Resources: 0 created, 0 changed, 1 deleted, 0 unchanged, 1 not selected | ||
|
|
||
| >>> print_requests.py --sort //jobs/delete | ||
| { | ||
| "method": "POST", | ||
| "path": "/api/2.2/jobs/delete", | ||
| "body": { | ||
| "job_id": [GONE_ID] | ||
| } | ||
| } | ||
|
|
||
| >>> [CLI] bundle plan | ||
| Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged | ||
|
|
||
| === Destroy | ||
| >>> [CLI] bundle destroy --auto-approve | ||
| The following resources will be deleted: | ||
| delete resources.jobs.keep | ||
|
|
||
| All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/select-del-plan-[UNIQUE_NAME]/default | ||
|
|
||
| Destroy: 1 deleted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we parametrize selector? $SELECTOR
in test.toml: EnvMatrix.SELECTOR = ["jobs.gone", "gone"]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trace outputs the command so the output would differ.
I added a second plan & deploy for "gone" below.