diff --git a/cmd/limactl/main_darwin.go b/cmd/limactl/main_darwin.go new file mode 100644 index 00000000000..013961969ec --- /dev/null +++ b/cmd/limactl/main_darwin.go @@ -0,0 +1,9 @@ +//go:build !external_vz + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package main + +// Import vz driver to register it in the registry on darwin. +import _ "github.com/lima-vm/lima/pkg/driver/vz" diff --git a/cmd/limactl/main_qemu.go b/cmd/limactl/main_qemu.go new file mode 100644 index 00000000000..ae2dab08f10 --- /dev/null +++ b/cmd/limactl/main_qemu.go @@ -0,0 +1,9 @@ +//go:build !external_qemu + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package main + +// Import qemu driver to register it in the registry on all platforms. +import _ "github.com/lima-vm/lima/pkg/driver/qemu" diff --git a/cmd/limactl/main_windows.go b/cmd/limactl/main_windows.go new file mode 100644 index 00000000000..698362e082b --- /dev/null +++ b/cmd/limactl/main_windows.go @@ -0,0 +1,9 @@ +//go:build !external_wsl2 + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package main + +// Import wsl2 driver to register it in the registry on windows. +import _ "github.com/lima-vm/lima/pkg/driver/wsl2" diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go index 082f847207b..e0a4759c25f 100644 --- a/pkg/driver/driver.go +++ b/pkg/driver/driver.go @@ -6,10 +6,12 @@ package driver import ( "context" "net" + + "github.com/lima-vm/lima/pkg/store" ) -// Driver interface is used by hostagent for managing vm. -type Driver interface { +// Lifecycle defines basic lifecycle operations. +type Lifecycle interface { // Validate returns error if the current driver isn't support for given config Validate() error @@ -29,43 +31,66 @@ type Driver interface { // The second argument may contain error occurred while starting driver Start(_ context.Context) (chan error, error) - // CanRunGUI returns bool to indicate if the hostagent need to run GUI synchronously - CanRunGUI() bool - - // RunGUI is for starting GUI synchronously by hostagent. This method should be wait and return only after vm terminates - // It returns error if there are any failures - RunGUI() error - // Stop will terminate the running vm instance. // It returns error if there are any errors during Stop Stop(_ context.Context) error +} - // Register will add an instance to a registry. - // It returns error if there are any errors during Register - Register(_ context.Context) error +// GUI defines GUI-related operations. +type GUI interface { + // RunGUI is for starting GUI synchronously by hostagent. This method should be wait and return only after vm terminates + // It returns error if there are any failures + RunGUI() error - // Unregister will perform any cleanup related to the vm instance. - // It returns error if there are any errors during Unregister - Unregister(_ context.Context) error + ChangeDisplayPassword(ctx context.Context, password string) error + DisplayConnection(ctx context.Context) (string, error) +} - ChangeDisplayPassword(_ context.Context, password string) error +// SnapshotManager defines operations for managing snapshots. +type SnapshotManager interface { + CreateSnapshot(ctx context.Context, tag string) error + ApplySnapshot(ctx context.Context, tag string) error + DeleteSnapshot(ctx context.Context, tag string) error + ListSnapshots(ctx context.Context) (string, error) +} - GetDisplayConnection(_ context.Context) (string, error) +// Registration defines operations for registering and unregistering the driver instance. +type Registration interface { + Register(ctx context.Context) error + Unregister(ctx context.Context) error +} - CreateSnapshot(_ context.Context, tag string) error +// GuestAgent defines operations for the guest agent. +type GuestAgent interface { + // ForwardGuestAgent returns if the guest agent sock needs forwarding by host agent. + ForwardGuestAgent() bool - ApplySnapshot(_ context.Context, tag string) error + // GuestAgentConn returns the guest agent connection, or nil (if forwarded by ssh). + GuestAgentConn(_ context.Context) (net.Conn, string, error) +} - DeleteSnapshot(_ context.Context, tag string) error +// Driver interface is used by hostagent for managing vm. +type Driver interface { + Lifecycle + GUI + SnapshotManager + Registration + GuestAgent - ListSnapshots(_ context.Context) (string, error) + Info() Info - // ForwardGuestAgent returns if the guest agent sock needs forwarding by host agent. - ForwardGuestAgent() bool + // SetConfig sets the configuration for the instance. + Configure(inst *store.Instance, sshLocalPort int) *ConfiguredDriver +} - // GuestAgentConn returns the guest agent connection, or nil (if forwarded by ssh). - GuestAgentConn(_ context.Context) (net.Conn, error) +type ConfiguredDriver struct { + Driver +} - VSockPort() int - VirtioPort() string +type Info struct { + DriverName string `json:"driverName"` + CanRunGUI bool `json:"canRunGui,omitempty"` + VsockPort int `json:"vsockPort"` + VirtioPort string `json:"virtioPort"` + InstanceDir string `json:"instanceDir,omitempty"` } diff --git a/pkg/driver/qemu/qemu_driver.go b/pkg/driver/qemu/qemu_driver.go index 084021b85f0..187509c4b90 100644 --- a/pkg/driver/qemu/qemu_driver.go +++ b/pkg/driver/qemu/qemu_driver.go @@ -50,7 +50,7 @@ type LimaQemuDriver struct { var _ driver.Driver = (*LimaQemuDriver)(nil) -func New(inst *store.Instance, sshLocalPort int) *LimaQemuDriver { +func New() *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 @@ -59,10 +59,17 @@ func New(inst *store.Instance, sshLocalPort int) *LimaQemuDriver { virtioPort = "" } return &LimaQemuDriver{ - Instance: inst, - vSockPort: 0, - virtioPort: virtioPort, - SSHLocalPort: sshLocalPort, + vSockPort: 0, + virtioPort: virtioPort, + } +} + +func (l *LimaQemuDriver) Configure(inst *store.Instance, sshLocalPort int) *driver.ConfiguredDriver { + l.Instance = inst + l.SSHLocalPort = sshLocalPort + + return &driver.ConfiguredDriver{ + Driver: l, } } @@ -238,7 +245,7 @@ func (l *LimaQemuDriver) ChangeDisplayPassword(_ context.Context, password strin return l.changeVNCPassword(password) } -func (l *LimaQemuDriver) GetDisplayConnection(_ context.Context) (string, error) { +func (l *LimaQemuDriver) DisplayConnection(_ context.Context) (string, error) { return l.getVNCDisplayPort() } @@ -450,10 +457,10 @@ func (l *LimaQemuDriver) ListSnapshots(_ context.Context) (string, error) { return List(qCfg, l.Instance.Status == store.StatusRunning) } -func (l *LimaQemuDriver) GuestAgentConn(ctx context.Context) (net.Conn, error) { +func (l *LimaQemuDriver) GuestAgentConn(ctx context.Context) (net.Conn, string, error) { var d net.Dialer dialContext, err := d.DialContext(ctx, "unix", filepath.Join(l.Instance.Dir, filenames.GuestAgentSock)) - return dialContext, err + return dialContext, "unix", err } type qArgTemplateApplier struct { @@ -508,12 +515,20 @@ func (a *qArgTemplateApplier) applyTemplate(qArg string) (string, error) { return b.String(), nil } -func (l *LimaQemuDriver) Initialize(_ context.Context) error { - return nil +func (l *LimaQemuDriver) Info() driver.Info { + var info driver.Info + if l.Instance != nil && l.Instance.Dir != "" { + info.InstanceDir = l.Instance.Dir + } + info.DriverName = "qemu" + info.CanRunGUI = false + info.VirtioPort = l.virtioPort + info.VsockPort = l.vSockPort + return info } -func (l *LimaQemuDriver) CanRunGUI() bool { - return false +func (l *LimaQemuDriver) Initialize(_ context.Context) error { + return nil } func (l *LimaQemuDriver) RunGUI() error { @@ -532,11 +547,3 @@ 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/driver/qemu/register.go b/pkg/driver/qemu/register.go new file mode 100644 index 00000000000..6b73d2c624c --- /dev/null +++ b/pkg/driver/qemu/register.go @@ -0,0 +1,12 @@ +//go:build !external_qemu + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package qemu + +import "github.com/lima-vm/lima/pkg/registry" + +func init() { + registry.Register(New()) +} diff --git a/pkg/driver/vz/errors_darwin.go b/pkg/driver/vz/errors_darwin.go index 2bc832cf98b..aa180c70255 100644 --- a/pkg/driver/vz/errors_darwin.go +++ b/pkg/driver/vz/errors_darwin.go @@ -8,4 +8,7 @@ package vz import "errors" //nolint:revive,staticcheck // false positives with proper nouns -var errRosettaUnsupported = errors.New("Rosetta is unsupported on non-ARM64 hosts") +var ( + errRosettaUnsupported = errors.New("Rosetta is unsupported on non-ARM64 hosts") + errUnimplemented = errors.New("unimplemented") +) diff --git a/pkg/driver/vz/register.go b/pkg/driver/vz/register.go new file mode 100644 index 00000000000..26997debcaa --- /dev/null +++ b/pkg/driver/vz/register.go @@ -0,0 +1,12 @@ +//go:build darwin && !external_vz + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package vz + +import "github.com/lima-vm/lima/pkg/registry" + +func init() { + registry.Register(New()) +} diff --git a/pkg/driver/vz/vz_driver_darwin.go b/pkg/driver/vz/vz_driver_darwin.go index 7242bf8bb34..d34441354b9 100644 --- a/pkg/driver/vz/vz_driver_darwin.go +++ b/pkg/driver/vz/vz_driver_darwin.go @@ -80,12 +80,19 @@ type LimaVzDriver struct { var _ driver.Driver = (*LimaVzDriver)(nil) -func New(inst *store.Instance, sshLocalPort int) *LimaVzDriver { +func New() *LimaVzDriver { return &LimaVzDriver{ - Instance: inst, - vSockPort: 2222, - virtioPort: "", - SSHLocalPort: sshLocalPort, + vSockPort: 2222, + virtioPort: "", + } +} + +func (l *LimaVzDriver) Configure(inst *store.Instance, sshLocalPort int) *driver.ConfiguredDriver { + l.Instance = inst + l.SSHLocalPort = sshLocalPort + + return &driver.ConfiguredDriver{ + Driver: l, } } @@ -197,7 +204,7 @@ func (l *LimaVzDriver) Start(ctx context.Context) (chan error, error) { return errCh, nil } -func (l *LimaVzDriver) CanRunGUI() bool { +func (l *LimaVzDriver) canRunGUI() bool { switch *l.Instance.Config.Video.Display { case "vz", "default": return true @@ -207,7 +214,7 @@ func (l *LimaVzDriver) CanRunGUI() bool { } func (l *LimaVzDriver) RunGUI() error { - if l.CanRunGUI() { + if l.canRunGUI() { return l.machine.StartGraphicApplication(1920, 1200) } return fmt.Errorf("RunGUI is not supported for the given driver '%s' and display '%s'", "vz", *l.Instance.Config.Video.Display) @@ -243,14 +250,28 @@ func (l *LimaVzDriver) Stop(_ context.Context) error { return errors.New("vz: CanRequestStop is not supported") } -func (l *LimaVzDriver) GuestAgentConn(_ context.Context) (net.Conn, error) { +func (l *LimaVzDriver) GuestAgentConn(_ context.Context) (net.Conn, string, error) { for _, socket := range l.machine.SocketDevices() { connect, err := socket.Connect(uint32(l.vSockPort)) - if err == nil && connect.SourcePort() != 0 { - return connect, nil - } + return connect, "vsock", err } - return nil, errors.New("unable to connect to guest agent via vsock port 2222") + + return nil, "", errors.New("unable to connect to guest agent via vsock port 2222") +} + +func (l *LimaVzDriver) Info() driver.Info { + var info driver.Info + if l.Instance != nil { + info.CanRunGUI = l.canRunGUI() + } + + info.DriverName = "vz" + info.VsockPort = l.vSockPort + info.VirtioPort = l.virtioPort + if l.Instance != nil { + info.InstanceDir = l.Instance.Dir + } + return info } func (l *LimaVzDriver) Register(_ context.Context) error { @@ -265,35 +286,27 @@ func (l *LimaVzDriver) ChangeDisplayPassword(_ context.Context, _ string) error return nil } -func (l *LimaVzDriver) GetDisplayConnection(_ context.Context) (string, error) { +func (l *LimaVzDriver) DisplayConnection(_ context.Context) (string, error) { return "", nil } func (l *LimaVzDriver) CreateSnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") + return errUnimplemented } func (l *LimaVzDriver) ApplySnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") + return errUnimplemented } func (l *LimaVzDriver) DeleteSnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") + return errUnimplemented } func (l *LimaVzDriver) ListSnapshots(_ context.Context) (string, error) { - return "", errors.New("unimplemented") + return "", errUnimplemented } 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 deleted file mode 100644 index 589d0e75486..00000000000 --- a/pkg/driver/vz/vz_driver_others.go +++ /dev/null @@ -1,109 +0,0 @@ -//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/driver/wsl2/errors_windows.go b/pkg/driver/wsl2/errors_windows.go new file mode 100644 index 00000000000..286bcf18a34 --- /dev/null +++ b/pkg/driver/wsl2/errors_windows.go @@ -0,0 +1,10 @@ +//go:build windows && !no_wsl + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package wsl2 + +import "errors" + +var errUnimplemented = errors.New("unimplemented") diff --git a/pkg/driver/wsl2/register.go b/pkg/driver/wsl2/register.go new file mode 100644 index 00000000000..cf990e91990 --- /dev/null +++ b/pkg/driver/wsl2/register.go @@ -0,0 +1,12 @@ +//go:build windows && !external_wsl2 + +// SPDX-FileCopyrightText: Copyright The Lima Authors +// SPDX-License-Identifier: Apache-2.0 + +package wsl2 + +import "github.com/lima-vm/lima/pkg/registry" + +func init() { + registry.Register(New()) +} diff --git a/pkg/driver/wsl2/wsl_driver_others.go b/pkg/driver/wsl2/wsl_driver_others.go deleted file mode 100644 index 274761b17ea..00000000000 --- a/pkg/driver/wsl2/wsl_driver_others.go +++ /dev/null @@ -1,109 +0,0 @@ -//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/driver/wsl2/wsl_driver_windows.go b/pkg/driver/wsl2/wsl_driver_windows.go index cd9df59e34d..1c93ee3422d 100644 --- a/pkg/driver/wsl2/wsl_driver_windows.go +++ b/pkg/driver/wsl2/wsl_driver_windows.go @@ -5,7 +5,6 @@ package wsl2 import ( "context" - "errors" "fmt" "net" "regexp" @@ -57,17 +56,24 @@ type LimaWslDriver struct { var _ driver.Driver = (*LimaWslDriver)(nil) -func New(inst *store.Instance, sshLocalPort int) *LimaWslDriver { +func New() *LimaWslDriver { port, err := freeport.VSock() if err != nil { logrus.WithError(err).Error("failed to get free VSock port") } return &LimaWslDriver{ - Instance: inst, - vSockPort: port, - virtioPort: "", - SSHLocalPort: sshLocalPort, + vSockPort: port, + virtioPort: "", + } +} + +func (l *LimaWslDriver) Configure(inst *store.Instance, sshLocalPort int) *driver.ConfiguredDriver { + l.Instance = inst + l.SSHLocalPort = sshLocalPort + + return &driver.ConfiguredDriver{ + Driver: l, } } @@ -163,7 +169,7 @@ func (l *LimaWslDriver) Start(ctx context.Context) (chan error, error) { // CanRunGUI requires WSLg, which requires specific version of WSL2 to be installed. // TODO: Add check and add support for WSLg (instead of VNC) to hostagent. -func (l *LimaWslDriver) CanRunGUI() bool { +func (l *LimaWslDriver) canRunGUI() bool { return false } @@ -195,20 +201,37 @@ func (l *LimaWslDriver) Unregister(ctx context.Context) error { // GuestAgentConn returns the guest agent connection, or nil (if forwarded by ssh). // As of 08-01-2024, github.com/mdlayher/vsock does not natively support vsock on // Windows, so use the winio library to create the connection. -func (l *LimaWslDriver) GuestAgentConn(ctx context.Context) (net.Conn, error) { +func (l *LimaWslDriver) GuestAgentConn(ctx context.Context) (net.Conn, string, error) { VMIDStr, err := windows.GetInstanceVMID(fmt.Sprintf("lima-%s", l.Instance.Name)) if err != nil { - return nil, err + return nil, "", err } VMIDGUID, err := guid.FromString(VMIDStr) if err != nil { - return nil, err + return nil, "", err } sockAddr := &winio.HvsockAddr{ VMID: VMIDGUID, ServiceID: winio.VsockServiceID(uint32(l.vSockPort)), } - return winio.Dial(ctx, sockAddr) + conn, err := winio.Dial(ctx, sockAddr) + if err != nil { + return nil, "", err + } + + return conn, "vsock", nil +} + +func (l *LimaWslDriver) Info() driver.Info { + var info driver.Info + if l.Instance != nil { + info.InstanceDir = l.Instance.Dir + } + info.DriverName = "wsl2" + info.CanRunGUI = l.canRunGUI() + info.VirtioPort = l.virtioPort + info.VsockPort = l.vSockPort + return info } func (l *LimaWslDriver) Initialize(_ context.Context) error { @@ -227,35 +250,27 @@ func (l *LimaWslDriver) ChangeDisplayPassword(_ context.Context, _ string) error return nil } -func (l *LimaWslDriver) GetDisplayConnection(_ context.Context) (string, error) { +func (l *LimaWslDriver) DisplayConnection(_ context.Context) (string, error) { return "", nil } func (l *LimaWslDriver) CreateSnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") + return errUnimplemented } func (l *LimaWslDriver) ApplySnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") + return errUnimplemented } func (l *LimaWslDriver) DeleteSnapshot(_ context.Context, _ string) error { - return errors.New("unimplemented") + return errUnimplemented } func (l *LimaWslDriver) ListSnapshots(_ context.Context) (string, error) { - return "", errors.New("unimplemented") + return "", errUnimplemented } 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/instance.go b/pkg/driverutil/instance.go index 0d68f66e1d1..e835dfa2cf5 100644 --- a/pkg/driverutil/instance.go +++ b/pkg/driverutil/instance.go @@ -4,21 +4,23 @@ package driverutil import ( + "fmt" + + "github.com/sirupsen/logrus" + "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/registry" "github.com/lima-vm/lima/pkg/store" ) -func CreateTargetDriverInstance(inst *store.Instance, sshLocalPort int) driver.Driver { +// CreateConfiguredDriver creates a driver.ConfiguredDriver for the given instance. +func CreateConfiguredDriver(inst *store.Instance, sshLocalPort int) (*driver.ConfiguredDriver, error) { limaDriver := inst.Config.VMType - if *limaDriver == limayaml.VZ { - return vz.New(inst, sshLocalPort) + _, intDriver, exists := registry.Get(*limaDriver) + if !exists { + return nil, fmt.Errorf("unknown or unsupported VM type: %s", *limaDriver) } - if *limaDriver == limayaml.WSL2 { - return wsl2.New(inst, sshLocalPort) - } - return qemu.New(inst, sshLocalPort) + + logrus.Infof("Using internal driver %q", intDriver.Info().DriverName) + return intDriver.Configure(inst, sshLocalPort), nil } diff --git a/pkg/hostagent/hostagent.go b/pkg/hostagent/hostagent.go index 8b0eceab09a..d1528859513 100644 --- a/pkg/hostagent/hostagent.go +++ b/pkg/hostagent/hostagent.go @@ -131,9 +131,13 @@ func New(instName string, stdout io.Writer, signalCh chan os.Signal, opts ...Opt } } - limaDriver := driverutil.CreateTargetDriverInstance(inst, sshLocalPort) - vSockPort := limaDriver.VSockPort() - virtioPort := limaDriver.VirtioPort() + limaDriver, err := driverutil.CreateConfiguredDriver(inst, sshLocalPort) + if err != nil { + return nil, fmt.Errorf("failed to create driver instance: %w", err) + } + + vSockPort := limaDriver.Info().VsockPort + virtioPort := limaDriver.Info().VirtioPort if err := cidata.GenerateCloudConfig(inst.Dir, instName, inst.Config); err != nil { return nil, err @@ -336,7 +340,7 @@ func (a *HostAgent) Run(ctx context.Context) error { return err } if strings.Contains(vncoptions, "to=") { - vncport, err = a.driver.GetDisplayConnection(ctx) + vncport, err = a.driver.DisplayConnection(ctx) if err != nil { return err } @@ -357,7 +361,7 @@ func (a *HostAgent) Run(ctx context.Context) error { logrus.Infof("VNC Password: `%s`", vncpwdfile) } - if a.driver.CanRunGUI() { + if a.driver.Info().CanRunGUI { go func() { err = a.startRoutinesAndWait(ctx, errCh) if err != nil { @@ -619,7 +623,7 @@ func (a *HostAgent) getOrCreateClient(ctx context.Context) (*guestagentclient.Gu } func (a *HostAgent) createConnection(ctx context.Context) (net.Conn, error) { - conn, err := a.driver.GuestAgentConn(ctx) + conn, _, err := a.driver.GuestAgentConn(ctx) // default to forwarded sock if conn == nil && err == nil { var d net.Dialer diff --git a/pkg/instance/create.go b/pkg/instance/create.go index 7b69ccc3100..5bb0912ae99 100644 --- a/pkg/instance/create.go +++ b/pkg/instance/create.go @@ -75,7 +75,10 @@ func Create(ctx context.Context, instName string, instConfig []byte, saveBrokenY return nil, err } - limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) + limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0) + if err != nil { + return nil, fmt.Errorf("failed to create driver instance: %w", err) + } if err := limaDriver.Register(ctx); err != nil { return nil, err diff --git a/pkg/instance/delete.go b/pkg/instance/delete.go index ca9a8ae3c01..9dc55f3bd1e 100644 --- a/pkg/instance/delete.go +++ b/pkg/instance/delete.go @@ -36,7 +36,10 @@ func Delete(ctx context.Context, inst *store.Instance, force bool) error { } func unregister(ctx context.Context, inst *store.Instance) error { - limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) + limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0) + if err != nil { + return fmt.Errorf("failed to create driver instance: %w", err) + } return limaDriver.Unregister(ctx) } diff --git a/pkg/instance/start.go b/pkg/instance/start.go index e465fa2755f..c318ca219a7 100644 --- a/pkg/instance/start.go +++ b/pkg/instance/start.go @@ -90,7 +90,10 @@ func Prepare(ctx context.Context, inst *store.Instance) (*Prepared, error) { return nil, err } } - limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) + limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0) + if err != nil { + return nil, fmt.Errorf("failed to create driver instance: %w", err) + } if err := limaDriver.Validate(); err != nil { return nil, err @@ -102,7 +105,7 @@ func Prepare(ctx context.Context, inst *store.Instance) (*Prepared, error) { // Check if the instance has been created (the base disk already exists) baseDisk := filepath.Join(inst.Dir, filenames.BaseDisk) - _, err := os.Stat(baseDisk) + _, err = os.Stat(baseDisk) created := err == nil kernel := filepath.Join(inst.Dir, filenames.Kernel) @@ -225,7 +228,7 @@ func Start(ctx context.Context, inst *store.Instance, limactl string, launchHost "hostagent", "--pidfile", haPIDPath, "--socket", haSockPath) - if prepared.Driver.CanRunGUI() { + if prepared.Driver.Info().CanRunGUI { args = append(args, "--run-gui") } if prepared.GuestAgent != "" { diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go index 4b269aeeaa1..c71f3ed34ab 100644 --- a/pkg/registry/registry.go +++ b/pkg/registry/registry.go @@ -14,9 +14,6 @@ import ( "github.com/sirupsen/logrus" "github.com/lima-vm/lima/pkg/driver" - "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/usrlocalsharelima" ) @@ -53,17 +50,6 @@ func List() map[string]string { vmTypes[name] = d.Path } - // This block will be removed while merging the internal driver pull request(#3693). - if len(vmTypes) == 0 { - vmTypes[limayaml.QEMU] = Internal - if vz.Enabled { - vmTypes[limayaml.VZ] = Internal - } - if wsl2.Enabled { - vmTypes[limayaml.WSL2] = Internal - } - } - return vmTypes } @@ -181,3 +167,11 @@ func registerDriverFile(path string) { func isExecutable(mode os.FileMode) bool { return mode&0o111 != 0 } + +func Register(driver driver.Driver) { + name := driver.Info().DriverName + if _, exists := internalDrivers[name]; exists { + return + } + internalDrivers[name] = driver +} diff --git a/pkg/snapshot/snapshot.go b/pkg/snapshot/snapshot.go index 9c48fc0c50a..14f7f24c30f 100644 --- a/pkg/snapshot/snapshot.go +++ b/pkg/snapshot/snapshot.go @@ -5,27 +5,42 @@ package snapshot import ( "context" + "fmt" "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(inst, 0) + limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0) + if err != nil { + return fmt.Errorf("failed to create driver instance: %w", err) + } + return limaDriver.DeleteSnapshot(ctx, tag) } func Save(ctx context.Context, inst *store.Instance, tag string) error { - limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) + limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0) + if err != nil { + return fmt.Errorf("failed to create driver instance: %w", err) + } return limaDriver.CreateSnapshot(ctx, tag) } func Load(ctx context.Context, inst *store.Instance, tag string) error { - limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) + limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0) + if err != nil { + return fmt.Errorf("failed to create driver instance: %w", err) + } return limaDriver.ApplySnapshot(ctx, tag) } func List(ctx context.Context, inst *store.Instance) (string, error) { - limaDriver := driverutil.CreateTargetDriverInstance(inst, 0) + limaDriver, err := driverutil.CreateConfiguredDriver(inst, 0) + if err != nil { + return "", fmt.Errorf("failed to create driver instance: %w", err) + } + return limaDriver.ListSnapshots(ctx) }