Skip to content

Restore per-mount source-subpath on the UUID-keyed mount contract #11526

@rapsealk

Description

@rapsealk

Summary

The new UUID-keyed mount contract introduced in #11434 (and refined in #11520) carries no per-mount source-subpath. There is currently no way to express "mount the <X> subdirectory of vfolder <Y> at container path <Z>" through any session-creation API surface, even though the lower-level mount machinery still supports it.

#11520 acknowledges this deferral explicitly:

Subpath syntax (name/subdir) remains rejected — full subpath support requires a separate, larger change that plumbs vfsubpath through MountInfoEntry / VFolderMountRequest.

This issue is that follow-up.

Where the capability disappeared

  • src/ai/backend/manager/api/rest/session/handler.py:327-333 — rejects every mounts entry containing /.
  • src/ai/backend/common/types.py:655-684MountInfoEntry carries only vfolder_id, mount_destination, mount_perm. No source-subpath slot.
  • src/ai/backend/manager/registry.py:_mount_entries_from_creation_config — projects creation_config["mount_ids"] / mount_id_map / mount_options into MountInfoEntry tuples; no slot to populate even if the wire format gained one.
  • src/ai/backend/manager/repositories/scheduler/db_source/db_source.py:1572-1580 — reconstitutes VFolderMountRequest(ref=UUID(...)) from MountInfoEntry. The string-form ref (which prepare_vfolder_mounts knows how to split into name + subpath) is no longer reachable from this path.

Where the capability still exists, just unreachable

src/ai/backend/manager/models/vfolder/row.py:925-940 (prepare_vfolder_mounts) still handles name/subpath strings:

for req in mount_requests:
    key = req.ref
    if isinstance(key, uuid.UUID):
        requested_vfolder_ids.add(key)
        continue
    name, _, subpath = key.partition("/")
    requested_vfolder_subpaths[key] = os.path.normpath(subpath)

When ref is a UUID, the subpath is forced to "." (mount root). The infrastructure to mount a subpath is intact — only the API-level addressability was removed.

Impact

Any caller that previously mounted a subdirectory of an existing vfolder at a specific container destination has to either:

  1. Replace each subdir with its own dedicated vfolder (costly migration; changes the user-visible vfolder layout).
  2. Mount the whole parent vfolder and live with deeper container-visible paths than before.

Neither preserves backwards compatibility for callers that built on the previous behavior. The pattern was common — typical layouts include <parent>/.shared/, <parent>/.scratch/<task_id>/, <parent>/inputs/... mounted at distinct container paths. With #11434's contract there is no way to express these without rearchitecting the parent vfolder into N separate vfolders per workflow.

Proposed fix

Re-introduce a per-mount source subpath on the contract:

  1. Add source_subpath: str | None = None to MountInfoEntry (or equivalent name; carries the subdir relative to the vfolder root).
  2. Plumb it through _mount_entries_from_creation_config. Wire it via either:
    • A new mount_id_subpaths: Mapping[UUID-str, str] field on creation_config, or
    • A richer dict shape inside mount_id_map (e.g. {uuid: {"dst": "/x", "subpath": ".shared"}}).
      The first form is simpler and avoids reshaping an existing field.
  3. Pass source_subpath through to VFolderMountRequest (which already accepts str ref with a / and parses it). One option: when source_subpath is set, build the ref as f"{name}/{source_subpath}" against the resolved vfolder name. Another: extend VFolderMountRequest directly with a subpath: str | None field. The latter is cleaner since it removes the string-format ambiguity and makes the data path explicit.
  4. Soften the rejection at _resolve_legacy_name_mounts:327-333 so legacy <name>/<subpath> entries on the deprecated mounts field are accepted again, resolved to (uuid, subpath), and forwarded through the new field. (This is optional but lets pre-existing v1 callers continue working without rewrite.)

Acceptance criteria

  • MountInfoEntry (or its equivalent) has a source_subpath field; None means "mount the vfolder root" (current behavior).
  • POST /session/_/create with a UUID-keyed mount_ids plus a per-mount source_subpath results in a session where the container destination is bind-mounted to <vfolder>/<source_subpath> rather than the vfolder root.
  • The legacy mounts: ["<name>/<subpath>"] form on the same endpoint stops raising InvalidAPIParameters(400) and produces an equivalent mount.
  • prepare_vfolder_mounts is exercised end-to-end with a non-"." subpath via the modern UUID-keyed surface (existing tests cover the legacy string surface).
  • No change to MountPermission, mount destination defaulting, or storage-proxy vfsubpath semantics.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    comp:commonRelated to Common componentcomp:managerRelated to Manager componentflow:hotfixtype:bugReports about that are not working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions