Skip to content

Commit

Permalink
Implement publishing API UNIX socket on Windows platforms
Browse files Browse the repository at this point in the history
gvproxy and win-sshproxy have capabilities to serve this type of enpoint.
This change only adds one additional API enpoint publishing by appending
proxy command lines.

Signed-off-by: Arthur Sengileyev <[email protected]>
  • Loading branch information
arixmkii committed Aug 31, 2024
1 parent ece759a commit 1732338
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 17 deletions.
96 changes: 96 additions & 0 deletions pkg/machine/e2e/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package e2e_test

import (
"context"
"os/exec"
"path/filepath"
"runtime"

"github.com/containers/podman/v5/pkg/machine"
"github.com/docker/docker/client"
jsoniter "github.com/json-iterator/go"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
)

const (
NamedPipeProto = "npipe://"
)

var _ = Describe("run podman API test calls", func() {

It("client connect to machine socket", func() {
if runtime.GOOS == "windows" {
Skip("Go docker client doesn't support unix socket on Windows")
}
name := randomString()
i := new(initMachine)
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withNow()).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))

inspectJSON := new(inspectMachine)
inspectSession, err := mb.setName(name).setCmd(inspectJSON).run()
Expect(err).ToNot(HaveOccurred())
Expect(inspectSession).To(Exit(0))

var inspectInfo []machine.InspectInfo
err = jsoniter.Unmarshal(inspectSession.Bytes(), &inspectInfo)
Expect(err).ToNot(HaveOccurred())
sockPath := inspectInfo[0].ConnectionInfo.PodmanSocket.GetPath()

cli, err := client.NewClientWithOpts(client.WithHost("unix://" + sockPath))
Expect(err).ToNot(HaveOccurred())
_, err = cli.Ping(context.Background())
Expect(err).ToNot(HaveOccurred())
})

It("client connect to machine named pipe", func() {
if runtime.GOOS != "windows" {
Skip("test is only supported on Windows")
}
name := randomString()
i := new(initMachine)
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withNow()).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))

inspectJSON := new(inspectMachine)
inspectSession, err := mb.setName(name).setCmd(inspectJSON).run()
Expect(err).ToNot(HaveOccurred())
Expect(inspectSession).To(Exit(0))

var inspectInfo []machine.InspectInfo
err = jsoniter.Unmarshal(inspectSession.Bytes(), &inspectInfo)
Expect(err).ToNot(HaveOccurred())
pipePath := inspectInfo[0].ConnectionInfo.PodmanPipe.GetPath()

cli, err := client.NewClientWithOpts(client.WithHost(NamedPipeProto + filepath.ToSlash(pipePath)))
Expect(err).ToNot(HaveOccurred())
_, err = cli.Ping(context.Background())
Expect(err).ToNot(HaveOccurred())
})

It("curl connect to machine socket", func() {
name := randomString()
i := new(initMachine)
session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withNow()).run()
Expect(err).ToNot(HaveOccurred())
Expect(session).To(Exit(0))

inspectJSON := new(inspectMachine)
inspectSession, err := mb.setName(name).setCmd(inspectJSON).run()
Expect(err).ToNot(HaveOccurred())
Expect(inspectSession).To(Exit(0))

var inspectInfo []machine.InspectInfo
err = jsoniter.Unmarshal(inspectSession.Bytes(), &inspectInfo)
Expect(err).ToNot(HaveOccurred())
sockPath := inspectInfo[0].ConnectionInfo.PodmanSocket.GetPath()

cmd := exec.Command("curl", "--unix-socket", sockPath, "http://d/v5.0.0/libpod/info")
err = cmd.Run()
Expect(err).ToNot(HaveOccurred())
})
})
3 changes: 0 additions & 3 deletions pkg/machine/e2e/inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ var _ = Describe("podman inspect stop", func() {
})

