Additional disks were always mounted at the hardcoded path
/mnt/lima-<name>, with no way to change that location or to attach a disk
without Lima mounting it. Issue #4065 asks for both: a custom mount point
and an attach-only mode so the guest can manage the disk itself (a
flexibility Colima can benefit from).
Add two optional, backwards-compatible fields to each additionalDisks
entry:
- mountPoint: absolute guest path to mount at (default /mnt/lima-<name>)
- mount: whether Lima auto-mounts the disk (default true; false attaches
the disk without mounting it)
A separate `mount` boolean is used rather than overloading an empty
mountPoint, per the discussion in #4065. nil for either field preserves
the current behavior. Values are passed to the guest via
LIMA_CIDATA_DISK_<i>_MOUNT / _MOUNTPOINT and honored by 05-lima-disks.sh
(non-swap disks only). mountPoint is validated to be an absolute guest
path (path.IsAbs, not the host-dependent filepath.IsAbs) and neither a
critical system path nor the reserved guest home directory.
Fixes#4065
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
`LimaVzDriver.Stop()` returned an error without stopping the VM when
`CanRequestStop()` reported false, and it never removed the driver PID file.
When launchd sends SIGTERM to the host agent of a LaunchDaemon instance, the
host agent exits with `vz: CanRequestStop is not supported` and leaves `vz.pid`
behind. Within the same boot this is harmless, because `ReadPIDFile` removes
the PID file of a dead process, but after a reboot the recorded PID may have
been reused by an unrelated process. The instance then shows up as `Broken`
with "vz driver is running but host agent is not", and launchd with
`KeepAlive` crash-loops `limactl start`.
Ask the guest to shut down over SSH whenever the request could not be made
through the Virtualization framework, not only for the macOS guests that ignore
`RequestStop()`. The VM is never stopped forcibly with `VirtualMachine.Stop()`:
that does not give the guest a chance to stop cleanly, and may corrupt the disk.
Always remove the PID file when the driver stops, as the qemu and krunkit
drivers already do.
Related to #5087
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
`ReadPIDFile` decides whether a PID file belongs to a running process by signaling
the PID. Within a single boot this is fine, because a PID file of a process that
has already exited gets removed. Across a reboot it is not: the recorded PID may
have been reused by an unrelated process, and Lima then reports the instance as
`Broken`, either with "driver is running but host agent is not", or by trying to
connect to a stale `ha.sock`. `limactl start` fails, and a LaunchDaemon with
`KeepAlive` crash-loops it.
Record the boot session ID of the host next to the PID files of an instance, and
ignore a PID file that was written during a different boot. The ID is read from
the `kern.bootsessionuuid` sysctl on macOS and from
`/proc/sys/kernel/random/boot_id` on Linux; on platforms without such an
identifier the behavior is unchanged, as it is for instances that were started by
an older version of Lima and have no marker.
The marker is shared by the PID files of the directory, so writing a PID file
during a new boot removes all of them before the marker is refreshed: refreshing
it must never make a PID file of a previous boot look current. Readers check the
boot before they read the PID, and leave the removal to the next writer, so that
a reader can never remove a PID file that another process is writing at that very
moment. The PID file itself is renamed into place.
When the boot session ID cannot be determined the PID file is not written at all,
because a marker left over from a previous boot would otherwise void a PID file
that is current. Only the platforms without support for a boot session ID fall
back to the previous behavior.
The PID of a stale PID file is never signaled, because it may belong to an
unrelated process.
`StartWithPaths` checked for `ha.pid` with `os.Stat`, which bypassed this logic;
it now uses `ReadPIDFile` as well.
Related to #5087
Related to #5075
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
Some distros publish CPU micro-architecture level variants of their
x86_64 cloud images (e.g. x86-64-v3, x86-64-v2) next to the regular one.
They still run as x86_64 in the guest, so they cannot be told apart by
arch alone.
Add an `archVariant` field on image entries, orthogonal to the existing
distro `variant` (server/minimal), plus a `--arch-variant` flag to select
it. Selection at start time filters by archVariant in parallel with
variant, so the base image stays the default and e.g. `--arch-variant v3`
picks the variant image. The arch field is left untouched (no x86_64v3).
Wire up:
- Ubuntu 26.04: amd64v3 image as archVariant v3.
- AlmaLinux 10: x86_64_v2 image as archVariant v2 (10 ships v3 by default
and v2 for older hardware).
Teach the ubuntu/almalinux update scripts to keep the vendor arch name
(amd64v3, x86_64_v2) for the stream-JSON/CHECKSUM lookup while emitting
arch: x86_64 for lima.
Relates to #5160
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
The external driver gRPC API had almost no documented contract: call
ordering, method semantics and idempotency were undocumented, so the proto
(which is what external driver authors actually see) did not describe the flow.
Add detailed doc comments to every RPC and message in driver.proto (which also
improve the godoc for the driver.Driver interface), document the driver.Info
and DriverFeatures structs carried in InfoResponse, and add a hand-written
"Driver lifecycle and call ordering" section in drivers.md that points at the
proto and godoc.
Fixes#4896
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
When the freshness HEAD check for a digest-less cached image fails,
getCached() must still copy the cached data to the local path instead
of just reporting StatusUsedCache without copying. This was broken in
v2.0.3/v2.1.4 and got fixed as a side effect of commit b13db25f, but
had no dedicated test coverage.
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
Add downloader.RemoveStaleTempFiles, which removes leftover "data.part" and
legacy "data.tmp.*" files from the cache while keeping the completed "data"
files. Each cache entry is locked before its partial files are removed, so a
download in progress is never disturbed.
"limactl prune --keep-referred" now calls it after pruning unreferred entries,
giving a non-nuclear way to reclaim space taken by interrupted downloads
(e.g. after Ctrl-C) without dropping valid cached images.
Refs #5171
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
`limactl sudoers` and the generated `networks.yaml` defaulted `group` to
`everyone`, which on macOS grants every account (including non-local /
directory accounts) permission to run `socket_vmnet` as `root:wheel` and to
access the vmnet socket. For the common single-user workstation this is
broader than necessary.
Change the default to `admin`. It is tighter than `everyone` (and `staff`),
and it matches the realistic audience: installing the sudoers file already
requires `sudo`, which on macOS is granted to admins by default, so `%admin`
covers exactly the users who can use this feature. A non-admin user must set
`group` to a group they belong to (e.g. `staff`).
Existing `networks.yaml` files are not rewritten, so current installations
keep their `everyone` value; the new default only applies to fresh setups.
Proper per-user scoping is deferred until `socket_vmnet` gains
`--socket-user=USER`.
Closes#5118
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
Add a dedicated config/plain.md page describing what plain mode disables,
what still works, and how to access the instance.
Document the per-OS behavior in the Linux, FreeBSD, and macOS guest pages,
and the underlying mechanics (boot scripts, LIMA_CIDATA_PLAIN, guest agent
injection) in dev/internals.
Cross-link the new page from the GitHub Actions example, the port
forwarding and mount pages, and the plain: comment in the default template.
Closes#5003
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
Replace `cat /etc/fstab.lima.tmp >/etc/fstab` with `cp` in
boot.Linux/05-lima-mounts.sh. Both truncate the existing /etc/fstab inode in
place, preserving its owner, mode and SELinux context, but `cp` states the
file-to-file copy intent directly and avoids the useless use of cat. (Only
`mv` would be wrong here, as it swaps in the temp file's inode and relabels
it.)
Also reword the util/unescape_fstab.sh header: it decodes the full set of
octal escapes the kernel emits in /proc/mounts (a superset of what
escape_fstab.sh produces), so it round-trips escape's output but is not its
exact two-sided inverse.
Follow-up to #5145.
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
A vz + virtiofs mount whose host path contains a space (e.g.
"/Volumes/External HD") was never mounted in the guest, and no error was
reported. cloud-init's cc_mounts writes each mount into /etc/fstab with a bare
"\t".join(fields) and does not octal-escape the mount point, so a space/tab in
the path makes an unparsable line that mount(8) silently skips via nofail.
cc_mounts already creates the directory from the unescaped value, so only the
fstab line needs repair.
Add two self-tested helpers under cidata.TEMPLATE.d/util/ (compare_version.sh
convention):
- escape_fstab.sh: octal-escapes the mount-point field of cloud-config virtiofs
entries; -F'\t' isolates the field and makes the pass idempotent.
- unescape_fstab.sh: the inverse decode, used by the SELinux remount in
05-lima-mounts.sh and (replacing an identical inline sed) by
04-persistent-data-volume.sh.
boot.Linux/05-lima-mounts.sh repairs the fstab via escape_fstab.sh, runs
mount -t virtiofs -a, and decodes via unescape_fstab.sh before the SELinux
remount. No Go/template changes; scoped to vz + virtiofs. Complements, but does
not depend on, the upstream cloud-init fix.
Fixes: lima-vm/lima#5136
Link: https://github.com/abiosoft/colima/issues/1471
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>
test-templates.sh boots a VM before invoking host tools such as nc,
socat, dig, curl, jq and timeout (directly and via
test-port-forwarding.pl). When one of them is missing, the script
failed only after a full create + boot cycle, wasting minutes on a
confusing late error.
Check the host commands required by the enabled checks up front, before
`limactl create`, and abort while listing every missing command. The
list is gated by the enabled checks, so a tool is only required when the
check that uses it runs. Add a reusable check_required_commands() helper
to common.inc.sh. Commands that are optional at runtime (rsync, w3m) are
intentionally not required.
Fixes#5038
Signed-off-by: Eugene Kalinin <e.v.kalinin@gmail.com>