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