Skip to content

Commit e1a34f8

Browse files
committed
Use VZ by default for new instances on macOS >= 13.5
VZ is now the default type for new instances >= 13.5, unless the config is incompatible with vz (e.g., `firmware.legacyBIOS=true`, `mountType=9p`). Existing instances will continue to use QEMU by default, unless `vz-identifier` is present in the instance directory. Run `limactl start` with `--debug` to see how the vmType is resolved. Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
1 parent 235bd49 commit e1a34f8

File tree

5 files changed

+105
-16
lines changed

5 files changed

+105
-16
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ jobs:
131131

132132
integration:
133133
name: Integration tests
134+
# on macOS 12, the default vmType is QEMU
134135
runs-on: macos-12
135136
timeout-minutes: 120
136137
steps:
@@ -400,13 +401,14 @@ jobs:
400401

401402
vz:
402403
name: "vz"
404+
# on macOS 13, the default vmType is VZ
403405
runs-on: macos-13
404406
timeout-minutes: 120
405407
strategy:
406408
fail-fast: false
407409
matrix:
408410
template:
409-
- experimental/vz.yaml
411+
- default.yaml
410412
- fedora.yaml
411413
steps:
412414
- uses: actions/checkout@v4
@@ -430,6 +432,4 @@ jobs:
430432
- name: Uninstall qemu
431433
run: brew uninstall --ignore-dependencies --force qemu
432434
- name: Test
433-
env:
434-
LIMACTL_CREATE_ARGS: "--vm-type vz --mount-type virtiofs --rosetta --network vzNAT"
435435
run: ./hack/test-templates.sh templates/${{ matrix.template }}

examples/default.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# VM type: "qemu" or "vz" (on macOS 13 and later).
99
# The vmType can be specified only on creating the instance.
1010
# The vmType of existing instances cannot be changed.
11-
# 🟢 Builtin default: "qemu"
11+
# 🟢 Builtin default: "vz" (on macOS 13.5 and later), "qemu" (on others)
1212
vmType: null
1313

1414
# OS: "Linux".

