Skip to content

filer: switch workspace upload from import-file to /workspace/import - #6149

Draft
Sankalp-Mittal wants to merge 9 commits into
mainfrom
sankalp-mittal/workspace-import-migration
Draft

filer: switch workspace upload from import-file to /workspace/import#6149
Sankalp-Mittal wants to merge 9 commits into
mainfrom
sankalp-mittal/workspace-import-migration

Conversation

@Sankalp-Mittal

@Sankalp-Mittal Sankalp-Mittal commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Changes

Replace POST /api/2.0/workspace-files/import-file/{path} with the multipart
variant of POST /api/2.0/workspace/import (via the SDK's Workspace.Upload
with format=AUTO) as the transport for all bundle file uploads. This is a
single call site: WorkspaceFilesClient.Write in libs/filer.

The error handling in Write is rewritten to branch on SDK sentinels
(errors.Is against ErrNotFound, ErrResourceAlreadyExists,
ErrAlreadyExists, ErrInvalidParameterValue, ErrPermissionDenied) instead
of raw HTTP status codes and message-substring matching. The overwrite/type-
mismatch collision is detected via the AIP-193 ErrorInfo reason
WORKSPACE_OBJECT_TYPE_MISMATCH, with a message-substring fallback for
workspaces where that detail (WP-6031) has not yet rolled out.

Why

  1. /workspace-files/import-file is deprecated.
  2. /workspace/import has a documented rate limit of 30 requests/sec per
    workspace (API rate limits), higher than the limit that applied to
    the previous endpoint, and is ~1.5–2× faster for a typical bundle deploy.
  3. Structured error details let us stop parsing error message strings to detect
    path collisions.

Why multipart

/workspace/import has two request forms. The JSON form sends content
base64-encoded in a content field capped at 10 MB, returning
MAX_NOTEBOOK_SIZE_EXCEEDED above it (see the content field description for
workspace.Import in .codegen/cli.json). The multipart form posts the bytes as
a file part and is bounded only by the workspace file size limit, so it accepts
the payload sizes import-file did.

Because format=AUTO lets the server classify each payload, the applicable
limit depends on the classification rather than on our request:

Content as classified by format=AUTO Limit Source
Regular workspace file 500 MB Workspace files — "Workspace file size is limited to 500MB"
Notebook, source format (.py/.sql/.scala/.r with a Databricks notebook source header) 10 MB Notebook limitations
Notebook, IPYNB format 100 MB Notebook limitations — "Import and export is supported for IPYNB notebooks up to 100 MB"

The notebook limits are enforced by the workspace for both /workspace/import
and /workspace-files/import-file, so migrating between the two does not change
the maximum uploadable notebook size.

Testserver

  • libs/testserver now decodes the multipart /workspace/import body and
    mirrors the real endpoint's format=AUTO notebook detection for
    .py/.sql/.scala/.r (header comment → NOTEBOOK, otherwise FILE), and
    returns the collision error shape the CLI branches on.
  • acceptance/internal/prepare_server.go records multipart bodies in a
    normalized, deterministic form (multipart_form with sorted fields; large or
    binary parts summarized) so recorded requests stay reviewable.
  • The fault-injection mechanism gains an optional bodyContains match
    (fault.py --body-contains SUBSTR). Because every upload now shares the
    /workspace/import method+path, a single file's upload can only be targeted
    by its multipart path field; the two migrate/destroy fault tests rely on
    this.

Tests

  • New acceptance test bundle/sync-upload-edge-cases covers the cases that
    differ between the two endpoints: a 12 MiB binary (over the 10 MB JSON cap), an empty
    file, notebooks in three languages, a header-less .py (stored as FILE), a
    .lvdash.json dashboard, and non-ASCII / spaced filenames. It asserts each
    upload's object type/language and that every upload sets format=AUTO.
  • Unit tests in libs/filer/workspace_files_client_test.go cover the success
    path (format/overwrite) and every error mapping (already-exists shapes,
    type-mismatch via ErrorInfo reason, 403, 500).
  • libs/testserver/fault_test.go covers the new bodyContains match.
  • Existing acceptance fixtures regenerated for the new request shape; the jq
    assertions in affected scripts re-aimed from .path to
    .body.multipart_form.path.

Notes

  • The type-mismatch fallback (message-substring) is load-bearing until WP-6031
    is confirmed rolled out everywhere, and can be removed afterward.
  • This PR does not change the sync concurrency limit.

This pull request and its description were written by Isaac.

Sankalp-Mittal and others added 3 commits August 3, 2026 14:02
Replace POST /api/2.0/workspace-files/import-file/{path} with the multipart
variant of POST /api/2.0/workspace/import (via the SDK's Workspace.Upload +
format=AUTO). The previous endpoint is deprecated; the new one has a higher
rate limit (30 vs 20 rps/workspace) and is ~1.5-2x faster for typical bundle
deployments.

Error handling is rewritten to branch on SDK sentinels (errors.Is against
ErrNotFound / ErrResourceAlreadyExists / ErrAlreadyExists /
ErrInvalidParameterValue / ErrPermissionDenied) and the AIP-193 ErrorInfo
reason WORKSPACE_OBJECT_TYPE_MISMATCH, with a message-substring fallback for
workspaces where WP-6031 has not rolled out.

The testserver now decodes the multipart /workspace/import body and mirrors the
real endpoint's format=AUTO notebook detection. A new bodyContains option on the
fault mechanism lets a test target a single file's upload, which is no longer
possible by URL since every upload shares the /workspace/import path.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 9a67c01

Run: 31011024432

