From 889454104e9fb5f3d15ba4bd3a15ad716c7cd22f Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Tue, 13 Feb 2024 15:40:04 -0600 Subject: [PATCH 1/3] Turn WSL machine tests back on [NO NEW TESTS NEEDED] Signed-off-by: Brent Baude --- .cirrus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index a270b7def0..6d6c979f9c 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -795,8 +795,8 @@ podman_machine_windows_task: platform: windows env: *winenv matrix: - #- env: - # TEST_FLAVOR: "machine-wsl" + - env: + TEST_FLAVOR: "machine-wsl" - env: TEST_FLAVOR: "machine-hyperv" clone_script: *winclone From 4fffa78eec4ec7ab7381b1c7ad9d5c2bd315ac97 Mon Sep 17 00:00:00 2001 From: "Jason T. Greene" Date: Wed, 14 Feb 2024 16:53:30 -0600 Subject: [PATCH 2/3] Manually discover wsl.exe location Works around a problem where recent Windows updates do not always redirect the system wsl to the app store wsl version correctly. Signed-off-by: Jason T. Greene --- cmd/podman-wslkerninst/main.go | 2 +- pkg/machine/wsl/machine.go | 24 +++++++------- pkg/machine/wsl/stubber.go | 7 ++-- pkg/machine/wsl/wutil/wutil.go | 59 ++++++++++++++++++++++++++++++++-- 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/cmd/podman-wslkerninst/main.go b/cmd/podman-wslkerninst/main.go index 0259ef34e2..a12306ba81 100644 --- a/cmd/podman-wslkerninst/main.go +++ b/cmd/podman-wslkerninst/main.go @@ -48,7 +48,7 @@ func installWslKernel() error { ) backoff := 500 * time.Millisecond for i := 1; i < 6; i++ { - err = wutil.SilentExec("wsl", "--update") + err = wutil.SilentExec(wutil.FindWSL(), "--update") if err == nil { break } diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go index 01eb0df2de..e9196f28a9 100644 --- a/pkg/machine/wsl/machine.go +++ b/pkg/machine/wsl/machine.go @@ -90,7 +90,7 @@ func provisionWSLDist(name string, imagePath string, prompt string) (string, err dist := machine.ToDist(name) fmt.Println(prompt) - if err = runCmdPassThrough("wsl", "--import", dist, distTarget, imagePath, "--version", "2"); err != nil { + if err = runCmdPassThrough(wutil.FindWSL(), "--import", dist, distTarget, imagePath, "--version", "2"); err != nil { return "", fmt.Errorf("the WSL import of guest OS failed: %w", err) } @@ -446,7 +446,7 @@ func installWslKernel() error { backoff := 500 * time.Millisecond for i := 0; i < 5; i++ { - err = runCmdPassThroughTee(log, "wsl", "--update") + err = runCmdPassThroughTee(log, wutil.FindWSL(), "--update") if err == nil { break } @@ -556,17 +556,17 @@ func withUser(s string, user string) string { func wslInvoke(dist string, arg ...string) error { newArgs := []string{"-u", "root", "-d", dist} newArgs = append(newArgs, arg...) - return runCmdPassThrough("wsl", newArgs...) + return runCmdPassThrough(wutil.FindWSL(), newArgs...) } func wslPipe(input string, dist string, arg ...string) error { newArgs := []string{"-u", "root", "-d", dist} newArgs = append(newArgs, arg...) - return pipeCmdPassThrough("wsl", input, newArgs...) + return pipeCmdPassThrough(wutil.FindWSL(), input, newArgs...) } func wslCreateKeys(identityPath string, dist string) (string, error) { - return machine.CreateSSHKeysPrefix(identityPath, true, true, "wsl", "-u", "root", "-d", dist) + return machine.CreateSSHKeysPrefix(identityPath, true, true, wutil.FindWSL(), "-u", "root", "-d", dist) } func runCmdPassThrough(name string, arg ...string) error { @@ -631,7 +631,7 @@ func obtainGlobalConfigLock() (*fileLock, error) { } func IsWSLFeatureEnabled() bool { - return wutil.SilentExec("wsl", "--set-default-version", "2") == nil + return wutil.SilentExec(wutil.FindWSL(), "--set-default-version", "2") == nil } func isWSLRunning(dist string) (bool, error) { @@ -657,7 +657,7 @@ func getAllWSLDistros(running bool) (map[string]struct{}, error) { if running { args = append(args, "--running") } - cmd := exec.Command("wsl", args...) + cmd := exec.Command(wutil.FindWSL(), args...) out, err := cmd.StdoutPipe() if err != nil { return nil, err @@ -681,7 +681,7 @@ func getAllWSLDistros(running bool) (map[string]struct{}, error) { } func isSystemdRunning(dist string) (bool, error) { - cmd := exec.Command("wsl", "-u", "root", "-d", dist, "sh") + cmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "sh") cmd.Stdin = strings.NewReader(sysdpid + "\necho $SYSDPID\n") out, err := cmd.StdoutPipe() if err != nil { @@ -706,12 +706,12 @@ func isSystemdRunning(dist string) (bool, error) { } func terminateDist(dist string) error { - cmd := exec.Command("wsl", "--terminate", dist) + cmd := exec.Command(wutil.FindWSL(), "--terminate", dist) return cmd.Run() } func unregisterDist(dist string) error { - cmd := exec.Command("wsl", "--unregister", dist) + cmd := exec.Command(wutil.FindWSL(), "--unregister", dist) return cmd.Run() } @@ -753,7 +753,7 @@ func getCPUs(name string) (uint64, error) { if run, _ := isWSLRunning(dist); !run { return 0, nil } - cmd := exec.Command("wsl", "-u", "root", "-d", dist, "nproc") + cmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "nproc") out, err := cmd.StdoutPipe() if err != nil { return 0, err @@ -777,7 +777,7 @@ func getMem(name string) (uint64, error) { if run, _ := isWSLRunning(dist); !run { return 0, nil } - cmd := exec.Command("wsl", "-u", "root", "-d", dist, "cat", "/proc/meminfo") + cmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "cat", "/proc/meminfo") out, err := cmd.StdoutPipe() if err != nil { return 0, err diff --git a/pkg/machine/wsl/stubber.go b/pkg/machine/wsl/stubber.go index 0ff1879f03..1af182e1c0 100644 --- a/pkg/machine/wsl/stubber.go +++ b/pkg/machine/wsl/stubber.go @@ -12,6 +12,7 @@ import ( "github.com/containers/podman/v5/pkg/machine/ocipull" "github.com/containers/podman/v5/pkg/machine/stdpull" + "github.com/containers/podman/v5/pkg/machine/wsl/wutil" gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/podman/v5/pkg/machine" @@ -105,7 +106,7 @@ func (w WSLStubber) Remove(mc *vmconfigs.MachineConfig) ([]string, func() error, // below if we wanted to hard error on the wsl unregister // of the vm wslRemoveFunc := func() error { - if err := runCmdPassThrough("wsl", "--unregister", machine.ToDist(mc.Name)); err != nil { + if err := runCmdPassThrough(wutil.FindWSL(), "--unregister", machine.ToDist(mc.Name)); err != nil { logrus.Error(err) } return machine.ReleaseMachinePort(mc.SSH.Port) @@ -266,13 +267,13 @@ func (w WSLStubber) StopVM(mc *vmconfigs.MachineConfig, hardStop bool) error { fmt.Fprintf(os.Stderr, "Could not stop API forwarding service (win-sshproxy.exe): %s\n", err.Error()) } - cmd := exec.Command("wsl", "-u", "root", "-d", dist, "sh") + cmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "sh") cmd.Stdin = strings.NewReader(waitTerm) if err = cmd.Start(); err != nil { return fmt.Errorf("executing wait command: %w", err) } - exitCmd := exec.Command("wsl", "-u", "root", "-d", dist, "/usr/local/bin/enterns", "systemctl", "exit", "0") + exitCmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "/usr/local/bin/enterns", "systemctl", "exit", "0") if err = exitCmd.Run(); err != nil { return fmt.Errorf("stopping sysd: %w", err) } diff --git a/pkg/machine/wsl/wutil/wutil.go b/pkg/machine/wsl/wutil/wutil.go index a8c67dcb98..81320be36c 100644 --- a/pkg/machine/wsl/wutil/wutil.go +++ b/pkg/machine/wsl/wutil/wutil.go @@ -5,14 +5,69 @@ package wutil import ( "bufio" "io" + "os" "os/exec" + "path/filepath" "strings" + "sync" "syscall" "golang.org/x/text/encoding/unicode" "golang.org/x/text/transform" ) +var ( + once sync.Once + wslPath string +) + +func FindWSL() string { + // At the time of this writing, a defect appeared in the OS preinstalled WSL executable + // where it no longer reliably locates the preferred Windows App Store variant. + // + // Manually discover (and cache) the wsl.exe location to bypass the problem + once.Do(func() { + var locs []string + + // Prefer Windows App Store version + if localapp := getLocalAppData(); localapp != "" { + locs = append(locs, filepath.Join(localapp, "Microsoft", "WindowsApps", "wsl.exe")) + } + + // Otherwise, the common location for the legacy system version + root := os.Getenv("SystemRoot") + if root == "" { + root = `C:\Windows` + } + locs = append(locs, filepath.Join(root, "System32", "wsl.exe")) + + for _, loc := range locs { + if _, err := os.Stat(loc); err == nil { + wslPath = loc + return + } + } + + // Hope for the best + wslPath = "wsl" + }) + + return wslPath +} + +func getLocalAppData() string { + localapp := os.Getenv("LOCALAPPDATA") + if localapp != "" { + return localapp + } + + if user := os.Getenv("USERPROFILE"); user != "" { + return filepath.Join(user, "AppData", "Local") + } + + return localapp +} + func SilentExec(command string, args ...string) error { cmd := exec.Command(command, args...) cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000} @@ -28,7 +83,7 @@ func SilentExecCmd(command string, args ...string) *exec.Cmd { } func IsWSLInstalled() bool { - cmd := SilentExecCmd("wsl", "--status") + cmd := SilentExecCmd(FindWSL(), "--status") out, err := cmd.StdoutPipe() cmd.Stderr = nil if err != nil { @@ -48,7 +103,7 @@ func IsWSLInstalled() bool { } func IsWSLStoreVersionInstalled() bool { - cmd := SilentExecCmd("wsl", "--version") + cmd := SilentExecCmd(FindWSL(), "--version") cmd.Stdout = nil cmd.Stderr = nil if err := cmd.Run(); err != nil { From f036476cfa18aadcd934945f74beaac0145e78e4 Mon Sep 17 00:00:00 2001 From: "Jason T. Greene" Date: Wed, 14 Feb 2024 17:22:04 -0600 Subject: [PATCH 3/3] fix usermode test Signed-off-by: Jason T. Greene --- cmd/podman/machine/inspect.go | 2 +- pkg/machine/e2e/init_windows_test.go | 23 ++++++++++++++++------- pkg/machine/e2e/machine_test.go | 1 + pkg/machine/shim/host.go | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/cmd/podman/machine/inspect.go b/cmd/podman/machine/inspect.go index 89a1d4503a..81699268d0 100644 --- a/cmd/podman/machine/inspect.go +++ b/cmd/podman/machine/inspect.go @@ -89,7 +89,7 @@ func inspect(cmd *cobra.Command, args []string) error { Resources: mc.Resources, SSHConfig: mc.SSH, State: state, - UserModeNetworking: false, + UserModeNetworking: provider.UserModeNetworkEnabled(mc), // TODO I think this should be the HostUser Rootful: mc.HostUser.Rootful, } diff --git a/pkg/machine/e2e/init_windows_test.go b/pkg/machine/e2e/init_windows_test.go index e19b4a53b0..92acd7f8d4 100644 --- a/pkg/machine/e2e/init_windows_test.go +++ b/pkg/machine/e2e/init_windows_test.go @@ -8,6 +8,7 @@ import ( "github.com/Microsoft/go-winio/vhd" "github.com/containers/libhvee/pkg/hypervctl" "github.com/containers/podman/v5/pkg/machine/define" + "github.com/containers/podman/v5/pkg/machine/wsl/wutil" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" @@ -36,6 +37,18 @@ var _ = Describe("podman machine init - windows only", func() { Expect(err).ToNot(HaveOccurred()) Expect(session).To(Exit(0)) + defer func() { + _, err := runSystemCommand(wutil.FindWSL(), []string{"--terminate", "podman-net-usermode"}, defaultTimeout, true) + if err != nil { + fmt.Println("unable to terminate podman-net-usermode") + } + + _, err = runSystemCommand(wutil.FindWSL(), []string{"--unregister", "podman-net-usermode"}, defaultTimeout, true) + if err != nil { + fmt.Println("unable to unregister podman-net-usermode") + } + }() + inspect := new(inspectMachine) inspect = inspect.withFormat("{{.UserModeNetworking}}") inspectSession, err := mb.setName(name).setCmd(inspect).run() @@ -81,10 +94,6 @@ var _ = Describe("podman machine init - windows only", func() { It("init should not overwrite existing WSL vms", func() { skipIfNotVmtype(define.WSLVirt, "WSL test only") - var ( - wsl string = "wsl" - ) - name := randomString() distName := fmt.Sprintf("podman-%s", name) exportedPath := filepath.Join(testDir, "bogus.tar") @@ -102,17 +111,17 @@ var _ = Describe("podman machine init - windows only", func() { // a vm outside the context of podman-machine and also // so we dont have to download a distribution from microsoft // servers - exportSession, err := runSystemCommand(wsl, []string{"--export", "podman-foobarexport", exportedPath}, defaultTimeout, true) + exportSession, err := runSystemCommand(wutil.FindWSL(), []string{"--export", "podman-foobarexport", exportedPath}, defaultTimeout, true) Expect(err).ToNot(HaveOccurred()) Expect(exportSession).To(Exit(0)) // importing the machine and creating a vm - importSession, err := runSystemCommand(wsl, []string{"--import", distName, distrDir, exportedPath}, defaultTimeout, true) + importSession, err := runSystemCommand(wutil.FindWSL(), []string{"--import", distName, distrDir, exportedPath}, defaultTimeout, true) Expect(err).ToNot(HaveOccurred()) Expect(importSession).To(Exit(0)) defer func() { - _, err := runSystemCommand(wsl, []string{"--unregister", distName}, defaultTimeout, true) + _, err := runSystemCommand(wutil.FindWSL(), []string{"--unregister", distName}, defaultTimeout, true) if err != nil { fmt.Println("unable to remove bogus wsl instance") } diff --git a/pkg/machine/e2e/machine_test.go b/pkg/machine/e2e/machine_test.go index f7af93ad17..35267ebe6d 100644 --- a/pkg/machine/e2e/machine_test.go +++ b/pkg/machine/e2e/machine_test.go @@ -201,6 +201,7 @@ func teardown(origHomeDir string, testDir string, mb *machineTestBuilder) { GinkgoWriter.Printf("error occurred rm'ing machine: %q\n", err) } } + if err := utils.GuardedRemoveAll(testDir); err != nil { Fail(fmt.Sprintf("failed to remove test dir: %q", err)) } diff --git a/pkg/machine/shim/host.go b/pkg/machine/shim/host.go index ea62c5d90b..f4de604711 100644 --- a/pkg/machine/shim/host.go +++ b/pkg/machine/shim/host.go @@ -50,7 +50,7 @@ func List(vmstubbers []vmconfigs.VMProvider, _ machine.ListOptions) ([]*machine. Port: mc.SSH.Port, RemoteUsername: mc.SSH.RemoteUsername, IdentityPath: mc.SSH.IdentityPath, - UserModeNetworking: false, // TODO Need to plumb this for WSL + UserModeNetworking: s.UserModeNetworkEnabled(mc), } lrs = append(lrs, &lr) }