Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
942c2e4
Do not report cluster fields supplied by a cluster policy as drift
denik Sep 4, 2026
780e7ec
Match cloud: no policy expansion for pipelines, enforce fixed values
denik Sep 4, 2026
3896c2f
Add PR link to changelog fragment
denik Sep 4, 2026
84e8eea
acc: show the spark_version verdict in fixed_values_applied
denik Sep 4, 2026
1ffb64a
acc: keep policy_no_drift_variants out of short cloud runs
denik Sep 4, 2026
72736b3
Make ignore_remote_additions when_set a path
denik Sep 7, 2026
cd7e7d7
acc: move jobs+policy tests under resources/jobs/cluster_policy
denik Sep 8, 2026
33a6ad6
Address review: honest changelog, inline YAML policies, gron over jq
denik Sep 8, 2026
f523278
Rename reason policy_managed -> remote_addition
denik Sep 8, 2026
b19fec7
acc: record the whole plan in policy_no_drift_variants, make it local…
denik Sep 9, 2026
c6a36cc
acc: record the pruned plan in policy_no_drift_variants; add prune_pl…
denik Sep 9, 2026
b78d7cf
acc: make policy_no_drift_variants local-only
denik Sep 9, 2026
e447832
acc: rename pol -> my_policy and drop dead read_id in policy_no_drift…
denik Sep 9, 2026
78c76de
acc: rename the policy resource to my_pol across the cluster_policy t…
denik Sep 9, 2026
6d22e3b
acc: use my_policy (not my_pol) for the policy resource key
denik Sep 9, 2026
e0a88b5
ci: re-trigger checks
denik Sep 9, 2026
5725a8c
Merge remote-tracking branch 'origin/main' into denik/cluster-policy-…
denik Sep 10, 2026
b1518e0
acc: opt policy_no_drift_variants out of the DMS matrix after merging…
denik Sep 10, 2026
2b5c067
acc: make prune_plan.py executable and pin policy_no_drift_variants t…
denik Sep 10, 2026
981bde2
Reword changelog: "direct:" prefix
denik Sep 11, 2026
df2ce3c
acc: split cluster-policy tests into single-condition tests
denik Sep 11, 2026
8aeb76c
acc: address review of the cluster_policy tests
denik Sep 11, 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-policy-no-drift.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* direct: `bundle plan` no longer reports a permanent update on a cluster that uses a cluster policy: when the cluster spec sets `policy_id`, a field present in the remote but absent from the bundle config is not treated as drift. ([#6531](https://github.com/databricks/cli/pull/6531))
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
bundle:
name: test-bundle-$UNIQUE_NAME

workspace:
root_path: ~/.bundle/$UNIQUE_NAME

resources:
cluster_policies:
my_policy:
name: test-policy-$UNIQUE_NAME
definition:
# Only a map key: the clusters resource force-sends spark_version, so a scalar the
# config omits arrives as "" and a fixed policy rejects it. The scalar-supply case is
# covered by fixed_addition, whose job-cluster new_cluster fields are omitempty.
custom_tags.CostCenter:
type: fixed
value: from-policy

clusters:
my_cluster:
cluster_name: test-cluster-$UNIQUE_NAME
spark_version: $DEFAULT_SPARK_VERSION
node_type_id: $NODE_TYPE_ID
# Shared pool avoids a cold boot; the policy tag under test is unaffected.
instance_pool_id: $TEST_INSTANCE_POOL_ID
num_workers: 1
policy_id: ${resources.cluster_policies.my_policy.id}

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

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

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/[UNIQUE_NAME]/files...
Created cluster_policies.my_policy
Created clusters.my_cluster
Files: 5 uploaded, 0 deleted
Resources: 2 created, 0 changed, 0 deleted, 0 unchanged

=== A cluster policy tag on a standalone cluster is not drift

>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

=== ...classified remote_addition

>>> [CLI] bundle plan -o json
{
"custom_tags": {
"action": "skip",
"reason": "remote_addition",
"remote": {
"CostCenter": "from-policy"
}
}
}

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.cluster_policies.my_policy
delete resources.clusters.my_cluster

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

Destroy: 2 deleted
15 changes: 15 additions & 0 deletions acceptance/bundle/resources/clusters/cluster_policy/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
trace $CLI bundle destroy --auto-approve
}
trap cleanup EXIT

trace $CLI bundle deploy

title "A cluster policy tag on a standalone cluster is not drift\n"
trace $CLI bundle plan

title "...classified remote_addition\n"
trace $CLI bundle plan -o json | jq -S '.plan["resources.clusters.my_cluster"].changes
| with_entries(select(.key | test("custom_tags")))'
12 changes: 12 additions & 0 deletions acceptance/bundle/resources/clusters/cluster_policy/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# The standalone clusters resource boots a real cluster at deploy, which is slow and has hit
# capacity limits on cloud; CloudSlow keeps it out of the per-PR run (it still runs locally and
# in the full cloud sweep). Output is projected to the policy tag so it is cloud-portable.
Cloud = true
CloudSlow = true
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"]

RecordRequests = false

Ignore = [
"databricks.yml",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
bundle:
name: test-bundle-$UNIQUE_NAME

workspace:
root_path: ~/.bundle/$UNIQUE_NAME

resources:
cluster_policies:
my_policy:
name: test-policy-$UNIQUE_NAME
definition:
custom_tags.CostCenter:
type: fixed
value: from-policy

jobs:
my_job:
name: test-job-$UNIQUE_NAME
job_clusters:
# The config sets the fixed attribute to a value the policy forbids.
- job_cluster_key: main
new_cluster:
policy_id: ${resources.cluster_policies.my_policy.id}
spark_version: $DEFAULT_SPARK_VERSION
node_type_id: $NODE_TYPE_ID
num_workers: 1
custom_tags:
CostCenter: not-what-the-policy-says
tasks:
- task_key: main
job_cluster_key: main
spark_python_task:
python_file: ./hello_world.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("hello")

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,21 @@

=== A cluster tag contradicting a fixed policy value is rejected at create

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/[UNIQUE_NAME]/files...
Error: cannot create resources.jobs.my_job: Cluster validation error: Validation failed for custom_tags, CostCenter must be from-policy (is "not-what-the-policy-says") (400 INVALID_PARAMETER_VALUE)

Endpoint: POST [DATABRICKS_URL]/api/2.2/jobs/create
HTTP Status: 400 Bad Request
API error_code: INVALID_PARAMETER_VALUE
API message: Cluster validation error: Validation failed for custom_tags, CostCenter must be from-policy (is "not-what-the-policy-says")

Files: 5 uploaded, 0 deleted

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

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

Destroy: 1 deleted
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
trace $CLI bundle destroy --auto-approve
}
trap cleanup EXIT

title "A cluster tag contradicting a fixed policy value is rejected at create\n"
musterr trace $CLI bundle deploy
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
bundle:
name: test-bundle-$UNIQUE_NAME

workspace:
root_path: ~/.bundle/$UNIQUE_NAME

resources:
cluster_policies:
my_policy:
name: test-policy-$UNIQUE_NAME
definition:
# A defaultValue element: the backend fills it into an omitted attribute only when
# the request sets apply_policy_default_values (unlike a fixed element).
custom_tags.DefaultTag:
type: unlimited
defaultValue: from-default
isOptional: true

jobs:
my_job:
name: test-job-$UNIQUE_NAME
job_clusters:
- job_cluster_key: flag_off
new_cluster:
policy_id: ${resources.cluster_policies.my_policy.id}
spark_version: $DEFAULT_SPARK_VERSION
node_type_id: $NODE_TYPE_ID
num_workers: 1
- job_cluster_key: flag_on
new_cluster:
policy_id: ${resources.cluster_policies.my_policy.id}
apply_policy_default_values: true
spark_version: $DEFAULT_SPARK_VERSION
node_type_id: $NODE_TYPE_ID
num_workers: 1
tasks:
- task_key: main
job_cluster_key: flag_off
spark_python_task:
python_file: ./hello_world.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("hello")

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,35 @@

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/[UNIQUE_NAME]/files...
Created cluster_policies.my_policy
Created jobs.my_job
Files: 5 uploaded, 0 deleted
Resources: 2 created, 0 changed, 0 deleted, 0 unchanged

=== defaultValue is supplied only with apply_policy_default_values (flag_on), not flag_off
[
{
"custom_tags": null,
"job_cluster_key": "flag_off"
},
{
"custom_tags": {
"DefaultTag": "from-default"
},
"job_cluster_key": "flag_on"
}
]

=== Neither is drift on a second plan

>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.cluster_policies.my_policy
delete resources.jobs.my_job

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

Destroy: 2 deleted
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
trace $CLI bundle destroy --auto-approve
}
trap cleanup EXIT

