Skip to content

Commit

Permalink
Merge pull request #1721 from pendo324/wsl2
Browse files Browse the repository at this point in the history
feat: add WSL2 driver
  • Loading branch information
AkihiroSuda authored Sep 7, 2023
2 parents de1b3ee + 9ed9bbc commit deed2d6
Show file tree
Hide file tree
Showing 57 changed files with 1,570 additions and 134 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ GO_BUILDTAGS += no_vz
endif
endif

ifeq ($(GOOS),windows)
WINVER_MAJOR=$(shell powershell.exe "[System.Environment]::OSVersion.Version.Major")
ifeq ($(WINVER_MAJOR),10)
WINVER_BUILD=$(shell powershell.exe "[System.Environment]::OSVersion.Version.Build")
WINVER_BUILD_HIGH_ENOUGH=$(shell powershell.exe $(WINVER_BUILD) -ge 19041)
ifeq ($(WINVER_BUILD_HIGH_ENOUGH),False)
GO_BUILDTAGS += no_wsl
endif
endif
endif

PACKAGE := github.com/lima-vm/lima

VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags)
Expand Down
32 changes: 25 additions & 7 deletions cmd/lima-guestagent/daemon_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/gorilla/mux"
"github.com/lima-vm/lima/pkg/guestagent"
"github.com/lima-vm/lima/pkg/guestagent/api/server"
"github.com/mdlayher/vsock"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
Expand All @@ -21,6 +22,7 @@ func newDaemonCommand() *cobra.Command {
RunE: daemonAction,
}
daemonCommand.Flags().Duration("tick", 3*time.Second, "tick for polling events")
daemonCommand.Flags().Int("vsock-port", 0, "use vsock server instead a UNIX socket")
return daemonCommand
}

