Skip to content

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

Open
denik wants to merge 7 commits into
mainfrom
denik/reproduce-schemas-issue
Open

direct: Fix spurious recreate of schemas and volumes with mixed-case names#5531
denik wants to merge 7 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

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