mirror of
https://github.com/containers/podman.git
synced 2026-02-05 06:45:31 +01:00
Fix WSL installation check on Windows
Fixes #25234 Signed-off-by: Mario Loriedo <mario.loriedo@gmail.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -652,7 +652,7 @@ localunit: test/goecho/goecho test/version/version
|
||||
UNIT=1 $(GINKGO) \
|
||||
-r \
|
||||
$(TESTFLAGS) \
|
||||
--skip-package test/e2e,pkg/bindings,hack,pkg/machine/e2e \
|
||||
--skip-package test/e2e,pkg/bindings,hack,pkg/machine/e2e,pkg/machine/wsl \
|
||||
--cover \
|
||||
--covermode atomic \
|
||||
--coverprofile coverprofile \
|
||||
|
||||
@@ -317,12 +317,12 @@ func checkAndInstallWSL(reExec bool) (bool, error) {
|
||||
|
||||
admin := HasAdminRights()
|
||||
|
||||
if !IsWSLFeatureEnabled() {
|
||||
if !wutil.IsWSLFeatureEnabled() {
|
||||
return false, attemptFeatureInstall(reExec, admin)
|
||||
}
|
||||
|
||||
skip := false
|
||||
if reExec && !admin {
|
||||
if !reExec && !admin {
|
||||
fmt.Println("Launching WSL Kernel Install...")
|
||||
if err := launchElevate(wslInstallKernel); err != nil {
|
||||
return false, err
|
||||
@@ -363,11 +363,11 @@ func attemptFeatureInstall(reExec, admin bool) error {
|
||||
message += "NOTE: A system reboot will be required as part of this process. " +
|
||||
"If you prefer, you may abort now, and perform a manual installation using the \"wsl --install\" command."
|
||||
|
||||
if reExec && MessageBox(message, "Podman Machine", false) != 1 {
|
||||
if !reExec && MessageBox(message, "Podman Machine", false) != 1 {
|
||||
return errors.New("the WSL installation aborted")
|
||||
}
|
||||
|
||||
if reExec && !admin {
|
||||
if !reExec && !admin {
|
||||
return launchElevate("install the Windows WSL Features")
|
||||
}
|
||||
|
||||
@@ -622,10 +622,6 @@ func obtainGlobalConfigLock() (*fileLock, error) {
|
||||
return lockFile(filepath.Join(lockDir, "podman-config.lck"))
|
||||
}
|
||||
|
||||
func IsWSLFeatureEnabled() bool {
|
||||
return wutil.SilentExec(wutil.FindWSL(), "--set-default-version", "2") == nil
|
||||
}
|
||||
|
||||
func isWSLRunning(dist string) (bool, error) {
|
||||
return wslCheckExists(dist, true)
|
||||
}
|
||||
|
||||
@@ -19,16 +19,26 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
wslPath string
|
||||
onceFind, onceStatus sync.Once
|
||||
wslPath string
|
||||
status wslStatus
|
||||
wslNotInstalledMessages = []string{"kernel file is not found", "The Windows Subsystem for Linux is not installed"}
|
||||
vmpDisabledMessages = []string{"enable the Virtual Machine Platform Windows feature", "Enable \"Virtual Machine Platform\""}
|
||||
wslDisabledMessages = []string{"enable the \"Windows Subsystem for Linux\" optional component"}
|
||||
)
|
||||
|
||||
type wslStatus struct {
|
||||
installed bool
|
||||
vmpFeatureEnabled bool
|
||||
wslFeatureEnabled bool
|
||||
}
|
||||
|
||||
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() {
|
||||
onceFind.Do(func() {
|
||||
var locs []string
|
||||
|
||||
// Prefer Windows App Store version
|
||||
@@ -87,24 +97,44 @@ func SilentExecCmd(command string, args ...string) *exec.Cmd {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseWSLStatus() wslStatus {
|
||||
onceStatus.Do(func() {
|
||||
status = wslStatus{
|
||||
installed: false,
|
||||
vmpFeatureEnabled: false,
|
||||
wslFeatureEnabled: false,
|
||||
}
|
||||
cmd := SilentExecCmd(FindWSL(), "--status")
|
||||
out, err := cmd.StdoutPipe()
|
||||
cmd.Stderr = nil
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = cmd.Start(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
status = matchOutputLine(out)
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func IsWSLInstalled() bool {
|
||||
cmd := SilentExecCmd(FindWSL(), "--status")
|
||||
out, err := cmd.StdoutPipe()
|
||||
cmd.Stderr = nil
|
||||
if err != nil {
|
||||
status := parseWSLStatus()
|
||||
return status.installed && status.vmpFeatureEnabled
|
||||
}
|
||||
|
||||
func IsWSLFeatureEnabled() bool {
|
||||
if SilentExec(FindWSL(), "--set-default-version", "2") != nil {
|
||||
return false
|
||||
}
|
||||
if err = cmd.Start(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
kernelNotFound := matchOutputLine(out, "kernel file is not found")
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return !kernelNotFound
|
||||
status := parseWSLStatus()
|
||||
return status.vmpFeatureEnabled
|
||||
}
|
||||
|
||||
func IsWSLStoreVersionInstalled() bool {
|
||||
@@ -118,13 +148,30 @@ func IsWSLStoreVersionInstalled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func matchOutputLine(output io.ReadCloser, match string) bool {
|
||||
func matchOutputLine(output io.ReadCloser) wslStatus {
|
||||
status := wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: true,
|
||||
wslFeatureEnabled: true,
|
||||
}
|
||||
scanner := bufio.NewScanner(transform.NewReader(output, unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder()))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, match) {
|
||||
return true
|
||||
for _, match := range wslNotInstalledMessages {
|
||||
if strings.Contains(line, match) {
|
||||
status.installed = false
|
||||
}
|
||||
}
|
||||
for _, match := range vmpDisabledMessages {
|
||||
if strings.Contains(line, match) {
|
||||
status.vmpFeatureEnabled = false
|
||||
}
|
||||
}
|
||||
for _, match := range wslDisabledMessages {
|
||||
if strings.Contains(line, match) {
|
||||
status.wslFeatureEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
return status
|
||||
}
|
||||
|
||||
145
pkg/machine/wsl/wutil/wutil_test.go
Normal file
145
pkg/machine/wsl/wutil/wutil_test.go
Normal file
@@ -0,0 +1,145 @@
|
||||
//go:build windows
|
||||
|
||||
package wutil
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
WSL1InstalledWithWSLAndVMPEnabled = `Default Version: 1`
|
||||
WSL2InstalledWithWSLAndVMPEnabled = `Default Version: 2`
|
||||
WSL1NotInstalled = `Default Version: 1
|
||||
|
||||
The Windows Subsystem for Linux kernel can be manually updated with 'wsl --update', but automatic updates cannot occur due to your system settings.
|
||||
To receive automatic kernel updates, please enable the Windows Update setting: 'Receive updates for other Microsoft products when you update Windows'.
|
||||
For more information please visit https://aka.ms/wsl2kernel.
|
||||
|
||||
The WSL 2 kernel file is not found. To update or restore the kernel please run 'wsl --update'.`
|
||||
WSL2NotInstalled = `The Windows Subsystem for Linux is not installed. You can install by running 'wsl.exe --install'.
|
||||
For more information please visit https://aka.ms/wslinstall`
|
||||
WSL2InstalledWithWSLDisabled = `Default Version: 2
|
||||
WSL1 is not supported with your current machine configuration.
|
||||
Please enable the "Windows Subsystem for Linux" optional component to use WSL1.`
|
||||
WSL2InstalledWithVMPDisabled = `Default Version: 2
|
||||
WSL2 is not supported with your current machine configuration.
|
||||
Please enable the "Virtual Machine Platform" optional component and ensure virtualization is enabled in the BIOS.
|
||||
Enable "Virtual Machine Platform" by running: wsl.exe --install --no-distribution
|
||||
For information please visit https://aka.ms/enablevirtualization`
|
||||
WSL2InstalledWithWSLAndVMPDisabled = `Default Version: 2
|
||||
WSL1 is not supported with your current machine configuration.
|
||||
Please enable the "Windows Subsystem for Linux" optional component to use WSL1.
|
||||
WSL2 is not supported with your current machine configuration.
|
||||
Please enable the "Virtual Machine Platform" optional component and ensure virtualization is enabled in the BIOS.
|
||||
Enable "Virtual Machine Platform" by running: wsl.exe --install --no-distribution
|
||||
For information please visit https://aka.ms/enablevirtualization`
|
||||
WSL1InstalledWithVMPDisabled = `Default Version: 1
|
||||
Please enable the Virtual Machine Platform Windows feature and ensure virtualization is enabled in the BIOS.
|
||||
For information please visit https://aka.ms/enablevirtualization`
|
||||
WSL1InstalledWithWSLDisabled = `Default Version: 1
|
||||
WSL1 is not supported with your current machine configuration.
|
||||
Please enable the "Windows Subsystem for Linux" optional component to use WSL1.`
|
||||
)
|
||||
|
||||
func TestMatchOutputLine(t *testing.T) {
|
||||
tests := []struct {
|
||||
winVariant string
|
||||
statusOutput string
|
||||
want wslStatus
|
||||
}{
|
||||
{
|
||||
"WSL1 configured and both Virtual Machine Platform enabled and Windows Subsystem for Linux are enabled",
|
||||
WSL1InstalledWithWSLAndVMPEnabled,
|
||||
wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: true,
|
||||
wslFeatureEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL2 configured and both Virtual Machine Platform enabled and Windows Subsystem for Linux enabled",
|
||||
WSL2InstalledWithWSLAndVMPEnabled,
|
||||
wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: true,
|
||||
wslFeatureEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL not installed (was previously configured as version 1)",
|
||||
WSL1NotInstalled,
|
||||
wslStatus{
|
||||
installed: false,
|
||||
vmpFeatureEnabled: true,
|
||||
wslFeatureEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL not installed (was previously configured as version 2)",
|
||||
WSL2NotInstalled,
|
||||
wslStatus{
|
||||
installed: false,
|
||||
vmpFeatureEnabled: true,
|
||||
wslFeatureEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL2 configured and Virtual Machine Platform is enabled but Windows Subsystem for Linux is disabled",
|
||||
WSL2InstalledWithWSLDisabled,
|
||||
wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: true,
|
||||
wslFeatureEnabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL2 configured and Virtual Machine Platform is disabled but Windows Subsystem for Linux is enabled",
|
||||
WSL2InstalledWithVMPDisabled,
|
||||
wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: false,
|
||||
wslFeatureEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL2 configured and both Virtual Machine Platform and Windows Subsystem for Linux are disabled",
|
||||
WSL2InstalledWithWSLAndVMPDisabled,
|
||||
wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: false,
|
||||
wslFeatureEnabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL1 configured and Virtual Machine Platform is disabled but Windows Subsystem for Linux is enabled",
|
||||
WSL1InstalledWithVMPDisabled,
|
||||
wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: false,
|
||||
wslFeatureEnabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"WSL1 configured and Virtual Machine Platform is enabled but Windows Subsystem for Linux is disabled",
|
||||
WSL1InstalledWithWSLDisabled,
|
||||
wslStatus{
|
||||
installed: true,
|
||||
vmpFeatureEnabled: true,
|
||||
wslFeatureEnabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.winVariant, func(t *testing.T) {
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewEncoder()
|
||||
encodedOutput, err := encoder.String(tt.statusOutput)
|
||||
assert.Nil(t, err)
|
||||
reader := io.NopCloser(strings.NewReader(encodedOutput))
|
||||
assert.Equal(t, tt.want, matchOutputLine(reader))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user