Skip to content

ssh: create the release folder before uploading the tunnel binaries - #7141

Draft
abdelrahmanomar1515 wants to merge 3 commits into
mainfrom
ssh-workspace-import-releases
Draft

abdelrahmanomar1515 wants to merge 3 commits into
mainfrom
ssh-workspace-import-releases

Conversation

@abdelrahmanomar1515

@abdelrahmanomar1515 abdelrahmanomar1515 commented Oct 21, 2026 •

Copy link
Copy Markdown

Changes

ssh connect now creates each release folder (<version>/databricks_cli_<version>_linux_<arch>/) with mkdirs before uploading the archive to import-file. mkdirs succeeds when the folder already exists. CreateParentDirectories stays as the fallback if the upload still gets a 404.

Why

import-file reports a missing parent folder with a 404 only after the whole archive has been sent. On the first upload of every new version, the filer then created the folder and sent the archive again. Every archive (~17 MB) was therefore uploaded twice, and half of the import-file calls showed up as failures.

The upload stays on import-file. Moving it to /workspace/import was considered, but format=AUTO imports a zip as a new folder that can't be overwritten. Overwriting is needed for dev builds and for concurrent connects. It also places an archive with a single top-level file next to that folder instead of inside it.

Tests

  • ssh/connect-serverless-feature-disabled now records the import-file requests: one per architecture. Without the change it records four.
  • New TestUploadReleasesSendsEachArchiveOnce: a fresh release upload, and a dev re-upload into existing folders, both send one import-file request per architecture. Without the change the fresh upload records the reported pattern: amd64 404, amd64 200, arm64 404, arm64 200.
  • Against a real AWS workspace with the v1.21.0 release archives: the old upload made import-file 404 → mkdirs 200 → import-file 200. The new one makes mkdirs 200 → import-file 200 per architecture, with the same extracted layout.
  • ./task lint-go and the ssh unit tests pass locally.

This pull request and its description were written by Isaac.

@abdelrahmanomar1515
abdelrahmanomar1515 requested review from a team as code owners October 21, 2026 10:15
@abdelrahmanomar1515
abdelrahmanomar1515 marked this pull request as draft October 21, 2026 10:40
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 689064c

Run: 39638424137

Env 🔄​flaky ✅​pass 🙈​skip Time
✅​ aws linux-2core-8gb 281 16 4:24
✅​ aws-windows-latest-4core-16gb 283 14 5:14
✅​ azure linux-2core-8gb 280 16 3:50
✅​ azure-windows-latest-4core-16gb 282 14 5:52
✅​ gcp linux-2core-8gb 281 16 4:17
🔄​ gcp-windows-latest-4core-16gb 1 282 14 3:37
Test Name gcp-windows-latest-4core-16gb
🔄​ TestSyncIncrementalFileOverwritesFolder 🔄​f
Top 3 slowest tests (at least 2 minutes):
duration env testname
5:48 azure-windows-latest-4core-16gb TestAccept
5:10 aws-windows-latest-4core-16gb TestAccept
3:12 gcp-windows-latest-4core-16gb TestAccept

import-file reports a missing parent folder with a 404 only after the
whole archive has been sent. On the first upload of every new version,
CreateParentDirectories then created the folder and sent the archive
again, so each ~17 MB archive was uploaded twice and half of the
import-file calls failed.

Create the release folder with mkdirs, which succeeds when it already
exists, and upload once.

Co-authored-by: Isaac <no-reply@databricks.com>
@abdelrahmanomar1515
abdelrahmanomar1515 force-pushed the ssh-workspace-import-releases branch from ddaef3c to 2c6d8d4 Compare October 21, 2026 15:08
@abdelrahmanomar1515 abdelrahmanomar1515 changed the title ssh: upload tunnel binaries via /workspace/import ssh: create the release folder before uploading the tunnel binaries Oct 21, 2026

// import-file reports a missing parent folder only after receiving the whole archive, so
// create the folder up front instead of letting CreateParentDirectories upload it twice.
err = workspaceFiler.Mkdir(ctx, remoteSubFolder)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

consider adding/modifying an existing acceptance test to record requests (that would show only a single /import-file call now instead of 2 before)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in b288cfb: ssh/connect-serverless-feature-disabled now prints the import-file requests, one per architecture. Without the mkdirs it records four, because each archive gets a 404 and is sent again.

- connect-serverless-feature-disabled now prints the import-file
  requests, showing one upload per architecture.
- Keep CreateParentDirectories as the fallback for a 404 after the
  folder was created, and drop the comment.
- The unit test reads status codes through the test server's
  ResponseCallback instead of copying the import-file handler.

Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Commit: 689064c89 | Workflow run

Regression test report

Selected 1 changed tests (limit=20, 0 not selected)

1 tests: regression=1 unreleased=0 coverage=0 failing=0

test branch main (bef6321) latest (v1.21.0)
TestAccept/ssh/connect-serverless-feature-disabled/DATABRICKS_BUNDLE_ENGINE=direct ✅ ❌ ❌
TestAccept/ssh/connect-serverless-feature-disabled/DATABRICKS_BUNDLE_ENGINE=direct: branch ✅ | main (bef6321) ❌ | latest (v1.21.0) ❌

main (bef6321):

