diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go index 457265aedd7..082f847207b 100644 --- a/pkg/driver/driver.go +++ b/pkg/driver/driver.go @@ -5,16 +5,10 @@ package driver import ( "context" - "errors" "net" - - "github.com/lima-vm/lima/pkg/store" ) // Driver interface is used by hostagent for managing vm. -// -// This interface is extended by BaseDriver which provides default implementation. -// All other driver definition must extend BaseDriver. type Driver interface { // Validate returns error if the current driver isn't support for given config Validate() error @@ -71,84 +65,7 @@ type Driver interface { // GuestAgentConn returns the guest agent connection, or nil (if forwarded by ssh). GuestAgentConn(_ context.Context) (net.Conn, error) -} - -type BaseDriver struct { - Instance *store.Instance - - SSHLocalPort int - VSockPort int - VirtioPort string -} - -var _ Driver = (*BaseDriver)(nil) - -func (d *BaseDriver) Validate() error { - return nil -} - -func (d *BaseDriver) Initialize(_ context.Context) error { - return nil -} - -func (d *BaseDriver) CreateDisk(_ context.Context) error { - return nil -} - -func (d *BaseDriver) Start(_ context.Context) (chan error, error) { - return nil, nil -} - -func (d *BaseDriver) CanRunGUI() bool { - return false -} - -func (d *BaseDriver) RunGUI() error { - return nil -} - -func (d *BaseDriver) Stop(_ context.Context) error { - return nil -} - -func (d *BaseDriver) Register(_ context.Context) error { - return nil -} - -func (d *BaseDriver) Unregister(_ context.Context) error { - return nil -} - -func (d *BaseDriver) ChangeDisplayPassword(_ context.Context, _ string) error { - return nil -} - -func (d *BaseDriver) GetDisplayConnection(_ context.Context) (string, error) { - return "", nil -} - -func (d *BaseDriver) CreateSnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") -} - -func (d *BaseDriver) ApplySnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") -} - -func (d *BaseDriver) DeleteSnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") -} - -func (d *BaseDriver) ListSnapshots(_ context.Context) (string, error) { - return "", errors.New("unimplemented") -} - -func (d *BaseDriver) ForwardGuestAgent() bool { - // if driver is not providing, use host agent - return d.VSockPort == 0 && d.VirtioPort == "" -} -func (d *BaseDriver) GuestAgentConn(_ context.Context) (net.Conn, error) { - // use the unix socket forwarded by host agent - return nil, nil + VSockPort() int + VirtioPort() string } diff --git a/pkg/qemu/entitlementutil/entitlementutil.go b/pkg/driver/qemu/entitlementutil/entitlementutil.go similarity index 100% rename from pkg/qemu/entitlementutil/entitlementutil.go rename to pkg/driver/qemu/entitlementutil/entitlementutil.go diff --git a/pkg/qemu/qemu.go b/pkg/driver/qemu/qemu.go similarity index 96% rename from pkg/qemu/qemu.go rename to pkg/driver/qemu/qemu.go index 2fb08886ffc..b1986d4358e 100644 --- a/pkg/qemu/qemu.go +++ b/pkg/driver/qemu/qemu.go @@ -28,12 +28,12 @@ import ( "github.com/sirupsen/logrus" "github.com/lima-vm/lima/pkg/fileutils" - "github.com/lima-vm/lima/pkg/imgutil/qemuimgutil" "github.com/lima-vm/lima/pkg/iso9660util" "github.com/lima-vm/lima/pkg/limayaml" "github.com/lima-vm/lima/pkg/networks" "github.com/lima-vm/lima/pkg/networks/usernet" "github.com/lima-vm/lima/pkg/osutil" + "github.com/lima-vm/lima/pkg/qemuimgutil" "github.com/lima-vm/lima/pkg/store" "github.com/lima-vm/lima/pkg/store/filenames" ) @@ -85,7 +85,7 @@ func minimumQemuVersion() (hardMin, softMin semver.Version) { } // EnsureDisk also ensures the kernel and the initrd. -func EnsureDisk(ctx context.Context, cfg Config) error { +func EnsureDisk(_ context.Context, cfg Config) error { diffDisk := filepath.Join(cfg.InstanceDir, filenames.DiffDisk) if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) { // disk is already ensured @@ -93,42 +93,7 @@ func EnsureDisk(ctx context.Context, cfg Config) error { } baseDisk := filepath.Join(cfg.InstanceDir, filenames.BaseDisk) - kernel := filepath.Join(cfg.InstanceDir, filenames.Kernel) - kernelCmdline := filepath.Join(cfg.InstanceDir, filenames.KernelCmdline) - initrd := filepath.Join(cfg.InstanceDir, filenames.Initrd) - if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) { - var ensuredBaseDisk bool - errs := make([]error, len(cfg.LimaYAML.Images)) - for i, f := range cfg.LimaYAML.Images { - if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *cfg.LimaYAML.Arch); err != nil { - errs[i] = err - continue - } - if f.Kernel != nil { - if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, false, "the kernel", *cfg.LimaYAML.Arch); err != nil { - errs[i] = err - continue - } - if f.Kernel.Cmdline != "" { - if err := os.WriteFile(kernelCmdline, []byte(f.Kernel.Cmdline), 0o644); err != nil { - errs[i] = err - continue - } - } - } - if f.Initrd != nil { - if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, "the initrd", *cfg.LimaYAML.Arch); err != nil { - errs[i] = err - continue - } - } - ensuredBaseDisk = true - break - } - if !ensuredBaseDisk { - return fileutils.Errors(errs) - } - } + diskSize, _ := units.RAMInBytes(*cfg.LimaYAML.Disk) if diskSize == 0 { return nil diff --git a/pkg/qemu/qemu_driver.go b/pkg/driver/qemu/qemu_driver.go similarity index 91% rename from pkg/qemu/qemu_driver.go rename to pkg/driver/qemu/qemu_driver.go index e28b23429d5..084021b85f0 100644 --- a/pkg/qemu/qemu_driver.go +++ b/pkg/driver/qemu/qemu_driver.go @@ -27,33 +27,42 @@ import ( "github.com/sirupsen/logrus" "github.com/lima-vm/lima/pkg/driver" + "github.com/lima-vm/lima/pkg/driver/qemu/entitlementutil" "github.com/lima-vm/lima/pkg/executil" "github.com/lima-vm/lima/pkg/limayaml" "github.com/lima-vm/lima/pkg/networks/usernet" "github.com/lima-vm/lima/pkg/osutil" - "github.com/lima-vm/lima/pkg/qemu/entitlementutil" "github.com/lima-vm/lima/pkg/store" "github.com/lima-vm/lima/pkg/store/filenames" ) type LimaQemuDriver struct { - *driver.BaseDriver + Instance *store.Instance + SSHLocalPort int + vSockPort int + virtioPort string + qCmd *exec.Cmd qWaitCh chan error vhostCmds []*exec.Cmd } -func New(driver *driver.BaseDriver) *LimaQemuDriver { - driver.VSockPort = 0 - driver.VirtioPort = filenames.VirtioPort +var _ driver.Driver = (*LimaQemuDriver)(nil) + +func New(inst *store.Instance, sshLocalPort int) *LimaQemuDriver { // virtserialport doesn't seem to work reliably: https://github.com/lima-vm/lima/issues/2064 // but on Windows default Unix socket forwarding is not available + var virtioPort string + virtioPort = filenames.VirtioPort if runtime.GOOS != "windows" { - driver.VirtioPort = "" + virtioPort = "" } return &LimaQemuDriver{ - BaseDriver: driver, + Instance: inst, + vSockPort: 0, + virtioPort: virtioPort, + SSHLocalPort: sshLocalPort, } } @@ -94,7 +103,7 @@ func (l *LimaQemuDriver) Start(ctx context.Context) (chan error, error) { LimaYAML: l.Instance.Config, SSHLocalPort: l.SSHLocalPort, SSHAddress: l.Instance.SSHAddress, - VirtioGA: l.VirtioPort != "", + VirtioGA: l.virtioPort != "", } qExe, qArgs, err := Cmdline(ctx, qCfg) if err != nil { @@ -212,7 +221,7 @@ func (l *LimaQemuDriver) Start(ctx context.Context) (chan error, error) { go func() { if usernetIndex := limayaml.FirstUsernetIndex(l.Instance.Config); usernetIndex != -1 { client := usernet.NewClientByName(l.Instance.Config.Networks[usernetIndex].Lima) - err := client.ConfigureDriver(ctx, l.BaseDriver) + err := client.ConfigureDriver(ctx, l.Instance, l.SSHLocalPort) if err != nil { l.qWaitCh <- err } @@ -260,11 +269,11 @@ func (l *LimaQemuDriver) checkBinarySignature() error { } // The codesign --xml option is only available on macOS Monterey and later if !macOSProductVersion.LessThan(*semver.New("12.0.0")) { - qExe, _, err := Exe(l.BaseDriver.Instance.Arch) + qExe, _, err := Exe(l.Instance.Arch) if err != nil { - return fmt.Errorf("failed to find the QEMU binary for the architecture %q: %w", l.BaseDriver.Instance.Arch, err) + return fmt.Errorf("failed to find the QEMU binary for the architecture %q: %w", l.Instance.Arch, err) } - if accel := Accel(l.BaseDriver.Instance.Arch); accel == "hvf" { + if accel := Accel(l.Instance.Arch); accel == "hvf" { entitlementutil.AskToSignIfNotSignedProperly(qExe) } } @@ -498,3 +507,36 @@ func (a *qArgTemplateApplier) applyTemplate(qArg string) (string, error) { } return b.String(), nil } + +func (l *LimaQemuDriver) Initialize(_ context.Context) error { + return nil +} + +func (l *LimaQemuDriver) CanRunGUI() bool { + return false +} + +func (l *LimaQemuDriver) RunGUI() error { + return nil +} + +func (l *LimaQemuDriver) Register(_ context.Context) error { + return nil +} + +func (l *LimaQemuDriver) Unregister(_ context.Context) error { + return nil +} + +func (l *LimaQemuDriver) ForwardGuestAgent() bool { + // if driver is not providing, use host agent + return l.vSockPort == 0 && l.virtioPort == "" +} + +func (l *LimaQemuDriver) VSockPort() int { + return l.vSockPort +} + +func (l *LimaQemuDriver) VirtioPort() string { + return l.virtioPort +} diff --git a/pkg/qemu/qemu_test.go b/pkg/driver/qemu/qemu_test.go similarity index 100% rename from pkg/qemu/qemu_test.go rename to pkg/driver/qemu/qemu_test.go diff --git a/pkg/driver/vz/disk.go b/pkg/driver/vz/disk.go new file mode 100644 index 00000000000..f98cf2290c8 --- /dev/null +++ b/pkg/driver/vz/disk.go @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package vz + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + + "github.com/docker/go-units" + + "github.com/lima-vm/lima/pkg/imgutil/proxyimgutil" + "github.com/lima-vm/lima/pkg/iso9660util" + "github.com/lima-vm/lima/pkg/store" + "github.com/lima-vm/lima/pkg/store/filenames" +) + +func EnsureDisk(_ context.Context, inst *store.Instance) error { + diffDisk := filepath.Join(inst.Dir, filenames.DiffDisk) + if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) { + // disk is already ensured + return err + } + + diskUtil := proxyimgutil.NewDiskUtil() + + baseDisk := filepath.Join(inst.Dir, filenames.BaseDisk) + + diskSize, _ := units.RAMInBytes(*inst.Config.Disk) + if diskSize == 0 { + return nil + } + isBaseDiskISO, err := iso9660util.IsISO9660(baseDisk) + if err != nil { + return err + } + if isBaseDiskISO { + // Create an empty data volume (sparse) + diffDiskF, err := os.Create(diffDisk) + if err != nil { + return err + } + + err = diskUtil.MakeSparse(diffDiskF, 0) + if err != nil { + diffDiskF.Close() + return fmt.Errorf("failed to create sparse diff disk %q: %w", diffDisk, err) + } + return diffDiskF.Close() + } + if err = diskUtil.ConvertToRaw(baseDisk, diffDisk, &diskSize, false); err != nil { + return fmt.Errorf("failed to convert %q to a raw disk %q: %w", baseDisk, diffDisk, err) + } + return err +} diff --git a/pkg/vz/errors_darwin.go b/pkg/driver/vz/errors_darwin.go similarity index 100% rename from pkg/vz/errors_darwin.go rename to pkg/driver/vz/errors_darwin.go diff --git a/pkg/vz/network_darwin.go b/pkg/driver/vz/network_darwin.go similarity index 100% rename from pkg/vz/network_darwin.go rename to pkg/driver/vz/network_darwin.go diff --git a/pkg/vz/network_darwin_test.go b/pkg/driver/vz/network_darwin_test.go similarity index 100% rename from pkg/vz/network_darwin_test.go rename to pkg/driver/vz/network_darwin_test.go diff --git a/pkg/vz/rosetta_directory_share.go b/pkg/driver/vz/rosetta_directory_share.go similarity index 100% rename from pkg/vz/rosetta_directory_share.go rename to pkg/driver/vz/rosetta_directory_share.go diff --git a/pkg/vz/rosetta_directory_share_arm64.go b/pkg/driver/vz/rosetta_directory_share_arm64.go similarity index 100% rename from pkg/vz/rosetta_directory_share_arm64.go rename to pkg/driver/vz/rosetta_directory_share_arm64.go diff --git a/pkg/vz/vm_darwin.go b/pkg/driver/vz/vm_darwin.go similarity index 80% rename from pkg/vz/vm_darwin.go rename to pkg/driver/vz/vm_darwin.go index 9ea33a8642b..147af63fddb 100644 --- a/pkg/vz/vm_darwin.go +++ b/pkg/driver/vz/vm_darwin.go @@ -24,7 +24,6 @@ import ( "github.com/lima-vm/go-qcow2reader/image/raw" "github.com/sirupsen/logrus" - "github.com/lima-vm/lima/pkg/driver" "github.com/lima-vm/lima/pkg/imgutil/proxyimgutil" "github.com/lima-vm/lima/pkg/iso9660util" "github.com/lima-vm/lima/pkg/limayaml" @@ -51,13 +50,13 @@ type virtualMachineWrapper struct { // Hold all *os.File created via socketpair() so that they won't get garbage collected. f.FD() gets invalid if f gets garbage collected. var vmNetworkFiles = make([]*os.File, 1) -func startVM(ctx context.Context, driver *driver.BaseDriver) (*virtualMachineWrapper, chan error, error) { - usernetClient, err := startUsernet(ctx, driver) +func startVM(ctx context.Context, inst *store.Instance, sshLocalPort int) (*virtualMachineWrapper, chan error, error) { + usernetClient, err := startUsernet(ctx, inst) if err != nil { return nil, nil, err } - machine, err := createVM(driver) + machine, err := createVM(inst) if err != nil { return nil, nil, err } @@ -95,7 +94,7 @@ func startVM(ctx context.Context, driver *driver.BaseDriver) (*virtualMachineWra case newState := <-machine.StateChangedNotify(): switch newState { case vz.VirtualMachineStateRunning: - pidFile := filepath.Join(driver.Instance.Dir, filenames.PIDFile(*driver.Instance.Config.VMType)) + pidFile := filepath.Join(inst.Dir, filenames.PIDFile(*inst.Config.VMType)) if _, err := os.Stat(pidFile); !errors.Is(err, os.ErrNotExist) { logrus.Errorf("pidfile %q already exists", pidFile) errCh <- err @@ -107,7 +106,7 @@ func startVM(ctx context.Context, driver *driver.BaseDriver) (*virtualMachineWra filesToRemove[pidFile] = struct{}{} logrus.Info("[VZ] - vm state change: running") - err := usernetClient.ConfigureDriver(ctx, driver) + err := usernetClient.ConfigureDriver(ctx, inst, sshLocalPort) if err != nil { errCh <- err } @@ -116,7 +115,7 @@ func startVM(ctx context.Context, driver *driver.BaseDriver) (*virtualMachineWra wrapper.mu.Lock() wrapper.stopped = true wrapper.mu.Unlock() - _ = usernetClient.UnExposeSSH(driver.SSHLocalPort) + _ = usernetClient.UnExposeSSH(inst.SSHLocalPort) errCh <- errors.New("vz driver state stopped") default: logrus.Debugf("[VZ] - vm state change: %q", newState) @@ -128,17 +127,17 @@ func startVM(ctx context.Context, driver *driver.BaseDriver) (*virtualMachineWra return wrapper, errCh, err } -func startUsernet(ctx context.Context, driver *driver.BaseDriver) (*usernet.Client, error) { - if firstUsernetIndex := limayaml.FirstUsernetIndex(driver.Instance.Config); firstUsernetIndex != -1 { - nwName := driver.Instance.Config.Networks[firstUsernetIndex].Lima +func startUsernet(ctx context.Context, inst *store.Instance) (*usernet.Client, error) { + if firstUsernetIndex := limayaml.FirstUsernetIndex(inst.Config); firstUsernetIndex != -1 { + nwName := inst.Config.Networks[firstUsernetIndex].Lima return usernet.NewClientByName(nwName), nil } // Start a in-process gvisor-tap-vsock - endpointSock, err := usernet.SockWithDirectory(driver.Instance.Dir, "", usernet.EndpointSock) + endpointSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.EndpointSock) if err != nil { return nil, err } - vzSock, err := usernet.SockWithDirectory(driver.Instance.Dir, "", usernet.FDSock) + vzSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.FDSock) if err != nil { return nil, err } @@ -150,7 +149,7 @@ func startUsernet(ctx context.Context, driver *driver.BaseDriver) (*usernet.Clie FdSocket: vzSock, Async: true, DefaultLeases: map[string]string{ - networks.SlirpIPAddress: limayaml.MACAddress(driver.Instance.Dir), + networks.SlirpIPAddress: limayaml.MACAddress(inst.Dir), }, Subnet: networks.SlirpNetwork, }) @@ -161,41 +160,41 @@ func startUsernet(ctx context.Context, driver *driver.BaseDriver) (*usernet.Clie return usernet.NewClient(endpointSock, subnetIP), err } -func createVM(driver *driver.BaseDriver) (*vz.VirtualMachine, error) { - vmConfig, err := createInitialConfig(driver) +func createVM(inst *store.Instance) (*vz.VirtualMachine, error) { + vmConfig, err := createInitialConfig(inst) if err != nil { return nil, err } - if err = attachPlatformConfig(driver, vmConfig); err != nil { + if err = attachPlatformConfig(inst, vmConfig); err != nil { return nil, err } - if err = attachSerialPort(driver, vmConfig); err != nil { + if err = attachSerialPort(inst, vmConfig); err != nil { return nil, err } - if err = attachNetwork(driver, vmConfig); err != nil { + if err = attachNetwork(inst, vmConfig); err != nil { return nil, err } - if err = attachDisks(driver, vmConfig); err != nil { + if err = attachDisks(inst, vmConfig); err != nil { return nil, err } - if err = attachDisplay(driver, vmConfig); err != nil { + if err = attachDisplay(inst, vmConfig); err != nil { return nil, err } - if err = attachFolderMounts(driver, vmConfig); err != nil { + if err = attachFolderMounts(inst, vmConfig); err != nil { return nil, err } - if err = attachAudio(driver, vmConfig); err != nil { + if err = attachAudio(inst, vmConfig); err != nil { return nil, err } - if err = attachOtherDevices(driver, vmConfig); err != nil { + if err = attachOtherDevices(inst, vmConfig); err != nil { return nil, err } @@ -207,20 +206,20 @@ func createVM(driver *driver.BaseDriver) (*vz.VirtualMachine, error) { return vz.NewVirtualMachine(vmConfig) } -func createInitialConfig(driver *driver.BaseDriver) (*vz.VirtualMachineConfiguration, error) { - bootLoader, err := bootLoader(driver) +func createInitialConfig(inst *store.Instance) (*vz.VirtualMachineConfiguration, error) { + bootLoader, err := bootLoader(inst) if err != nil { return nil, err } - bytes, err := units.RAMInBytes(*driver.Instance.Config.Memory) + bytes, err := units.RAMInBytes(*inst.Config.Memory) if err != nil { return nil, err } vmConfig, err := vz.NewVirtualMachineConfiguration( bootLoader, - uint(*driver.Instance.Config.CPUs), + uint(*inst.Config.CPUs), uint64(bytes), ) if err != nil { @@ -229,8 +228,8 @@ func createInitialConfig(driver *driver.BaseDriver) (*vz.VirtualMachineConfigura return vmConfig, nil } -func attachPlatformConfig(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfiguration) error { - machineIdentifier, err := getMachineIdentifier(driver) +func attachPlatformConfig(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error { + machineIdentifier, err := getMachineIdentifier(inst) if err != nil { return err } @@ -241,7 +240,7 @@ func attachPlatformConfig(driver *driver.BaseDriver, vmConfig *vz.VirtualMachine } // nested virt - if *driver.Instance.Config.NestedVirtualization { + if *inst.Config.NestedVirtualization { macOSProductVersion, err := osutil.ProductVersion() if err != nil { return fmt.Errorf("failed to get macOS product version: %w", err) @@ -264,8 +263,8 @@ func attachPlatformConfig(driver *driver.BaseDriver, vmConfig *vz.VirtualMachine return nil } -func attachSerialPort(driver *driver.BaseDriver, config *vz.VirtualMachineConfiguration) error { - path := filepath.Join(driver.Instance.Dir, filenames.SerialVirtioLog) +func attachSerialPort(inst *store.Instance, config *vz.VirtualMachineConfiguration) error { + path := filepath.Join(inst.Dir, filenames.SerialVirtioLog) serialPortAttachment, err := vz.NewFileSerialPortAttachment(path, false) if err != nil { return err @@ -302,14 +301,14 @@ func newVirtioNetworkDeviceConfiguration(attachment vz.NetworkDeviceAttachment, return networkConfig, nil } -func attachNetwork(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfiguration) error { +func attachNetwork(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error { var configurations []*vz.VirtioNetworkDeviceConfiguration - // Configure default usernetwork with limayaml.MACAddress(driver.Instance.Dir) for eth0 interface - firstUsernetIndex := limayaml.FirstUsernetIndex(driver.Instance.Config) + // Configure default usernetwork with limayaml.MACAddress(inst.Dir) for eth0 interface + firstUsernetIndex := limayaml.FirstUsernetIndex(inst.Config) if firstUsernetIndex == -1 { // slirp network using gvisor netstack - vzSock, err := usernet.SockWithDirectory(driver.Instance.Dir, "", usernet.FDSock) + vzSock, err := usernet.SockWithDirectory(inst.Dir, "", usernet.FDSock) if err != nil { return err } @@ -317,13 +316,13 @@ func attachNetwork(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigu if err != nil { return err } - networkConfig, err := newVirtioFileNetworkDeviceConfiguration(networkConn, limayaml.MACAddress(driver.Instance.Dir)) + networkConfig, err := newVirtioFileNetworkDeviceConfiguration(networkConn, limayaml.MACAddress(inst.Dir)) if err != nil { return err } configurations = append(configurations, networkConfig) } else { - vzSock, err := usernet.Sock(driver.Instance.Config.Networks[firstUsernetIndex].Lima, usernet.FDSock) + vzSock, err := usernet.Sock(inst.Config.Networks[firstUsernetIndex].Lima, usernet.FDSock) if err != nil { return err } @@ -331,14 +330,14 @@ func attachNetwork(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigu if err != nil { return err } - networkConfig, err := newVirtioFileNetworkDeviceConfiguration(networkConn, limayaml.MACAddress(driver.Instance.Dir)) + networkConfig, err := newVirtioFileNetworkDeviceConfiguration(networkConn, limayaml.MACAddress(inst.Dir)) if err != nil { return err } configurations = append(configurations, networkConfig) } - for i, nw := range driver.Instance.Networks { + for i, nw := range inst.Networks { if nw.VZNAT != nil && *nw.VZNAT { attachment, err := vz.NewNATNetworkDeviceAttachment() if err != nil { @@ -434,10 +433,10 @@ func validateDiskFormat(diskPath string) error { return nil } -func attachDisks(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfiguration) error { - baseDiskPath := filepath.Join(driver.Instance.Dir, filenames.BaseDisk) - diffDiskPath := filepath.Join(driver.Instance.Dir, filenames.DiffDisk) - ciDataPath := filepath.Join(driver.Instance.Dir, filenames.CIDataISO) +func attachDisks(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error { + baseDiskPath := filepath.Join(inst.Dir, filenames.BaseDisk) + diffDiskPath := filepath.Join(inst.Dir, filenames.DiffDisk) + ciDataPath := filepath.Join(inst.Dir, filenames.CIDataISO) isBaseDiskCDROM, err := iso9660util.IsISO9660(baseDiskPath) if err != nil { return err @@ -473,7 +472,7 @@ func attachDisks(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigura diskUtil := proxyimgutil.NewDiskUtil() - for _, d := range driver.Instance.Config.AdditionalDisks { + for _, d := range inst.Config.AdditionalDisks { diskName := d.Name disk, err := store.InspectDisk(diskName) if err != nil { @@ -484,7 +483,7 @@ func attachDisks(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigura return fmt.Errorf("failed to run attach disk %q, in use by instance %q", diskName, disk.Instance) } logrus.Infof("Mounting disk %q on %q", diskName, disk.MountPoint) - err = disk.Lock(driver.Instance.Dir) + err = disk.Lock(inst.Dir) if err != nil { return fmt.Errorf("failed to run lock disk %q: %w", diskName, err) } @@ -523,8 +522,8 @@ func attachDisks(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigura return nil } -func attachDisplay(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfiguration) error { - switch *driver.Instance.Config.Video.Display { +func attachDisplay(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error { + switch *inst.Config.Video.Display { case "vz", "default": graphicsDeviceConfiguration, err := vz.NewVirtioGraphicsDeviceConfiguration() if err != nil { @@ -543,14 +542,14 @@ func attachDisplay(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigu case "none": return nil default: - return fmt.Errorf("unexpected video display %q", *driver.Instance.Config.Video.Display) + return fmt.Errorf("unexpected video display %q", *inst.Config.Video.Display) } } -func attachFolderMounts(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfiguration) error { +func attachFolderMounts(inst *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error { var mounts []vz.DirectorySharingDeviceConfiguration - if *driver.Instance.Config.MountType == limayaml.VIRTIOFS { - for i, mount := range driver.Instance.Config.Mounts { + if *inst.Config.MountType == limayaml.VIRTIOFS { + for i, mount := range inst.Config.Mounts { if _, err := os.Stat(mount.Location); errors.Is(err, os.ErrNotExist) { err := os.MkdirAll(mount.Location, 0o750) if err != nil { @@ -577,7 +576,7 @@ func attachFolderMounts(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineCo } } - if *driver.Instance.Config.Rosetta.Enabled { + if *inst.Config.Rosetta.Enabled { logrus.Info("Setting up Rosetta share") directorySharingDeviceConfig, err := createRosettaDirectoryShareConfiguration() if err != nil { @@ -593,8 +592,8 @@ func attachFolderMounts(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineCo return nil } -func attachAudio(driver *driver.BaseDriver, config *vz.VirtualMachineConfiguration) error { - switch *driver.Instance.Config.Audio.Device { +func attachAudio(inst *store.Instance, config *vz.VirtualMachineConfiguration) error { + switch *inst.Config.Audio.Device { case "vz", "default": outputStream, err := vz.NewVirtioSoundDeviceHostOutputStreamConfiguration() if err != nil { @@ -612,11 +611,11 @@ func attachAudio(driver *driver.BaseDriver, config *vz.VirtualMachineConfigurati case "", "none": return nil default: - return fmt.Errorf("unexpected audio device %q", *driver.Instance.Config.Audio.Device) + return fmt.Errorf("unexpected audio device %q", *inst.Config.Audio.Device) } } -func attachOtherDevices(_ *driver.BaseDriver, vmConfig *vz.VirtualMachineConfiguration) error { +func attachOtherDevices(_ *store.Instance, vmConfig *vz.VirtualMachineConfiguration) error { entropyConfig, err := vz.NewVirtioEntropyDeviceConfiguration() if err != nil { return err @@ -690,8 +689,8 @@ func attachOtherDevices(_ *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigu return nil } -func getMachineIdentifier(driver *driver.BaseDriver) (*vz.GenericMachineIdentifier, error) { - identifier := filepath.Join(driver.Instance.Dir, filenames.VzIdentifier) +func getMachineIdentifier(inst *store.Instance) (*vz.GenericMachineIdentifier, error) { + identifier := filepath.Join(inst.Dir, filenames.VzIdentifier) if _, err := os.Stat(identifier); os.IsNotExist(err) { machineIdentifier, err := vz.NewGenericMachineIdentifier() if err != nil { @@ -706,15 +705,15 @@ func getMachineIdentifier(driver *driver.BaseDriver) (*vz.GenericMachineIdentifi return vz.NewGenericMachineIdentifierWithDataPath(identifier) } -func bootLoader(driver *driver.BaseDriver) (vz.BootLoader, error) { - linuxBootLoader, err := linuxBootLoader(driver) +func bootLoader(inst *store.Instance) (vz.BootLoader, error) { + linuxBootLoader, err := linuxBootLoader(inst) if linuxBootLoader != nil { return linuxBootLoader, nil } else if !errors.Is(err, os.ErrNotExist) { return nil, err } - efiVariableStore, err := getEFI(driver) + efiVariableStore, err := getEFI(inst) if err != nil { return nil, err } @@ -722,10 +721,10 @@ func bootLoader(driver *driver.BaseDriver) (vz.BootLoader, error) { return vz.NewEFIBootLoader(vz.WithEFIVariableStore(efiVariableStore)) } -func linuxBootLoader(driver *driver.BaseDriver) (*vz.LinuxBootLoader, error) { - kernel := filepath.Join(driver.Instance.Dir, filenames.Kernel) - kernelCmdline := filepath.Join(driver.Instance.Dir, filenames.KernelCmdline) - initrd := filepath.Join(driver.Instance.Dir, filenames.Initrd) +func linuxBootLoader(inst *store.Instance) (*vz.LinuxBootLoader, error) { + kernel := filepath.Join(inst.Dir, filenames.Kernel) + kernelCmdline := filepath.Join(inst.Dir, filenames.KernelCmdline) + initrd := filepath.Join(inst.Dir, filenames.Initrd) if _, err := os.Stat(kernel); err != nil { if errors.Is(err, os.ErrNotExist) { logrus.Debugf("Kernel file %q not found", kernel) @@ -747,8 +746,8 @@ func linuxBootLoader(driver *driver.BaseDriver) (*vz.LinuxBootLoader, error) { return vz.NewLinuxBootLoader(kernel, opt...) } -func getEFI(driver *driver.BaseDriver) (*vz.EFIVariableStore, error) { - efi := filepath.Join(driver.Instance.Dir, filenames.VzEfi) +func getEFI(inst *store.Instance) (*vz.EFIVariableStore, error) { + efi := filepath.Join(inst.Dir, filenames.VzEfi) if _, err := os.Stat(efi); os.IsNotExist(err) { return vz.NewEFIVariableStore(efi, vz.WithCreatingEFIVariableStore()) } diff --git a/pkg/vz/vz_driver_darwin.go b/pkg/driver/vz/vz_driver_darwin.go similarity index 79% rename from pkg/vz/vz_driver_darwin.go rename to pkg/driver/vz/vz_driver_darwin.go index ee1b34b910f..7242bf8bb34 100644 --- a/pkg/vz/vz_driver_darwin.go +++ b/pkg/driver/vz/vz_driver_darwin.go @@ -22,6 +22,7 @@ import ( "github.com/lima-vm/lima/pkg/limayaml" "github.com/lima-vm/lima/pkg/osutil" "github.com/lima-vm/lima/pkg/reflectutil" + "github.com/lima-vm/lima/pkg/store" ) var knownYamlProperties = []string{ @@ -68,16 +69,23 @@ var knownYamlProperties = []string{ const Enabled = true type LimaVzDriver struct { - *driver.BaseDriver + Instance *store.Instance + + SSHLocalPort int + vSockPort int + virtioPort string machine *virtualMachineWrapper } -func New(driver *driver.BaseDriver) *LimaVzDriver { - driver.VSockPort = 2222 - driver.VirtioPort = "" +var _ driver.Driver = (*LimaVzDriver)(nil) + +func New(inst *store.Instance, sshLocalPort int) *LimaVzDriver { return &LimaVzDriver{ - BaseDriver: driver, + Instance: inst, + vSockPort: 2222, + virtioPort: "", + SSHLocalPort: sshLocalPort, } } @@ -167,17 +175,17 @@ func (l *LimaVzDriver) Validate() error { } func (l *LimaVzDriver) Initialize(_ context.Context) error { - _, err := getMachineIdentifier(l.BaseDriver) + _, err := getMachineIdentifier(l.Instance) return err } func (l *LimaVzDriver) CreateDisk(ctx context.Context) error { - return EnsureDisk(ctx, l.BaseDriver) + return EnsureDisk(ctx, l.Instance) } func (l *LimaVzDriver) Start(ctx context.Context) (chan error, error) { logrus.Infof("Starting VZ (hint: to watch the boot progress, see %q)", filepath.Join(l.Instance.Dir, "serial*.log")) - vm, errCh, err := startVM(ctx, l.BaseDriver) + vm, errCh, err := startVM(ctx, l.Instance, l.SSHLocalPort) if err != nil { if errors.Is(err, vz.ErrUnsupportedOSVersion) { return nil, fmt.Errorf("vz driver requires macOS 13 or higher to run: %w", err) @@ -237,10 +245,55 @@ func (l *LimaVzDriver) Stop(_ context.Context) error { func (l *LimaVzDriver) GuestAgentConn(_ context.Context) (net.Conn, error) { for _, socket := range l.machine.SocketDevices() { - connect, err := socket.Connect(uint32(l.VSockPort)) + connect, err := socket.Connect(uint32(l.vSockPort)) if err == nil && connect.SourcePort() != 0 { return connect, nil } } return nil, errors.New("unable to connect to guest agent via vsock port 2222") } + +func (l *LimaVzDriver) Register(_ context.Context) error { + return nil +} + +func (l *LimaVzDriver) Unregister(_ context.Context) error { + return nil +} + +func (l *LimaVzDriver) ChangeDisplayPassword(_ context.Context, _ string) error { + return nil +} + +func (l *LimaVzDriver) GetDisplayConnection(_ context.Context) (string, error) { + return "", nil +} + +func (l *LimaVzDriver) CreateSnapshot(_ context.Context, _ string) error { + return errors.New("unimplemented") +} + +func (l *LimaVzDriver) ApplySnapshot(_ context.Context, _ string) error { + return errors.New("unimplemented") +} + +func (l *LimaVzDriver) DeleteSnapshot(_ context.Context, _ string) error { + return errors.New("unimplemented") +} + +func (l *LimaVzDriver) ListSnapshots(_ context.Context) (string, error) { + return "", errors.New("unimplemented") +} + +func (l *LimaVzDriver) ForwardGuestAgent() bool { + // If driver is not providing, use host agent + return l.vSockPort == 0 && l.virtioPort == "" +} + +func (l *LimaVzDriver) VSockPort() int { + return l.vSockPort +} + +func (l *LimaVzDriver) VirtioPort() string { + return l.virtioPort +} diff --git a/pkg/driver/vz/vz_driver_others.go b/pkg/driver/vz/vz_driver_others.go new file mode 100644 index 00000000000..589d0e75486 --- /dev/null +++ b/pkg/driver/vz/vz_driver_others.go @@ -0,0 +1,109 @@ +//go:build !darwin || no_vz + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package vz + +import ( + "context" + "errors" + "net" + + "github.com/lima-vm/lima/pkg/driver" + "github.com/lima-vm/lima/pkg/store" +) + +var ErrUnsupported = errors.New("vm driver 'vz' needs macOS 13 or later (Hint: try recompiling Lima if you are seeing this error on macOS 13)") + +const Enabled = false + +type LimaVzDriver struct { + Instance *store.Instance + + SSHLocalPort int + vSockPort int + virtioPort string +} + +var _ driver.Driver = (*LimaVzDriver)(nil) + +func New(_ *store.Instance, _ int) *LimaVzDriver { + return &LimaVzDriver{} +} + +func (l *LimaVzDriver) Validate() error { + return ErrUnsupported +} + +func (l *LimaVzDriver) Initialize(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) CreateDisk(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) Start(_ context.Context) (chan error, error) { + return nil, ErrUnsupported +} + +func (l *LimaVzDriver) Stop(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) CanRunGUI() bool { + return false +} + +func (l *LimaVzDriver) RunGUI() error { + return ErrUnsupported +} + +func (l *LimaVzDriver) ChangeDisplayPassword(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) GetDisplayConnection(_ context.Context) (string, error) { + return "", ErrUnsupported +} + +func (l *LimaVzDriver) CreateSnapshot(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) ApplySnapshot(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) DeleteSnapshot(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) ListSnapshots(_ context.Context) (string, error) { + return "", ErrUnsupported +} + +func (l *LimaVzDriver) Register(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) Unregister(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaVzDriver) ForwardGuestAgent() bool { + return false +} + +func (l *LimaVzDriver) GuestAgentConn(_ context.Context) (net.Conn, error) { + return nil, ErrUnsupported +} + +func (l *LimaVzDriver) VSockPort() int { + return l.vSockPort +} + +func (l *LimaVzDriver) VirtioPort() string { + return l.virtioPort +} diff --git a/pkg/wsl2/fs.go b/pkg/driver/wsl2/fs.go similarity index 65% rename from pkg/wsl2/fs.go rename to pkg/driver/wsl2/fs.go index 8a3060ac924..53823a7fb06 100644 --- a/pkg/wsl2/fs.go +++ b/pkg/driver/wsl2/fs.go @@ -11,19 +11,19 @@ import ( "github.com/sirupsen/logrus" - "github.com/lima-vm/lima/pkg/driver" "github.com/lima-vm/lima/pkg/fileutils" + "github.com/lima-vm/lima/pkg/store" "github.com/lima-vm/lima/pkg/store/filenames" ) // EnsureFs downloads the root fs. -func EnsureFs(ctx context.Context, driver *driver.BaseDriver) error { - baseDisk := filepath.Join(driver.Instance.Dir, filenames.BaseDisk) +func EnsureFs(ctx context.Context, inst *store.Instance) error { + baseDisk := filepath.Join(inst.Dir, filenames.BaseDisk) if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) { var ensuredBaseDisk bool - errs := make([]error, len(driver.Instance.Config.Images)) - for i, f := range driver.Instance.Config.Images { - if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *driver.Instance.Config.Arch); err != nil { + errs := make([]error, len(inst.Config.Images)) + for i, f := range inst.Config.Images { + if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *inst.Config.Arch); err != nil { errs[i] = err continue } diff --git a/pkg/wsl2/lima-init.TEMPLATE b/pkg/driver/wsl2/lima-init.TEMPLATE similarity index 100% rename from pkg/wsl2/lima-init.TEMPLATE rename to pkg/driver/wsl2/lima-init.TEMPLATE diff --git a/pkg/wsl2/vm_windows.go b/pkg/driver/wsl2/vm_windows.go similarity index 100% rename from pkg/wsl2/vm_windows.go rename to pkg/driver/wsl2/vm_windows.go diff --git a/pkg/driver/wsl2/wsl_driver_others.go b/pkg/driver/wsl2/wsl_driver_others.go new file mode 100644 index 00000000000..274761b17ea --- /dev/null +++ b/pkg/driver/wsl2/wsl_driver_others.go @@ -0,0 +1,109 @@ +//go:build !windows || no_wsl + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package wsl2 + +import ( + "context" + "errors" + "net" + + "github.com/lima-vm/lima/pkg/driver" + "github.com/lima-vm/lima/pkg/store" +) + +var ErrUnsupported = errors.New("vm driver 'wsl2' requires Windows 10 build 19041 or later (Hint: try recompiling Lima if you are seeing this error on Windows 10+)") + +const Enabled = false + +type LimaWslDriver struct { + Instance *store.Instance + + SSHLocalPort int + vSockPort int + virtioPort string +} + +var _ driver.Driver = (*LimaWslDriver)(nil) + +func New(_ *store.Instance, _ int) *LimaWslDriver { + return &LimaWslDriver{} +} + +func (l *LimaWslDriver) Validate() error { + return ErrUnsupported +} + +func (l *LimaWslDriver) Initialize(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) CreateDisk(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) Start(_ context.Context) (chan error, error) { + return nil, ErrUnsupported +} + +func (l *LimaWslDriver) Stop(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) CanRunGUI() bool { + return false +} + +func (l *LimaWslDriver) RunGUI() error { + return ErrUnsupported +} + +func (l *LimaWslDriver) ChangeDisplayPassword(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) GetDisplayConnection(_ context.Context) (string, error) { + return "", ErrUnsupported +} + +func (l *LimaWslDriver) CreateSnapshot(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) ApplySnapshot(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) DeleteSnapshot(_ context.Context, _ string) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) ListSnapshots(_ context.Context) (string, error) { + return "", ErrUnsupported +} + +func (l *LimaWslDriver) Register(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) Unregister(_ context.Context) error { + return ErrUnsupported +} + +func (l *LimaWslDriver) ForwardGuestAgent() bool { + return false +} + +func (l *LimaWslDriver) GuestAgentConn(_ context.Context) (net.Conn, error) { + return nil, ErrUnsupported +} + +func (l *LimaWslDriver) VSockPort() int { + return l.vSockPort +} + +func (l *LimaWslDriver) VirtioPort() string { + return l.virtioPort +} diff --git a/pkg/wsl2/wsl_driver_windows.go b/pkg/driver/wsl2/wsl_driver_windows.go similarity index 75% rename from pkg/wsl2/wsl_driver_windows.go rename to pkg/driver/wsl2/wsl_driver_windows.go index 4ad7d472452..cd9df59e34d 100644 --- a/pkg/wsl2/wsl_driver_windows.go +++ b/pkg/driver/wsl2/wsl_driver_windows.go @@ -5,6 +5,7 @@ package wsl2 import ( "context" + "errors" "fmt" "net" "regexp" @@ -47,18 +48,26 @@ var knownYamlProperties = []string{ const Enabled = true type LimaWslDriver struct { - *driver.BaseDriver + Instance *store.Instance + + SSHLocalPort int + vSockPort int + virtioPort string } -func New(driver *driver.BaseDriver) *LimaWslDriver { +var _ driver.Driver = (*LimaWslDriver)(nil) + +func New(inst *store.Instance, sshLocalPort int) *LimaWslDriver { port, err := freeport.VSock() if err != nil { logrus.WithError(err).Error("failed to get free VSock port") } - driver.VSockPort = port - driver.VirtioPort = "" + return &LimaWslDriver{ - BaseDriver: driver, + Instance: inst, + vSockPort: port, + virtioPort: "", + SSHLocalPort: sshLocalPort, } } @@ -123,10 +132,10 @@ func (l *LimaWslDriver) Start(ctx context.Context) (chan error, error) { distroName := "lima-" + l.Instance.Name if status == store.StatusUninitialized { - if err := EnsureFs(ctx, l.BaseDriver); err != nil { + if err := EnsureFs(ctx, l.Instance); err != nil { return nil, err } - if err := initVM(ctx, l.BaseDriver.Instance.Dir, distroName); err != nil { + if err := initVM(ctx, l.Instance.Dir, distroName); err != nil { return nil, err } } @@ -139,8 +148,8 @@ func (l *LimaWslDriver) Start(ctx context.Context) (chan error, error) { if err := provisionVM( ctx, - l.BaseDriver.Instance.Dir, - l.BaseDriver.Instance.Name, + l.Instance.Dir, + l.Instance.Name, distroName, errCh, ); err != nil { @@ -197,7 +206,56 @@ func (l *LimaWslDriver) GuestAgentConn(ctx context.Context) (net.Conn, error) { } sockAddr := &winio.HvsockAddr{ VMID: VMIDGUID, - ServiceID: winio.VsockServiceID(uint32(l.VSockPort)), + ServiceID: winio.VsockServiceID(uint32(l.vSockPort)), } return winio.Dial(ctx, sockAddr) } + +func (l *LimaWslDriver) Initialize(_ context.Context) error { + return nil +} + +func (l *LimaWslDriver) CreateDisk(_ context.Context) error { + return nil +} + +func (l *LimaWslDriver) Register(_ context.Context) error { + return nil +} + +func (l *LimaWslDriver) ChangeDisplayPassword(_ context.Context, _ string) error { + return nil +} + +func (l *LimaWslDriver) GetDisplayConnection(_ context.Context) (string, error) { + return "", nil +} + +func (l *LimaWslDriver) CreateSnapshot(_ context.Context, _ string) error { + return errors.New("unimplemented") +} + +func (l *LimaWslDriver) ApplySnapshot(_ context.Context, _ string) error { + return errors.New("unimplemented") +} + +func (l *LimaWslDriver) DeleteSnapshot(_ context.Context, _ string) error { + return errors.New("unimplemented") +} + +func (l *LimaWslDriver) ListSnapshots(_ context.Context) (string, error) { + return "", errors.New("unimplemented") +} + +func (l *LimaWslDriver) ForwardGuestAgent() bool { + // If driver is not providing, use host agent + return l.vSockPort == 0 && l.virtioPort == "" +} + +func (l *LimaWslDriver) VSockPort() int { + return l.vSockPort +} + +func (l *LimaWslDriver) VirtioPort() string { + return l.virtioPort +} diff --git a/pkg/driverutil/driverutil.go b/pkg/driverutil/driverutil.go index eb27833e7ad..1a95721105a 100644 --- a/pkg/driverutil/driverutil.go +++ b/pkg/driverutil/driverutil.go @@ -4,9 +4,9 @@ package driverutil import ( + "github.com/lima-vm/lima/pkg/driver/vz" + "github.com/lima-vm/lima/pkg/driver/wsl2" "github.com/lima-vm/lima/pkg/limayaml" - "github.com/lima-vm/lima/pkg/vz" - "github.com/lima-vm/lima/pkg/wsl2" ) // Drivers returns the available drivers. diff --git a/pkg/driverutil/instance.go b/pkg/driverutil/instance.go index d7c443ff5d2..0d68f66e1d1 100644 --- a/pkg/driverutil/instance.go +++ b/pkg/driverutil/instance.go @@ -5,19 +5,20 @@ package driverutil import ( "github.com/lima-vm/lima/pkg/driver" + "github.com/lima-vm/lima/pkg/driver/qemu" + "github.com/lima-vm/lima/pkg/driver/vz" + "github.com/lima-vm/lima/pkg/driver/wsl2" "github.com/lima-vm/lima/pkg/limayaml" - "github.com/lima-vm/lima/pkg/qemu" - "github.com/lima-vm/lima/pkg/vz" - "github.com/lima-vm/lima/pkg/wsl2" + "github.com/lima-vm/lima/pkg/store" ) -func CreateTargetDriverInstance(base *driver.BaseDriver) driver.Driver { - limaDriver := base.Instance.Config.VMType +func CreateTargetDriverInstance(inst *store.Instance, sshLocalPort int) driver.Driver { + limaDriver := inst.Config.VMType if *limaDriver == limayaml.VZ { - return vz.New(base) + return vz.New(inst, sshLocalPort) } if *limaDriver == limayaml.WSL2 { - return wsl2.New(base) + return wsl2.New(inst, sshLocalPort) } - return qemu.New(base) + return qemu.New(inst, sshLocalPort) } diff --git a/pkg/hostagent/hostagent.go b/pkg/hostagent/hostagent.go index c0452c8ba72..22ee61547ce 100644 --- a/pkg/hostagent/hostagent.go +++ b/pkg/hostagent/hostagent.go @@ -131,13 +131,9 @@ func New(instName string, stdout io.Writer, signalCh chan os.Signal, opts ...Opt } } - baseDriver := driver.BaseDriver{ - Instance: inst, - SSHLocalPort: sshLocalPort, - } - limaDriver := driverutil.CreateTargetDriverInstance(&baseDriver) - vSockPort := baseDriver.VSockPort - virtioPort := baseDriver.VirtioPort + limaDriver := driverutil.CreateTargetDriverInstance(inst, sshLocalPort) + vSockPort := limaDriver.VSockPort() + virtioPort := limaDriver.VirtioPort() if err := cidata.GenerateCloudConfig(inst.Dir, instName, inst.Config); err != nil { return nil, err diff --git a/pkg/imgutil/proxyimgutil/proxyimgutil.go b/pkg/imgutil/proxyimgutil/proxyimgutil.go index 7ff88abcef0..0c56ca82a45 100644 --- a/pkg/imgutil/proxyimgutil/proxyimgutil.go +++ b/pkg/imgutil/proxyimgutil/proxyimgutil.go @@ -10,7 +10,7 @@ import ( "github.com/lima-vm/lima/pkg/imgutil" "github.com/lima-vm/lima/pkg/imgutil/nativeimgutil" - "github.com/lima-vm/lima/pkg/imgutil/qemuimgutil" + "github.com/lima-vm/lima/pkg/qemuimgutil" ) // ImageDiskManager is a proxy implementation of imgutil.ImageDiskManager that uses both QEMU and native image utilities. diff --git a/pkg/instance/create.go b/pkg/instance/create.go index b9088785976..7b69ccc3100 100644 --- a/pkg/instance/create.go +++ b/pkg/instance/create.go @@ -11,7 +11,6 @@ import ( "path/filepath" "github.com/lima-vm/lima/pkg/cidata" - "github.com/lima-vm/lima/pkg/driver" "github.com/lima-vm/lima/pkg/driverutil" "github.com/lima-vm/lima/pkg/limayaml" "github.com/lima-vm/lima/pkg/osutil" @@ -76,9 +75,7 @@ func Create(ctx context.Context, instName string, instConfig []byte, saveBrokenY return nil, err } - limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{ - Instance: inst, - }) + limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) if err := limaDriver.Register(ctx); err != nil { return nil, err diff --git a/pkg/instance/delete.go b/pkg/instance/delete.go index c4078d48a11..ca9a8ae3c01 100644 --- a/pkg/instance/delete.go +++ b/pkg/instance/delete.go @@ -9,7 +9,6 @@ import ( "fmt" "os" - "github.com/lima-vm/lima/pkg/driver" "github.com/lima-vm/lima/pkg/driverutil" "github.com/lima-vm/lima/pkg/store" ) @@ -37,9 +36,7 @@ func Delete(ctx context.Context, inst *store.Instance, force bool) error { } func unregister(ctx context.Context, inst *store.Instance) error { - limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{ - Instance: inst, - }) + limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) return limaDriver.Unregister(ctx) } diff --git a/pkg/instance/start.go b/pkg/instance/start.go index acd3741e0bd..d0c344fc8d7 100644 --- a/pkg/instance/start.go +++ b/pkg/instance/start.go @@ -90,9 +90,7 @@ func Prepare(ctx context.Context, inst *store.Instance) (*Prepared, error) { return nil, err } } - limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{ - Instance: inst, - }) + limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) if err := limaDriver.Validate(); err != nil { return nil, err @@ -107,6 +105,43 @@ func Prepare(ctx context.Context, inst *store.Instance) (*Prepared, error) { _, err := os.Stat(baseDisk) created := err == nil + kernel := filepath.Join(inst.Dir, filenames.Kernel) + kernelCmdline := filepath.Join(inst.Dir, filenames.KernelCmdline) + initrd := filepath.Join(inst.Dir, filenames.Initrd) + if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) { + var ensuredBaseDisk bool + errs := make([]error, len(inst.Config.Images)) + for i, f := range inst.Config.Images { + if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *inst.Config.Arch); err != nil { + errs[i] = err + continue + } + if f.Kernel != nil { + if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, false, "the kernel", *inst.Config.Arch); err != nil { + errs[i] = err + continue + } + if f.Kernel.Cmdline != "" { + if err := os.WriteFile(kernelCmdline, []byte(f.Kernel.Cmdline), 0o644); err != nil { + errs[i] = err + continue + } + } + } + if f.Initrd != nil { + if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, "the initrd", *inst.Config.Arch); err != nil { + errs[i] = err + continue + } + } + ensuredBaseDisk = true + break + } + if !ensuredBaseDisk { + return nil, fileutils.Errors(errs) + } + } + if err := limaDriver.CreateDisk(ctx); err != nil { return nil, err } diff --git a/pkg/networks/usernet/client.go b/pkg/networks/usernet/client.go index 2296f103ed1..8bc478cb0f2 100644 --- a/pkg/networks/usernet/client.go +++ b/pkg/networks/usernet/client.go @@ -17,10 +17,10 @@ import ( gvproxyclient "github.com/containers/gvisor-tap-vsock/pkg/client" "github.com/containers/gvisor-tap-vsock/pkg/types" - "github.com/lima-vm/lima/pkg/driver" "github.com/lima-vm/lima/pkg/httpclientutil" "github.com/lima-vm/lima/pkg/limayaml" "github.com/lima-vm/lima/pkg/networks/usernet/dnshosts" + "github.com/lima-vm/lima/pkg/store" ) type Client struct { @@ -32,18 +32,18 @@ type Client struct { subnet net.IP } -func (c *Client) ConfigureDriver(ctx context.Context, driver *driver.BaseDriver) error { - macAddress := limayaml.MACAddress(driver.Instance.Dir) +func (c *Client) ConfigureDriver(ctx context.Context, inst *store.Instance, sshLocalPort int) error { + macAddress := limayaml.MACAddress(inst.Dir) ipAddress, err := c.ResolveIPAddress(ctx, macAddress) if err != nil { return err } - err = c.ResolveAndForwardSSH(ipAddress, driver.SSHLocalPort) + err = c.ResolveAndForwardSSH(ipAddress, sshLocalPort) if err != nil { return err } - hosts := driver.Instance.Config.HostResolver.Hosts - hosts[fmt.Sprintf("%s.internal", driver.Instance.Hostname)] = ipAddress + hosts := inst.Config.HostResolver.Hosts + hosts[fmt.Sprintf("%s.internal", inst.Hostname)] = ipAddress err = c.AddDNSHosts(hosts) return err } diff --git a/pkg/imgutil/qemuimgutil/qemuimgutil.go b/pkg/qemuimgutil/qemuimgutil.go similarity index 100% rename from pkg/imgutil/qemuimgutil/qemuimgutil.go rename to pkg/qemuimgutil/qemuimgutil.go diff --git a/pkg/imgutil/qemuimgutil/qemuimgutil_test.go b/pkg/qemuimgutil/qemuimgutil_test.go similarity index 100% rename from pkg/imgutil/qemuimgutil/qemuimgutil_test.go rename to pkg/qemuimgutil/qemuimgutil_test.go diff --git a/pkg/snapshot/snapshot.go b/pkg/snapshot/snapshot.go index 520a41d92a4..9c48fc0c50a 100644 --- a/pkg/snapshot/snapshot.go +++ b/pkg/snapshot/snapshot.go @@ -6,35 +6,26 @@ package snapshot import ( "context" - "github.com/lima-vm/lima/pkg/driver" "github.com/lima-vm/lima/pkg/driverutil" "github.com/lima-vm/lima/pkg/store" ) func Del(ctx context.Context, inst *store.Instance, tag string) error { - limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{ - Instance: inst, - }) + limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) return limaDriver.DeleteSnapshot(ctx, tag) } func Save(ctx context.Context, inst *store.Instance, tag string) error { - limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{ - Instance: inst, - }) + limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) return limaDriver.CreateSnapshot(ctx, tag) } func Load(ctx context.Context, inst *store.Instance, tag string) error { - limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{ - Instance: inst, - }) + limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) return limaDriver.ApplySnapshot(ctx, tag) } func List(ctx context.Context, inst *store.Instance) (string, error) { - limaDriver := driverutil.CreateTargetDriverInstance(&driver.BaseDriver{ - Instance: inst, - }) + limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) return limaDriver.ListSnapshots(ctx) } diff --git a/pkg/vz/disk.go b/pkg/vz/disk.go deleted file mode 100644 index 06194faf5d2..00000000000 --- a/pkg/vz/disk.go +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: Copyright The Lima Authors -// SPDX-License-Identifier: Apache-2.0 - -package vz - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - - "github.com/docker/go-units" - - "github.com/lima-vm/lima/pkg/driver" - "github.com/lima-vm/lima/pkg/fileutils" - "github.com/lima-vm/lima/pkg/imgutil/proxyimgutil" - "github.com/lima-vm/lima/pkg/iso9660util" - "github.com/lima-vm/lima/pkg/store/filenames" -) - -func EnsureDisk(ctx context.Context, driver *driver.BaseDriver) error { - diffDisk := filepath.Join(driver.Instance.Dir, filenames.DiffDisk) - if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) { - // disk is already ensured - return err - } - - diskUtil := proxyimgutil.NewDiskUtil() - - baseDisk := filepath.Join(driver.Instance.Dir, filenames.BaseDisk) - kernel := filepath.Join(driver.Instance.Dir, filenames.Kernel) - kernelCmdline := filepath.Join(driver.Instance.Dir, filenames.KernelCmdline) - initrd := filepath.Join(driver.Instance.Dir, filenames.Initrd) - if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) { - var ensuredBaseDisk bool - errs := make([]error, len(driver.Instance.Config.Images)) - for i, f := range driver.Instance.Config.Images { - if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *driver.Instance.Config.Arch); err != nil { - errs[i] = err - continue - } - if f.Kernel != nil { - // ensure decompress kernel because vz expects it to be decompressed - if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, true, "the kernel", *driver.Instance.Config.Arch); err != nil { - errs[i] = err - continue - } - if f.Kernel.Cmdline != "" { - if err := os.WriteFile(kernelCmdline, []byte(f.Kernel.Cmdline), 0o644); err != nil { - errs[i] = err - continue - } - } - } - if f.Initrd != nil { - if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, "the initrd", *driver.Instance.Config.Arch); err != nil { - errs[i] = err - continue - } - } - ensuredBaseDisk = true - break - } - if !ensuredBaseDisk { - return fileutils.Errors(errs) - } - } - diskSize, _ := units.RAMInBytes(*driver.Instance.Config.Disk) - if diskSize == 0 { - return nil - } - isBaseDiskISO, err := iso9660util.IsISO9660(baseDisk) - if err != nil { - return err - } - if isBaseDiskISO { - // Create an empty data volume (sparse) - diffDiskF, err := os.Create(diffDisk) - if err != nil { - return err - } - - err = diskUtil.MakeSparse(diffDiskF, 0) - if err != nil { - diffDiskF.Close() - return fmt.Errorf("failed to create sparse diff disk %q: %w", diffDisk, err) - } - return diffDiskF.Close() - } - if err = diskUtil.ConvertToRaw(baseDisk, diffDisk, &diskSize, false); err != nil { - return fmt.Errorf("failed to convert %q to a raw disk %q: %w", baseDisk, diffDisk, err) - } - return err -} diff --git a/pkg/vz/vz_driver_others.go b/pkg/vz/vz_driver_others.go deleted file mode 100644 index 66265628a49..00000000000 --- a/pkg/vz/vz_driver_others.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build !darwin || no_vz - -// SPDX-FileCopyrightText: Copyright The Lima Authors -// SPDX-License-Identifier: Apache-2.0 - -package vz - -import ( - "context" - "errors" - - "github.com/lima-vm/lima/pkg/driver" -) - -var ErrUnsupported = errors.New("vm driver 'vz' needs macOS 13 or later (Hint: try recompiling Lima if you are seeing this error on macOS 13)") - -const Enabled = false - -type LimaVzDriver struct { - *driver.BaseDriver -} - -func New(driver *driver.BaseDriver) *LimaVzDriver { - return &LimaVzDriver{ - BaseDriver: driver, - } -} - -func (l *LimaVzDriver) Validate() error { - return ErrUnsupported -} - -func (l *LimaVzDriver) CreateDisk(_ context.Context) error { - return ErrUnsupported -} - -func (l *LimaVzDriver) Start(_ context.Context) (chan error, error) { - return nil, ErrUnsupported -} - -func (l *LimaVzDriver) Stop(_ context.Context) error { - return ErrUnsupported -} diff --git a/pkg/wsl2/wsl_driver_others.go b/pkg/wsl2/wsl_driver_others.go deleted file mode 100644 index 4ad86d02768..00000000000 --- a/pkg/wsl2/wsl_driver_others.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build !windows || no_wsl - -// SPDX-FileCopyrightText: Copyright The Lima Authors -// SPDX-License-Identifier: Apache-2.0 - -package wsl2 - -import ( - "context" - "errors" - - "github.com/lima-vm/lima/pkg/driver" -) - -var ErrUnsupported = errors.New("vm driver 'wsl2' requires Windows 10 build 19041 or later (Hint: try recompiling Lima if you are seeing this error on Windows 10+)") - -const Enabled = false - -type LimaWslDriver struct { - *driver.BaseDriver -} - -func New(driver *driver.BaseDriver) *LimaWslDriver { - return &LimaWslDriver{ - BaseDriver: driver, - } -} - -func (l *LimaWslDriver) Validate() error { - return ErrUnsupported -} - -func (l *LimaWslDriver) CreateDisk(_ context.Context) error { - return ErrUnsupported -} - -func (l *LimaWslDriver) Start(_ context.Context) (chan error, error) { - return nil, ErrUnsupported -} - -func (l *LimaWslDriver) Stop(_ context.Context) error { - return ErrUnsupported -}