Send X-Databricks-Workspace-Id on workspace-routed API calls#5368
Send X-Databricks-Workspace-Id on workspace-routed API calls#5368Divyansh-db wants to merge 4 commits into
Conversation
On unified Databricks hosts that serve multiple workspaces, the CLI sends a
routing header so the gateway can dispatch each request to the correct
workspace. The platform is consolidating workspace addressing onto a single
header name. Switch the header sent on workspace-scoped API calls from
X-Databricks-Org-Id to X-Databricks-Workspace-Id. The previous header
continues to be accepted by the platform, so older CLI versions keep working.
This change covers the hand-written paths in the CLI that issue workspace-
routed API calls without going through generated SDK service methods:
- databricks api {verb} (cmd/api/api.go)
- Files API filer (libs/filer/files_client.go)
- Workspace files filer (libs/filer/workspace_files_client.go)
- Telemetry uploads (libs/telemetry/logger.go)
The value continues to come from the workspace_id config field or
DATABRICKS_WORKSPACE_ID.
The CurrentWorkspaceID() helper in the SDK still reads X-Databricks-Org-Id
from the response on /api/2.0/preview/scim/v2/Me, so the response-side
references in libs/testserver/handlers.go and libs/testproxy/server.go
intentionally remain on the legacy header name.
Approval status: pending
|
|
Commit: c579a1c |
The cmd_exec_id placeholder regressed from [CMD-EXEC-ID] to [UUID] when the fixture was regenerated locally with jq 1.6. The test script uses jq '.headers."User-Agent".[0]' syntax that only works in jq 1.7+; on the older runtime that pipeline silently produced no replacement, leaving the raw UUID in place which then matched the generic UUID replacement. Re-regenerated with jq 1.7. CI was already running 1.7+ which is why the discrepancy only showed up against the wire output, not locally.
| func attempt(ctx context.Context, apiClient *client.DatabricksClient, protoLogs []string) (*ResponseBody, error) { | ||
| resp := &ResponseBody{} | ||
| err := apiClient.Do(ctx, http.MethodPost, "/telemetry-ext", orgIDHeaders(apiClient), nil, RequestBody{ | ||
| err := apiClient.Do(ctx, http.MethodPost, "/telemetry-ext", workspaceIDHeaders(apiClient), nil, RequestBody{ |
There was a problem hiding this comment.
There are a bunch of places where we call ApiClient.Do but don't set the headers like for example
Lines 64 to 78 in 6795f16
@simonfaltum any thoughts on it?
bundle/deploy/filer.go has its own stateFiler that fetches the bundle deployment state from /api/2.0/workspace-files/ using client.Do() directly (bypassing generated SDK service methods). Apply the same X-Databricks-Org-Id → X-Databricks-Workspace-Id swap here so bundle deploy/summary against unified hosts uses the new routing header consistently with the rest of the CLI. Method renamed orgIDHeaders → workspaceIDHeaders for consistency with the other filer helpers updated in this PR.
simonfaltum
left a comment
There was a problem hiding this comment.
Code review note:
The PR still misses some raw workspace API callers that bypass generated SDK methods and send no workspace routing header. The PR scope says it covers hand-written workspace-routed calls, but these remain uncovered:
bundle/generate/downloader.go:161cmd/pipelines/utils.go:185libs/databrickscfg/cfgpickers/warehouses.go:140libs/apps/prompt/listers.go:178libs/git/info.go:64
On unified hosts with WorkspaceID, those calls can still route incorrectly or fail. I would add a shared helper for the new X-Databricks-Workspace-Id request header and use it for these raw callers, or explicitly document why each one is out of scope. This matches the existing review comment from @andrewnester, with a few more examples.
Summary
On unified Databricks hosts that serve multiple workspaces, the CLI sends a routing header so the gateway can dispatch each request to the correct workspace. The platform is consolidating workspace addressing onto a single header name. This PR switches the header sent on workspace-scoped API calls from
X-Databricks-Org-IdtoX-Databricks-Workspace-Id. The previous header continues to be accepted by the platform, so older CLI versions keep working.The value continues to come from the
workspace_idconfig field orDATABRICKS_WORKSPACE_IDenvironment variable.Scope
Hand-written CLI paths that issue workspace-routed API calls without going through generated SDK service methods:
databricks api {verb}(cmd/api/api.go)libs/filer/files_client.go)libs/filer/workspace_files_client.go)libs/telemetry/logger.go)The matching change inside the SDK landed in databricks/databricks-sdk-go#1688 and will reach generated service methods on the next SDK bump.
Asymmetric migration
Only the request-side header flips. The SDK's
CurrentWorkspaceID()still readsX-Databricks-Org-Idfrom the response on/api/2.0/preview/scim/v2/Me, because the server continues to echo the legacy response header. The two CLI test fakes that support that flow stay on the legacy name intentionally:libs/testserver/handlers.go—/Memock response headerlibs/testproxy/server.go—includeResponseHeadersfor the proxyTest plan
go test ./cmd/api/... ./libs/filer/... ./libs/telemetry/...— greengo test ./acceptance -run 'TestAccept/cmd/api|TestAccept/telemetry/(failure|timeout|partial)'— green (acceptance fixtures regenerated via-update)./task lint-q— 0 issues;./task fmt— no changesgit grep -in 'X-Databricks-Org' -- ':!*.md' ':!*.sum' ':!bundle/'— only the two intentional response-side fakes plus a context comment incmd/api/api.go