pkg/limayaml/defaults.go

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package limayaml
33
import (
44
"bytes"
55
"crypto/sha256"
6+
"errors"
67
"fmt"
78
"net"
89
"os"
@@ -11,6 +12,7 @@ import (
1112
"strconv"
1213
"text/template"
1314

15+
"github.com/coreos/go-semver/semver"
1416
"github.com/docker/go-units"
1517
"github.com/lima-vm/lima/pkg/networks"
1618
"github.com/pbnjay/memory"
@@ -127,13 +129,7 @@ func defaultGuestInstallPrefix() string {
127129
// - DNS are picked from the highest priority where DNS is not empty.
128130
// - CACertificates Files and Certs are uniquely appended in d, y, o order
129131
func FillDefault(y, d, o *LimaYAML, filePath string) {
130-
if y.VMType == nil {
131-
y.VMType = d.VMType
132-
}
133-
if o.VMType != nil {
134-
y.VMType = o.VMType
135-
}
136-
y.VMType = pointer.String(ResolveVMType(y.VMType))
132+
y.VMType = pointer.String(ResolveVMType(y, d, o, filePath))
137133
if y.OS == nil {
138134
y.OS = d.OS
139135
}
@@ -860,11 +856,95 @@ func NewVMType(driver string) VMType {
860856
}
861857
}
862858

863-
func ResolveVMType(s *string) VMType {
864-
if s == nil || *s == "" || *s == "default" {
859+
func isExistingInstanceDir(dir string) bool {
860+
// existence of "lima.yaml" does not signify existence of the instance,
861+
// because the file is created during the initialization of the instance.
862+
for _, f := range []string{filenames.HostAgentStdoutLog, filenames.HostAgentStderrLog,
863+
filenames.VzIdentifier, filenames.BaseDisk, filenames.DiffDisk, filenames.CIDataISO} {
864+
file := filepath.Join(dir, f)
865+
if _, err := os.Lstat(file); !errors.Is(err, os.ErrNotExist) {
866+
return true
867+
}
868+
}
869+
return false
870+
}
871+
872+
func ResolveVMType(y, d, o *LimaYAML, filePath string) VMType {
873+
// Check if the VMType is explicitly specified
874+
for i, f := range []*LimaYAML{o, y, d} {
875+
if f.VMType != nil && *f.VMType != "" && *f.VMType != "default" {
876+
logrus.Debugf("ResolveVMType: resolved VMType %q (explicitly specified in []*LimaYAML{o,y,d}[%d])", *f.VMType, i)
877+
return NewVMType(*f.VMType)
878+
}
879+
}
880+
881+
// If this is an existing instance, guess the VMType from the contents of the instance directory.
882+
// Note that the instance directory may be created by a previous version of Lima.
883+
if dir, basename := filepath.Split(filePath); dir != "" && basename == filenames.LimaYAML && isExistingInstanceDir(dir) {
884+
vzIdentifier := filepath.Join(dir, filenames.VzIdentifier)
885+
if _, err := os.Lstat(vzIdentifier); !errors.Is(err, os.ErrNotExist) {
886+
logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, with %q)", VZ, vzIdentifier)
887+
return VZ
888+
}
889+
logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, without %q)", QEMU, vzIdentifier)
890+
return QEMU
891+
}
892+
893+
// Resolve the best type, depending on GOOS
894+
switch runtime.GOOS {
895+
case "darwin":
896+
macOSProductVersion, err := osutil.MacOSProductVersion()
897+
if err != nil {
898+
logrus.WithError(err).Warn("Failed to get macOS product version")
899+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for unknown version of macOS)", QEMU)
900+
return QEMU
901+
}
902+
// Virtualization.framework in macOS prior to 13.5 could not boot Linux kernel v6.2 on Intel
903+
// https://github.com/lima-vm/lima/issues/1577
904+
if macOSProductVersion.LessThan(*semver.New("13.5.0")) {
905+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS prior to 13.5)", QEMU)
906+
return QEMU
907+
}
908+
// Use QEMU if the config depends on QEMU
909+
for i, f := range []*LimaYAML{o, y, d} {
910+
if f.Arch != nil && !IsNativeArch(*f.Arch) {
911+
logrus.Debugf("ResolveVMType: resolved VMType %q (non-native arch=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Arch, i)
912+
return QEMU
913+
}
914+
if f.Firmware.LegacyBIOS != nil && *f.Firmware.LegacyBIOS {
915+
logrus.Debugf("ResolveVMType: resolved VMType %q (firmware.legacyBIOS is specified in []*LimaYAML{o,y,d}[%d])", QEMU, i)
916+
return QEMU
917+
}
918+
if f.MountType != nil && *f.MountType == NINEP {
919+
logrus.Debugf("ResolveVMType: resolved VMType %q (mountType=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, NINEP, i)
920+
return QEMU
921+
}
922+
if f.Audio.Device != nil {
923+
switch *f.Audio.Device {
924+
case "", "none", "default", "vz":
925+
// NOP
926+
default:
927+
logrus.Debugf("ResolveVMType: resolved VMType %q (audio.device=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Audio.Device, i)
928+
return QEMU
929+
}
930+
}
931+
if f.Video.Display != nil {
932+
switch *f.Video.Display {
933+
case "", "none", "default", "vz":
934+
// NOP
935+
default:
936+
logrus.Debugf("ResolveVMType: resolved VMType %q (video.display=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Video.Display, i)
937+
return QEMU
938+
}
939+
}
940+
}
941+
// Use VZ if the config is compatible with VZ
942+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS 13.5 and later)", VZ)
943+
return VZ
944+
default:
945+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for GOOS=%q)", QEMU, runtime.GOOS)
865946
return QEMU
866947
}
867-
return NewVMType(*s)
868948
}
869949

870950
func ResolveOS(s *string) OS {

pkg/limayaml/defaults_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ import (
1414
"github.com/lima-vm/lima/pkg/osutil"
1515
"github.com/lima-vm/lima/pkg/store/dirnames"
1616
"github.com/lima-vm/lima/pkg/store/filenames"
17+
"github.com/sirupsen/logrus"
1718
"github.com/xorcare/pointer"
1819
"gotest.tools/v3/assert"
1920
)
2021

2122
func TestFillDefault(t *testing.T) {
23+
logrus.SetLevel(logrus.DebugLevel)
2224
var d, y, o LimaYAML
2325

26+
defaultVMType := ResolveVMType(&y, &d, &o, "")
27+
2428
opts := []cmp.Option{
2529
// Consider nil slices and empty slices to be identical
2630
cmpopts.EquateEmpty(),
@@ -60,7 +64,7 @@ func TestFillDefault(t *testing.T) {
6064

6165
// Builtin default values
6266
builtin := LimaYAML{
63-
VMType: pointer.String("qemu"),
67+
VMType: &defaultVMType,
6468
OS: pointer.String(LINUX),
6569
Arch: pointer.String(arch),
6670
CPUType: map[Arch]string{
@@ -184,6 +188,7 @@ func TestFillDefault(t *testing.T) {
184188
}
185189

186190
expect := builtin
191+
expect.VMType = pointer.String(QEMU) // due to NINEP
187192
expect.HostResolver.Hosts = map[string]string{
188193
"MY.Host": "host.lima.internal",
189194
}
@@ -439,6 +444,7 @@ func TestFillDefault(t *testing.T) {
439444
// "TWO" does not exist in filledDefaults.Env, so is set from d.Env
440445
expect.Env["TWO"] = d.Env["TWO"]
441446

447+
t.Logf("d.vmType=%q, y.vmType=%q, expect.vmType=%q", *d.VMType, *y.VMType, *expect.VMType)
442448
FillDefault(&y, &d, &LimaYAML{}, filePath)
443449
assert.DeepEqual(t, &y, &expect, opts...)
444450

website/content/en/docs/Config/VMType/_index.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ flowchart
2222
intel_on_arm -- "No" --> vz["VZ"]
2323
```
2424

25+
The default vmType is QEMU in Lima prior to v1.0.
26+
Starting with Lima v1.0, Lima will use VZ by default on macOS (>= 13.5) for new instances,
27+
unless the config is incompatible with VZ.
28+
2529
## QEMU
2630
"qemu" option makes use of QEMU to run guest operating system.
27-
This option is used by default if "vmType" is not set.
2831

2932
## VZ
3033
> **Warning**

0 commit comments

Comments
 (0)