Skip to content

Commit 4648e1f

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 57eb3a6 commit 4648e1f

File tree

5 files changed

+107
-10
lines changed

5 files changed

+107
-10
lines changed

.github/workflows/test.yml

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

149149
integration:
150150
name: Integration tests
151+
# on macOS 12, the default vmType is QEMU
151152
runs-on: macos-12
152153
timeout-minutes: 120
153154
steps:
@@ -389,13 +390,14 @@ jobs:
389390

390391
vz:
391392
name: "vz"
393+
# on macOS 13, the default vmType is VZ
392394
runs-on: macos-13
393395
timeout-minutes: 120
394396
strategy:
395397
fail-fast: false
396398
matrix:
397399
template:
398-
- experimental/vz.yaml
400+
- default.yaml
399401
- fedora.yaml
400402
steps:
401403
- uses: actions/checkout@v4
@@ -422,6 +424,4 @@ jobs:
422424
- name: Uninstall qemu
423425
run: brew uninstall --ignore-dependencies --force qemu
424426
- name: Test
425-
env:
426-
LIMACTL_CREATE_ARGS: "--vm-type vz --mount-type virtiofs --rosetta --network vzNAT"
427427
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", "vz" (on macOS 13 and later), or "default".
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: 92 additions & 4 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"
@@ -13,6 +14,7 @@ import (
1314
"strings"
1415
"text/template"
1516

17+
"github.com/coreos/go-semver/semver"
1618
"github.com/docker/go-units"
1719
"github.com/pbnjay/memory"
1820
"github.com/sirupsen/logrus"
@@ -178,7 +180,7 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
178180
if o.VMType != nil {
179181
y.VMType = o.VMType
180182
}
181-
y.VMType = ptr.Of(ResolveVMType(y.VMType))
183+
y.VMType = ptr.Of(ResolveVMType(y, d, o, filePath))
182184
if y.OS == nil {
183185
y.OS = d.OS
184186
}
@@ -905,11 +907,97 @@ func NewVMType(driver string) VMType {
905907
}
906908
}
907909

