Skip to content

Commit

Permalink
Use VZ by default for new instances on macOS >= 13.5
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
AkihiroSuda committed Oct 26, 2023
1 parent 2c2c4d5 commit ed39486
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 15 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ jobs:

integration:
name: Integration tests
# on macOS 12, the default vmType is QEMU
runs-on: macos-12
timeout-minutes: 120
steps:
Expand Down Expand Up @@ -397,6 +398,7 @@ jobs:

vz:
name: "vz"
# on macOS 12, the default vmType is VZ
runs-on: macos-13
timeout-minutes: 120
steps:
Expand All @@ -411,12 +413,12 @@ jobs:
with:
path: ~/Library/Caches/lima/download
# hashFiles do not seem to support symlinks
key: ${{ runner.os }}-${{ hashFiles('examples/experimental/vz.yaml') }}
key: ${{ runner.os }}-${{ hashFiles('examples/default.yaml') }}
- name: Make
run: make
- name: Install
run: make install
- name: Install test dependencies
run: brew install qemu bash coreutils
- name: Test
run: ./hack/test-templates.sh templates/experimental/vz.yaml
run: ./hack/test-templates.sh templates/default.yaml
2 changes: 1 addition & 1 deletion examples/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# VM type: "qemu" or "vz" (on macOS 13 and later).
# The vmType can be specified only on creating the instance.
# The vmType of existing instances cannot be changed.
# 🟢 Builtin default: "qemu"
# 🟢 Builtin default: "vz" (on macOS 13.5 and later), "qemu" (on others)
vmType: null

