Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1af5070
add cluster policy basics to repo
Sankalp-Mittal Aug 11, 2026
13be270
fix double quotes
Sankalp-Mittal Aug 11, 2026
7b6d07e
add CRUD policies
Sankalp-Mittal Aug 11, 2026
bc14d25
register cluster policies in all.go
Sankalp-Mittal Aug 11, 2026
bb2bf71
add cluster policies to the testserver
Sankalp-Mittal Aug 11, 2026
e27c2e9
fix syntax error
Sankalp-Mittal Aug 11, 2026
7a9e2f9
add generated bundle files
Sankalp-Mittal Aug 11, 2026
ead636f
add acceptance tests for cluster policies
Sankalp-Mittal Aug 11, 2026
859ef5a
add cluster_policies to mutator
Sankalp-Mittal Aug 11, 2026
81eedd8
add URL to for policy to output
Sankalp-Mittal Aug 11, 2026
b84b348
fix tests
Sankalp-Mittal Aug 11, 2026
eb8c5d6
make cluster policies direct deployments only
Sankalp-Mittal Aug 11, 2026
2f553a1
add cluster policy test everywhere
Sankalp-Mittal Aug 11, 2026
8d887e0
Add bind tests
Sankalp-Mittal Aug 11, 2026
2eb9d69
fix linting
Sankalp-Mittal Aug 11, 2026
a75f34c
add changelog
Sankalp-Mittal Aug 11, 2026
43ebecd
regenerate schema files for cluster_policies
Sankalp-Mittal Aug 11, 2026
63d592a
fix workspace_open tests for cluster_policies resource type
Sankalp-Mittal Aug 11, 2026
fd6e1cb
update experimental/open acceptance golden for cluster_policies
Sankalp-Mittal Aug 11, 2026
8284e05
add cluster_policies invariant test coverage
Sankalp-Mittal Aug 11, 2026
52c8f46
test: expand cluster_policies acceptance coverage
Sankalp-Mittal Aug 13, 2026
5b85f01
Support authoring cluster_policies definition as inline YAML
Sankalp-Mittal Aug 13, 2026
7f861fd
test: cover cluster_policies inline-YAML definition
Sankalp-Mittal Aug 13, 2026
f1c33ea
regenerate refschema for cluster_policies inline-YAML definition
Sankalp-Mittal Aug 13, 2026
e26ffc5
test: cluster_policies rejected in terraform mode
Sankalp-Mittal Aug 13, 2026
8b95a79
test: cluster_policies dangling reference fails to plan
Sankalp-Mittal Aug 13, 2026
22e60f3
test: cross-bundle cluster_policy use via hardcoded id
Sankalp-Mittal Aug 13, 2026
a93ad20
test: cross-bundle cluster_policy use via lookup by name
Sankalp-Mittal Aug 13, 2026
1ce85e0
test: vary cluster_policies definition authoring across fixtures
Sankalp-Mittal Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .nextchanges/bundles/cluster-policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for the `cluster_policies` resource type in Declarative Automation Bundles. Cluster policies are only supported in direct deployment mode.
8 changes: 8 additions & 0 deletions acceptance/bundle/invariant/configs/cluster_policy.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
bundle:
name: test-bundle-$UNIQUE_NAME

resources:
cluster_policies:
foo:
name: test-cluster-policy-$UNIQUE_NAME
definition: '{"spark_version":{"type":"fixed","value":"13.3.x-scala2.12"}}'
3 changes: 3 additions & 0 deletions acceptance/bundle/invariant/continue_293/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ EnvMatrixExclude.no_genie_space = ["INPUT_CONFIG=genie_space.yml.tmpl"]
# instance_pools resource is not supported on v0.293.0
EnvMatrixExclude.no_instance_pool = ["INPUT_CONFIG=instance_pool.yml.tmpl"]

# cluster_policies resource is not supported on v0.293.0
EnvMatrixExclude.no_cluster_policy = ["INPUT_CONFIG=cluster_policy.yml.tmpl"]