trace $CLI bundle deploy
job_id=$(read_id.py my_job)

title "defaultValue is supplied only with apply_policy_default_values (flag_on), not flag_off\n"
$CLI jobs get "$job_id" | jq -S '[.settings.job_clusters[]
| {job_cluster_key, custom_tags: .new_cluster.custom_tags}]'

title "Neither is drift on a second plan\n"
trace $CLI bundle plan
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
bundle:
name: test-bundle-$UNIQUE_NAME

workspace:
root_path: ~/.bundle/$UNIQUE_NAME

resources:
cluster_policies:
my_policy:
name: test-policy-$UNIQUE_NAME
definition:
# A fixed scalar and a fixed map key; every cluster below omits both, so the policy is
# the sole source and each supplied value must be classified remote_addition.
spark_version:
type: fixed
value: $DEFAULT_SPARK_VERSION
custom_tags.CostCenter:
type: fixed
value: from-policy

jobs:
my_job:
name: test-job-$UNIQUE_NAME
job_clusters:
- job_cluster_key: job_cluster
new_cluster:
policy_id: ${resources.cluster_policies.my_policy.id}
node_type_id: $NODE_TYPE_ID
num_workers: 1
tasks:
- task_key: on_job_cluster
job_cluster_key: job_cluster
spark_python_task:
python_file: ./hello_world.py
- task_key: task_cluster
new_cluster:
policy_id: ${resources.cluster_policies.my_policy.id}
node_type_id: $NODE_TYPE_ID
num_workers: 1
spark_python_task:
python_file: ./hello_world.py
- task_key: for_each
for_each_task:
inputs: "[1]"
task:
task_key: for_each_cluster
new_cluster:
policy_id: ${resources.cluster_policies.my_policy.id}
node_type_id: $NODE_TYPE_ID
num_workers: 1
spark_python_task:
python_file: ./hello_world.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("hello")

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,63 @@

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/[UNIQUE_NAME]/files...
Created cluster_policies.my_policy
Created jobs.my_job
Files: 5 uploaded, 0 deleted
Resources: 2 created, 0 changed, 0 deleted, 0 unchanged

