From 3d5726646407ef834e22377025982f6f61cb7541 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 23 Sep 2026 11:13:00 +0200 Subject: [PATCH 1/5] acceptance: add invariant/auto-migrate covering all resources New invariant target: deploy on terraform, then deploy on the direct default (auto-migrating the state), then assert no drift - across every resource config. Mirrors invariant/migrate but exercises the deploy-triggered auto path instead of the explicit "bundle deployment migrate" command. schema.yml.tmpl is excluded for now because it drifts on main; the migrate-before-deploy change (#6749) fixes it and drops the exclusion. Co-authored-by: Isaac --- .../invariant/auto-migrate/out.test.toml | 47 ++++++++++++++ .../bundle/invariant/auto-migrate/output.txt | 2 + .../bundle/invariant/auto-migrate/script | 16 +++++ .../bundle/invariant/auto-migrate/test.toml | 65 +++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 acceptance/bundle/invariant/auto-migrate/out.test.toml create mode 100644 acceptance/bundle/invariant/auto-migrate/output.txt create mode 100644 acceptance/bundle/invariant/auto-migrate/script create mode 100644 acceptance/bundle/invariant/auto-migrate/test.toml diff --git a/acceptance/bundle/invariant/auto-migrate/out.test.toml b/acceptance/bundle/invariant/auto-migrate/out.test.toml new file mode 100644 index 00000000000..099b356372e --- /dev/null +++ b/acceptance/bundle/invariant/auto-migrate/out.test.toml @@ -0,0 +1,47 @@ +Cloud = true +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] +EnvMatrix.DMS = [""] +EnvMatrix.INPUT_CONFIG = [ + "alert.yml.tmpl", + "app.yml.tmpl", + "cluster.yml.tmpl", + "cluster_apply_policy_default_values.yml.tmpl", + "dashboard.yml.tmpl", + "job_apply_policy_default_values_job_cluster.yml.tmpl", + "job_apply_policy_default_values_task_cluster.yml.tmpl", + "job_apply_policy_default_values_for_each_task.yml.tmpl", + "database_catalog.yml.tmpl", + "database_instance.yml.tmpl", + "experiment.yml.tmpl", + "job.yml.tmpl", + "job_pydabs_10_tasks.yml.tmpl", + "job_escaped_refs.yml.tmpl", + "job_run_job_ref.yml.tmpl", + "job_table_update_trigger.yml.tmpl", + "job_with_depends_on.yml.tmpl", + "job_with_task.yml.tmpl", + "model.yml.tmpl", + "model_with_permissions.yml.tmpl", + "model_serving_endpoint.yml.tmpl", + "pipeline.yml.tmpl", + "pipeline_allow_duplicate_names.yml.tmpl", + "pipeline_apply_policy_default_values.yml.tmpl", + "pipeline_config_dots.yml.tmpl", + "postgres_branch.yml.tmpl", + "postgres_catalog.yml.tmpl", + "postgres_database.yml.tmpl", + "postgres_endpoint.yml.tmpl", + "postgres_project.yml.tmpl", + "postgres_role.yml.tmpl", + "postgres_synced_table.yml.tmpl", + "registered_model.yml.tmpl", + "schema_tf_compat.yml.tmpl", + "schema_empty_grants.yml.tmpl", + "schema_uppercase_name.yml.tmpl", + "secret_scope.yml.tmpl", + "secret_scope_default_backend_type.yml.tmpl", + "synced_database_table.yml.tmpl", + "volume.yml.tmpl", + "volume_external.yml.tmpl", + "volume_path_job_ref.yml.tmpl" +] diff --git a/acceptance/bundle/invariant/auto-migrate/output.txt b/acceptance/bundle/invariant/auto-migrate/output.txt new file mode 100644 index 00000000000..fa9cb80d9e5 --- /dev/null +++ b/acceptance/bundle/invariant/auto-migrate/output.txt @@ -0,0 +1,2 @@ +INPUT_CONFIG_OK +INPUT_CONFIG_OK diff --git a/acceptance/bundle/invariant/auto-migrate/script b/acceptance/bundle/invariant/auto-migrate/script new file mode 100644 index 00000000000..b5ac1990936 --- /dev/null +++ b/acceptance/bundle/invariant/auto-migrate/script @@ -0,0 +1,16 @@ +# Invariant to test: auto-migration on deploy is successful, no drift after deploy +# Additional checks: no internal errors / panics in any commands + +unset DATABRICKS_BUNDLE_ENGINE + +invariant_setup + +invariant_deploy LOG.deploy DATABRICKS_BUNDLE_ENGINE=terraform $CLI bundle deploy + +# Deploy on the direct default (engine unset): this migrates the terraform state to the +# direct engine before deploying, so it exercises the auto path (MigrateTerraformState: +# reverse-interpolate, plan-check/recreate-guard, commit) rather than the explicit +# "bundle deployment migrate" command that migrate/ covers. +invariant_deploy LOG.migrate $CLI bundle deploy + +invariant_verify_no_drift diff --git a/acceptance/bundle/invariant/auto-migrate/test.toml b/acceptance/bundle/invariant/auto-migrate/test.toml new file mode 100644 index 00000000000..436713eaead --- /dev/null +++ b/acceptance/bundle/invariant/auto-migrate/test.toml @@ -0,0 +1,65 @@ +# Recording needs a bundle it has seen from the start. This test seeds a state file, +# so recording refuses it. TODO(DMS): drop this once existing state can be +# handed over to the service (see the TODO in dstate.Open). +EnvMatrix.DMS = [""] + +# vector_search_endpoints and vector_search_indexes have no terraform converter +EnvMatrixExclude.no_vector_search_endpoint = ["INPUT_CONFIG=vector_search_endpoint.yml.tmpl"] +EnvMatrixExclude.no_vector_search_index = ["INPUT_CONFIG=vector_search_index.yml.tmpl"] + +# job_runs is a direct-only resource with no terraform converter, so the +# terraform deploy that seeds the migration fails for it. +EnvMatrixExclude.no_job_run = ["INPUT_CONFIG=job_run.yml.tmpl"] + +# Error: Catalog resources are only supported with direct deployment mode +EnvMatrixExclude.no_catalog = ["INPUT_CONFIG=catalog.yml.tmpl"] +EnvMatrixExclude.no_catalog_optional_fields = ["INPUT_CONFIG=catalog_optional_fields.yml.tmpl"] +EnvMatrixExclude.no_external_location = ["INPUT_CONFIG=external_location.yml.tmpl"] +# uc_trailing_slash includes a catalog, which is direct-only (see above). +EnvMatrixExclude.no_uc_trailing_slash = ["INPUT_CONFIG=uc_trailing_slash.yml.tmpl"] +# Genie spaces are direct-only too; the terraform deploy that seeds the migration fails for them. +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"] +# Cluster libraries are direct-only; the terraform deploy that seeds the migration fails for them. +EnvMatrixExclude.no_cluster_libraries = ["INPUT_CONFIG=cluster_libraries.yml.tmpl"] +# AI Gateway securables are direct-only; the terraform deploy that seeds the migration fails for them. +EnvMatrixExclude.no_model_service = ["INPUT_CONFIG=model_service.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 +# ${databricks_job.job_b.permissions[0].level}, but Terraform's databricks_job resource +# does not expose permissions as output attributes (permissions are a separate +# databricks_permissions resource in terraform), so the literal unresolved string +# ends up as the permission level value. +EnvMatrixExclude.no_permission_ref = ["INPUT_CONFIG=job_permission_ref.yml.tmpl"] +EnvMatrixExclude.no_cross_resource_ref = ["INPUT_CONFIG=job_cross_resource_ref.yml.tmpl"] + +# Grant cross-references require the EmbeddedSlice pattern not present in terraform mode. +EnvMatrixExclude.no_grant_ref = ["INPUT_CONFIG=schema_grant_ref.yml.tmpl"] + +# SQL warehouses currently failing with migration with permanent drift. TODO: fix this. +EnvMatrixExclude.no_sql_warehouse = ["INPUT_CONFIG=sql_warehouse.yml.tmpl"] + +# The 1000-task scale case is covered by no_drift. Running it here adds ~1.5 min +# per variant (deploy + migrate + plan at 1000 tasks) without incremental coverage. +EnvMatrixExclude.no_pydabs_1000_tasks = ["INPUT_CONFIG=job_pydabs_1000_tasks.yml.tmpl"] + +# migrate deploys via Terraform first, and the TF provider rejects an uppercase +# volume schema_name ("inconsistent final plan"). Covered by no_drift on direct. +EnvMatrixExclude.no_volume_uppercase = ["INPUT_CONFIG=volume_uppercase_name.yml.tmpl"] + +EnvMatrixExclude.no_secret = ["INPUT_CONFIG=secret.yml.tmpl"] + +# Terraform types sampling_fraction as an integer and truncates 0.5; covered by no_drift. +EnvMatrixExclude.no_model_serving_endpoint_telemetry = ["INPUT_CONFIG=model_serving_endpoint_telemetry.yml.tmpl"] + +# schema.yml.tmpl drifts through auto-migration on main: a plain schema does not converge + +# after migrate-then-deploy. The migrate-before-deploy change (#6749) fixes it and drops this + +# exclusion. + +EnvMatrixExclude.no_schema = ["INPUT_CONFIG=schema.yml.tmpl"] From a579ce4b2afc3a19d7e5be9dce7327845dec3161 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 23 Sep 2026 11:16:59 +0200 Subject: [PATCH 2/5] acceptance: emit INPUT_CONFIG_OK once in auto-migrate The second (auto-migrate) deploy used invariant_deploy, which re-echoes the INPUT_CONFIG_OK fuzzer marker, so it printed twice. The config is already validated by the terraform deploy above; a failure in the auto-migrate deploy is a bug, not an invalid config. Use a plain trace + panic/internal-error check for it, matching invariant/migrate, so the marker fires once. Co-authored-by: Isaac --- acceptance/bundle/invariant/auto-migrate/output.txt | 1 - acceptance/bundle/invariant/auto-migrate/script | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/acceptance/bundle/invariant/auto-migrate/output.txt b/acceptance/bundle/invariant/auto-migrate/output.txt index fa9cb80d9e5..7a28cb73a58 100644 --- a/acceptance/bundle/invariant/auto-migrate/output.txt +++ b/acceptance/bundle/invariant/auto-migrate/output.txt @@ -1,2 +1 @@ INPUT_CONFIG_OK -INPUT_CONFIG_OK diff --git a/acceptance/bundle/invariant/auto-migrate/script b/acceptance/bundle/invariant/auto-migrate/script index b5ac1990936..e2bac3ac3bd 100644 --- a/acceptance/bundle/invariant/auto-migrate/script +++ b/acceptance/bundle/invariant/auto-migrate/script @@ -8,9 +8,10 @@ invariant_setup invariant_deploy LOG.deploy DATABRICKS_BUNDLE_ENGINE=terraform $CLI bundle deploy # Deploy on the direct default (engine unset): this migrates the terraform state to the -# direct engine before deploying, so it exercises the auto path (MigrateTerraformState: -# reverse-interpolate, plan-check/recreate-guard, commit) rather than the explicit -# "bundle deployment migrate" command that migrate/ covers. -invariant_deploy LOG.migrate $CLI bundle deploy +# direct engine before deploying, exercising the auto path. Not invariant_deploy -- the +# config was already validated by the terraform deploy above, so a failure here is a bug, +# not an invalid config (and it must not re-emit the INPUT_CONFIG_OK marker). +trace $CLI bundle deploy &> LOG.migrate +cat LOG.migrate | contains.py '!panic:' '!internal error' > /dev/null invariant_verify_no_drift From fca98d4d8fcd9fa6b6701fd00933639a87f0a36b Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 23 Sep 2026 11:24:42 +0200 Subject: [PATCH 3/5] acceptance: align auto-migrate excludes with migrate; document no_secret Sync the exclude list to the current migrate/test.toml: schema.yml.tmpl is already excluded via no_schema_custom_retention (custom_max_retention_hours drifts a terraform-first migrate; schema_tf_compat.yml covers schemas), so drop the separate no_schema exclusion I had added. Add the missing comment on no_secret (UC secrets are direct-only, so the terraform seed deploy fails for them). Co-authored-by: Isaac --- acceptance/bundle/invariant/auto-migrate/test.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/acceptance/bundle/invariant/auto-migrate/test.toml b/acceptance/bundle/invariant/auto-migrate/test.toml index 436713eaead..4d205bb49ec 100644 --- a/acceptance/bundle/invariant/auto-migrate/test.toml +++ b/acceptance/bundle/invariant/auto-migrate/test.toml @@ -3,6 +3,11 @@ # handed over to the service (see the TODO in dstate.Open). EnvMatrix.DMS = [""] +# schema.yml sets custom_max_retention_hours, which the terraform databricks_schema resource cannot +# set (only direct does), so a terraform-first migrate would drift. schema_tf_compat.yml keeps migrate +# coverage for schemas. +EnvMatrixExclude.no_schema_custom_retention = ["INPUT_CONFIG=schema.yml.tmpl"] + # vector_search_endpoints and vector_search_indexes have no terraform converter EnvMatrixExclude.no_vector_search_endpoint = ["INPUT_CONFIG=vector_search_endpoint.yml.tmpl"] EnvMatrixExclude.no_vector_search_index = ["INPUT_CONFIG=vector_search_index.yml.tmpl"] @@ -51,15 +56,10 @@ EnvMatrixExclude.no_pydabs_1000_tasks = ["INPUT_CONFIG=job_pydabs_1000_tasks.yml # volume schema_name ("inconsistent final plan"). Covered by no_drift on direct. EnvMatrixExclude.no_volume_uppercase = ["INPUT_CONFIG=volume_uppercase_name.yml.tmpl"] +# UC secrets are direct-only (no terraform converter), so the terraform deploy that seeds +# the migration fails for them. EnvMatrixExclude.no_secret = ["INPUT_CONFIG=secret.yml.tmpl"] # Terraform types sampling_fraction as an integer and truncates 0.5; covered by no_drift. EnvMatrixExclude.no_model_serving_endpoint_telemetry = ["INPUT_CONFIG=model_serving_endpoint_telemetry.yml.tmpl"] -# schema.yml.tmpl drifts through auto-migration on main: a plain schema does not converge - -# after migrate-then-deploy. The migrate-before-deploy change (#6749) fixes it and drops this - -# exclusion. - -EnvMatrixExclude.no_schema = ["INPUT_CONFIG=schema.yml.tmpl"] From 983a90331ec0e5c2d612fc419b7a64a7e7065a61 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 23 Sep 2026 11:31:46 +0200 Subject: [PATCH 4/5] acceptance: drop trailing blank line in auto-migrate/test.toml Co-authored-by: Isaac --- acceptance/bundle/invariant/auto-migrate/test.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/acceptance/bundle/invariant/auto-migrate/test.toml b/acceptance/bundle/invariant/auto-migrate/test.toml index 4d205bb49ec..1e7a9351e39 100644 --- a/acceptance/bundle/invariant/auto-migrate/test.toml +++ b/acceptance/bundle/invariant/auto-migrate/test.toml @@ -62,4 +62,3 @@ EnvMatrixExclude.no_secret = ["INPUT_CONFIG=secret.yml.tmpl"] # Terraform types sampling_fraction as an integer and truncates 0.5; covered by no_drift. EnvMatrixExclude.no_model_serving_endpoint_telemetry = ["INPUT_CONFIG=model_serving_endpoint_telemetry.yml.tmpl"] - From 97123451654e0536dccce401f44071854da9d9d7 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 23 Sep 2026 11:46:41 +0200 Subject: [PATCH 5/5] acceptance: update selection selftest golden for new auto-migrate invariant Co-authored-by: Isaac --- acceptance/selftest/selection/output.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/acceptance/selftest/selection/output.txt b/acceptance/selftest/selection/output.txt index 505dd11316c..49786a52b46 100644 --- a/acceptance/selftest/selection/output.txt +++ b/acceptance/selftest/selection/output.txt @@ -28,7 +28,8 @@ Selected 2 changed tests (limit=50, 0 not selected) === Touching an invariant config runs every invariant test, for that config only >>> selection M:acceptance/bundle/invariant/configs/job.yml.tmpl -Selected 5 changed tests (limit=50, 0 not selected) +Selected 6 changed tests (limit=50, 0 not selected) + 5 ^bundle$/^invariant$/^auto-migrate$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ 5 ^bundle$/^invariant$/^continue_293$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ 5 ^bundle$/^invariant$/^delete_idempotent$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ 5 ^bundle$/^invariant$/^destroy_idempotent$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ @@ -39,13 +40,15 @@ Selected 5 changed tests (limit=50, 0 not selected) === Adding one invariant config and touching another: only the new variant is new >>> selection A:acceptance/bundle/invariant/configs/pipeline.yml.tmpl M:acceptance/bundle/invariant/configs/job.yml.tmpl -Selected 10 changed tests (limit=50, 0 not selected) +Selected 12 changed tests (limit=50, 0 not selected) + 10 ^bundle$/^invariant$/^auto-migrate$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=pipeline\.yml\.tmpl$ 10 ^bundle$/^invariant$/^continue_293$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=pipeline\.yml\.tmpl$ 10 ^bundle$/^invariant$/^delete_idempotent$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=pipeline\.yml\.tmpl$ 10 ^bundle$/^invariant$/^destroy_idempotent$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=pipeline\.yml\.tmpl$ 10 ^bundle$/^invariant$/^migrate$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=pipeline\.yml\.tmpl$ 10 ^bundle$/^invariant$/^no_drift$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=pipeline\.yml\.tmpl$ 10 ^bundle$/^invariant$/^no_drift$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=true$/^INPUT_CONFIG=pipeline\.yml\.tmpl$ + 5 ^bundle$/^invariant$/^auto-migrate$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ 5 ^bundle$/^invariant$/^continue_293$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ 5 ^bundle$/^invariant$/^delete_idempotent$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ 5 ^bundle$/^invariant$/^destroy_idempotent$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ @@ -71,7 +74,7 @@ Selected 1 changed tests (limit=50, 0 not selected) === The limit keeps the highest scoring tests >>> selection -limit 3 A:acceptance/selftest/basic/script M:acceptance/selftest/diff/script M:acceptance/bundle/invariant/configs/job.yml.tmpl -Selected 3 changed tests (limit=3, 4 not selected) +Selected 3 changed tests (limit=3, 5 not selected) 10 ^selftest$/^basic$ + 5 ^bundle$/^invariant$/^auto-migrate$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ 5 ^bundle$/^invariant$/^continue_293$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$ - 5 ^bundle$/^invariant$/^delete_idempotent$/^DATABRICKS_BUNDLE_ENGINE=direct$/^DMS=$/^INPUT_CONFIG=job\.yml\.tmpl$