Expand All @@ -30,6 +32,10 @@ func daemonAction(cmd *cobra.Command, _ []string) error {
if err != nil {
return err
}
vSockPort, err := cmd.Flags().GetInt("vsock-port")
if err != nil {
return err
}
if tick == 0 {
return errors.New("tick must be specified")
}
Expand Down Expand Up @@ -60,13 +66,25 @@ func daemonAction(cmd *cobra.Command, _ []string) error {
if err != nil {
return err
}
l, err := net.Listen("unix", socket)
if err != nil {
return err
}
if err := os.Chmod(socket, 0777); err != nil {
return err

var l net.Listener
if vSockPort != 0 {
vsockL, err := vsock.Listen(uint32(vSockPort), nil)
if err != nil {
return err
}
l = vsockL
logrus.Infof("serving the guest agent on vsock port: %d", vSockPort)
} else {
socketL, err := net.Listen("unix", socket)
if err != nil {
return err
}
if err := os.Chmod(socket, 0777); err != nil {
return err
}
l = socketL
logrus.Infof("serving the guest agent on %q", socket)
}
logrus.Infof("serving the guest agent on %q", socket)
return srv.Serve(l)
}
23 changes: 18 additions & 5 deletions cmd/lima-guestagent/install_systemd_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
_ "embed"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
Expand All @@ -19,11 +20,16 @@ func newInstallSystemdCommand() *cobra.Command {
Short: "install a systemd unit (user)",
RunE: installSystemdAction,
}
installSystemdCommand.Flags().Int("vsock-port", 0, "use vsock server on specified port")
return installSystemdCommand
}

func installSystemdAction(_ *cobra.Command, _ []string) error {
unit, err := generateSystemdUnit()
func installSystemdAction(cmd *cobra.Command, _ []string) error {
vsockPort, err := cmd.Flags().GetInt("vsock-port")
if err != nil {
return err
}
unit, err := generateSystemdUnit(vsockPort)
if err != nil {
return err
}
Expand All @@ -40,11 +46,11 @@ func installSystemdAction(_ *cobra.Command, _ []string) error {
return err
}
logrus.Infof("Written file %q", unitPath)
argss := [][]string{
args := [][]string{
{"daemon-reload"},
{"enable", "--now", "lima-guestagent.service"},
}
for _, args := range argss {
for _, args := range args {
cmd := exec.Command("systemctl", append([]string{"--system"}, args...)...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Expand All @@ -60,13 +66,20 @@ func installSystemdAction(_ *cobra.Command, _ []string) error {
//go:embed lima-guestagent.TEMPLATE.service
var systemdUnitTemplate string

func generateSystemdUnit() ([]byte, error) {
func generateSystemdUnit(vsockPort int) ([]byte, error) {
selfExeAbs, err := os.Executable()
if err != nil {
return nil, err
}

var args []string
if vsockPort != 0 {
args = append(args, fmt.Sprintf("--vsock-port %d", vsockPort))
}

m := map[string]string{
"Binary": selfExeAbs,
"Args": strings.Join(args, " "),
}
return textutil.ExecuteTemplate(systemdUnitTemplate, m)
}
2 changes: 1 addition & 1 deletion cmd/lima-guestagent/lima-guestagent.TEMPLATE.service
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Description=lima-guestagent

[Service]
ExecStart={{.Binary}} daemon
ExecStart={{.Binary}} daemon {{.Args}}
Type=simple
Restart=on-failure

Expand Down
1 change: 1 addition & 0 deletions cmd/limactl/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func deleteInstance(ctx context.Context, inst *store.Instance, force bool) error
if err := os.RemoveAll(inst.Dir); err != nil {
return fmt.Errorf("failed to remove %q: %w", inst.Dir, err)
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions cmd/limactl/hostagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func hostagentAction(cmd *cobra.Command, args []string) error {
return err
}
l, err := net.Listen("unix", socket)
logrus.Infof("hostagent socket created at %s", socket)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/limactl/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func shellAction(cmd *cobra.Command, args []string) error {
sshArgs = append(sshArgs, []string{
"-q",
"-p", strconv.Itoa(inst.SSHLocalPort),
"127.0.0.1",
inst.SSHAddress,
"--",
script,
}...)
Expand Down
1 change: 1 addition & 0 deletions docs/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The following features are experimental and subject to change:
- `mountType: 9p`
- `mountType: virtiofs` on Linux
- `vmType: vz` and relevant configurations (`mountType: virtiofs`, `rosetta`, `[]networks.vzNAT`)
- `vmType: wsl2` and relevant configurations (`mountType: wsl2`)
- `arch: riscv64`
- `video.display: vnc` and relevant configuration (`video.vnc.display`)
- `mode: user-v2` in `networks.yml` and relevant configuration in `lima.yaml`
Expand Down
19 changes: 19 additions & 0 deletions docs/mount.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,22 @@ mounts:
- For macOS, the "virtiofs" mount type is supported only on macOS 13 or above with `vmType: vz` config. See also [`vmtype.md`](./vmtype.md).
- For Linux, the "virtiofs" mount type requires the [Rust version of virtiofsd](https://gitlab.com/virtio-fs/virtiofsd).
Using the version from QEMU (usually packaged as `qemu-virtiofsd`) will *not* work, as it requires root access to run.

### wsl2
> **Warning**
> "wsl2" mode is experimental

| :zap: Requirement | Lima >= 0.18 + (Windows >= 10 Build 19041 OR Windows 11) |
| ----------------- | -------------------------------------------------------- |

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/`).

An example configuration:
```yaml
vmType: "wsl2"
mountType: "wsl2"
```

#### Caveats
- 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))
- 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))
33 changes: 33 additions & 0 deletions docs/vmtype.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,36 @@ mountType: "virtiofs"
kernel v6.3 and later should boot, as long as it is booted via GRUB.
https://github.com/lima-vm/lima/issues/1577#issuecomment-1565625668
The issue is fixed in macOS 13.5.

## WSL2
> **Warning**
> "wsl2" mode is experimental

| :zap: Requirement | Lima >= 0.18 + (Windows >= 10 Build 19041 OR Windows 11) |
| ----------------- | -------------------------------------------------------- |

"wsl2" option makes use of native virtualization support provided by Windows' `wsl.exe` ([more info](https://learn.microsoft.com/en-us/windows/wsl/about)).

An example configuration:
```yaml
# Example to run Fedora using vmType: wsl2
vmType: wsl2
images:
# Source: https://github.com/runfinch/finch-core/blob/main/Dockerfile
- location: "https://deps.runfinch.com/common/x86-64/finch-rootfs-production-amd64-1690920103.tar.zst"
arch: "x86_64"
digest: "sha256:53f2e329b8da0f6a25e025d1f6cc262ae228402ba615ad095739b2f0ec6babc9"
mountType: wsl2
containerd:
system: true
user: false
```

### Caveats
- "wsl2" option is only supported on newer versions of Windows (roughly anything since 2019)

### Known Issues
- "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.
- When running lima using "wsl2", `${LIMA_HOME}/<INSTANCE>/serial.log` will not contain kernel boot logs
- WSL2 requires a `tar` formatted rootfs archive instead of a VM image
- 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.
17 changes: 17 additions & 0 deletions examples/experimental/wsl2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# This template requires Lima v0.18.0 or later and only works on Windows versions
# that support WSL2 (Windows 10 Build >= 19041, all Windows 11).
vmType: wsl2

images:
# Source: https://github.com/runfinch/finch-core/blob/main/Dockerfile
- location: "https://deps.runfinch.com/common/x86-64/finch-rootfs-production-amd64-1690920103.tar.zst"
arch: "x86_64"
digest: "sha256:53f2e329b8da0f6a25e025d1f6cc262ae228402ba615ad095739b2f0ec6babc9"

mountType: wsl2

# Use system because of an error when setting up RootlessKit (see https://github.com/microsoft/WSL/issues/8842)
# There are possible workarounds, just not implemented yet.
containerd:
system: true
user: false
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ require (

require (
github.com/Code-Hex/go-infinity-channel v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/go-winio v0.6.1
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/a8m/envsubst v1.4.2 // indirect
github.com/alecthomas/participle/v2 v2.0.0 // indirect
Expand Down Expand Up @@ -89,7 +89,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect
github.com/mdlayher/vsock v1.2.1
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand All @@ -103,11 +103,12 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.14.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/term v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/text v0.12.0
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.3 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -264,14 +264,16 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand Down
17 changes: 17 additions & 0 deletions pkg/cidata/cidata.TEMPLATE.d/boot/02-wsl2-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
# This script replaces the cloud-init functionality of creating a user and setting its SSH keys
# when using a WSL2 VM.
[ "$LIMA_CIDATA_VMTYPE" = "wsl2" ] || exit 0

# create user
sudo useradd -u "${LIMA_CIDATA_UID}" "${LIMA_CIDATA_USER}" -d "${LIMA_CIDATA_HOME}"
sudo mkdir "${LIMA_CIDATA_HOME}"/.ssh/
sudo cp "${LIMA_CIDATA_MNT}"/ssh_authorized_keys "${LIMA_CIDATA_HOME}"/.ssh/authorized_keys
sudo chown "${LIMA_CIDATA_USER}" "${LIMA_CIDATA_HOME}"/.ssh/authorized_keys

# add $LIMA_CIDATA_USER to sudoers
echo "${LIMA_CIDATA_USER} ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/99_lima_sudoers

# copy some CIDATA to the hardcoded path for requirement checks (TODO: make this not hardcoded)
sudo mkdir -p /mnt/lima-cidata
sudo cp "${LIMA_CIDATA_MNT}"/meta-data /mnt/lima-cidata/meta-data
6 changes: 5 additions & 1 deletion pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,9 @@ else
# Remove legacy systemd service
rm -f "${LIMA_CIDATA_HOME}/.config/systemd/user/lima-guestagent.service"

sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd
if [ "$LIMA_CIDATA_VMTYPE" = "wsl2" ]; then
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd --vsock-port "${LIMA_CIDATA_VSOCK_PORT}"
else
sudo "${LIMA_CIDATA_GUEST_INSTALL_PREFIX}"/bin/lima-guestagent install-systemd
fi
fi
2 changes: 2 additions & 0 deletions pkg/cidata/cidata.TEMPLATE.d/lima.env
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION=1
{{- else}}
LIMA_CIDATA_SKIP_DEFAULT_DEPENDENCY_RESOLUTION=
{{- end}}
LIMA_CIDATA_VMTYPE={{ .VMType }}
LIMA_CIDATA_VSOCK_PORT={{ .VSockPort }}
Loading

0 comments on commit deed2d6

Please sign in to comment.