908-
func ResolveVMType(s *string) VMType {
909-
if s == nil || *s == "" || *s == "default" {
910+
func isExistingInstanceDir(dir string) bool {
911+
// existence of "lima.yaml" does not signify existence of the instance,
912+
// because the file is created during the initialization of the instance.
913+
for _, f := range []string{
914+
filenames.HostAgentStdoutLog, filenames.HostAgentStderrLog,
915+
filenames.VzIdentifier, filenames.BaseDisk, filenames.DiffDisk, filenames.CIDataISO,
916+
} {
917+
file := filepath.Join(dir, f)
918+
if _, err := os.Lstat(file); !errors.Is(err, os.ErrNotExist) {
919+
return true
920+
}
921+
}
922+
return false
923+
}
924+
925+
func ResolveVMType(y, d, o *LimaYAML, filePath string) VMType {
926+
// Check if the VMType is explicitly specified
927+
for i, f := range []*LimaYAML{o, y, d} {
928+
if f.VMType != nil && *f.VMType != "" && *f.VMType != "default" {
929+
logrus.Debugf("ResolveVMType: resolved VMType %q (explicitly specified in []*LimaYAML{o,y,d}[%d])", *f.VMType, i)
930+
return NewVMType(*f.VMType)
931+
}
932+
}
933+
934+
// If this is an existing instance, guess the VMType from the contents of the instance directory.
935+
// Note that the instance directory may be created by a previous version of Lima.
936+
if dir, basename := filepath.Split(filePath); dir != "" && basename == filenames.LimaYAML && isExistingInstanceDir(dir) {
937+
vzIdentifier := filepath.Join(dir, filenames.VzIdentifier) // since Lima v0.14
938+
if _, err := os.Lstat(vzIdentifier); !errors.Is(err, os.ErrNotExist) {
939+
logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, with %q)", VZ, vzIdentifier)
940+
return VZ
941+
}
942+
logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, without %q)", QEMU, vzIdentifier)
943+
return QEMU
944+
}
945+
946+
// Resolve the best type, depending on GOOS
947+
switch runtime.GOOS {
948+
case "darwin":
949+
macOSProductVersion, err := osutil.ProductVersion()
950+
if err != nil {
951+
logrus.WithError(err).Warn("Failed to get macOS product version")
952+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for unknown version of macOS)", QEMU)
953+
return QEMU
954+
}
955+
// Virtualization.framework in macOS prior to 13.5 could not boot Linux kernel v6.2 on Intel
956+
// https://github.com/lima-vm/lima/issues/1577
957+
if macOSProductVersion.LessThan(*semver.New("13.5.0")) {
958+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS prior to 13.5)", QEMU)
959+
return QEMU
960+
}
961+
// Use QEMU if the config depends on QEMU
962+
for i, f := range []*LimaYAML{o, y, d} {
963+
if f.Arch != nil && !IsNativeArch(*f.Arch) {
964+
logrus.Debugf("ResolveVMType: resolved VMType %q (non-native arch=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Arch, i)
965+
return QEMU
966+
}
967+
if f.Firmware.LegacyBIOS != nil && *f.Firmware.LegacyBIOS {
968+
logrus.Debugf("ResolveVMType: resolved VMType %q (firmware.legacyBIOS is specified in []*LimaYAML{o,y,d}[%d])", QEMU, i)
969+
return QEMU
970+
}
971+
if f.MountType != nil && *f.MountType == NINEP {
972+
logrus.Debugf("ResolveVMType: resolved VMType %q (mountType=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, NINEP, i)
973+
return QEMU
974+
}
975+
if f.Audio.Device != nil {
976+
switch *f.Audio.Device {
977+
case "", "none", "default", "vz":
978+
// NOP
979+
default:
980+
logrus.Debugf("ResolveVMType: resolved VMType %q (audio.device=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Audio.Device, i)
981+
return QEMU
982+
}
983+
}
984+
if f.Video.Display != nil {
985+
switch *f.Video.Display {
986+
case "", "none", "default", "vz":
987+
// NOP
988+
default:
989+
logrus.Debugf("ResolveVMType: resolved VMType %q (video.display=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Video.Display, i)
990+
return QEMU
991+
}
992+
}
993+
}
994+
// Use VZ if the config is compatible with VZ
995+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS 13.5 and later)", VZ)
996+
return VZ
997+
default:
998+
logrus.Debugf("ResolveVMType: resolved VMType %q (default for GOOS=%q)", QEMU, runtime.GOOS)
910999
return QEMU
9111000
}
912-
return NewVMType(*s)
9131001
}
9141002

9151003
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,12 +14,16 @@ import (
1414
"github.com/lima-vm/lima/pkg/ptr"
1515
"github.com/lima-vm/lima/pkg/store/dirnames"
1616
"github.com/lima-vm/lima/pkg/store/filenames"
17+
"github.com/sirupsen/logrus"
1718
"gotest.tools/v3/assert"
1819
)
1920

2021
func TestFillDefault(t *testing.T) {
22+
logrus.SetLevel(logrus.DebugLevel)
2123
var d, y, o LimaYAML
2224

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

6064
// Builtin default values
6165
builtin := LimaYAML{
62-
VMType: ptr.Of("qemu"),
66+
VMType: &defaultVMType,
6367
OS: ptr.Of(LINUX),
6468
Arch: ptr.Of(arch),
6569
CPUType: defaultCPUType(),
@@ -189,6 +193,7 @@ func TestFillDefault(t *testing.T) {
189193
}
190194

191195
expect := builtin
196+
expect.VMType = ptr.Of(QEMU) // due to NINEP
192197
expect.HostResolver.Hosts = map[string]string{
193198
"MY.Host": "host.lima.internal",
194199
}
@@ -459,6 +464,7 @@ func TestFillDefault(t *testing.T) {
459464
// "TWO" does not exist in filledDefaults.Env, so is set from d.Env
460465
expect.Env["TWO"] = d.Env["TWO"]
461466

467+
t.Logf("d.vmType=%q, y.vmType=%q, expect.vmType=%q", *d.VMType, *y.VMType, *expect.VMType)
462468
FillDefault(&y, &d, &LimaYAML{}, filePath)
463469
assert.DeepEqual(t, &y, &expect, opts...)
464470

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. (e.g., legacyBIOS or 9p is enabled)
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)