# job_runs resource is not supported on v0.293.0
EnvMatrixExclude.no_job_run = ["INPUT_CONFIG=job_run.yml.tmpl"]

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions acceptance/bundle/invariant/migrate/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ EnvMatrixExclude.no_external_location = ["INPUT_CONFIG=external_location.yml.tmp
EnvMatrixExclude.no_genie_space = ["INPUT_CONFIG=genie_space.yml.tmpl"]
# Instance pools are direct-only; the terraform deploy that seeds the migration fails for them.
EnvMatrixExclude.no_instance_pool = ["INPUT_CONFIG=instance_pool.yml.tmpl"]
# Cluster policies are direct-only; the terraform deploy that seeds the migration fails for them.
EnvMatrixExclude.no_cluster_policy = ["INPUT_CONFIG=cluster_policy.yml.tmpl"]

# Cross-resource permission references (e.g. ${resources.jobs.job_b.permissions[0].level})
# don't work in terraform mode: the terraform interpolator converts the path to
Expand Down
1 change: 1 addition & 0 deletions acceptance/bundle/invariant/no_drift/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions acceptance/bundle/invariant/test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ EnvMatrix.INPUT_CONFIG = [
"catalog_optional_fields.yml.tmpl",
"cluster.yml.tmpl",
"cluster_apply_policy_default_values.yml.tmpl",
"cluster_policy.yml.tmpl",
"dashboard.yml.tmpl",
"job_apply_policy_default_values_job_cluster.yml.tmpl",
"job_apply_policy_default_values_task_cluster.yml.tmpl",
Expand Down
33 changes: 33 additions & 0 deletions acceptance/bundle/refschema/out.fields.txt
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,39 @@ resources.catalogs.*.grants[*] catalog.PrivilegeAssignment ALL
resources.catalogs.*.grants[*].principal string ALL
resources.catalogs.*.grants[*].privileges []catalog.Privilege ALL
resources.catalogs.*.grants[*].privileges[*] catalog.Privilege ALL
resources.cluster_policies.*.created_at_timestamp int64 REMOTE
resources.cluster_policies.*.creator_user_name string REMOTE
resources.cluster_policies.*.definition any INPUT
resources.cluster_policies.*.definition string ALL
resources.cluster_policies.*.description string ALL
resources.cluster_policies.*.id string INPUT
resources.cluster_policies.*.is_default bool REMOTE
resources.cluster_policies.*.libraries []compute.Library ALL
resources.cluster_policies.*.libraries[*] compute.Library ALL
resources.cluster_policies.*.libraries[*].cran *compute.RCranLibrary ALL
resources.cluster_policies.*.libraries[*].cran.package string ALL
resources.cluster_policies.*.libraries[*].cran.repo string ALL
resources.cluster_policies.*.libraries[*].egg string ALL
resources.cluster_policies.*.libraries[*].jar string ALL
resources.cluster_policies.*.libraries[*].maven *compute.MavenLibrary ALL
resources.cluster_policies.*.libraries[*].maven.coordinates string ALL
resources.cluster_policies.*.libraries[*].maven.exclusions []string ALL
resources.cluster_policies.*.libraries[*].maven.exclusions[*] string ALL
resources.cluster_policies.*.libraries[*].maven.repo string ALL
resources.cluster_policies.*.libraries[*].pypi *compute.PythonPyPiLibrary ALL
resources.cluster_policies.*.libraries[*].pypi.package string ALL
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.prevent_destroy bool INPUT
resources.cluster_policies.*.max_clusters_per_user int64 ALL
resources.cluster_policies.*.modified_status string INPUT
resources.cluster_policies.*.name string ALL
resources.cluster_policies.*.policy_family_definition_overrides string ALL
resources.cluster_policies.*.policy_family_id string ALL
resources.cluster_policies.*.policy_id string REMOTE
resources.cluster_policies.*.url string INPUT
resources.clusters.*.apply_policy_default_values bool ALL
resources.clusters.*.autoscale *compute.AutoScale ALL
resources.clusters.*.autoscale.max_workers int ALL
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
bundle:
name: test_cluster_policy

resources:
cluster_policies:
test_cluster_policy:
name: my_cluster_policy
definition: '{"spark_version":{"type":"fixed","value":"13.3.x-scala2.12"}}'

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

126 changes: 126 additions & 0 deletions acceptance/bundle/resources/cluster_policies/basic/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@

>>> [CLI] bundle validate
Name: test_cluster_policy
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default

Validation OK!

>>> [CLI] bundle validate -o json
{
"test_cluster_policy": {
"definition": "{\"spark_version\":{\"type\":\"fixed\",\"value\":\"13.3.x-scala2.12\"}}",
"name": "my_cluster_policy"
}
}

>>> [CLI] bundle summary
Name: test_cluster_policy
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default
Resources:
Cluster Policies:
test_cluster_policy:
Name: my_cluster_policy
URL: (not deployed)

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

=== Verify the create request
>>> jq select(.method == "POST" and (.path | contains("/policies/clusters/create"))) out.requests.txt
{
"method": "POST",
"path": "/api/2.0/policies/clusters/create",
"body": {
"definition": "{\"spark_version\":{\"type\":\"fixed\",\"value\":\"13.3.x-scala2.12\"}}",
"name": "my_cluster_policy"
}
}

>>> [CLI] bundle summary
Name: test_cluster_policy
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default
Resources:
Cluster Policies:
test_cluster_policy:
Name: my_cluster_policy
URL: [DATABRICKS_URL]/compute/policies/[UUID]?w=[NUMID]

=== Update the cluster policy name
>>> update_file.py databricks.yml my_cluster_policy my_cluster_policy_2

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

=== Verify the update request
>>> jq select(.method == "POST" and (.path | contains("/policies/clusters/edit"))) out.requests.txt
{
"method": "POST",
"path": "/api/2.0/policies/clusters/edit",
"body": {
"definition": "{\"spark_version\":{\"type\":\"fixed\",\"value\":\"13.3.x-scala2.12\"}}",
"name": "my_cluster_policy_2",
"policy_id": "[UUID]"
}
}

>>> [CLI] bundle summary
Name: test_cluster_policy
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default
Resources:
Cluster Policies:
test_cluster_policy:
Name: my_cluster_policy_2
URL: [DATABRICKS_URL]/compute/policies/[UUID]?w=[NUMID]

=== Destroy the cluster policy
>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.cluster_policies.test_cluster_policy

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default

Deleting files...
Destroy complete!

=== Verify the destroy request
>>> jq select(.method == "POST" and (.path | contains("/policies/clusters/delete"))) out.requests.txt
{
"method": "POST",
"path": "/api/2.0/policies/clusters/delete",
"body": {
"policy_id": "[UUID]"
}
}

>>> [CLI] bundle summary
Name: test_cluster_policy
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test_cluster_policy/default
Resources:
Cluster Policies:
test_cluster_policy:
Name: my_cluster_policy_2
URL: (not deployed)

>>> [CLI] bundle destroy --auto-approve
No active deployment found to destroy!
33 changes: 33 additions & 0 deletions acceptance/bundle/resources/cluster_policies/basic/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
trace $CLI bundle validate
trace $CLI bundle validate -o json | jq ".resources.cluster_policies"

trace $CLI bundle summary

cleanup() {
trace $CLI bundle destroy --auto-approve
rm out.requests.txt
}
trap cleanup EXIT
trace $CLI bundle deploy

title "Verify the create request"
trace jq 'select(.method == "POST" and (.path | contains("/policies/clusters/create")))' out.requests.txt

trace $CLI bundle summary

title "Update the cluster policy name"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a new test case (not in basic/) for an out-of-band edit to the policy?

trace update_file.py databricks.yml my_cluster_policy my_cluster_policy_2
trace $CLI bundle deploy

title "Verify the update request"
trace jq 'select(.method == "POST" and (.path | contains("/policies/clusters/edit")))' out.requests.txt

trace $CLI bundle summary

title "Destroy the cluster policy"
trace $CLI bundle destroy --auto-approve

title "Verify the destroy request"
trace jq 'select(.method == "POST" and (.path | contains("/policies/clusters/delete")))' out.requests.txt

trace $CLI bundle summary
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
bundle:
name: cluster_policy_producer

resources:
cluster_policies:
pol:
name: shared_policy
definition: '{"spark_version":{"type":"fixed","value":"13.3.x-scala2.12"}}'
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
bundle:
name: cluster_policy_consumer

resources:
jobs:
j:
name: consumer_job
tasks:
- task_key: main
new_cluster:
# Replaced at test time with the policy id created by bundle_a.
policy_id: PLACEHOLDER_POLICY_ID
spark_version: 13.3.x-scala2.12
num_workers: 1

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

=== Bundle A creates the cluster policy
>>> withdir bundle_a [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/cluster_policy_producer/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

=== Inject A's policy id into bundle B, then deploy B
>>> update_file.py bundle_b/databricks.yml PLACEHOLDER_POLICY_ID [POL_ID]

>>> withdir bundle_b [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/cluster_policy_consumer/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

=== Policy created by A, then B's job carries that same policy id
>>> print_requests.py //policies/clusters //jobs
{
"method": "POST",
"path": "/api/2.0/policies/clusters/create",
"body": {
"definition": "{\"spark_version\":{\"type\":\"fixed\",\"value\":\"13.3.x-scala2.12\"}}",
"name": "shared_policy"
}
}
{
"method": "POST",
"path": "/api/2.2/jobs/create",
"body": {
"deployment": {
"kind": "BUNDLE",
"metadata_file_path": "/Workspace/Users/[USERNAME]/.bundle/cluster_policy_consumer/default/state/metadata.json"
},
"edit_mode": "UI_LOCKED",
"format": "MULTI_TASK",
"max_concurrent_runs": 1,
"name": "consumer_job",
"queue": {
"enabled": true
},
"tasks": [
{
"new_cluster": {
"num_workers": 1,
"policy_id": "[POL_ID]",
"spark_version": "13.3.x-scala2.12"
},
"task_key": "main"
}
]
}
}

=== Cleanup
>>> withdir bundle_b [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.jobs.j

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/cluster_policy_consumer/default

Deleting files...
Destroy complete!

>>> withdir bundle_a [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.cluster_policies.pol

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/cluster_policy_producer/default

Deleting files...
Destroy complete!
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
title "Bundle A creates the cluster policy"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about the value of the cross_bundle_ tests - this is not really resource specific and standard DABs behaviuor

trace withdir bundle_a $CLI bundle deploy

# Capture A's server-generated policy id and register [POL_ID].
pol_id=$(withdir bundle_a read_id.py pol)

title "Inject A's policy id into bundle B, then deploy B"
trace update_file.py bundle_b/databricks.yml PLACEHOLDER_POLICY_ID "$pol_id"
trace withdir bundle_b $CLI bundle deploy

title "Policy created by A, then B's job carries that same policy id"
trace print_requests.py //policies/clusters //jobs

title "Cleanup"
trace withdir bundle_b $CLI bundle destroy --auto-approve
trace withdir bundle_a $CLI bundle destroy --auto-approve
rm -f out.requests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ignore = [".databricks"]
Loading
Loading