diff --git a/cmd/start.go b/cmd/start.go index d9b55c74..97a46e03 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -290,6 +290,10 @@ func setConfigDefaults(conf *config.Config) { // handle macOS virtualization.framework transition if conf.VMType == "" { conf.VMType = defaultVMType + // if on macOS with no qemu, use vz + if err := util.AssertQemuImg(); err != nil && util.MacOS13OrNewer() { + conf.VMType = "vz" + } } if conf.MountType == "" { diff --git a/config/configmanager/configmanager.go b/config/configmanager/configmanager.go index 02edccbc..adc5c41f 100644 --- a/config/configmanager/configmanager.go +++ b/config/configmanager/configmanager.go @@ -71,6 +71,11 @@ func ValidateConfig(c config.Config) error { if _, ok := validVMTypes[c.VMType]; !ok { return fmt.Errorf("invalid vmType: '%s'", c.VMType) } + if c.VMType == "qemu" { + if err := util.AssertQemuImg(); err != nil { + return fmt.Errorf("cannot use vmType: '%s', error: %w", c.VMType, err) + } + } return nil } diff --git a/environment/vm/lima/lima.go b/environment/vm/lima/lima.go index ab982321..95900437 100644 --- a/environment/vm/lima/lima.go +++ b/environment/vm/lima/lima.go @@ -319,6 +319,11 @@ func (l *limaVM) syncDiskSize(ctx context.Context, conf config.Config) config.Co return false } + if err := util.AssertQemuImg(); err != nil { + log.Warnln(fmt.Errorf("unable to resize disk: %w", err)) + return false + } + sizeStr := fmt.Sprintf("%dG", conf.Disk) args := []string{"qemu-img", "resize"} disk := limautil.ColimaDiffDisk(config.CurrentProfile().ID) diff --git a/environment/vm/lima/limautil/image.go b/environment/vm/lima/limautil/image.go index 3c6dedb8..a877073f 100644 --- a/environment/vm/lima/limautil/image.go +++ b/environment/vm/lima/limautil/image.go @@ -12,6 +12,7 @@ import ( "github.com/abiosoft/colima/environment" "github.com/abiosoft/colima/environment/host" "github.com/abiosoft/colima/environment/vm/lima/limaconfig" + "github.com/abiosoft/colima/util" "github.com/abiosoft/colima/util/downloader" "github.com/sirupsen/logrus" ) @@ -32,7 +33,7 @@ func ImageCached(arch environment.Arch, runtime string) (limaconfig.File, bool) image := diskImageFile(downloader.CacheFilename(img.Location)) - img.Location = image.Raw() + img.Location = image.Location() img.Digest = "" return img, image.Generated() @@ -65,8 +66,18 @@ func DownloadImage(arch environment.Arch, runtime string) (f limaconfig.File, er if err != nil { return f, err } + + diskImage := diskImageFile(qcow2) + + // if qemu-img is missing, ignore raw conversion + if err := util.AssertQemuImg(); err != nil { + img.Location = diskImage.String() + img.Digest = "" // remove digest + return img, nil + } + // convert from qcow2 to raw - raw, err := qcow2ToRaw(host, diskImageFile(qcow2)) + raw, err := qcow2ToRaw(host, diskImage) if err != nil { return f, err } @@ -160,6 +171,14 @@ type diskImageFile string func (d diskImageFile) String() string { return strings.TrimSuffix(string(d), ".raw") } func (d diskImageFile) Raw() string { return d.String() + ".raw" } func (d diskImageFile) Generated() bool { - stat, err := os.Stat(d.Raw()) + stat, err := os.Stat(d.Location()) return err == nil && !stat.IsDir() } + +// Location returns the expected location of the image based on availability of qemu. +func (d diskImageFile) Location() string { + if err := util.AssertQemuImg(); err == nil { + return d.Raw() + } + return d.String() +} diff --git a/util/qemu.go b/util/qemu.go new file mode 100644 index 00000000..1669bc89 --- /dev/null +++ b/util/qemu.go @@ -0,0 +1,16 @@ +package util + +import ( + "fmt" + "os/exec" +) + +// AssertQemuImg checks if qemu-img is available. +func AssertQemuImg() error { + cmd := "qemu-img" + if _, err := exec.LookPath(cmd); err != nil { + return fmt.Errorf("%s not found, run 'brew install %s' to install", cmd, "qemu") + } + + return nil +}