Skip to content

Conversation

@denik
Copy link
Contributor

@denik denik commented Oct 30, 2025

Changes

New migrate command to convert terraform state to direct engine state. This currently only works locally (needs bundle deploy to sync changes) and does not support permissions.

Depends on #3875

Tests

Acceptance tests.

@denik denik temporarily deployed to test-trigger-is October 30, 2025 12:45 — with GitHub Actions Inactive
@eng-dev-ecosystem-bot
Copy link
Collaborator

eng-dev-ecosystem-bot commented Oct 30, 2025

Run: 19166282007

Env ❌​FAIL 🟨​KNOWN 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip
💚​ aws linux 1 1 356 599
💚​ aws windows 1 1 357 598
💚​ aws-ucws linux 1 1 479 494
🔄​ aws-ucws windows 1 1 1 479 493
💚​ azure linux 1 1 356 598
💚​ azure windows 1 1 357 597
🔄​ azure-ucws linux 3 1 473 493
💚​ azure-ucws windows 1 1 476 492
❌​ gcp linux 21 1 1 334 600
❌​ gcp windows 23 1 1 333 599
48 failing tests:
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 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 🔄​f 💚​R 🟨​K 🟨​K
TestAccept/bundle/deploy/mlops-stacks ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/deployment/bind/dashboard ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestAccept/bundle/deployment/bind/dashboard/recreation ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/deployment/bind/experiment ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ❌​F
TestAccept/bundle/deployment/bind/job/generate-and-bind ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestAccept/bundle/deployment/bind/job/job-abort-bind ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestAccept/bundle/deployment/bind/model-serving-endpoint ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestAccept/bundle/deployment/unbind/permissions ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestAccept/bundle/resources/clusters/deploy/data_security_mode ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
TestAccept/bundle/resources/clusters/deploy/data_security_mode/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
TestAccept/bundle/resources/dashboards/change-embed-credentials ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/resources/dashboards/change-embed-credentials/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/resources/dashboards/change-parent-path ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/resources/dashboards/change-parent-path/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/resources/dashboards/detect-change ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/resources/dashboards/detect-change/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestAccept/bundle/run/app-with-job 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
TestAccept/bundle/templates/default-python/integration_classic ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestAccept/bundle/templates/default-python/integration_classic/DATABRICKS_BUNDLE_ENGINE=direct/UV_PYTHON=3.12 ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestAccept/bundle/templates/default-python/integration_classic/DATABRICKS_BUNDLE_ENGINE=direct/UV_PYTHON=3.13 ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpDir ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpDir/dbfs_to_dbfs ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpDir/local_to_dbfs ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpDirToDirFileNotOverwritten ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpDirToDirFileNotOverwritten/dbfs_to_dbfs ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpDirToDirFileNotOverwritten/dbfs_to_local ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpDirToDirFileNotOverwritten/local_to_dbfs ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpFileToDir ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpFileToDir/dbfs_to_dbfs ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpFileToDir/dbfs_to_local ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpFileToDirFileNotOverwritten ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestFsCpFileToDirFileNotOverwritten/dbfs_to_local ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p
TestSyncIncrementalFileOverwritesFolder ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestFilerRecursiveDelete ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestFilerRecursiveDelete/workspace_files ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestFilerWorkspaceFilesExtensionsDelete ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestFilerWorkspaceFilesExtensionsRead ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestFilerWorkspaceFilesExtensionsReadDir ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestWorkspaceFilesExtensions_ExportFormatIsPreserved ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestWorkspaceFilesExtensions_ExportFormatIsPreserved/jupyter_python ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestWorkspaceFilesExtensions_ExportFormatIsPreserved/jupyter_r ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestWorkspaceFilesExtensions_ExportFormatIsPreserved/jupyter_scala ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestWorkspaceFilesExtensions_ExportFormatIsPreserved/jupyter_sql ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestWorkspaceFilesExtensions_ExportFormatIsPreserved/source_python ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestWorkspaceFilesExtensions_ExportFormatIsPreserved/source_sql ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
TestFetchRepositoryInfoAPI_FromRepo ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
TestLock ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F