# OS: "Linux".
Expand Down
100 changes: 90 additions & 10 deletions pkg/limayaml/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package limayaml
import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"net"
"os"
Expand All @@ -11,6 +12,7 @@ import (
"strconv"
"text/template"

"github.com/coreos/go-semver/semver"
"github.com/docker/go-units"
"github.com/lima-vm/lima/pkg/networks"
"github.com/pbnjay/memory"
Expand Down Expand Up @@ -127,13 +129,7 @@ func defaultGuestInstallPrefix() string {
// - DNS are picked from the highest priority where DNS is not empty.
// - CACertificates Files and Certs are uniquely appended in d, y, o order
func FillDefault(y, d, o *LimaYAML, filePath string) {
if y.VMType == nil {
y.VMType = d.VMType
}
if o.VMType != nil {
y.VMType = o.VMType
}
y.VMType = pointer.String(ResolveVMType(y.VMType))
y.VMType = pointer.String(ResolveVMType(y, d, o, filePath))
if y.OS == nil {
y.OS = d.OS
}
Expand Down Expand Up @@ -860,11 +856,95 @@ func NewVMType(driver string) VMType {
}
}

func ResolveVMType(s *string) VMType {
if s == nil || *s == "" || *s == "default" {
func isExistingInstanceDir(dir string) bool {
// existence of "lima.yaml" does not signify existence of the instance,
// because the file is created during the initialization of the instance.
for _, f := range []string{filenames.HostAgentStdoutLog, filenames.HostAgentStderrLog,
filenames.VzIdentifier, filenames.BaseDisk, filenames.DiffDisk, filenames.CIDataISO} {
file := filepath.Join(dir, f)
if _, err := os.Lstat(file); !errors.Is(err, os.ErrNotExist) {
return true
}
}
return false
}

func ResolveVMType(y, d, o *LimaYAML, filePath string) VMType {
// Check if the VMType is explicitly specified
for i, f := range []*LimaYAML{o, y, d} {
if f.VMType != nil && *f.VMType != "" && *f.VMType != "default" {
logrus.Debugf("ResolveVMType: resolved VMType %q (explicitly specified in []*LimaYAML{o,y,d}[%d])", *f.VMType, i)
return NewVMType(*f.VMType)
}
}

// If this is an existing instance, guess the VMType from the contents of the instance directory.
// Note that the instance directory may be created by a previous version of Lima.
if dir, basename := filepath.Split(filePath); dir != "" && basename == filenames.LimaYAML && isExistingInstanceDir(dir) {
vzIdentifier := filepath.Join(dir, filenames.VzIdentifier)
if _, err := os.Lstat(vzIdentifier); !errors.Is(err, os.ErrNotExist) {
logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, with %q)", VZ, vzIdentifier)
return VZ
}
logrus.Debugf("ResolveVMType: resolved VMType %q (existing instance, without %q)", QEMU, vzIdentifier)
return QEMU
}

// Resolve the best type, depending on GOOS
switch runtime.GOOS {
case "darwin":
macOSProductVersion, err := osutil.MacOSProductVersion()
if err != nil {
logrus.WithError(err).Warn("Failed to get macOS product version")
logrus.Debugf("ResolveVMType: resolved VMType %q (default for unknown version of macOS)", QEMU)
return QEMU
}
// Virtualization.framework in macOS prior to 13.5 could not boot Linux kernel v6.2 on Intel
// https://github.com/lima-vm/lima/issues/1577
if macOSProductVersion.LessThan(*semver.New("13.5.0")) {
logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS prior to 13.5)", QEMU)
return QEMU
}
// Use QEMU if the config depends on QEMU
for i, f := range []*LimaYAML{o, y, d} {
if f.Arch != nil && !IsNativeArch(*f.Arch) {
logrus.Debugf("ResolveVMType: resolved VMType %q (non-native arch=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Arch, i)
return QEMU
}
if f.Firmware.LegacyBIOS != nil && *f.Firmware.LegacyBIOS {
logrus.Debugf("ResolveVMType: resolved VMType %q (firmware.legacyBIOS is specified in []*LimaYAML{o,y,d}[%d])", QEMU, i)
return QEMU
}
if f.MountType != nil && *f.MountType == NINEP {
logrus.Debugf("ResolveVMType: resolved VMType %q (mountType=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, NINEP, i)
return QEMU
}
if f.Audio.Device != nil {
switch *f.Audio.Device {
case "", "none", "default", "vz":
// NOP
default:
logrus.Debugf("ResolveVMType: resolved VMType %q (audio.device=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Audio.Device, i)
return QEMU
}
}
if f.Video.Display != nil {
switch *f.Video.Display {
case "", "none", "default", "vz":
// NOP
default:
logrus.Debugf("ResolveVMType: resolved VMType %q (video.display=%q is specified in []*LimaYAML{o,y,d}[%d])", QEMU, *f.Video.Display, i)
return QEMU
}
}
}
// Use VZ if the config is compatible with VZ
logrus.Debugf("ResolveVMType: resolved VMType %q (default for macOS 13.5 and later)", VZ)
return VZ
default:
logrus.Debugf("ResolveVMType: resolved VMType %q (default for GOOS=%q)", QEMU, runtime.GOOS)
return QEMU
}
return NewVMType(*s)
}

func ResolveOS(s *string) OS {
Expand Down
8 changes: 7 additions & 1 deletion pkg/limayaml/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ import (
"github.com/lima-vm/lima/pkg/osutil"
"github.com/lima-vm/lima/pkg/store/dirnames"
"github.com/lima-vm/lima/pkg/store/filenames"
"github.com/sirupsen/logrus"
"github.com/xorcare/pointer"
"gotest.tools/v3/assert"
)

func TestFillDefault(t *testing.T) {
logrus.SetLevel(logrus.DebugLevel)
var d, y, o LimaYAML

defaultVMType := ResolveVMType(&y, &d, &o, "")

opts := []cmp.Option{
// Consider nil slices and empty slices to be identical
cmpopts.EquateEmpty(),
Expand Down Expand Up @@ -60,7 +64,7 @@ func TestFillDefault(t *testing.T) {

// Builtin default values
builtin := LimaYAML{
VMType: pointer.String("qemu"),
VMType: &defaultVMType,
OS: pointer.String(LINUX),
Arch: pointer.String(arch),
CPUType: map[Arch]string{
Expand Down Expand Up @@ -184,6 +188,7 @@ func TestFillDefault(t *testing.T) {
}

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

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

Expand Down
5 changes: 4 additions & 1 deletion website/content/en/docs/Config/VMType/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ flowchart
intel_on_arm -- "No" --> vz["VZ"]
```

The default vmType is QEMU in Lima prior to v1.0.
Starting with Lima v1.0, Lima will use VZ by default on macOS (>= 13.5) for new instances,
unless the config is incompatible with VZ.

## QEMU
"qemu" option makes use of QEMU to run guest operating system.
This option is used by default if "vmType" is not set.

## VZ
> **Warning**
Expand Down

0 comments on commit ed39486

Please sign in to comment.