mirror of
https://github.com/containers/podman.git
synced 2026-11-08 09:02:51 -05:00
Require WSL version 2.5.1 or later
Podman machines v6.x don't start on versions of WSL earlier than v2.5.1
because of their old Kernels with cgroupv1 support.
Signed-off-by: Mario Loriedo <mario.loriedo@gmail.com>
(cherry picked from commit f999886ce2)
This commit is contained in:
1 parent
375bd63144
commit
421a07d834
6 files changed
+149
-6
No files matched your search
+1
-1
@@ -115,7 +115,7 @@ the following command, from a PowerShell or Windows Command Prompt terminal in
|
||||
wsl --install
|
||||
```
|
||||
|
||||
For more information refer to
|
||||
Podman requires WSL v2.5.1 or later. For more information refer to
|
||||
[the official documentation](https://learn.microsoft.com/en-us/windows/wsl/).
|
||||
|
||||
#### Hyper-V
|
||||
|
||||
@@ -53,6 +53,8 @@ later. Internally, WSL and Hyper-V use virtualization, so your system must
|
||||
support and have hardware virtualization enabled. If you are running Windows on
|
||||
a VM, you must have a VM that supports nested virtualization.
|
||||
|
||||
WSL v2.5.1 or later is required.
|
||||
|
||||
Hyper-V is only available on Windows Enterprise, Pro, or Education editions (not
|
||||
Home). The command to initialize the first Hyper-V Podman machine, and the command
|
||||
to remove the last one, both require administrator privileges because they create
|
||||
|
||||
@@ -119,6 +119,22 @@ func provisionWSLDist(name string, imagePath string, prompt string) (string, err
|
||||
return dist, nil
|
||||
}
|
||||
|
||||
func verifyWSLVersion(rootful bool) error {
|
||||
// WSL v2.5.1 or later is required. Earlier versions will fail to
|
||||
// start Podman machines because they supported cgroupv1.
|
||||
if !wutil.WSLVersionAtLeast(2, 5, 1) {
|
||||
return fmt.Errorf("WSL version 2.5.1 or later is required to run Podman. Please upgrade WSL with: wsl --update")
|
||||
}
|
||||
|
||||
// WSL v2.7.5 or later is required in rootful mode. Earlier versions
|
||||
// don't support nftables:
|
||||
// https://github.com/podman-container-tools/podman/issues/25201
|
||||
if rootful && !wutil.WSLVersionAtLeast(2, 7, 5) {
|
||||
return fmt.Errorf("WSL version 2.7.5 or later is required to run Podman in rootful mode. Please use rootless mode or upgrade WSL with: wsl --update")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createKeys(mc *vmconfigs.MachineConfig, dist string) error {
|
||||
user := mc.SSH.RemoteUsername
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ func (w WSLStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.MachineConf
|
||||
|
||||
_ = setupWslProxyEnv()
|
||||
|
||||
if err = verifyWSLVersion(mc.HostUser.Rootful); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.UserModeNetworking {
|
||||
if err = verifyWSLUserModeCompat(); err != nil {
|
||||
return err
|
||||
@@ -134,6 +138,9 @@ func (w WSLStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, opts define.Se
|
||||
}
|
||||
|
||||
if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful {
|
||||
if err = verifyWSLVersion(*opts.Rootful); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mc.SetRootful(*opts.Rootful); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -19,6 +21,8 @@ import (
|
||||
var (
|
||||
onceStatus sync.Once
|
||||
status wslStatus
|
||||
onceVersion sync.Once
|
||||
version wslVersion
|
||||
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"}
|
||||
@@ -30,6 +34,12 @@ type wslStatus struct {
|
||||
wslFeatureEnabled bool
|
||||
}
|
||||
|
||||
type wslVersion struct {
|
||||
val [3]int
|
||||
cmdErr error
|
||||
parseErr error
|
||||
}
|
||||
|
||||
func NewWSLCommand(arg ...string) *exec.Cmd {
|
||||
cmd := exec.Command("wsl", arg...)
|
||||
cmd.Env = append(os.Environ(), "WSL_UTF8=1")
|
||||
@@ -88,14 +98,69 @@ func IsWSLInstalled() bool {
|
||||
}
|
||||
|
||||
func IsWSLStoreVersionInstalled() bool {
|
||||
cmd := SilentExecCmd("--version")
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
if err := cmd.Run(); err != nil {
|
||||
// The Windows built-in version of WSL returns an error when running
|
||||
// `wsl --version`. Recent versions of WSL instead, are distributed
|
||||
// via the Microsoft store and supports `wsl --version`.
|
||||
return parseWSLVersion().cmdErr == nil
|
||||
}
|
||||
|
||||
// WSLVersionAtLeast returns true if the installed WSL version is >= major.minor.patch
|
||||
// or if it fails to parse the wsl --version output. It returns false otherwise and if
|
||||
// the `wsl --version` command has failed.
|
||||
func WSLVersionAtLeast(major, minor, patch int) bool {
|
||||
v := parseWSLVersion()
|
||||
// When the `wsl --version` command fails we return false
|
||||
// because it's older WSL versions behavior.
|
||||
if v.cmdErr != nil {
|
||||
logrus.Debugf("command error while checking the WSL version: %v", v.cmdErr)
|
||||
return false
|
||||
}
|
||||
// When there is a parsing error we assume that's a WSL future version
|
||||
// where the output format has been changed.
|
||||
if v.parseErr != nil {
|
||||
logrus.Debugf("parsing error while checking the WSL version: %v", v.parseErr)
|
||||
return true
|
||||
}
|
||||
return v.val[0] > major ||
|
||||
(v.val[0] == major && v.val[1] > minor) ||
|
||||
(v.val[0] == major && v.val[1] == minor && v.val[2] >= patch)
|
||||
}
|
||||
|
||||
return true
|
||||
// parseWSLVersion returns the WSL version as [major, minor, patch] in the
|
||||
// returned wslVersion struct.
|
||||
// The returned `wslVersion.cmdErr` is non nil if the `wsl --version` command fails.
|
||||
// The returned `wslVersion.parseErr` is non nil if the major.minor.patch string
|
||||
// cannot found in the returned output.
|
||||
func parseWSLVersion() wslVersion {
|
||||
onceVersion.Do(func() {
|
||||
cmd := SilentExecCmd("--version")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
version = wslVersion{cmdErr: fmt.Errorf("running wsl --version failed: %w", err)}
|
||||
return
|
||||
}
|
||||
version = versionFromLocalizedOutput(string(out))
|
||||
})
|
||||
return version
|
||||
}
|
||||
|
||||
// versionFromLocalizedOutput returns the WSL version from the output of "wsl --version".
|
||||
// The output labels are localized, so the version is the first version number
|
||||
// in the output, that is the WSL package version in all languages.
|
||||
func versionFromLocalizedOutput(out string) wslVersion {
|
||||
v := wslVersion{}
|
||||
versionRegexp := regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)`)
|
||||
m := versionRegexp.FindStringSubmatch(out)
|
||||
if m == nil {
|
||||
return wslVersion{parseErr: fmt.Errorf("could not parse WSL version from %q", out)}
|
||||
}
|
||||
for i := range v.val {
|
||||
var err error
|
||||
if v.val[i], err = strconv.Atoi(m[i+1]); err != nil {
|
||||
return wslVersion{parseErr: fmt.Errorf("could not parse the WSL version digit %q", m[i+1])}
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func matchOutputLine(output io.ReadCloser) (wslStatus, error) {
|
||||
|
||||
@@ -150,3 +150,56 @@ func TestNewWSLCommand(t *testing.T) {
|
||||
assert.Equal(t, []string{"--status"}, cmd.Args[1:])
|
||||
assert.Contains(t, cmd.Env, "WSL_UTF8=1")
|
||||
}
|
||||
|
||||
func TestVersionFromLocalizedOutput(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
output string
|
||||
wantVersionVal [3]int
|
||||
wantParseErr bool
|
||||
}{
|
||||
{
|
||||
"English",
|
||||
"WSL version: 2.6.1.0\nKernel version: 6.6.87.2-1\nWSLg version: 1.0.66\nWindows version: 10.0.26100.4652\n",
|
||||
[3]int{2, 6, 1},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"German",
|
||||
"WSL-Version: 2.5.10.0\nKernelversion: 6.6.87.2-1\nWSLg-Version: 1.0.66\nWindows-Version: 10.0.26100.4652\n",
|
||||
[3]int{2, 5, 10},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Japanese",
|
||||
"WSL バージョン: 3.0.3.0\nカーネル バージョン: 6.6.87.2-1\nWSLg バージョン: 1.0.66\nWindows バージョン: 10.0.26100.4652\n",
|
||||
[3]int{3, 0, 3},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"CRLF line endings",
|
||||
"WSL version: 2.5.1.0\r\nKernel version: 6.6.87.2-1\r\n",
|
||||
[3]int{2, 5, 1},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"No version",
|
||||
"Invalid command line option: --version\n",
|
||||
[3]int{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Empty",
|
||||
"",
|
||||
[3]int{},
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
v := versionFromLocalizedOutput(tt.output)
|
||||
assert.Equal(t, tt.wantVersionVal, v.val)
|
||||
assert.Equal(t, tt.wantParseErr, v.parseErr != nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user