Skip to content

Commit

Permalink
Windows QEMU machine support
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur Sengileyev <arthur.sengileyev@gmail.com>
  • Loading branch information
arixmkii committed Dec 22, 2022
1 parent b8e4e7c commit 5063d1a
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 25 deletions.
6 changes: 2 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ endif
# include this lightweight helper binary.
#
GV_GITURL=https://github.com/containers/gvisor-tap-vsock.git
GV_SHA=1382207678c2da7bc6be7d9dcf6806e862e424f8
GV_SHA=aab0ac9367fc5142f5857c36ac2352bcb3c60ab7

###
### Primary entry-point targets
Expand Down Expand Up @@ -764,11 +764,9 @@ gvproxy: test/version/version
git init; \
git remote add origin $(GV_GITURL); \
git fetch --depth 1 origin $(GV_SHA); \
git checkout FETCH_HEAD; make gvproxy win-sshproxy)
git checkout FETCH_HEAD; make win-gvproxy win-sshproxy)
mkdir -p bin/windows/
cp tmp-gv/bin/win-sshproxy.exe bin/windows/
# workaround the build artifact naming
cp tmp-gv/bin/gvproxy tmp-gv/bin/gvproxy.exe
cp tmp-gv/bin/gvproxy.exe bin/windows/
rm -rf tmp-gv

Expand Down
13 changes: 12 additions & 1 deletion cmd/podman/machine/platform_windows.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
package machine

import (
"os"
"strings"

"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/wsl"
"github.com/containers/podman/v4/pkg/machine/qemu"
)

func GetSystemDefaultProvider() machine.Provider {
return wsl.GetWSLProvider()
switch strings.ToUpper(os.Getenv("CONTAINERS_MACHINE_PROVIDER")) {
case "WSL":
return wsl.GetWSLProvider()
case "QEMU":
return qemu.GetVirtualizationProvider()
default:
return wsl.GetWSLProvider()
}
}
91 changes: 72 additions & 19 deletions pkg/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strconv"
"strings"
"syscall"
Expand Down Expand Up @@ -128,7 +129,12 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
// Add network
// Right now the mac address is hardcoded so that the host networking gives it a specific IP address. This is
// why we can only run one vm at a time right now
cmd = append(cmd, []string{"-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee"}...)
if runtime.GOOS != "windows" {
cmd = append(cmd, []string{"-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee"}...)
} else {
vlanSocket := machine.VMFile{Path: toVlanSockPath(monitor.Address.GetPath())}
cmd = append(cmd, []string{"-netdev", fmt.Sprintf("stream,id=vlan,server=off,addr.type=unix,addr.path=%s", vlanSocket.GetPath()), "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee"}...)
}
if err := vm.setReadySocket(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -335,7 +341,11 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
}
}
v.Mounts = mounts
v.UID = os.Getuid()
if runtime.GOOS != "windows" {
v.UID = os.Getuid()
} else {
v.UID = 501 // Hardcoded to match FCOS image, can we get something better?
}

