Skip to content

OneLake data plane

The onelake.dfs.fabric.microsoft.com surface: an ADLS-Gen2-shaped data plane over the same store as the control plane, accepting Storage-audience Entra tokens. Grounding: onelake-access-api.md and onelake-api-parity.md in the pinned fabric-docs commit (see 03-architecture.md, “Version grounding”).

An ADLS-Gen2 / Blob subset (DFS endpoint), Storage-audience token. The filesystem is the workspace (account name is always onelake), so listing happens at the workspace level:

  • PUT /{workspace}/{item}.{type}/{path}?resource=file|directory — create
  • PATCH …?action=append + ?action=flush — write
  • GET /{workspace}/{item}.{type}/{path} — read
  • GET /{workspace}?resource=filesystem&recursive=false[&directory={item}.{type}/Files] — list
  • DELETE …

Managed-folder rules (onelake-api-parity.md — core fidelity, not optional): ADLS/Blob APIs can never create, rename, or delete workspaces or items — only HEAD is allowed at the workspace (container) and tenant (account) level. An item’s top-level folder (/MyLakehouse.lakehouse) and its first level (/Files, /Tables) are Fabric-managed: protected from create/delete/rename; full CRUD only within them. Disallowed query parameters (e.g. action=setAccessControl) reject the request; disallowed headers (e.g. x-ms-owner) are ignored and echoed back in x-ms-rejected-headers. Permission response headers are canned: x-ms-owner/x-ms-group = $superuser, x-ms-permissions = ---------.

Enough for shortcut / trusted-workspace-access smoke tests. GUID and name-addressing both resolve to the same item.

Wire shapes are REST-reference-only (/rest/api/fabric/core/onelake-shortcuts; fabric-docs covers shortcut creation portal-side). A shortcut is a symlink in OneLake: a named entry inside an item’s managed folders whose reads resolve into another location. OneLake, ADLS Gen2, and Amazon S3 targets are supported; external reads use the referenced Connection’s write-only credentials. Dataverse remains unsupported and returns 501.

Method + pathNotes
POST /v1/workspaces/{wid}/items/{iid}/shortcutscreate → 201
GET /v1/workspaces/{wid}/items/{iid}/shortcutslist sync
GET /v1/workspaces/{wid}/items/{iid}/shortcuts/{path}/{name}get sync
DELETE /v1/workspaces/{wid}/items/{iid}/shortcuts/{path}/{name}delete (removes the link, never the target)

Create body (the OneLake target):

{
"path": "Files",
"name": "linked-data",
"target": { "oneLake": { "workspaceId": "", "itemId": "", "path": "Files/raw" } }
}
  • Read-only resolution: shortcuts resolve on reads only (GET/HEAD). On the DFS surface, /{ws}/{item}/Files/linked-data/… resolves through to the target item’s Files/raw/… when the direct path is absent. Resolution is authorized against the target workspace’s RBAC (the caller needs Contributor/ReadAll there — the trusted-workspace-access smoke path).
  • External resolution: ADLS Gen2 and Amazon S3 locations must be HTTP(S) URLs and name an existing Connection. Anonymous, Basic, Key, and SAS credentials are applied to read-through requests; failures surface as 502.
  • Not in listings: the DFS list handler enumerates only real stored paths, so shortcut entries do not appear in directory listings.
  • Writes don’t follow: PUT/PATCH/DELETE on a shortcut path write the source item, not the target — resolution is a read-side concern only.
  • API shape: the shortcut endpoints return { path, name, target } only — there is no isShortcut field.
  • Integrity: creating a shortcut to a missing item is rejected (400 TargetNotFound); deleting the target after creation leaves a dangling shortcut whose resolution 404s (matching real behavior); deleting the shortcut never touches target data. Self-referential cycles are rejected at create (400 InvalidTarget).
  • Storage: the shortcuts table stores either OneLake ids or external target type/location/connection metadata. No data is copied.

OneLake serves the same store over a Blob dialect (onelake.blob.fabric.microsoft.com) alongside DFS (onelake-api-parity.md). The Blob dialect is what Rust object_store — and therefore delta-rs — speaks, so this is the surface delta writers actually hit. Two addressings reach it:

  • Host onelake.blob.…/{workspace}/{blob…}
  • Any host (endpoint override, azurite-style) → /onelake/{workspace}/{blob…} — the /onelake account prefix is stripped by the router; the account name is always the literal onelake.

Same managed-folder rules as DFS: PUT/DELETE at the workspace, item root, or its first managed level are rejected (409); blobs live only within the managed first level.

OperationNotes
PUT …/{path}Put Blob (whole-blob write)
PUT …/{path}?comp=block&blockid=…Put Block — stage an uncommitted block (base64 id)
PUT …/{path}?comp=blocklistPut Block List — commit staged blocks in order (XML body)
PUT …/{path} + x-ms-copy-sourceCopy Blob
GET/HEAD …/{path}read (Range supported)
DELETE …/{path}delete
GET /{workspace}?comp=listList Blobs (XML) — prefix, delimiter, marker, maxresults, startFrom

Delta commit primitive. Put Blob with If-None-Match: * is a put-if-absent: it succeeds only if the blob does not yet exist, else 409 BlobAlreadyExists. This is exactly how Delta Lake commits a new _delta_log entry atomically — the conditional create is what makes concurrent writers race safely for a version number. delta-rs / object_store rely on it; the emulator honors it against the same store the DFS surface reads.

Listing offsets (startFrom). object_store implements list_with_offset on Azure with a startFrom parameter, and it is inclusive — the opposite of S3/GCP’s exclusive start-after, which object_store reconciles by dropping the first entry when it equals the offset. Half-open semantics here would therefore lose a blob, and ignoring the parameter is worse still: delta-rs’s get_latest_version() receives a log segment starting at version 0 when it asked for one starting at N, and the Delta kernel rejects it with Invalid table version: N. Plain writes keep working, so the breakage shows up only in the commit-conflict paths — OPTIMIZE, VACUUM, MERGE. TestBlobListStartFrom pins both the inclusivity and the precedence of marker over startFrom.