Env ❌​FAIL 🟨​KNOWN 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🔄​ aws linux 7 3 4 302 1091 9:45
❌​ aws windows 2 1 3 4 308 1089 19:32
🔄​ azure linux 4 4 4 303 1091 12:25
🔄​ azure windows 4 3 4 306 1089 20:34
💚​ gcp linux 1 5 308 1091 8:13
💚​ gcp windows 1 5 310 1089 10:42
21 interesting tests: 11 flaky, 4 SKIP, 3 RECOVERED, 2 FAIL, 1 KNOWN
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
🟨​ TestAccept 🔄​f 🟨​K 💚​R 🔄​f 💚​R 💚​R
🔄​ TestAccept/bundle/deployment/bind/pipelines/recreate ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/deployment/bind/pipelines/recreate/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
❌​ TestAccept/bundle/resources/quality_monitors/change_assets_dir ✅​p ❌​F ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/resources/quality_monitors/change_assets_dir/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p
❌​ TestAccept/bundle/resources/quality_monitors/change_assets_dir/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ❌​F ✅​p 🔄​f ✅​p ✅​p
🔄​ TestAccept/bundle/resources/quality_monitors/change_table_name 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/resources/quality_monitors/change_table_name/DATABRICKS_BUNDLE_ENGINE=direct 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/resources/secret_scopes/delete_scope ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/resources/secret_scopes/delete_scope/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestFsCpFileToDirFileNotOverwritten/dbfs_to_uc-volumes 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestFsCpFileToDirFileNotOverwritten/uc-volumes_to_local 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestFilerWorkspaceNotebook 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestFilerWorkspaceNotebook/rNb.r 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
💚​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R
Top 13 slowest tests (at least 2 minutes):
duration env testname
7:02 gcp windows TestAccept
4:43 azure linux TestAccept/bundle/resources/quality_monitors/change_output_schema_name/DATABRICKS_BUNDLE_ENGINE=terraform
3:43 aws windows TestAccept/bundle/resources/quality_monitors/change_output_schema_name/DATABRICKS_BUNDLE_ENGINE=terraform
3:40 gcp linux TestAccept/bundle/resources/quality_monitors/change_table_name/DATABRICKS_BUNDLE_ENGINE=direct
3:17 gcp linux TestAccept
2:44 azure windows TestAccept/bundle/resources/quality_monitors/change_output_schema_name/DATABRICKS_BUNDLE_ENGINE=terraform
2:36 azure windows TestAccept/bundle/resources/quality_monitors/change_output_schema_name/DATABRICKS_BUNDLE_ENGINE=direct
2:24 gcp linux TestAccept/bundle/resources/quality_monitors/change_output_schema_name/DATABRICKS_BUNDLE_ENGINE=terraform
2:13 gcp windows TestAccept/bundle/resources/quality_monitors/change_assets_dir/DATABRICKS_BUNDLE_ENGINE=terraform
2:10 aws windows TestAccept/bundle/deployment/bind/pipelines/recreate/DATABRICKS_BUNDLE_ENGINE=terraform
2:09 gcp linux TestAccept/bundle/resources/quality_monitors/change_assets_dir/DATABRICKS_BUNDLE_ENGINE=terraform
2:06 gcp linux TestAccept/bundle/resources/secret_scopes/delete_scope/DATABRICKS_BUNDLE_ENGINE=terraform
2:01 azure windows TestAccept/bundle/resources/quality_monitors/change_assets_dir/DATABRICKS_BUNDLE_ENGINE=terraform

@Sankalp-Mittal
Sankalp-Mittal marked this pull request as ready for review August 4, 2026 08:22
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Approval status: pending

/acceptance/bundle/ - needs approval

77 files changed
Suggested: @denik
Also eligible: @pietern, @janniklasrose, @shreyas-goenka, @andrewnester, @anton-107, @lennartkats-db

/libs/filer/ - needs approval

Files: libs/filer/workspace_files_client.go, libs/filer/workspace_files_client_test.go
Suggested: @simonfaltum
Also eligible: @renaudhartert-db, @Divyansh-db, @hectorcast-db, @parthban-db, @tanmay-db, @tejaskochar-db, @mihaimitrea-db, @chrisst, @rauchy

General files (require maintainer)

9 files changed
Based on git history:

  • @denik -- recent work in libs/testserver/, .nextchanges/bundles/, libs/filer/

Any maintainer (@andrewnester, @anton-107, @denik, @pietern, @shreyas-goenka, @simonfaltum, @renaudhartert-db, @janniklasrose, @lennartkats-db) can approve all areas.
See OWNERS for ownership rules.

@Sankalp-Mittal
Sankalp-Mittal marked this pull request as draft August 4, 2026 11:10
Sankalp-Mittal and others added 5 commits August 4, 2026 13:10
The size limits in WorkspaceFilesClient.Write were described using internal
config flag names and figures measured by hand against one workspace, neither
of which a reader can verify. Replace them with the documented limits and link
the sources.

This corrects one figure: the notebook cap was described as a flat 10 MiB, but
IPYNB notebooks are documented at 100 MB. Only source-format notebooks are
capped at 10 MB, so the limit depends on how format=AUTO classifies the
payload.

Also restore the rate limit doc link to MaxRequestsInFlight, which the comment
carried when the constant was introduced in #81. The value is unchanged.

Add a comment above each test in workspace_files_client_test.go stating what it
covers.

Co-authored-by: Isaac
The local_code_source test filtered recorded uploads by URL path, which no
longer matches: /workspace/import carries the target filename in the multipart
body. Filter on the body instead, the same way auto-migrate-empty-tfstate does.

--del-field raw_body is dropped because the tarball is binary and the request
recorder already summarizes it as a size placeholder.

This test was added in #6110, after the upload migration branch was cut, so it
was not covered by the earlier fixture updates.

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.

2 participants