@denik denik force-pushed the denik/deployment-migrate branch from 900c30b to 54e0bab Compare October 30, 2025 13:12
@denik denik temporarily deployed to test-trigger-is October 30, 2025 13:12 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is October 30, 2025 13:28 — with GitHub Actions Inactive
@denik denik force-pushed the denik/direct-exp-to-direct branch from d00f343 to 0f1d24c Compare October 30, 2025 14:30
Base automatically changed from denik/direct-exp-to-direct to main October 31, 2025 09:41
@denik denik force-pushed the denik/deployment-migrate branch from 00025d4 to bd5cb0a Compare October 31, 2025 13:35
@denik denik temporarily deployed to test-trigger-is October 31, 2025 13:35 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 3, 2025 10:29 — with GitHub Actions Inactive
@denik denik force-pushed the denik/deployment-migrate branch from 665ab46 to 546d9f8 Compare November 3, 2025 10:32
@denik denik temporarily deployed to test-trigger-is November 3, 2025 10:32 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 3, 2025 11:06 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 3, 2025 11:13 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 3, 2025 11:48 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 3, 2025 12:04 — with GitHub Actions Inactive
@denik denik force-pushed the denik/deployment-migrate branch from 6317768 to 3e06c6a Compare November 3, 2025 13:15
@denik denik temporarily deployed to test-trigger-is November 3, 2025 13:15 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 3, 2025 16:51 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 3, 2025 20:44 — with GitHub Actions Inactive
@denik denik force-pushed the denik/deployment-migrate branch from f5457b4 to cb1ecd3 Compare November 3, 2025 20:45
@denik denik temporarily deployed to test-trigger-is November 3, 2025 20:45 — with GitHub Actions Inactive
@denik denik force-pushed the denik/deployment-migrate branch from cb1ecd3 to 8926051 Compare November 4, 2025 08:46
@denik denik temporarily deployed to test-trigger-is November 4, 2025 08:46 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 4, 2025 09:11 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 4, 2025 09:55 — with GitHub Actions Inactive
@denik denik force-pushed the denik/deployment-migrate branch from 3e44d15 to e457ff8 Compare November 4, 2025 09:56
@denik denik temporarily deployed to test-trigger-is November 4, 2025 09:56 — with GitHub Actions Inactive
@denik denik force-pushed the denik/deployment-migrate branch from e457ff8 to d84d6c1 Compare November 4, 2025 11:53
@denik denik temporarily deployed to test-trigger-is November 4, 2025 11:53 — with GitHub Actions Inactive
Copy link
Contributor

@pietern pietern left a comment

Choose a reason for hiding this comment

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

Nice! Less code than I had thought.


