Skip to content

feat: add user-specified mounts to container machines#1837

Open
danielsyauqi wants to merge 3 commits into
apple:mainfrom
danielsyauqi:feat/machine-user-mounts
Open

feat: add user-specified mounts to container machines#1837
danielsyauqi wants to merge 3 commits into
apple:mainfrom
danielsyauqi:feat/machine-user-mounts

Conversation

@danielsyauqi

Copy link
Copy Markdown

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

Closes #1805.

container machine currently mounts only the user's home directory, configurable through --home-mount. There is no way to bind-mount additional arbitrary host directories into a machine, which the issue requests for parity with the container --volume workflow.

This change adds a repeatable --mount host:guest[:ro|rw] option to container machine create:

container machine create --mount /Volumes/Project:/Project --mount /tmp/data:/data:ro alpine:3.22

Summary of changes:

  • MachineConfig gains a self-contained Mount type (source, destination, readOnly) and a mounts field. Specifications are parsed and validated in with(_:mounts:): the host path must be an existing directory, the guest path must be absolute, the mode must be ro or rw (default rw), and duplicate destinations are rejected. Paths are resolved to absolute form at parse time.
  • The field is Codable with backward compatibility. Boot configurations written before this change decode to an empty list, and an empty list is omitted on encode. The field is intentionally skipped on the ConfigSnapshotDecoder path, because the system-wide [machine] TOML section cannot represent arrays of structs; mounts are a per-machine value carried in boot-config.json (JSON) only.
  • MachinesService.toContainerConfig appends each configured mount as a virtiofs share at boot, alongside the existing home mount.
  • container machine inspect surfaces the configured mounts.
  • Documentation updated in docs/command-reference.md and docs/container-machine.md.

Scope is limited to create time for this revision; mounts are fixed for the lifetime of a machine. Adding or removing mounts on an existing machine via container machine set is deferred, as the current key=value last-wins semantics do not fit a repeatable list.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

Ten unit tests were added to MachineConfigTests covering specification parsing (read-write, read-only, multiple mounts), validation failures (missing source, non-directory source, invalid mode, relative destination, malformed input, duplicate destinations), JSON round-tripping, and backward-compatible decoding of configurations without the field. The full unit suite (swift test --skip TestCLI, 573 tests) passes. The integration suite, which boots a virtual machine, has not been run in this environment and should be exercised on an Apple Silicon host before merge.


This change was implemented by Claude (Anthropic), at the request of and reviewed by @danielsyauqi.

danielsyauqi and others added 2 commits June 26, 2026 19:19
Adds a repeatable `--mount host:guest[:ro|rw]` flag to `container machine
create`, letting users bind-mount arbitrary host directories into a machine
the same way `--volume` works for containers. Closes apple#1805.

- MachineConfig gains a self-contained `Mount` type and `mounts` field,
  parsed/validated in `with(_:mounts:)` (source must be an existing dir,
  guest path absolute, mode ro/rw; duplicate destinations rejected).
- The field is Codable with back-compat: boot configs predating mounts
  decode to an empty list, and an empty list is omitted on encode. Mounts
  are skipped on the ConfigSnapshotDecoder path since the system-wide
  `[machine]` TOML config cannot represent arrays of structs.
- MachinesService appends each mount as a virtiofs share at boot.
- `container machine inspect` surfaces configured mounts.
- Docs + 10 new unit tests; full unit suite (573 tests) passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generic return value was unused at every call site, which fails the
project's -warnings-as-errors build (used by make, not by plain swift test).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@danielsyauqi

Copy link
Copy Markdown
Author

Local test verification

Run on Apple M5, macOS 26.5, Swift 6.3.2, debug build.

Unit tests (swift test --skip TestCLI, with -warnings-as-errors): all 573 pass. A follow-up commit adjusts a test helper to return Void, since its previously generic return value was unused at every call site and tripped the project's -warnings-as-errors build (make), though not plain swift test.

Integration tests, scoped to the machine suites via make APP_ROOT=test-data integration INTEGRATION_TEST_SUITES="TestCLIMachineCommand TestCLIMachineRuntime":

  • TestCLIMachineCommand: passed in full. This suite exercises the create and inspect surfaces touched by this change.
  • TestCLIMachineRuntime: 60 of 61 cases pass. The single failure is testCreateNameLongestValid(), which fails when booting a maximum-length-named machine with XPC timeout for request to ...machine-apiserver/bootMachine.

The failure is unrelated to this change. It was reproduced on an unmodified main checkout (this change fully reverted), where the same test fails with the identical XPC boot timeout. The affected code path is independent of mounts: a machine created without --mount carries an empty mount list, so the added logic is a no-op, and the persisted boot configuration is byte-identical to main. The timeout appears to be a pre-existing, name-length-related boot issue under debug builds.

This change and its verification were carried out by Claude (Anthropic) at the request of and under review by @danielsyauqi.

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.

[Request]: User-specified mounts in machines.

1 participant