Skip to content

direct: Fix spurious recreate of schemas and volumes with mixed-case names#5531

Merged
denik merged 9 commits into
mainfrom
denik/reproduce-schemas-issue
Jun 10, 2026
Merged

direct: Fix spurious recreate of schemas and volumes with mixed-case names#5531
denik merged 9 commits into
mainfrom
denik/reproduce-schemas-issue

Conversation

@denik

@denik denik commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

The direct engine saves local config to state, so when Unity Catalog lowercases a schema/volume identifier, the next deploy sees the original mixed-case value drift against the normalized remote value and recreates/renames the resource — on every second deploy with no config changes. This PR fixes that.

The fix is expressed declaratively via a new resources.yml key, normalize_case. The same mechanism also absorbs the existing trailing-slash storage_location suppression (#5145) as a second key, normalize_slash — a refactor of behavior that already lived in per-resource OverrideChangeDesc methods, not a new behavior.

denik added 2 commits June 9, 2026 16:10
The direct engine saves local config to state, so when the UC API normalizes
an identifier (lowercases catalog/schema/volume names) or strips a trailing
slash from a storage URL, the next plan compares the original local value
against the normalized remote value and triggers a spurious recreate/update.
On every second deploy with no config changes, schemas and volumes were
recreated/renamed.

Previously this was suppressed with per-resource OverrideChangeDesc methods.
Replace those with two declarative resources.yml keys, normalize_case and
normalize_slash, parsed at runtime like the other lifecycle rules and applied
in addPerFieldActions before recreate/update classification. Adding a new UC
resource is now a few YAML lines instead of a Go method.

- config.go: NormalizeCase / NormalizeSlash on ResourceLifecycleConfig
- bundle_plan.go: shouldSkipNormalized wired into the skip-ladder
- schema.go, volume.go: delete OverrideChangeDesc; declare fields in resources.yml
- testserver: lowercase schema/volume identifier names to mimic UC
- schema_uppercase_name invariant config is schema-only (the migrate invariant
  deploys via Terraform first, and the TF provider rejects an uppercase volume
  schema_name); volume coverage lives in resources/volumes/uppercase-name

Co-authored-by: Isaac
@denik denik temporarily deployed to test-trigger-is June 10, 2026 10:16 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 10, 2026 10:16 — with GitHub Actions Inactive
denik added 2 commits June 10, 2026 12:39
volume_uppercase_name covers the uppercase no-drift case on direct via the
no_drift invariant; excluded from migrate (Terraform deploys first and rejects
an uppercase volume schema_name). The dedicated schemas/uppercase-name test is
redundant with the no_drift invariant, so remove it.

Co-authored-by: Isaac
@denik denik changed the title Make UC case/slash normalization declarative in resources.yml direct: Fix spurious recreate of schemas and volumes with mixed-case names Jun 10, 2026
@denik denik temporarily deployed to test-trigger-is June 10, 2026 10:55 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 10, 2026 10:55 — with GitHub Actions Inactive
Co-authored-by: Isaac

# 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"]

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.

Interesting; this error doesn't happen for schemas?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

no

denik added 2 commits June 10, 2026 14:21
shouldSkipNormalized returned a hardcoded reason and ignored the per-field
reason from resources.yml, unlike every other rule. Route the config reason
through (like recreate_on_changes etc.) and drop the now-unused
Reason{UC,URL}Normalization constants.

Record the relevant plan changes (field action + reason) in the
volumes/uppercase-name test so the skip classification is visible.

Co-authored-by: Isaac
@denik denik enabled auto-merge June 10, 2026 12:25
@denik denik temporarily deployed to test-trigger-is June 10, 2026 12:25 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 10, 2026 12:25 — with GitHub Actions Inactive
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Commit: 0169c0c

Run: 27276089821

Env 🟨​KNOWN 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🟨​ aws linux 7 15 261 949 8:16
🟨​ aws windows 7 15 263 947 15:25
💚​ aws-ucws linux 7 15 357 863 8:04
💚​ aws-ucws windows 7 15 359 861 14:40
💚​ azure linux 1 17 264 947 6:24
💚​ azure windows 1 17 266 945 11:19
💚​ azure-ucws linux 1 17 362 859 7:55
💚​ azure-ucws windows 1 17 364 857 12:22
💚​ gcp linux 1 17 260 950 8:23
💚​ gcp windows 1 17 262 948 13:10
22 interesting tests: 15 SKIP, 7 KNOWN
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🟨​ TestAccept 🟨​K 🟨​K 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🙈​ TestAccept/bundle/resources/postgres_branches/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/replace_existing 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/update_protected 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/without_branch_id 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_projects/update_display_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/grants/select 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
Top 28 slowest tests (at least 2 minutes):
duration env testname
6:11 aws-ucws windows TestAccept
6:04 gcp windows TestAccept
5:53 azure windows TestAccept
5:34 azure-ucws windows TestAccept
4:39 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:22 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:14 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:13 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:45 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:27 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:25 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:25 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:24 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:20 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:12 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:12 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:10 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:09 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:01 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:54 gcp linux TestAccept
2:53 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:52 azure linux TestAccept
2:52 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:50 aws-ucws linux TestAccept
2:47 azure-ucws linux TestAccept
2:26 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:25 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:22 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct

denik added 2 commits June 10, 2026 16:55
&>> is bash 4+ syntax; macOS CI runners use the stock bash 3.2, which fails
to parse the whole script ("syntax error near unexpected token '>'") and
produces no output files. Use >> ... 2>&1 instead.

Co-authored-by: Isaac
@denik denik temporarily deployed to test-trigger-is June 10, 2026 14:58 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is June 10, 2026 14:58 — with GitHub Actions Inactive
@denik denik disabled auto-merge June 10, 2026 15:10
@denik denik merged commit 6b0282f into main Jun 10, 2026
23 checks passed
@denik denik deleted the denik/reproduce-schemas-issue branch June 10, 2026 15:10
deco-sdk-tagging Bot added a commit that referenced this pull request Jun 10, 2026
## Release v1.3.0

### Notable Changes
* The `direct` deployment engine is now Generally Available and the default for new deployments. To opt out, set `engine: terraform` under `bundle` in your `databricks.yml` or set `DATABRICKS_BUNDLE_ENGINE=terraform`. Existing deployments keep their current engine; see https://docs.databricks.com/aws/en/dev-tools/bundles/direct to migrate.

### CLI
* Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively ([#5464](#5464)).
* Add `databricks version --check` to report whether a newer CLI version is available and print the upgrade command for the detected install method ([#5469](#5469)).
* `databricks auth describe` now verifies credentials against both the workspace and account endpoints before reporting a failure, fixing false "Unable to authenticate" errors for account console profiles ([#5479](#5479)).
* `databricks auth login` no longer prompts for workspace selection when logging in to an account console host (`https://accounts.*`). Pass `--workspace-id` explicitly to store a workspace ID on such a profile ([#5504](#5504)).
* `databricks auth profiles --skip-validate` no longer makes any network calls; the host metadata fetch is skipped along with validation ([#5530](#5530)).

### Bundles
* Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](#5452)).
* Mark vector search index index_subtype as backend_default to prevent drift after deployment ([#5454](#5454)).
* `bundle deployment migrate`: handle resources added to or removed from `databricks.yml` since the last Terraform deploy ([#5463](#5463)).
* Add the `genie_spaces` bundle resource for managing Databricks Genie spaces as code, plus `bundle generate genie-space` to import an existing space. Direct deployment engine only ([#5282](#5282)).
* Fix spurious recreate of schemas and volumes whose names use mixed case ([#5531](#5531)).
janniklasrose added a commit that referenced this pull request Jun 11, 2026
The GitHub web conflict editor left the <<<<<<< / ======= / >>>>>>>
markers in resources.yml, breaking YAML parsing (lint, direct tests,
and validate-generated). Keep both sides: backend_defaults from this
branch plus normalize_case/normalize_slash from main (#5531), ordered
to match the volumes section.

Co-authored-by: Isaac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants