Skip to content

Commit f01d311

Browse files
committed
feat: add WSL2 driver
Signed-off-by: Justin Alvarez <[email protected]>
1 parent faf2aa6 commit f01d311

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1574
-139
lines changed

Diff for: Makefile

+11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ GO_BUILDTAGS += no_vz
2222
endif
2323
endif
2424

25+
ifeq ($(GOOS),windows)
26+
WINVER_MAJOR=$(shell powershell.exe "[System.Environment]::OSVersion.Version.Major")
27+
ifeq ($(WINVER_MAJOR),10)
28+
WINVER_BUILD=$(shell powershell.exe "[System.Environment]::OSVersion.Version.Build")
29+
WINVER_BUILD_HIGH_ENOUGH=$(shell powershell.exe $(WINVER_BUILD) -ge 19041)
30+
ifeq ($(WINVER_BUILD_HIGH_ENOUGH),False)
31+
GO_BUILDTAGS += no_wsl
32+
endif
33+
endif
34+
endif
35+
2536
PACKAGE := github.com/lima-vm/lima
2637

2738
VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags)

Diff for: cmd/lima-guestagent/daemon_linux.go

+25-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/gorilla/mux"
1111
"github.com/lima-vm/lima/pkg/guestagent"
1212
"github.com/lima-vm/lima/pkg/guestagent/api/server"
13+
"github.com/mdlayher/vsock"
1314
"github.com/sirupsen/logrus"
1415
"github.com/spf13/cobra"
1516
)
@@ -21,6 +22,7 @@ func newDaemonCommand() *cobra.Command {
2122
RunE: daemonAction,
2223
}
2324
daemonCommand.Flags().Duration("tick", 3*time.Second, "tick for polling events")
25+
daemonCommand.Flags().Int("vsock-port", 0, "use vsock server instead a UNIX socket")
2426
return daemonCommand
2527
}
2628

@@ -30,6 +32,10 @@ func daemonAction(cmd *cobra.Command, _ []string) error {
3032
if err != nil {
3133
return err
3234
}
35+
vSockPort, err := cmd.Flags().GetInt("vsock-port")
36+
if err != nil {
37+
return err
38+
}
3339
if tick == 0 {
3440
return errors.New("tick must be specified")
3541
}
@@ -60,13 +66,25 @@ func daemonAction(cmd *cobra.Command, _ []string) error {
6066
if err != nil {
6167
return err
6268
}
63-
l, err := net.Listen("unix", socket)
64-
if err != nil {
65-
return err
66-
}
67-
if err := os.Chmod(socket, 0777); err != nil {
68-
return err
69+
70+
var l net.Listener
71+
if vSockPort != 0 {
72+
vsockL, err := vsock.Listen(uint32(vSockPort), nil)
73+
if err != nil {
74+
return err
75+
}
76+
l = vsockL
77+
logrus.Infof("serving the guest agent on vsock port: %d", vSockPort)
78+
} else {
79+
socketL, err := net.Listen("unix", socket)
80+
if err != nil {
81+
return err
82+
}
83+
if err := os.Chmod(socket, 0777); err != nil {
84+
return err
85+
}
86+
l = socketL
87+
logrus.Infof("serving the guest agent on %q", socket)
6988
}
70-
logrus.Infof("serving the guest agent on %q", socket)
7189
return srv.Serve(l)
7290
}

Diff for: cmd/lima-guestagent/install_systemd_linux.go

+18-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
_ "embed"
55
"errors"
6+
"fmt"
67
"os"
78
"os/exec"
89
"path/filepath"
@@ -19,11 +20,16 @@ func newInstallSystemdCommand() *cobra.Command {
1920
Short: "install a systemd unit (user)",
2021
RunE: installSystemdAction,
2122
}
23+
installSystemdCommand.Flags().Int("vsock-port", 0, "use vsock server on specified port")
2224
return installSystemdCommand
2325
}
2426

25-
func installSystemdAction(_ *cobra.Command, _ []string) error {
26-
unit, err := generateSystemdUnit()
27+
func installSystemdAction(cmd *cobra.Command, _ []string) error {
28+
vsockPort, err := cmd.Flags().GetInt("vsock-port")
29+
if err != nil {
30+
return err
31+
}
32+
unit, err := generateSystemdUnit(vsockPort)
2733
if err != nil {
2834
return err
2935
}
@@ -40,11 +46,11 @@ func installSystemdAction(_ *cobra.Command, _ []string) error {
4046
return err
4147
}
4248
logrus.Infof("Written file %q", unitPath)
43-
argss := [][]string{
49+
args := [][]string{
4450
{"daemon-reload"},
4551
{"enable", "--now", "lima-guestagent.service"},
4652
}
47-
for _, args := range argss {
53+
for _, args := range args {
4854
cmd := exec.Command("systemctl", append([]string{"--system"}, args...)...)
4955
cmd.Stdout = os.Stdout
5056
cmd.Stderr = os.Stderr
@@ -60,13 +66,20 @@ func installSystemdAction(_ *cobra.Command, _ []string) error {
6066
//go:embed lima-guestagent.TEMPLATE.service
6167
var systemdUnitTemplate string
6268

63-
func generateSystemdUnit() ([]byte, error) {
69+
func generateSystemdUnit(vsockPort int) ([]byte, error) {
6470
selfExeAbs, err := os.Executable()
6571
if err != nil {
6672
return nil, err
6773
}
74+
75+
var args []string
76+
if vsockPort != 0 {
77+
args = append(args, fmt.Sprintf("--vsock-port %d", vsockPort))
78+
}
79+
6880
m := map[string]string{
6981
"Binary": selfExeAbs,
82+
"Args": strings.Join(args, " "),
7083
}
7184
return textutil.ExecuteTemplate(systemdUnitTemplate, m)
7285
}

Diff for: cmd/lima-guestagent/lima-guestagent.TEMPLATE.service

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Description=lima-guestagent
33

44
[Service]
5-
ExecStart={{.Binary}} daemon
5+
ExecStart={{.Binary}} daemon {{.Args}}
66
Type=simple
77
Restart=on-failure
88

Diff for: cmd/limactl/delete.go

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func deleteInstance(ctx context.Context, inst *store.Instance, force bool) error
6262
if err := os.RemoveAll(inst.Dir); err != nil {
6363
return fmt.Errorf("failed to remove %q: %w", inst.Dir, err)
6464
}
65+
6566
return nil
6667
}
6768

Diff for: cmd/limactl/hostagent.go

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func hostagentAction(cmd *cobra.Command, args []string) error {
9898
return err
9999
}
100100
l, err := net.Listen("unix", socket)
101+
logrus.Infof("hostagent socket created at %s", socket)
101102
if err != nil {
102103
return err
103104
}

Diff for: cmd/limactl/shell.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ func shellAction(cmd *cobra.Command, args []string) error {
184184
sshArgs = append(sshArgs, []string{
185185
"-q",
186186
"-p", strconv.Itoa(inst.SSHLocalPort),
187-
"127.0.0.1",
187+
inst.SSHAddress,
188188
"--",
189189
script,
190190
}...)

Diff for: docs/experimental.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ The following features are experimental and subject to change:
55
- `mountType: 9p`
66
- `mountType: virtiofs` on Linux
77
- `vmType: vz` and relevant configurations (`mountType: virtiofs`, `rosetta`, `[]networks.vzNAT`)
8+
- `vmType: wsl2` and relevant configurations (`mountType: wsl2`)
89
- `arch: riscv64`
910
- `video.display: vnc` and relevant configuration (`video.vnc.display`)
1011
- `mode: user-v2` in `networks.yml` and relevant configuration in `lima.yaml`

Diff for: docs/mount.md

+19
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,22 @@ mounts:
106106
- For macOS, the "virtiofs" mount type is supported only on macOS 13 or above with `vmType: vz` config. See also [`vmtype.md`](./vmtype.md).
107107
- For Linux, the "virtiofs" mount type requires the [Rust version of virtiofsd](https://gitlab.com/virtio-fs/virtiofsd).
108108
Using the version from QEMU (usually packaged as `qemu-virtiofsd`) will *not* work, as it requires root access to run.
109+
110+
### wsl2
111+
> **Warning**
112+
> "wsl2" mode is experimental
113+
114+
| :zap: Requirement | Lima >= 0.18 + (Windows >= 10 Build 19041 OR Windows 11) |
115+
| ----------------- | -------------------------------------------------------- |
116+
117+
The "wsl2" mount type relies on using WSL2's navite disk sharing, where the root disk is available by default at `/mnt/$DISK_LETTER` (e.g. `/mnt/c/`).
118+
119+
An example configuration:
120+
```yaml
121+
vmType: "wsl2"
122+
mountType: "wsl2"
123+
```
124+
125+
#### Caveats
126+
- WSL2 file permissions may not work exactly as expected when accessing files that are natively on the Windows disk ([more info](https://github.com/MicrosoftDocs/WSL/blob/mattw-wsl2-explainer/WSL/file-permissions.md))
127+
- WSL2's disk sharing system uses a 9P protocol server, making the performance similar to [Lima's 9p](#9p) mode ([more info](https://github.com/MicrosoftDocs/WSL/blob/mattw-wsl2-explainer/WSL/wsl2-architecture.md#wsl-2-architectural-flow))

Diff for: docs/vmtype.md

+33
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,36 @@ mountType: "virtiofs"
4545
kernel v6.3 and later should boot, as long as it is booted via GRUB.
4646
https://github.com/lima-vm/lima/issues/1577#issuecomment-1565625668
4747
The issue is fixed in macOS 13.5.
48+
49+
## WSL2
50+
> **Warning**
51+
> "wsl2" mode is experimental
52+
53+
| :zap: Requirement | Lima >= 0.14, macOS >= 13.0 |
54+
|-------------------|-----------------------------|
55+
56+
"wsl2" option makes use of native virtualization support provided by Windows' `wsl.exe` ([more info](https://learn.microsoft.com/en-us/windows/wsl/about)).
57+
58+
An example configuration:
59+
```yaml
60+
# Example to run Fedora using vmType: wsl2
61+
vmType: wsl2
62+
images:
63+
# Source: https://github.com/runfinch/finch-core/blob/main/Dockerfile
64+
- location: "https://deps.runfinch.com/common/x86-64/finch-rootfs-production-amd64-1690920103.tar.zst"
65+
arch: "x86_64"
66+
digest: "sha256:53f2e329b8da0f6a25e025d1f6cc262ae228402ba615ad095739b2f0ec6babc9"
67+
mountType: wsl2
68+
containerd:
69+
system: true
70+
user: false
71+
```
72+
73+
### Caveats
74+
- "wsl2" option is only supported on newer versions of Windows (roughly anything since 2019)
75+
76+
### Known Issues
77+
- "wsl2" currently doesn't support many of Lima's options. See [this file](../pkg/wsl2/wsl_driver_windows.go#35) for the latest supported options.
78+
- When running lima using "wsl2", `${LIMA_HOME}/<INSTANCE>/serial.log` will not contain kernel boot logs
79+
- WSL2 requires a `tar` formatted rootfs archive instead of a VM image
80+
- Windows doesn't ship with ssh.exe, gzip.exe, etc. which are used by Lima at various points. The easiest way around this is to run `winget install -e --id Git.MinGit` (winget is now built in to Windows as well), and add the resulting `C:\Program Files\Git\usr\bin\` directory to your path.

Diff for: examples/experimental/wsl2.yaml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This template requires Lima v0.18.0 or later and only works on Windows versions
2+
# that support WSL2 (Windows 10 Build >= 19041, all Windows 11).
3+
vmType: wsl2
4+
5+
images:
6+
# Source: https://github.com/runfinch/finch-core/blob/main/Dockerfile
7+
- location: "https://deps.runfinch.com/common/x86-64/finch-rootfs-production-amd64-1690920103.tar.zst"
8+
arch: "x86_64"
9+
digest: "sha256:53f2e329b8da0f6a25e025d1f6cc262ae228402ba615ad095739b2f0ec6babc9"
10+
11+
mountType: wsl2
12+
13+
# Use system because of an error when setting up RootlessKit (see https://github.com/microsoft/WSL/issues/8842)
14+
# There are possible workarounds, just not implemented yet.
15+
containerd:
16+
system: true
17+
user: false

Diff for: go.mod

+5-4
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ require (
5050

5151
require (
5252
github.com/Code-Hex/go-infinity-channel v1.0.0 // indirect
53-
github.com/Microsoft/go-winio v0.6.1 // indirect
53+
github.com/Microsoft/go-winio v0.6.1
5454
github.com/VividCortex/ewma v1.2.0 // indirect
5555
github.com/a8m/envsubst v1.4.2 // indirect
5656
github.com/alecthomas/participle/v2 v2.0.0 // indirect
@@ -89,7 +89,7 @@ require (
8989
github.com/mattn/go-colorable v0.1.13 // indirect
9090
github.com/mattn/go-runewidth v0.0.14 // indirect
9191
github.com/mdlayher/socket v0.4.1 // indirect
92-
github.com/mdlayher/vsock v1.2.1 // indirect
92+
github.com/mdlayher/vsock v1.2.1
9393
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
9494
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
9595
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -103,11 +103,12 @@ require (
103103
go.uber.org/atomic v1.7.0 // indirect
104104
go.uber.org/multierr v1.7.0 // indirect
105105
golang.org/x/crypto v0.12.0 // indirect
106-
golang.org/x/mod v0.10.0 // indirect
106+
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b
107+
golang.org/x/mod v0.11.0 // indirect
107108
golang.org/x/net v0.14.0 // indirect
108109
golang.org/x/oauth2 v0.8.0 // indirect
109110
golang.org/x/term v0.11.0 // indirect
110-
golang.org/x/text v0.12.0 // indirect
111+
golang.org/x/text v0.12.0
111112
golang.org/x/time v0.3.0 // indirect
112113
golang.org/x/tools v0.9.3 // indirect
113114
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect

Diff for: go.sum

+4-2
Original file line numberDiff line numberDiff line change
@@ -264,14 +264,16 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
264264
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
265265
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
266266
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
267+
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI=
268+
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
267269
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
268270
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
269271
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
270272
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
271273
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
272274
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
273-
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
274-
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
275+
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
276+
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
275277
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
276278
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
277279
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=

Diff for: pkg/cidata/cidata.TEMPLATE.d/boot/02-wsl2-setup.sh

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
# This script replaces the cloud-init functionality of creating a user and setting its SSH keys
3+
# when using a WSL2 VM.
4+
[ "$LIMA_CIDATA_VMTYPE" = "wsl2" ] || exit 0
5+
6+
# create user
7+
sudo useradd -u "${LIMA_CIDATA_UID}" "${LIMA_CIDATA_USER}" -d "${LIMA_CIDATA_HOME}"
8+
sudo mkdir "${LIMA_CIDATA_HOME}"/.ssh/
9+
sudo cp "${LIMA_CIDATA_MNT}"/ssh_authorized_keys "${LIMA_CIDATA_HOME}"/.ssh/authorized_keys
10+
sudo chown "${LIMA_CIDATA_USER}" "${LIMA_CIDATA_HOME}"/.ssh/authorized_keys
11+
12+
# add $LIMA_CIDATA_USER to sudoers
13+
echo "${LIMA_CIDATA_USER} ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/99_lima_sudoers
14+
15+
# copy some CIDATA to the hardcoded path for requirement checks (TODO: make this not hardcoded)
16+
sudo mkdir -p /mnt/lima-cidata
17+
sudo cp "${LIMA_CIDATA_MNT}"/meta-data /mnt/lima-cidata/meta-data

Diff for: pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh

+5-1
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,9 @@ else
4040
# Remove legacy systemd service
4141
rm -f "${LIMA_CIDATA_HOME}/.config/systemd/user/lima-guestagent.service"
4242

43-
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd
43+
if [ "$LIMA_CIDATA_VMTYPE" = "wsl2" ]; then
44+
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --vsock-port "${LIMA_CIDATA_VSOCK_PORT}"
45+
else
46+
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd
47+
fi
4448
fi

Diff for: pkg/cidata/cidata.TEMPLATE.d/lima.env

+2
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION=1
3939
{{- else}}
4040
LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION=
4141
{{- end}}
42+
LIMA_CIDATA_VMTYPE={{ .VMType }}
43+
LIMA_CIDATA_VSOCK_PORT={{ .VSockPort }}

0 commit comments

Comments
 (0)