=== Policy-supplied spark_version and custom_tags are not drift at any cluster-spec location

>>> [CLI] bundle plan
Plan: 0 to add, 0 to change, 0 to delete, 2 unchanged

=== Each is classified remote_addition

>>> [CLI] bundle plan -o json
{
"job_clusters[job_cluster_key='job_cluster'].new_cluster.custom_tags": {
"action": "skip",
"reason": "remote_addition",
"remote": {
"CostCenter": "from-policy"
}
},
"job_clusters[job_cluster_key='job_cluster'].new_cluster.spark_version": {
"action": "skip",
"reason": "remote_addition",
"remote": "13.3.x-snapshot-scala2.12"
},
"tasks[task_key='for_each'].for_each_task.task.new_cluster.custom_tags": {
"action": "skip",
"reason": "remote_addition",
"remote": {
"CostCenter": "from-policy"
}
},
"tasks[task_key='for_each'].for_each_task.task.new_cluster.spark_version": {
"action": "skip",
"reason": "remote_addition",
"remote": "13.3.x-snapshot-scala2.12"
},
"tasks[task_key='task_cluster'].new_cluster.custom_tags": {
"action": "skip",
"reason": "remote_addition",
"remote": {
"CostCenter": "from-policy"
}
},
"tasks[task_key='task_cluster'].new_cluster.spark_version": {
"action": "skip",
"reason": "remote_addition",
"remote": "13.3.x-snapshot-scala2.12"
}
}

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.cluster_policies.my_policy
delete resources.jobs.my_job

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

Destroy: 2 deleted
Loading
Loading