// Add location of bootable image
v.CmdLine = append(v.CmdLine, "-drive", "if=virtio,file="+v.getImageFile())
Expand Down Expand Up @@ -471,6 +481,7 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
var (
conn net.Conn
err error
fd *os.File
qemuSocketConn net.Conn
wait = time.Millisecond * 500
)
Expand Down Expand Up @@ -526,24 +537,30 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
if err := v.QMPMonitor.Address.Delete(); err != nil {
return err
}
for i := 0; i < 6; i++ {
qemuSocketConn, err = net.Dial("unix", v.QMPMonitor.Address.GetPath())
if err == nil {
break
}
time.Sleep(wait)
wait++
}
if err != nil {
vlanSocket := machine.VMFile{Path: toVlanSockPath(v.QMPMonitor.Address.GetPath())}
if err := vlanSocket.Delete(); err != nil {
return err
}
defer qemuSocketConn.Close()
if runtime.GOOS != "windows" {
for i := 0; i < 6; i++ {
qemuSocketConn, err = net.Dial("unix", v.QMPMonitor.Address.GetPath())
if err == nil {
break
}
time.Sleep(wait)
wait++
}
if err != nil {
return err
}
defer qemuSocketConn.Close()

fd, err := qemuSocketConn.(*net.UnixConn).File()
if err != nil {
return err
fd, err := qemuSocketConn.(*net.UnixConn).File()
if err != nil {
return err
}
defer fd.Close()
}
defer fd.Close()
dnr, err := os.OpenFile(os.DevNull, os.O_RDONLY, 0755)
if err != nil {
return err
Expand All @@ -556,7 +573,10 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
defer dnw.Close()

attr := new(os.ProcAttr)
files := []*os.File{dnr, dnw, dnw, fd}
files := []*os.File{dnr, dnw, dnw}
if runtime.GOOS != "windows" {
files = append(files, fd)
}
attr.Files = files
cmdLine := v.CmdLine

Expand All @@ -578,7 +598,9 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
Stdin: dnr,
Stdout: dnw,
Stderr: stderrBuf,
ExtraFiles: []*os.File{fd},
}
if runtime.GOOS != "windows" {
cmd.ExtraFiles = []*os.File{fd}
}
err = cmd.Start()
if err != nil {
Expand Down Expand Up @@ -688,6 +710,11 @@ func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
}

v.waitAPIAndPrintInfo(forwardState, forwardSock, opts.NoInfo)
// Remove vlan socket
vlanSocket = machine.VMFile{Path: toVlanSockPath(v.QMPMonitor.Address.GetPath())}
if err := vlanSocket.Delete(); err != nil {
return err
}
return nil
}

Expand Down Expand Up @@ -831,6 +858,11 @@ func (v *MachineVM) Stop(_ string, _ machine.StopOptions) error {
if err := v.QMPMonitor.Address.Delete(); err != nil {
return err
}
// Remove vlan socket (should not really exist, because removed after successful start)
vlanSocket := machine.VMFile{Path: toVlanSockPath(v.QMPMonitor.Address.GetPath())}
if err := vlanSocket.Delete(); err != nil {
return err
}

if err := qmpMonitor.Disconnect(); err != nil {
// FIXME: this error should probably be returned
Expand Down Expand Up @@ -1229,6 +1261,10 @@ func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) {
return "", noForwarding, err
}
binary, err := cfg.FindHelperBinary(machine.ForwarderBinaryName, false)
// workaround for lookup on Windows
if runtime.GOOS == "windows" {
binary, err = cfg.FindHelperBinary(machine.ForwarderBinaryName + ".exe", false)
}
if err != nil {
return "", noForwarding, err
}
Expand All @@ -1248,7 +1284,12 @@ func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) {

attr.Files = []*os.File{dnr, dnw, dnw}
cmd := []string{binary}
cmd = append(cmd, []string{"-listen-qemu", fmt.Sprintf("unix://%s", v.QMPMonitor.Address.GetPath()), "-pid-file", v.PidFilePath.GetPath()}...)
if runtime.GOOS != "windows" {
cmd = append(cmd, []string{"-listen-qemu", fmt.Sprintf("unix://%s", v.QMPMonitor.Address.GetPath()), "-pid-file", v.PidFilePath.GetPath()}...)
} else {
vlanSocket := machine.VMFile{Path: toVlanSockPath(v.QMPMonitor.Address.GetPath())}
cmd = append(cmd, []string{"-listen-qemu", fmt.Sprintf("unix://%s", strings.Replace(vlanSocket.GetPath(), "\\", "/", -1)), "-pid-file", v.PidFilePath.GetPath()}...)
}
// Add the ssh port
cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", v.Port)}...)

Expand Down Expand Up @@ -1289,6 +1330,14 @@ func (v *MachineVM) setupAPIForwarding(cmd []string) ([]string, string, apiForwa
cmd = append(cmd, []string{"-forward-user", forwardUser}...)
cmd = append(cmd, []string{"-forward-identity", v.IdentityPath}...)

// Workaround for Podman Desktop compatibility
if runtime.GOOS == "windows" {
cmd = append(cmd, []string{"-forward-sock", fmt.Sprintf("npipe:////./pipe/%s", v.Name)}...)
cmd = append(cmd, []string{"-forward-dest", destSock}...)
cmd = append(cmd, []string{"-forward-user", forwardUser}...)
cmd = append(cmd, []string{"-forward-identity", v.IdentityPath}...)
}

// 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
// repositioned without updating docker.sock.
Expand Down Expand Up @@ -1749,6 +1798,10 @@ func (p *Provider) VMType() string {
return vmtype
}

func toVlanSockPath(path string) string {
return strings.Replace(path, "qmp_", "vlan_", 1)
}

func isRootful() bool {
// Rootless is not relevant on Windows. In the future rootless.IsRootless
// could be switched to return true on Windows, and other codepaths migrated
Expand Down
2 changes: 1 addition & 1 deletion pkg/machine/qemu/options_windows_amd64.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package qemu

var (
QemuCommand = "qemu-system-x86_64"
QemuCommand = "qemu-system-x86_64w"
)

func (v *MachineVM) addArchOptions() []string {
Expand Down
19 changes: 19 additions & 0 deletions pkg/machine/qemu/options_windows_arm64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package qemu

var (
QemuCommand = "qemu-system-aarch64w"
)

func (v *MachineVM) addArchOptions() []string {
// stub to fix compilation issues
opts := []string{}
return opts
}

func (v *MachineVM) prepare() error {
return nil
}

func (v *MachineVM) archRemovalFiles() []string {
return []string{}
}

0 comments on commit 5063d1a

Please sign in to comment.