acceptance_test.go:1307: Diff:
        --- ssh/connect-serverless-feature-disabled/output.txt
        +++ /tmp/TestAcceptsshconnect-serverless-feature-disabledDATABRICKS_BU1723650894/002/output.txt
        @@ -20,6 +20,13 @@
         }
         {
           "method": "POST",
        +  "path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.databricks/ssh-tunnel/[CLI_VERSION]/databricks_cli_linux_amd64/databricks.zip",
        +  "q": {
        +    "overwrite": "true"
        +  }
        +}
        +{
        +  "method": "POST",
           "path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.databricks/ssh-tunnel/[CLI_VERSION]/databricks_cli_linux_arm64/databricks.zip",
           "q": {
             "overwrite": "true"
        @@ -27,6 +34,13 @@
         }
         {
           "method": "POST",
        +  "path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.databricks/ssh-tunnel/[CLI_VERSION]/databricks_cli_linux_arm64/databricks.zip",
        +  "q": {
        +    "overwrite": "true"
        +  }
        +}
        +{
        +  "method": "POST",
           "path": "/api/2.2/jobs/runs/cancel",
           "body": {
             "run_id": [RUN_ID]
        
FAIL

latest (v1.21.0):

acceptance_test.go:2012: Incomplete entry in ACC_REPLS: "{\"Literal\": \"\", \"New\": \"[RUN_ID]\", \"Order\": -100}"
    acceptance_test.go:1307: Diff:
        --- ssh/connect-serverless-feature-disabled/output.txt
        +++ /tmp/TestAcceptsshconnect-serverless-feature-disabledDATABRICKS_BU1027551346/002/output.txt
        @@ -6,29 +6,8 @@
         === Reported error category
         
         >>> jq -r select(.path == "/telemetry-ext") | .body.protoLogs[] | fromjson | .entry.databricks_cli_log.ssh_tunnel_event.error_category [OUTPUT_DIR]/out.requests.txt
        -DRIVER_PROXY_FORBIDDEN
        +BINARY_UPLOAD_FAILED
         
         === Each release archive is uploaded once, and the submitted run is cancelled
         
         >>> print_requests.py //api/2.0/workspace-files/import-file //api/2.2/jobs/runs/cancel
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.databricks/ssh-tunnel/[CLI_VERSION]/databricks_cli_linux_amd64/databricks.zip",
        -  "q": {
        -    "overwrite": "true"
        -  }
        -}
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/workspace-files/import-file/Workspace/Users/[USERNAME]/.databricks/ssh-tunnel/[CLI_VERSION]/databricks_cli_linux_arm64/databricks.zip",
        -  "q": {
        -    "overwrite": "true"
        -  }
        -}
        -{
        -  "method": "POST",
        -  "path": "/api/2.2/jobs/runs/cancel",
        -  "body": {
        -    "run_id": [RUN_ID]
        -  }
        -}
        
    acceptance_test.go:1307: 
        	Error Trace:	/home/runner/work/cli/cli/libs/testdiff/testdiff.go:22
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1307
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1089
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:655
        	Error:      	Not equal: 
        	            	expected: "Connecting to feature-disabled...\nUploading binaries...\nStarting SSH server...\nJob submitted successfully with run ID: [RUN_ID]\nError: failed to ensure that ssh server is running: the workspace refused the SSH tunnel connection: FEATURE_DISABLED: An administrator has disabled port forwarding to serverless compute for this workspace, which includes the SSH tunnel used by `databricks ssh connect`\n"
        	            	actual  : "Connecting to feature-disabled...\nUploading binaries...\nError: failed to upload ssh-tunnel binaries: failed to get archive for architecture amd64: failed to open [TEST_TMP_DIR]/releases/databricks_cli_[CLI_VERSION]_linux_amd64.zip: open [TEST_TMP_DIR]/releases/databricks_cli_[CLI_VERSION]_linux_amd64.zip: no such file or directory\n"
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -2,5 +2,3 @@
        	            	 Uploading binaries...
        	            	-Starting SSH server...
        	            	-Job submitted successfully with run ID: [RUN_ID]
        	            	-Error: failed to ensure that ssh server is running: the workspace refused the SSH tunnel connection: FEATURE_DISABLED: An administrator has disabled port forwarding to serverless compute for this workspace, which includes the SSH tunnel used by `databricks ssh connect`
        	            	+Error: failed to upload ssh-tunnel binaries: failed to get archive for architecture amd64: failed to open [TEST_TMP_DIR]/releases/databricks_cli_[CLI_VERSION]_linux_amd64.zip: open [TEST_TMP_DIR]/releases/databricks_cli_[CLI_VERSION]_linux_amd64.zip: no such file or directory
        	            	 
        	Test:       	TestAccept/ssh/connect-serverless-feature-disabled/DATABRICKS_BUNDLE_ENGINE=direct
        	Messages:   	ssh/connect-serverless-feature-disabled/out.connect.txt vs /tmp/TestAcceptsshconnect-serverless-feature-disabledDATABRICKS_BU1027551346/001/out.connect.txt
FAIL

Run mkdirs before getting the release, so a failed mkdirs doesn't leave
a started GitHub download open. Cover a dev re-upload into existing
folders in the unit test, keeping each case's version in one place, and
mention the upload check in the RecordRequests comment of
connect-serverless-feature-disabled.

Co-authored-by: Isaac <no-reply@databricks.com>

This branch has not been deployed

No deployments
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