From cd844752bc25b9d9dd5813ace8c81df6032e5ea7 Mon Sep 17 00:00:00 2001 From: Abiola Ibrahim Date: Thu, 7 Nov 2024 14:18:19 +0100 Subject: [PATCH] core: make qemu an optional dependency Signed-off-by: Abiola Ibrahim --- cmd/start.go | 16 +++++++++++++--- config/configmanager/configmanager.go | 5 +++++ environment/vm/lima/lima.go | 5 +++++ environment/vm/lima/limautil/image.go | 25 ++++++++++++++++++++++--- util/qemu.go | 16 ++++++++++++++++ 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 util/qemu.go diff --git a/cmd/start.go b/cmd/start.go index d9b55c749..45230a8ad 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -113,13 +113,15 @@ const ( defaultDisk = 60 defaultKubernetesVersion = kubernetes.DefaultVersion - defaultVMType = "qemu" defaultMountTypeQEMU = "sshfs" defaultMountTypeVZ = "virtiofs" ) -var defaultK3sArgs = []string{"--disable=traefik"} -var envSaveConfig = osutil.EnvVar("COLIMA_SAVE_CONFIG") +var ( + defaultVMType = "qemu" + defaultK3sArgs = []string{"--disable=traefik"} + envSaveConfig = osutil.EnvVar("COLIMA_SAVE_CONFIG") +) var startCmdArgs struct { config.Config @@ -149,6 +151,10 @@ func init() { saveConfigDefault = envSaveConfig.Bool() } + if util.AssertQemuImg() != nil && util.MacOS13OrNewer() { + defaultVMType = "vz" + } + root.Cmd().AddCommand(startCmd) startCmd.Flags().StringVarP(&startCmdArgs.Runtime, "runtime", "r", docker.Name, "container runtime ("+runtimes+")") startCmd.Flags().BoolVar(&startCmdArgs.Flags.ActivateRuntime, "activate", true, "set as active Docker/Kubernetes context on startup") @@ -290,6 +296,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 02edccbc4..adc5c41f1 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 ab9823211..959004372 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 3c6dedb81..a877073f0 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 000000000..1669bc89c --- /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 +}