if at == deployplan.ActionTypeDelete {
if migrateMode {
logdiag.LogError(ctx, fmt.Errorf("%s: Unexpected delete action during migration", errorPrefix))
Copy link
Contributor

Choose a reason for hiding this comment

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

This error should be more actionable; e.g. revert to previous configuration, or run a non-migration deploy first to achieve a clean slate, etc.

logdiag.LogError(ctx, fmt.Errorf("state entry not found for %q", resourceKey))
return false
}
err = b.StateDB.SaveState(resourceKey, dbentry.ID, entry.NewState.Config)
Copy link
Contributor

Choose a reason for hiding this comment

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

But doesn't this open up the probability for drift, given that we go off of the local config to determine if we deploy or not. If the previous deploy was done with TF, now we changed 1 field in some config, ran deploy, we may persist a config snapshot that we never materialized.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's why migration needs to happen after clean deploy with terraform.


if targetEngine.IsDirect() {
b.DeploymentBundle.Apply(ctx, b.WorkspaceClient(), &b.Config, plan)
b.DeploymentBundle.Apply(ctx, b.WorkspaceClient(), &b.Config, plan, direct.MigrateMode(false))
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice hybrid between bools and enums, without the need for unnecessary consts.

Copy link
Contributor

Choose a reason for hiding this comment

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

Only downside is that it shows up at every callsite.

Potential opportunity is to make .Migrate a dedicated function. Not blocking.


>>> [CLI] bundle deployment migrate
Migrated 3 resources to direct engine state file: [TEST_TMP_DIR]/.databricks/bundle/default/resources.json
To finalize deployment, run "bundle deploy".
Copy link
Contributor

Choose a reason for hiding this comment

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

We can suggest running "bundle plan" as well, to surface differences/updates.

"s3://deco-uc-prod-isolated-aws-us-east-1/metastore/[UUID]/volumes/[UUID]"

>>> DATABRICKS_BUNDLE_ENGINE=terraform musterr [CLI] bundle plan
Error: Required engine "terraform" does not match present state files. Set required engine via "DATABRICKS_BUNDLE_ENGINE" env var.
Copy link
Contributor

Choose a reason for hiding this comment

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

... or leave it empty to infer the right engine.

if stateDesc.Lineage == "" {
cmdio.LogString(ctx, `This command migrates existing terraform state file (terraform.tfstate) to direct deployment engine state file (resources.json). However, no existing local or remote state found.
To start using direct engine, deploy with DATABRICKS_BUNDLE_ENGINE=direct env var or bundle.engine="direct" in databricks.yml.`)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
To start using direct engine, deploy with DATABRICKS_BUNDLE_ENGINE=direct env var or bundle.engine="direct" in databricks.yml.`)
To start using the direct deployment engine, deploy with the environment variable DATABRICKS_BUNDLE_ENGINE=direct or bundle.engine="direct" in databricks.yml.`)

@denik denik temporarily deployed to test-trigger-is November 5, 2025 11:47 — with GitHub Actions Inactive
@denik denik force-pushed the denik/deployment-migrate branch from 5f6fb14 to 3b9e0f9 Compare November 5, 2025 12:02
@denik denik temporarily deployed to test-trigger-is November 5, 2025 12:02 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 5, 2025 12:05 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 5, 2025 12:11 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 5, 2025 13:31 — with GitHub Actions Inactive
@denik denik temporarily deployed to test-trigger-is November 5, 2025 13:32 — with GitHub Actions Inactive
@denik denik requested a review from pietern November 5, 2025 15:19
if at == deployplan.ActionTypeDelete {
if migrateMode {
logdiag.LogError(ctx, fmt.Errorf("%s: Unexpected delete action during migration", errorPrefix))
return true
Copy link
Contributor

Choose a reason for hiding this comment

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

Should it be false instead, so we abort the migration?


// TODO: redo calcDiff to downgrade planned action if possible (?)
if migrateMode {
// In migration mode we're going through deploy so that we have fully resolved config snapshots stored
Copy link
Contributor

Choose a reason for hiding this comment

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

Either one of the comments is confusing, or I am misunderstanding something, but we don't seem to execute the deploy in this branch, only in the others.

_, localPath := b.StateFilenameDirect(ctx)
tempStatePath := localPath + ".temp-migration"
if _, err = os.Stat(tempStatePath); err == nil {
return fmt.Errorf("temporary state file %s already exists, another migration is in progress or was interrupated. In the latter case, delete the file", tempStatePath)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return fmt.Errorf("temporary state file %s already exists, another migration is in progress or was interrupated. In the latter case, delete the file", tempStatePath)
return fmt.Errorf("temporary state file %s already exists, another migration is in progress or was interrupted. In the latter case, delete the file", tempStatePath)

@denik denik force-pushed the denik/env-var-strict branch from 3876283 to a39c803 Compare November 7, 2025 10:41
denik and others added 8 commits November 7, 2025 11:43
update

export DeployPrepare, make it explicit in plan commands

rewrite migration to do plan + dry run deploy

warning fix

lint & fix

Extend jobs to record full state

wip migrate command & test

Reject same serials in direct and terraform state file

update

fix warning/error in checkDashboardsModified remotely

add missing files

update

update

lint

update test

ident

update test

add 'debug states' command

add bad_env

Use EngineType; enforce env var engine matching state

lint fix

move to config/engin

update message

to slash

toslash for state files
@denik denik force-pushed the denik/deployment-migrate branch from d122238 to 59c6e02 Compare November 7, 2025 10:58
@denik denik temporarily deployed to test-trigger-is November 7, 2025 10:58 — with GitHub Actions Inactive
Base automatically changed from denik/env-var-strict to main November 7, 2025 14:53
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.

5 participants