It("inspect shows a unique socket name per machine", func() {
skipIfVmtype(define.WSLVirt, "test is only relevant for Unix based providers")
skipIfVmtype(define.HyperVVirt, "test is only relevant for Unix based machines")

var socks []string
for c := 0; c < 2; c++ {
name := randomString()
Expand Down
8 changes: 8 additions & 0 deletions pkg/machine/machine_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
winio "github.com/Microsoft/go-winio"
"github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/env"
"github.com/containers/podman/v5/pkg/machine/sockets"
"github.com/containers/storage/pkg/fileutils"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -45,6 +46,7 @@ type WinProxyOpts struct {
RemoteUsername string
Rootful bool
VMType define.VMType
Socket *define.VMFile
}

func GetProcessState(pid int) (active bool, exitCode int) {
Expand Down Expand Up @@ -160,6 +162,12 @@ func launchWinProxy(opts WinProxyOpts) (bool, string, error) {
waitPipe = GlobalNamedPipe
}

hostURL, err := sockets.ToUnixURL(opts.Socket)
if err != nil {
return false, "", err
}
args = append(args, hostURL.String(), dest, opts.IdentityPath)

cmd := exec.Command(command, args...)
logrus.Debugf("winssh command: %s %v", command, args)
if err := cmd.Start(); err != nil {
Expand Down
14 changes: 13 additions & 1 deletion pkg/machine/shim/networking_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/containers/podman/v5/pkg/machine"
"github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/env"
sc "github.com/containers/podman/v5/pkg/machine/sockets"
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
)

Expand All @@ -22,5 +23,16 @@ func setupMachineSockets(mc *vmconfigs.MachineConfig, dirs *define.MachineDirs)
state = machine.DockerGlobal
}

return sockets, sockets[len(sockets)-1], state, nil
hostSocket, err := mc.APISocket()
if err != nil {
return nil, "", 0, err
}

hostURL, err := sc.ToUnixURL(hostSocket)
if err != nil {
return nil, "", 0, err
}
sockets = append(sockets, hostURL.String())

return sockets, sockets[len(sockets)-2], state, nil
}
14 changes: 1 addition & 13 deletions pkg/machine/vmconfigs/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/containers/podman/v5/pkg/errorhandling"
"github.com/containers/podman/v5/pkg/machine/connection"
"github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/env"
"github.com/containers/podman/v5/pkg/machine/lock"
"github.com/containers/podman/v5/pkg/machine/ports"
"github.com/containers/storage/pkg/fileutils"
Expand Down Expand Up @@ -331,19 +330,8 @@ func (mc *MachineConfig) IsFirstBoot() (bool, error) {
}

func (mc *MachineConfig) ConnectionInfo(vmtype define.VMType) (*define.VMFile, *define.VMFile, error) {
var (
socket *define.VMFile
pipe *define.VMFile
)

if vmtype == define.HyperVVirt || vmtype == define.WSLVirt {
pipeName := env.WithPodmanPrefix(mc.Name)
pipe = &define.VMFile{Path: `\\.\pipe\` + pipeName}
return nil, pipe, nil
}

socket, err := mc.APISocket()
return socket, nil, err
return socket, getPipe(mc.Name), err
}

// LoadMachineByName returns a machine config based on the vm name and provider
Expand Down
11 changes: 11 additions & 0 deletions pkg/machine/vmconfigs/machine_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd

package vmconfigs

import (
"github.com/containers/podman/v5/pkg/machine/define"
)

func getPipe(name string) *define.VMFile {
return nil
}
11 changes: 11 additions & 0 deletions pkg/machine/vmconfigs/machine_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package vmconfigs

import (
"github.com/containers/podman/v5/pkg/machine/define"
"github.com/containers/podman/v5/pkg/machine/env"
)

func getPipe(name string) *define.VMFile {
pipeName := env.WithPodmanPrefix(name)
return &define.VMFile{Path: `\\.\pipe\` + pipeName}
}
5 changes: 5 additions & 0 deletions pkg/machine/wsl/stubber.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,18 @@ func (w WSLStubber) RequireExclusiveActive() bool {
}

func (w WSLStubber) PostStartNetworking(mc *vmconfigs.MachineConfig, noInfo bool) error {
socket, err := mc.APISocket()
if err != nil {
return err
}
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(),
Socket: socket,
}
machine.LaunchWinProxy(winProxyOpts, noInfo)

Expand Down

0 comments on commit 1732338

Please sign in to comment.