wsl - wip

Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
Brent Baude
2024-02-01 09:00:36 -06:00
committed by Jason T. Greene
parent 7c7b4430a5
commit d7cb66492b
20 changed files with 891 additions and 1070 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/containers/podman/v5/pkg/machine/applehv/vfkit" "github.com/containers/podman/v5/pkg/machine/applehv/vfkit"
"github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/ignition" "github.com/containers/podman/v5/pkg/machine/ignition"
"github.com/containers/podman/v5/pkg/machine/shim/diskpull"
"github.com/containers/podman/v5/pkg/machine/sockets" "github.com/containers/podman/v5/pkg/machine/sockets"
"github.com/containers/podman/v5/pkg/machine/vmconfigs" "github.com/containers/podman/v5/pkg/machine/vmconfigs"
"github.com/containers/podman/v5/utils" "github.com/containers/podman/v5/utils"
@ -38,6 +39,10 @@ type AppleHVStubber struct {
vmconfigs.AppleHVConfig vmconfigs.AppleHVConfig
} }
func (a AppleHVStubber) UserModeNetworkEnabled(_ *vmconfigs.MachineConfig) bool {
return true
}
func (a AppleHVStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.MachineConfig, ignBuilder *ignition.IgnitionBuilder) error { func (a AppleHVStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.MachineConfig, ignBuilder *ignition.IgnitionBuilder) error {
mc.AppleHypervisor = new(vmconfigs.AppleHVConfig) mc.AppleHypervisor = new(vmconfigs.AppleHVConfig)
mc.AppleHypervisor.Vfkit = vfkit.VfkitHelper{} mc.AppleHypervisor.Vfkit = vfkit.VfkitHelper{}
@ -317,3 +322,7 @@ func (a AppleHVStubber) PrepareIgnition(_ *vmconfigs.MachineConfig, _ *ignition.
func (a AppleHVStubber) PostStartNetworking(mc *vmconfigs.MachineConfig) error { func (a AppleHVStubber) PostStartNetworking(mc *vmconfigs.MachineConfig) error {
return nil return nil
} }
func (a AppleHVStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, a.VMType(), mc.Name)
}

View File

@ -10,8 +10,10 @@ var (
) )
type CreateVMOpts struct { type CreateVMOpts struct {
Name string Name string
Dirs *MachineDirs Dirs *MachineDirs
ReExec bool
UserModeNetworking bool
} }
type MachineDirs struct { type MachineDirs struct {

View File

@ -2,6 +2,7 @@ package e2e_test
import ( import (
"fmt" "fmt"
"github.com/containers/podman/v4/pkg/machine/wsl"
"io" "io"
url2 "net/url" url2 "net/url"
"os" "os"
@ -61,9 +62,20 @@ var _ = BeforeSuite(func() {
downloadLocation := os.Getenv("MACHINE_IMAGE") downloadLocation := os.Getenv("MACHINE_IMAGE")
if downloadLocation == "" { if downloadLocation == "" {
downloadLocation, err = GetDownload(testProvider.VMType()) // TODO so beautifully gross ... ideally we can spend some time
if err != nil { // here making life easier on the next person
Fail("unable to derive download disk from fedora coreos") switch testProvider.VMType() {
case define.WSLVirt:
dl, _, _, _, err := wsl.GetFedoraDownloadForWSL()
if err != nil {
Fail("unable to determine WSL download")
}
downloadLocation = dl.String()
default:
downloadLocation, err = GetDownload(testProvider.VMType())
if err != nil {
Fail("unable to derive download disk from fedora coreos")
}
} }
} }

View File

@ -171,6 +171,9 @@ var _ = Describe("podman machine set", func() {
if testProvider.VMType() != define.WSLVirt { if testProvider.VMType() != define.WSLVirt {
Skip("Test is only for WSL") Skip("Test is only for WSL")
} }
// TODO - this currently fails
Skip("test fails bc usermode network needs plumbing for WSL")
name := randomString() name := randomString()
i := new(initMachine) i := new(initMachine)
session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath)).run() session, err := mb.setName(name).setCmd(i.withImagePath(mb.imagePath)).run()

View File

@ -10,6 +10,8 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"github.com/containers/podman/v5/pkg/machine/shim/diskpull"
"github.com/Microsoft/go-winio" "github.com/Microsoft/go-winio"
"github.com/containers/common/pkg/strongunits" "github.com/containers/common/pkg/strongunits"
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
@ -27,6 +29,10 @@ type HyperVStubber struct {
vmconfigs.HyperVConfig vmconfigs.HyperVConfig
} }
func (h HyperVStubber) UserModeNetworkEnabled(mc *vmconfigs.MachineConfig) bool {
return true
}
func (h HyperVStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.MachineConfig, builder *ignition.IgnitionBuilder) error { func (h HyperVStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.MachineConfig, builder *ignition.IgnitionBuilder) error {
var ( var (
err error err error
@ -459,6 +465,10 @@ func (h HyperVStubber) PostStartNetworking(mc *vmconfigs.MachineConfig) error {
return err return err
} }
func (h HyperVStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, h.VMType(), mc.Name)
}
func resizeDisk(newSize strongunits.GiB, imagePath *define.VMFile) error { func resizeDisk(newSize strongunits.GiB, imagePath *define.VMFile) error {
resize := exec.Command("powershell", []string{"-command", fmt.Sprintf("Resize-VHD %s %d", imagePath.GetPath(), newSize.ToBytes())}...) resize := exec.Command("powershell", []string{"-command", fmt.Sprintf("Resize-VHD %s %d", imagePath.GetPath(), newSize.ToBytes())}...)
logrus.Debug(resize.Args) logrus.Debug(resize.Args)

View File

@ -134,6 +134,13 @@ func launchWinProxy(opts WinProxyOpts) (bool, string, error) {
cmd := exec.Command(command, args...) cmd := exec.Command(command, args...)
logrus.Debugf("winssh command: %s %v", command, args) logrus.Debugf("winssh command: %s %v", command, args)
f, err := os.Open("c:\\Users\\baude\\sshproxy.log")
if err != nil {
return false, "", err
}
cmd.Stderr = f
cmd.Stdout = f
defer f.Close()
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return globalName, "", err return globalName, "", err
} }

View File

@ -2,9 +2,11 @@ package provider
import ( import (
"fmt" "fmt"
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
"os" "os"
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
"github.com/containers/podman/v5/pkg/machine/wsl"
"github.com/containers/common/pkg/config" "github.com/containers/common/pkg/config"
"github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/hyperv" "github.com/containers/podman/v5/pkg/machine/hyperv"
@ -27,9 +29,8 @@ func Get() (vmconfigs.VMProvider, error) {
logrus.Debugf("Using Podman machine with `%s` virtualization provider", resolvedVMType.String()) logrus.Debugf("Using Podman machine with `%s` virtualization provider", resolvedVMType.String())
switch resolvedVMType { switch resolvedVMType {
// TODO re-enable this with WSL case define.WSLVirt:
//case define.WSLVirt: return new(wsl.WSLStubber), nil
// return wsl.VirtualizationProvider(), nil
case define.HyperVVirt: case define.HyperVVirt:
return new(hyperv.HyperVStubber), nil return new(hyperv.HyperVStubber), nil
default: default:

View File

@ -11,14 +11,14 @@ import (
"strings" "strings"
"time" "time"
"github.com/containers/podman/v5/pkg/machine/ignition"
"github.com/containers/common/pkg/config" "github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/strongunits" "github.com/containers/common/pkg/strongunits"
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
"github.com/containers/podman/v5/pkg/machine" "github.com/containers/podman/v5/pkg/machine"
"github.com/containers/podman/v5/pkg/machine/define" "github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/ignition"
"github.com/containers/podman/v5/pkg/machine/qemu/command" "github.com/containers/podman/v5/pkg/machine/qemu/command"
"github.com/containers/podman/v5/pkg/machine/shim/diskpull"
"github.com/containers/podman/v5/pkg/machine/sockets" "github.com/containers/podman/v5/pkg/machine/sockets"
"github.com/containers/podman/v5/pkg/machine/vmconfigs" "github.com/containers/podman/v5/pkg/machine/vmconfigs"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -30,6 +30,10 @@ type QEMUStubber struct {
Command command.QemuCmd Command command.QemuCmd
} }
func (q QEMUStubber) UserModeNetworkEnabled(*vmconfigs.MachineConfig) bool {
return true
}
func (q *QEMUStubber) setQEMUCommandLine(mc *vmconfigs.MachineConfig) error { func (q *QEMUStubber) setQEMUCommandLine(mc *vmconfigs.MachineConfig) error {
qemuBinary, err := findQEMUBinary() qemuBinary, err := findQEMUBinary()
if err != nil { if err != nil {
@ -326,3 +330,7 @@ func (q *QEMUStubber) MountType() vmconfigs.VolumeMountType {
func (q *QEMUStubber) PostStartNetworking(mc *vmconfigs.MachineConfig) error { func (q *QEMUStubber) PostStartNetworking(mc *vmconfigs.MachineConfig) error {
return nil return nil
} }
func (q *QEMUStubber) GetDisk(userInputPath string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
return diskpull.GetDisk(userInputPath, dirs, mc.ImagePath, q.VMType(), mc.Name)
}

View File

@ -0,0 +1,32 @@
package diskpull
import (
"context"
"strings"
"github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/ocipull"
"github.com/containers/podman/v5/pkg/machine/stdpull"
)
func GetDisk(userInputPath string, dirs *define.MachineDirs, imagePath *define.VMFile, vmType define.VMType, name string) error {
var (
err error
mydisk ocipull.Disker
)
if userInputPath == "" {
mydisk, err = ocipull.NewVersioned(context.Background(), dirs.DataDir, name, vmType.String(), imagePath)
} else {
if strings.HasPrefix(userInputPath, "http") {
// TODO probably should use tempdir instead of datadir
mydisk, err = stdpull.NewDiskFromURL(userInputPath, imagePath, dirs.DataDir, nil)
} else {
mydisk, err = stdpull.NewStdDiskPull(userInputPath, imagePath)
}
}
if err != nil {
return err
}
return mydisk.Get()
}

View File

@ -1,12 +1,10 @@
package shim package shim
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
"strings"
"time" "time"
"github.com/containers/common/pkg/util" "github.com/containers/common/pkg/util"
@ -14,30 +12,13 @@ import (
"github.com/containers/podman/v5/pkg/machine/connection" "github.com/containers/podman/v5/pkg/machine/connection"
machineDefine "github.com/containers/podman/v5/pkg/machine/define" machineDefine "github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/ignition" "github.com/containers/podman/v5/pkg/machine/ignition"
"github.com/containers/podman/v5/pkg/machine/ocipull"
"github.com/containers/podman/v5/pkg/machine/stdpull"
"github.com/containers/podman/v5/pkg/machine/vmconfigs" "github.com/containers/podman/v5/pkg/machine/vmconfigs"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
/*
Host
├ Info
├ OS Apply
├ SSH
├ List
├ Init
├ VMExists
├ CheckExclusiveActiveVM *HyperV/WSL need to check their hypervisors as well
*/
func Info() {}
func OSApply() {}
func SSH() {}
// List is done at the host level to allow for a *possible* future where // List is done at the host level to allow for a *possible* future where
// more than one provider is used // more than one provider is used
func List(vmstubbers []vmconfigs.VMProvider, opts machine.ListOptions) ([]*machine.ListResponse, error) { func List(vmstubbers []vmconfigs.VMProvider, _ machine.ListOptions) ([]*machine.ListResponse, error) {
var ( var (
lrs []*machine.ListResponse lrs []*machine.ListResponse
) )
@ -114,6 +95,10 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) (*vmconfigs.M
Dirs: dirs, Dirs: dirs,
} }
if umn := opts.UserModeNetworking; umn != nil {
createOpts.UserModeNetworking = *umn
}
// Get Image // Get Image
// TODO This needs rework bigtime; my preference is most of below of not living in here. // TODO This needs rework bigtime; my preference is most of below of not living in here.
// ideally we could get a func back that pulls the image, and only do so IF everything works because // ideally we could get a func back that pulls the image, and only do so IF everything works because
@ -137,8 +122,7 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) (*vmconfigs.M
if err != nil { if err != nil {
return nil, err return nil, err
} }
mc.ImagePath = imagePath
var mydisk ocipull.Disker
// TODO The following stanzas should be re-written in a differeent place. It should have a custom // TODO The following stanzas should be re-written in a differeent place. It should have a custom
// parser for our image pulling. It would be nice if init just got an error and mydisk back. // parser for our image pulling. It would be nice if init just got an error and mydisk back.
@ -149,25 +133,12 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) (*vmconfigs.M
// "/path // "/path
// "docker://quay.io/something/someManifest // "docker://quay.io/something/someManifest
if opts.ImagePath == "" { // TODO Ideally this changes into some way better ...
mydisk, err = ocipull.NewVersioned(context.Background(), dirs.DataDir, opts.Name, mp.VMType().String(), imagePath) err = mp.GetDisk(opts.ImagePath, dirs, mc)
} else {
if strings.HasPrefix(opts.ImagePath, "http") {
// TODO probably should use tempdir instead of datadir
mydisk, err = stdpull.NewDiskFromURL(opts.ImagePath, imagePath, dirs.DataDir)
} else {
mydisk, err = stdpull.NewStdDiskPull(opts.ImagePath, imagePath)
}
}
if err != nil {
return nil, err
}
err = mydisk.Get()
if err != nil { if err != nil {
return nil, err return nil, err
} }
mc.ImagePath = imagePath
callbackFuncs.Add(mc.ImagePath.Delete) callbackFuncs.Add(mc.ImagePath.Delete)
logrus.Debugf("--> imagePath is %q", imagePath.GetPath()) logrus.Debugf("--> imagePath is %q", imagePath.GetPath())
@ -182,8 +153,18 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) (*vmconfigs.M
uid = 1000 uid = 1000
} }
// TODO the definition of "user" should go into
// common for WSL
userName := opts.Username
if mp.VMType() == machineDefine.WSLVirt {
if opts.Username == "core" {
userName = "user"
mc.SSH.RemoteUsername = "user"
}
}
ignBuilder := ignition.NewIgnitionBuilder(ignition.DynamicIgnition{ ignBuilder := ignition.NewIgnitionBuilder(ignition.DynamicIgnition{
Name: opts.Username, Name: userName,
Key: sshKey, Key: sshKey,
TimeZone: opts.TimeZone, TimeZone: opts.TimeZone,
UID: uid, UID: uid,
@ -223,7 +204,9 @@ func Init(opts machineDefine.InitOptions, mp vmconfigs.VMProvider) (*vmconfigs.M
ignBuilder.WithUnit(readyUnit) ignBuilder.WithUnit(readyUnit)
// Mounts // Mounts
mc.Mounts = CmdLineVolumesToMounts(opts.Volumes, mp.MountType()) if mp.VMType() != machineDefine.WSLVirt {
mc.Mounts = CmdLineVolumesToMounts(opts.Volumes, mp.MountType())
}
// TODO AddSSHConnectionToPodmanSocket could take an machineconfig instead // TODO AddSSHConnectionToPodmanSocket could take an machineconfig instead
if err := connection.AddSSHConnectionsToPodmanSocket(mc.HostUser.UID, mc.SSH.Port, mc.SSH.IdentityPath, mc.Name, mc.SSH.RemoteUsername, opts); err != nil { if err := connection.AddSSHConnectionsToPodmanSocket(mc.HostUser.UID, mc.SSH.Port, mc.SSH.IdentityPath, mc.Name, mc.SSH.RemoteUsername, opts); err != nil {
@ -347,21 +330,23 @@ func Stop(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, dirs *machineDef
} }
// Stop GvProxy and remove PID file // Stop GvProxy and remove PID file
gvproxyPidFile, err := dirs.RuntimeDir.AppendToNewVMFile("gvproxy.pid", nil) if mp.UserModeNetworkEnabled(mc) {
if err != nil { gvproxyPidFile, err := dirs.RuntimeDir.AppendToNewVMFile("gvproxy.pid", nil)
return err if err != nil {
} return err
defer func() {
if err := machine.CleanupGVProxy(*gvproxyPidFile); err != nil {
logrus.Errorf("unable to clean up gvproxy: %q", err)
} }
}()
defer func() {
if err := machine.CleanupGVProxy(*gvproxyPidFile); err != nil {
logrus.Errorf("unable to clean up gvproxy: %q", err)
}
}()
}
return nil return nil
} }
func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, dirs *machineDefine.MachineDirs, opts machine.StartOptions) error { func Start(mc *vmconfigs.MachineConfig, mp vmconfigs.VMProvider, _ *machineDefine.MachineDirs, opts machine.StartOptions) error {
defaultBackoff := 500 * time.Millisecond defaultBackoff := 500 * time.Millisecond
maxBackoffs := 6 maxBackoffs := 6

View File

@ -23,16 +23,12 @@ const (
dockerConnectTimeout = 5 * time.Second dockerConnectTimeout = 5 * time.Second
) )
func startNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) (string, machine.APIForwardingState, error) { func startUserModeNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider, dirs *define.MachineDirs, hostSocket *define.VMFile) error {
var (
forwardingState machine.APIForwardingState
forwardSock string
)
// the guestSock is "inside" the guest machine
guestSock := fmt.Sprintf(defaultGuestSock, mc.HostUser.UID)
forwardUser := mc.SSH.RemoteUsername forwardUser := mc.SSH.RemoteUsername
// TODO should this go up the stack higher // TODO should this go up the stack higher or
// the guestSock is "inside" the guest machine
guestSock := fmt.Sprintf(defaultGuestSock, mc.HostUser.UID)
if mc.HostUser.Rootful { if mc.HostUser.Rootful {
guestSock = "/run/podman/podman.sock" guestSock = "/run/podman/podman.sock"
forwardUser = "root" forwardUser = "root"
@ -40,38 +36,18 @@ func startNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider)
cfg, err := config.Default() cfg, err := config.Default()
if err != nil { if err != nil {
return "", 0, err return err
} }
binary, err := cfg.FindHelperBinary(machine.ForwarderBinaryName, false) binary, err := cfg.FindHelperBinary(machine.ForwarderBinaryName, false)
if err != nil { if err != nil {
return "", 0, err return err
}
dataDir, err := mc.DataDir()
if err != nil {
return "", 0, err
}
hostSocket, err := dataDir.AppendToNewVMFile("podman.sock", nil)
if err != nil {
return "", 0, err
}
runDir, err := mc.RuntimeDir()
if err != nil {
return "", 0, err
}
linkSocketPath := filepath.Dir(dataDir.GetPath())
linkSocket, err := define.NewMachineFile(filepath.Join(linkSocketPath, "podman.sock"), nil)
if err != nil {
return "", 0, err
} }
cmd := gvproxy.NewGvproxyCommand() cmd := gvproxy.NewGvproxyCommand()
// GvProxy PID file path is now derived // GvProxy PID file path is now derived
cmd.PidFile = filepath.Join(runDir.GetPath(), "gvproxy.pid") cmd.PidFile = filepath.Join(dirs.RuntimeDir.GetPath(), "gvproxy.pid")
// TODO This can be re-enabled when gvisor-tap-vsock #305 is merged // TODO This can be re-enabled when gvisor-tap-vsock #305 is merged
// debug is set, we dump to a logfile as well // debug is set, we dump to a logfile as well
@ -94,6 +70,36 @@ func startNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider)
// This allows a provider to perform additional setup as well as // This allows a provider to perform additional setup as well as
// add in any provider specific options for gvproxy // add in any provider specific options for gvproxy
if err := provider.StartNetworking(mc, &cmd); err != nil { if err := provider.StartNetworking(mc, &cmd); err != nil {
return err
}
c := cmd.Cmd(binary)
logrus.Debugf("gvproxy command-line: %s %s", binary, strings.Join(cmd.ToCmdline(), " "))
if err := c.Start(); err != nil {
return fmt.Errorf("unable to execute: %q: %w", cmd.ToCmdline(), err)
}
return nil
}
func startNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) (string, machine.APIForwardingState, error) {
var (
forwardingState machine.APIForwardingState
forwardSock string
)
dirs, err := machine.GetMachineDirs(provider.VMType())
if err != nil {
return "", 0, err
}
hostSocket, err := dirs.DataDir.AppendToNewVMFile("podman.sock", nil)
if err != nil {
return "", 0, err
}
linkSocketPath := filepath.Dir(dirs.DataDir.GetPath())
linkSocket, err := define.NewMachineFile(filepath.Join(linkSocketPath, "podman.sock"), nil)
if err != nil {
return "", 0, err return "", 0, err
} }
@ -101,21 +107,15 @@ func startNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider)
forwardSock, forwardingState = setupAPIForwarding(hostSocket, linkSocket) forwardSock, forwardingState = setupAPIForwarding(hostSocket, linkSocket)
} }
c := cmd.Cmd(binary) if provider.UserModeNetworkEnabled(mc) {
if err := startUserModeNetworking(mc, provider, dirs, hostSocket); err != nil {
logrus.Debugf("gvproxy command-line: %s %s", binary, strings.Join(cmd.ToCmdline(), " ")) return "", 0, err
if err := c.Start(); err != nil { }
return forwardSock, 0, fmt.Errorf("unable to execute: %q: %w", cmd.ToCmdline(), err)
} }
return forwardSock, forwardingState, nil return forwardSock, forwardingState, nil
} }
type apiOptions struct { //nolint:unused
socketpath, destinationSocketPath *define.VMFile
fowardUser string
}
func setupAPIForwarding(hostSocket, linkSocket *define.VMFile) (string, machine.APIForwardingState) { func setupAPIForwarding(hostSocket, linkSocket *define.VMFile) (string, machine.APIForwardingState) {
// The linking pattern is /var/run/docker.sock -> user global sock (link) -> machine sock (socket) // The linking pattern is /var/run/docker.sock -> user global sock (link) -> machine sock (socket)
// This allows the helper to only have to maintain one constant target to the user, which can be // This allows the helper to only have to maintain one constant target to the user, which can be

View File

@ -23,7 +23,7 @@ type DiskFromURL struct {
tempLocation *define.VMFile tempLocation *define.VMFile
} }
func NewDiskFromURL(inputPath string, finalPath *define.VMFile, tempDir *define.VMFile) (*DiskFromURL, error) { func NewDiskFromURL(inputPath string, finalPath *define.VMFile, tempDir *define.VMFile, optionalTempFileName *string) (*DiskFromURL, error) {
var ( var (
err error err error
) )
@ -40,6 +40,9 @@ func NewDiskFromURL(inputPath string, finalPath *define.VMFile, tempDir *define.
} }
remoteImageName := path.Base(inputPath) remoteImageName := path.Base(inputPath)
if optionalTempFileName != nil {
remoteImageName = *optionalTempFileName
}
if remoteImageName == "" { if remoteImageName == "" {
return nil, fmt.Errorf("invalid url: unable to determine image name in %q", inputPath) return nil, fmt.Errorf("invalid url: unable to determine image name in %q", inputPath)
} }

View File

@ -107,6 +107,10 @@ func (f fcosMachineImage) path() string {
type VMProvider interface { //nolint:interfacebloat type VMProvider interface { //nolint:interfacebloat
CreateVM(opts define.CreateVMOpts, mc *MachineConfig, builder *ignition.IgnitionBuilder) error CreateVM(opts define.CreateVMOpts, mc *MachineConfig, builder *ignition.IgnitionBuilder) error
// GetDisk should be only temporary. It is largely here only because WSL disk pulling is different
// TODO
// Let's deprecate this ASAP
GetDisk(userInputPath string, dirs *define.MachineDirs, mc *MachineConfig) error
PrepareIgnition(mc *MachineConfig, ignBuilder *ignition.IgnitionBuilder) (*ignition.ReadyUnitOpts, error) PrepareIgnition(mc *MachineConfig, ignBuilder *ignition.IgnitionBuilder) (*ignition.ReadyUnitOpts, error)
GetHyperVisorVMs() ([]string, error) GetHyperVisorVMs() ([]string, error)
MountType() VolumeMountType MountType() VolumeMountType
@ -121,6 +125,7 @@ type VMProvider interface { //nolint:interfacebloat
StopVM(mc *MachineConfig, hardStop bool) error StopVM(mc *MachineConfig, hardStop bool) error
StopHostNetworking(mc *MachineConfig, vmType define.VMType) error StopHostNetworking(mc *MachineConfig, vmType define.VMType) error
VMType() define.VMType VMType() define.VMType
UserModeNetworkEnabled(mc *MachineConfig) bool
} }
// HostUser describes the host user // HostUser describes the host user

View File

@ -13,7 +13,8 @@ type HyperVConfig struct {
} }
type WSLConfig struct { type WSLConfig struct {
//wslstuff *aThing // Uses usermode networking
UserModeNetworking bool
} }
// Stubs // Stubs

View File

@ -77,6 +77,7 @@ func NewMachineConfig(opts define.InitOptions, dirs *define.MachineDirs, sshIden
} }
mc.Resources = mrc mc.Resources = mrc
// TODO WSL had a locking port mechanism, we should consider this.
sshPort, err := utils.GetRandomPort() sshPort, err := utils.GetRandomPort()
if err != nil { if err != nil {
return nil, err return nil, err

247
pkg/machine/wsl/declares.go Normal file
View File

@ -0,0 +1,247 @@
package wsl
const (
ErrorSuccessRebootInitiated = 1641
ErrorSuccessRebootRequired = 3010
currentMachineVersion = 3
)
const containersConf = `[containers]
[engine]
cgroup_manager = "cgroupfs"
`
const registriesConf = `unqualified-search-registries=["docker.io"]
`
const appendPort = `grep -q Port\ %d /etc/ssh/sshd_config || echo Port %d >> /etc/ssh/sshd_config`
const changePort = `sed -E -i 's/^Port[[:space:]]+[0-9]+/Port %d/' /etc/ssh/sshd_config`
const configServices = `ln -fs /usr/lib/systemd/system/sshd.service /etc/systemd/system/multi-user.target.wants/sshd.service
ln -fs /usr/lib/systemd/system/podman.socket /etc/systemd/system/sockets.target.wants/podman.socket
rm -f /etc/systemd/system/getty.target.wants/console-getty.service
rm -f /etc/systemd/system/getty.target.wants/getty@tty1.service
rm -f /etc/systemd/system/multi-user.target.wants/systemd-resolved.service
rm -f /etc/systemd/system/sysinit.target.wants//systemd-resolved.service
rm -f /etc/systemd/system/dbus-org.freedesktop.resolve1.service
ln -fs /dev/null /etc/systemd/system/console-getty.service
ln -fs /dev/null /etc/systemd/system/systemd-oomd.socket
mkdir -p /etc/systemd/system/systemd-sysusers.service.d/
echo CREATE_MAIL_SPOOL=no >> /etc/default/useradd
adduser -m [USER] -G wheel
mkdir -p /home/[USER]/.config/systemd/[USER]/
chown [USER]:[USER] /home/[USER]/.config
`
const sudoers = `%wheel ALL=(ALL) NOPASSWD: ALL
`
const bootstrap = `#!/bin/bash
ps -ef | grep -v grep | grep -q systemd && exit 0
nohup unshare --kill-child --fork --pid --mount --mount-proc --propagation shared /lib/systemd/systemd >/dev/null 2>&1 &
sleep 0.1
`
const wslmotd = `
You will be automatically entered into a nested process namespace where
systemd is running. If you need to access the parent namespace, hit ctrl-d
or type exit. This also means to log out you need to exit twice.
`
const sysdpid = "SYSDPID=`ps -eo cmd,pid | grep -m 1 ^/lib/systemd/systemd | awk '{print $2}'`"
const profile = sysdpid + `
if [ ! -z "$SYSDPID" ] && [ "$SYSDPID" != "1" ]; then
cat /etc/wslmotd
/usr/local/bin/enterns
fi
`
const enterns = "#!/bin/bash\n" + sysdpid + `
if [ ! -z "$SYSDPID" ] && [ "$SYSDPID" != "1" ]; then
NSENTER=("nsenter" "-m" "-p" "-t" "$SYSDPID" "--wd=$PWD")
if [ "$UID" != "0" ]; then
NSENTER=("sudo" "${NSENTER[@]}")
if [ "$#" != "0" ]; then
NSENTER+=("sudo" "-u" "$USER")
else
NSENTER+=("su" "-l" "$USER")
fi
fi
"${NSENTER[@]}" "$@"
fi`
const waitTerm = sysdpid + `
if [ ! -z "$SYSDPID" ]; then
timeout 60 tail -f /dev/null --pid $SYSDPID
fi
`
const wslConf = `[user]
default=[USER]
`
const wslConfUserNet = `
[network]
generateResolvConf = false
`
const resolvConfUserNet = `
nameserver 192.168.127.1
`
// WSL kernel does not have sg and crypto_user modules
const overrideSysusers = `[Service]
LoadCredential=
`
const lingerService = `[Unit]
Description=A systemd user unit demo
After=network-online.target
Wants=network-online.target podman.socket
[Service]
ExecStart=/usr/bin/sleep infinity
`
const lingerSetup = `mkdir -p /home/[USER]/.config/systemd/user/default.target.wants
ln -fs /home/[USER]/.config/systemd/user/linger-example.service \
/home/[USER]/.config/systemd/user/default.target.wants/linger-example.service
`
const bindMountSystemService = `
[Unit]
Description=Bind mount for system podman sockets
After=podman.socket
[Service]
RemainAfterExit=true
Type=oneshot
# Ensure user services can register sockets as well
ExecStartPre=mkdir -p -m 777 /mnt/wsl/podman-sockets
ExecStartPre=mkdir -p -m 777 /mnt/wsl/podman-sockets/%[1]s
ExecStartPre=touch /mnt/wsl/podman-sockets/%[1]s/podman-root.sock
ExecStart=mount --bind %%t/podman/podman.sock /mnt/wsl/podman-sockets/%[1]s/podman-root.sock
ExecStop=umount /mnt/wsl/podman-sockets/%[1]s/podman-root.sock
`
const bindMountUserService = `
[Unit]
Description=Bind mount for user podman sockets
After=podman.socket
[Service]
RemainAfterExit=true
Type=oneshot
# Consistency with system service (supports racing)
ExecStartPre=mkdir -p -m 777 /mnt/wsl/podman-sockets
ExecStartPre=mkdir -p -m 777 /mnt/wsl/podman-sockets/%[1]s
ExecStartPre=touch /mnt/wsl/podman-sockets/%[1]s/podman-user.sock
# Relies on /etc/fstab entry for user mounting
ExecStart=mount /mnt/wsl/podman-sockets/%[1]s/podman-user.sock
ExecStop=umount /mnt/wsl/podman-sockets/%[1]s/podman-user.sock
`
const bindMountFsTab = `/run/user/1000/podman/podman.sock /mnt/wsl/podman-sockets/%s/podman-user.sock none noauto,user,bind,defaults 0 0
`
const (
defaultTargetWants = "default.target.wants"
userSystemdPath = "/home/%[1]s/.config/systemd/user"
sysSystemdPath = "/etc/systemd/system"
userSystemdWants = userSystemdPath + "/" + defaultTargetWants
sysSystemdWants = sysSystemdPath + "/" + defaultTargetWants
bindUnitFileName = "podman-mnt-bindings.service"
bindUserUnitPath = userSystemdPath + "/" + bindUnitFileName
bindUserUnitWant = userSystemdWants + "/" + bindUnitFileName
bindSysUnitPath = sysSystemdPath + "/" + bindUnitFileName
bindSysUnitWant = sysSystemdWants + "/" + bindUnitFileName
podmanSocketDropin = "podman.socket.d"
podmanSocketDropinPath = sysSystemdPath + "/" + podmanSocketDropin
)
const configBindServices = "mkdir -p " + userSystemdWants + " " + sysSystemdWants + " " + podmanSocketDropinPath + "\n" +
"ln -fs " + bindUserUnitPath + " " + bindUserUnitWant + "\n" +
"ln -fs " + bindSysUnitPath + " " + bindSysUnitWant + "\n"
const overrideSocketGroup = `
[Socket]
SocketMode=0660
SocketGroup=wheel
`
const proxyConfigSetup = `#!/bin/bash
SYSTEMD_CONF=/etc/systemd/system.conf.d/default-env.conf
ENVD_CONF=/etc/environment.d/default-env.conf
PROFILE_CONF=/etc/profile.d/default-env.sh
IFS="|"
read proxies
mkdir -p /etc/profile.d /etc/environment.d /etc/systemd/system.conf.d/
rm -f $SYSTEMD_CONF
for proxy in $proxies; do
output+="$proxy "
done
echo "[Manager]" >> $SYSTEMD_CONF
echo -ne "DefaultEnvironment=" >> $SYSTEMD_CONF
echo $output >> $SYSTEMD_CONF
rm -f $ENVD_CONF
for proxy in $proxies; do
echo "$proxy" >> $ENVD_CONF
done
rm -f $PROFILE_CONF
for proxy in $proxies; do
echo "export $proxy" >> $PROFILE_CONF
done
`
const proxyConfigAttempt = `if [ -f /usr/local/bin/proxyinit ]; \
then /usr/local/bin/proxyinit; \
else exit 42; \
fi`
const clearProxySettings = `rm -f /etc/systemd/system.conf.d/default-env.conf \
/etc/environment.d/default-env.conf \
/etc/profile.d/default-env.sh`
const wslInstallError = `Could not %s. See previous output for any potential failure details.
If you can not resolve the issue, and rerunning fails, try the "wsl --install" process
outlined in the following article:
http://docs.microsoft.com/en-us/windows/wsl/install
`
const wslKernelError = `Could not %s. See previous output for any potential failure details.
If you can not resolve the issue, try rerunning the "podman machine init command". If that fails
try the "wsl --update" command and then rerun "podman machine init". Finally, if all else fails,
try following the steps outlined in the following article:
http://docs.microsoft.com/en-us/windows/wsl/install
`
const wslInstallKernel = "install the WSL Kernel"
const wslOldVersion = `Automatic installation of WSL can not be performed on this version of Windows
Either update to Build 19041 (or later), or perform the manual installation steps
outlined in the following article:
http://docs.microsoft.com/en-us/windows/wsl/install\
`
const (
gvProxy = "gvproxy.exe"
winSShProxy = "win-sshproxy.exe"
pipePrefix = "npipe:////./pipe/"
globalPipe = "docker_engine"
userModeDist = "podman-net-usermode"
rootfulSock = "/run/podman/podman.sock"
rootlessSock = "/run/user/1000/podman/podman.sock"
)

View File

@ -1,10 +1,9 @@
//go:build windows
package wsl package wsl
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/sirupsen/logrus"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -27,8 +26,10 @@ type FedoraDownload struct {
machine.Download machine.Download
} }
// NewFedoraDownloader
// deprecated
func NewFedoraDownloader(vmType define.VMType, vmName, releaseStream string) (machine.DistributionDownload, error) { func NewFedoraDownloader(vmType define.VMType, vmName, releaseStream string) (machine.DistributionDownload, error) {
downloadURL, version, arch, size, err := getFedoraDownload() downloadURL, version, arch, size, err := GetFedoraDownloadForWSL()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -82,7 +83,7 @@ func (f FedoraDownload) CleanCache() error {
return machine.RemoveImageAfterExpire(f.CacheDir, expire) return machine.RemoveImageAfterExpire(f.CacheDir, expire)
} }
func getFedoraDownload() (*url.URL, string, string, int64, error) { func GetFedoraDownloadForWSL() (*url.URL, string, string, int64, error) {
var releaseURL string var releaseURL string
arch := machine.DetermineMachineArch() arch := machine.DetermineMachineArch()
switch arch { switch arch {
@ -118,11 +119,14 @@ func getFedoraDownload() (*url.URL, string, string, int64, error) {
return nil, "", "", -1, fmt.Errorf("get request failed: %s: %w", verURL.String(), err) return nil, "", "", -1, fmt.Errorf("get request failed: %s: %w", verURL.String(), err)
} }
defer resp.Body.Close() defer func() {
bytes, err := io.ReadAll(&io.LimitedReader{R: resp.Body, N: 1024}) if err := resp.Body.Close(); err != nil {
logrus.Errorf("error closing http boddy: %q", err)
}
}()
b, err := io.ReadAll(&io.LimitedReader{R: resp.Body, N: 1024})
if err != nil { if err != nil {
return nil, "", "", -1, fmt.Errorf("failed reading: %s: %w", verURL.String(), err) return nil, "", "", -1, fmt.Errorf("failed reading: %s: %w", verURL.String(), err)
} }
return downloadURL, strings.TrimSpace(string(b)), arch, contentLen, nil
return downloadURL, strings.TrimSpace(string(bytes)), arch, contentLen, nil
} }

File diff suppressed because it is too large Load Diff

362
pkg/machine/wsl/stubber.go Normal file
View File

@ -0,0 +1,362 @@
//go:build windows
package wsl
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/containers/podman/v5/pkg/machine/ocipull"
"github.com/containers/podman/v5/pkg/machine/stdpull"
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
"github.com/containers/podman/v5/pkg/machine"
"github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/ignition"
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
"github.com/sirupsen/logrus"
)
type WSLStubber struct {
vmconfigs.WSLConfig
}
func (w WSLStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.MachineConfig, _ *ignition.IgnitionBuilder) error {
var (
err error
)
// cleanup half-baked files if init fails at any point
callbackFuncs := machine.InitCleanup()
defer callbackFuncs.CleanIfErr(&err)
go callbackFuncs.CleanOnSignal()
mc.WSLHypervisor = new(vmconfigs.WSLConfig)
// TODO
// USB opts are unsupported in WSL. Need to account for that here
// or up the stack
// if len(opts.USBs) > 0 {
// return nil, fmt.Errorf("USB host passthrough is not supported for WSL machines")
// }
if cont, err := checkAndInstallWSL(opts.ReExec); !cont {
appendOutputIfError(opts.ReExec, err)
return err
}
_ = setupWslProxyEnv()
if opts.UserModeNetworking {
if err = verifyWSLUserModeCompat(); err != nil {
return err
}
mc.WSLHypervisor.UserModeNetworking = true
}
const prompt = "Importing operating system into WSL (this may take a few minutes on a new WSL install)..."
dist, err := provisionWSLDist(mc.Name, mc.ImagePath.GetPath(), prompt)
if err != nil {
return err
}
unprovisionCallbackFunc := func() error {
return unprovisionWSL(mc)
}
callbackFuncs.Add(unprovisionCallbackFunc)
if mc.WSLHypervisor.UserModeNetworking {
if err = installUserModeDist(dist, mc.ImagePath.GetPath()); err != nil {
_ = unregisterDist(dist)
return err
}
}
fmt.Println("Configuring system...")
if err = configureSystem(mc, dist); err != nil {
return err
}
if err = installScripts(dist); err != nil {
return err
}
if err = createKeys(mc, dist); err != nil {
return err
}
// recycle vm
return terminateDist(dist)
}
func (w WSLStubber) PrepareIgnition(_ *vmconfigs.MachineConfig, _ *ignition.IgnitionBuilder) (*ignition.ReadyUnitOpts, error) {
return nil, nil
}
func (w WSLStubber) GetHyperVisorVMs() ([]string, error) {
vms, err := getAllWSLDistros(false)
if err != nil {
return nil, err
}
wslVMs := make([]string, 0)
for name := range vms {
wslVMs = append(wslVMs, name)
}
return wslVMs, nil
}
func (w WSLStubber) MountType() vmconfigs.VolumeMountType {
//TODO implement me
panic("implement me")
}
func (w WSLStubber) MountVolumesToVM(mc *vmconfigs.MachineConfig, quiet bool) error {
return nil
}
func (w WSLStubber) Remove(mc *vmconfigs.MachineConfig) ([]string, func() error, error) {
// Note: we could consider swapping the two conditionals
// below if we wanted to hard error on the wsl unregister
// of the vm
wslRemoveFunc := func() error {
if err := runCmdPassThrough("wsl", "--unregister", mc.Name); err != nil {
logrus.Error(err)
}
return machine.ReleaseMachinePort(mc.SSH.Port)
}
return []string{}, wslRemoveFunc, nil
}
func (w WSLStubber) RemoveAndCleanMachines(_ *define.MachineDirs) error {
return nil
}
func (w WSLStubber) SetProviderAttrs(mc *vmconfigs.MachineConfig, opts define.SetOptions) error {
mc.Lock()
defer mc.Unlock()
// TODO the check for running when setting rootful is something I have not
// seen in the other distributions. I wonder if this is true everywhere or just
// with WSL?
// TODO maybe the "rule" for set is that it must be done when the machine is
// stopped?
// if opts.Rootful != nil && v.Rootful != *opts.Rootful {
// err := v.setRootful(*opts.Rootful)
// if err != nil {
// setErrors = append(setErrors, fmt.Errorf("setting rootful option: %w", err))
// } else {
// if v.isRunning() {
// logrus.Warn("restart is necessary for rootful change to go into effect")
// }
// v.Rootful = *opts.Rootful
// }
// }
if opts.Rootful != nil && mc.HostUser.Rootful != *opts.Rootful {
if err := mc.SetRootful(*opts.Rootful); err != nil {
return err
}
}
if opts.CPUs != nil {
return errors.New("changing CPUs not supported for WSL machines")
}
if opts.Memory != nil {
return errors.New("changing memory not supported for WSL machines")
}
// TODO USB still needs to be plumbed for all providers
// if USBs != nil {
// setErrors = append(setErrors, errors.New("changing USBs not supported for WSL machines"))
// }
if opts.DiskSize != nil {
return errors.New("changing disk size not supported for WSL machines")
}
// TODO This needs to be plumbed in for set as well
//if opts.UserModeNetworking != nil && *opts.UserModeNetworking != v.UserModeNetworking {
// update := true
//
// if v.isRunning() {
// update = false
// setErrors = append(setErrors, fmt.Errorf("user-mode networking can only be changed when the machine is not running"))
// } else {
// dist := toDist(v.Name)
// if err := changeDistUserModeNetworking(dist, v.RemoteUsername, v.ImagePath, *opts.UserModeNetworking); err != nil {
// update = false
// setErrors = append(setErrors, err)
// }
// }
//
// if update {
// v.UserModeNetworking = *opts.UserModeNetworking
// }
return nil
}
func (w WSLStubber) StartNetworking(mc *vmconfigs.MachineConfig, cmd *gvproxy.GvproxyCommand) error {
// Startup user-mode networking if enabled
if mc.WSLHypervisor.UserModeNetworking {
return startUserModeNetworking(mc)
}
return nil
}
func (w WSLStubber) UserModeNetworkEnabled(mc *vmconfigs.MachineConfig) bool {
return mc.WSLHypervisor.UserModeNetworking
}
func (w WSLStubber) PostStartNetworking(mc *vmconfigs.MachineConfig) error {
if mc.WSLHypervisor.UserModeNetworking {
winProxyOpts := machine.WinProxyOpts{
Name: mc.Name,
IdentityPath: mc.SSH.IdentityPath,
Port: mc.SSH.Port,
RemoteUsername: mc.SSH.RemoteUsername,
Rootful: mc.HostUser.Rootful,
VMType: w.VMType(),
}
machine.LaunchWinProxy(winProxyOpts, false)
}
return nil
}
func (w WSLStubber) StartVM(mc *vmconfigs.MachineConfig) (func() error, func() error, error) {
useProxy := setupWslProxyEnv()
// TODO Quiet is hard set to false: follow up
if err := configureProxy(mc.Name, useProxy, false); err != nil {
return nil, nil, err
}
// TODO The original code checked to see if the SSH port was actually open and re-assigned if it was
// we could consider this but it should be higher up the stack
// if !machine.IsLocalPortAvailable(v.Port) {
// logrus.Warnf("SSH port conflict detected, reassigning a new port")
// if err := v.reassignSshPort(); err != nil {
// return err
// }
// }
err := wslInvoke(mc.Name, "/root/bootstrap")
if err != nil {
err = fmt.Errorf("the WSL bootstrap script failed: %w", err)
}
// TODO we dont show this for any other provider. perhaps we should ? and if
// so, we need to move it up the stack
//if !v.Rootful && !opts.NoInfo {
// fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n")
// fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n")
// fmt.Printf("issues with non-podman clients, you can switch using the following command: \n")
//
// suffix := ""
// if name != machine.DefaultMachineName {
// suffix = " " + name
// }
// fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix)
//}
readyFunc := func() error {
return nil
}
return nil, readyFunc, err
}
func (w WSLStubber) State(mc *vmconfigs.MachineConfig, bypass bool) (define.Status, error) {
running, err := isRunning(mc.Name)
if err != nil {
return "", err
}
if running {
return define.Running, nil
}
return define.Stopped, nil
}
func (w WSLStubber) StopVM(mc *vmconfigs.MachineConfig, hardStop bool) error {
var (
err error
)
// by this time, state has been verified to be running and a request
// to stop is fair game
mc.Lock()
defer mc.Unlock()
// Stop user-mode networking if enabled
if err := stopUserModeNetworking(mc); err != nil {
fmt.Fprintf(os.Stderr, "Could not cleanly stop user-mode networking: %s\n", err.Error())
}
if err := machine.StopWinProxy(mc.Name, vmtype); err != nil {
fmt.Fprintf(os.Stderr, "Could not stop API forwarding service (win-sshproxy.exe): %s\n", err.Error())
}
cmd := exec.Command("wsl", "-u", "root", "-d", mc.Name, "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", mc.Name, "/usr/local/bin/enterns", "systemctl", "exit", "0")
if err = exitCmd.Run(); err != nil {
return fmt.Errorf("stopping sysd: %w", err)
}
if err = cmd.Wait(); err != nil {
return err
}
return terminateDist(mc.Name)
}
func (w WSLStubber) StopHostNetworking(mc *vmconfigs.MachineConfig, vmType define.VMType) error {
return stopUserModeNetworking(mc)
}
func (w WSLStubber) VMType() define.VMType {
return define.WSLVirt
}
func (w WSLStubber) GetDisk(_ string, dirs *define.MachineDirs, mc *vmconfigs.MachineConfig) error {
var (
myDisk ocipull.Disker
)
// check github for the latest version of the WSL dist
downloadURL, downloadVersion, _, _, err := GetFedoraDownloadForWSL()
if err != nil {
return err
}
// we now save the "cached" rootfs in the form of "v<version-number>-rootfs.tar.xz"
// i.e.v39.0.31-rootfs.tar.xz
versionedBase := fmt.Sprintf("%s-%s", downloadVersion, filepath.Base(downloadURL.Path))
// TODO we need a mechanism for "flushing" old cache files
cachedFile, err := dirs.DataDir.AppendToNewVMFile(versionedBase, nil)
if err != nil {
return err
}
// if we find the same file cached (determined by filename only), then dont pull
if _, err = os.Stat(cachedFile.GetPath()); err == nil {
logrus.Debugf("%q already exists locally", cachedFile.GetPath())
myDisk, err = stdpull.NewStdDiskPull(cachedFile.GetPath(), mc.ImagePath)
} else {
// no cached file
myDisk, err = stdpull.NewDiskFromURL(downloadURL.String(), mc.ImagePath, dirs.DataDir, &versionedBase)
}
if err != nil {
return err
}
// up until now, nothing has really happened
// pull if needed and decompress to image location
return myDisk.Get()
}

View File

@ -5,6 +5,7 @@ package wsl
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -69,8 +70,8 @@ func verifyWSLUserModeCompat() error {
prefix) prefix)
} }
func (v *MachineVM) startUserModeNetworking() error { func startUserModeNetworking(mc *vmconfigs.MachineConfig) error {
if !v.UserModeNetworking { if !mc.WSLHypervisor.UserModeNetworking {
return nil return nil
} }
@ -79,7 +80,7 @@ func (v *MachineVM) startUserModeNetworking() error {
return fmt.Errorf("could not locate %s, which is necessary for user-mode networking, please reinstall", gvProxy) return fmt.Errorf("could not locate %s, which is necessary for user-mode networking, please reinstall", gvProxy)
} }
flock, err := v.obtainUserModeNetLock() flock, err := obtainUserModeNetLock()
if err != nil { if err != nil {
return err return err
} }
@ -93,17 +94,17 @@ func (v *MachineVM) startUserModeNetworking() error {
// Start or reuse // Start or reuse
if !running { if !running {
if err := v.launchUserModeNetDist(exe); err != nil { if err := launchUserModeNetDist(exe); err != nil {
return err return err
} }
} }
if err := createUserModeResolvConf(toDist(v.Name)); err != nil { if err := createUserModeResolvConf(mc.Name); err != nil {
return err return err
} }
// Register in-use // Register in-use
err = v.addUserModeNetEntry() err = addUserModeNetEntry(mc)
if err != nil { if err != nil {
return err return err
} }
@ -111,23 +112,23 @@ func (v *MachineVM) startUserModeNetworking() error {
return nil return nil
} }
func (v *MachineVM) stopUserModeNetworking(dist string) error { func stopUserModeNetworking(mc *vmconfigs.MachineConfig) error {
if !v.UserModeNetworking { if !mc.WSLHypervisor.UserModeNetworking {
return nil return nil
} }
flock, err := v.obtainUserModeNetLock() flock, err := obtainUserModeNetLock()
if err != nil { if err != nil {
return err return err
} }
defer flock.unlock() defer flock.unlock()
err = v.removeUserModeNetEntry() err = removeUserModeNetEntry(mc.Name)
if err != nil { if err != nil {
return err return err
} }
count, err := v.cleanupAndCountNetEntries() count, err := cleanupAndCountNetEntries()
if err != nil { if err != nil {
return err return err
} }
@ -159,7 +160,7 @@ func isGvProxyVMRunning() bool {
return wslInvoke(userModeDist, "bash", "-c", "ps -eo args | grep -q -m1 ^/usr/local/bin/vm || exit 42") == nil return wslInvoke(userModeDist, "bash", "-c", "ps -eo args | grep -q -m1 ^/usr/local/bin/vm || exit 42") == nil
} }
func (v *MachineVM) launchUserModeNetDist(exeFile string) error { func launchUserModeNetDist(exeFile string) error {
fmt.Println("Starting user-mode networking...") fmt.Println("Starting user-mode networking...")
exe, err := specgen.ConvertWinMountPath(exeFile) exe, err := specgen.ConvertWinMountPath(exeFile)
@ -220,7 +221,7 @@ func createUserModeResolvConf(dist string) error {
return err return err
} }
func (v *MachineVM) getUserModeNetDir() (string, error) { func getUserModeNetDir() (string, error) {
vmDataDir, err := machine.GetDataDir(vmtype) vmDataDir, err := machine.GetDataDir(vmtype)
if err != nil { if err != nil {
return "", err return "", err
@ -234,8 +235,8 @@ func (v *MachineVM) getUserModeNetDir() (string, error) {
return dir, nil return dir, nil
} }
func (v *MachineVM) getUserModeNetEntriesDir() (string, error) { func getUserModeNetEntriesDir() (string, error) {
netDir, err := v.getUserModeNetDir() netDir, err := getUserModeNetDir()
if err != nil { if err != nil {
return "", err return "", err
} }
@ -248,13 +249,13 @@ func (v *MachineVM) getUserModeNetEntriesDir() (string, error) {
return dir, nil return dir, nil
} }
func (v *MachineVM) addUserModeNetEntry() error { func addUserModeNetEntry(mc *vmconfigs.MachineConfig) error {
entriesDir, err := v.getUserModeNetEntriesDir() entriesDir, err := getUserModeNetEntriesDir()
if err != nil { if err != nil {
return err return err
} }
path := filepath.Join(entriesDir, toDist(v.Name)) path := filepath.Join(entriesDir, mc.Name)
file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil { if err != nil {
return fmt.Errorf("could not add user-mode networking registration: %w", err) return fmt.Errorf("could not add user-mode networking registration: %w", err)
@ -263,18 +264,18 @@ func (v *MachineVM) addUserModeNetEntry() error {
return nil return nil
} }
func (v *MachineVM) removeUserModeNetEntry() error { func removeUserModeNetEntry(name string) error {
entriesDir, err := v.getUserModeNetEntriesDir() entriesDir, err := getUserModeNetEntriesDir()
if err != nil { if err != nil {
return err return err
} }
path := filepath.Join(entriesDir, toDist(v.Name)) path := filepath.Join(entriesDir, name)
return os.Remove(path) return os.Remove(path)
} }
func (v *MachineVM) cleanupAndCountNetEntries() (uint, error) { func cleanupAndCountNetEntries() (uint, error) {
entriesDir, err := v.getUserModeNetEntriesDir() entriesDir, err := getUserModeNetEntriesDir()
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -302,8 +303,8 @@ func (v *MachineVM) cleanupAndCountNetEntries() (uint, error) {
return count, nil return count, nil
} }
func (v *MachineVM) obtainUserModeNetLock() (*fileLock, error) { func obtainUserModeNetLock() (*fileLock, error) {
dir, err := v.getUserModeNetDir() dir, err := getUserModeNetDir()
if err != nil { if err != nil {
return nil, err return nil, err