mirror of
https://github.com/containers/podman.git
synced 2026-10-31 06:11:20 -04:00
Since gvisor-tap-vsock v0.9.0 (containers/gvisor-tap-vsock#718),
gvproxy and win-sshproxy no longer delete a leftover unix socket before
listening on it; they only remove it on a clean exit. When the proxy is
killed instead (host shutdown or restart, crash, SIGKILL), the API
socket is left behind and the next proxy fails to bind it:
- WSL: win-sshproxy exits and takes the named pipes with it, while
`machine start` still reports success.
- Hyper-V, macOS and Linux: gvproxy exits, which also breaks SSH
forwarding, so `machine start` fails (or hangs on macOS).
Remove the API socket in startNetworking, after cleanupStaleHostForwarder
has handled any orphaned proxy. On WSL a failed delete only warns, since
win-sshproxy serves only the API and SSH goes through wslrelay.
On macOS and Linux, `machine stop` also failed after gvproxy was killed
("looking up PID ...: process does not exist"); treat a missing gvproxy
as already stopped, as the Windows code does.
The "client connect to machine socket" e2e test now also kills the proxy
by the PID from its pid/tid file, restarts the machine and checks the API
again, and runs on Windows too.
Fixes: #29971
Signed-off-by: Srilal Sachintha <SrilalSachintha@Gmail.com>
99 lines
3.0 KiB
Go
99 lines
3.0 KiB
Go
package e2e_test
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"time"
|
|
|
|
jsoniter "github.com/json-iterator/go"
|
|
"github.com/moby/moby/client"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
. "github.com/onsi/gomega/gexec"
|
|
"go.podman.io/podman/v6/pkg/machine"
|
|
"go.podman.io/podman/v6/pkg/machine/define"
|
|
)
|
|
|
|
const (
|
|
NamedPipeProto = "npipe://"
|
|
)
|
|
|
|
var _ = Describe("run podman API test calls", func() {
|
|
It("client 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()
|
|
Eventually(sockPath, 10*time.Second).Should(BeAnExistingFile())
|
|
|
|
checkAPI := func() {
|
|
// check with docker client
|
|
host := "unix://" + sockPath
|
|
if runtime.GOOS == "windows" {
|
|
// Go docker client doesn't support unix socket on Windows,
|
|
// use the pipe connection instead
|
|
host = NamedPipeProto + filepath.ToSlash(inspectInfo[0].ConnectionInfo.PodmanPipe.GetPath())
|
|
}
|
|
cli, err := client.New(client.WithHost(host))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err = cli.Ping(context.Background(), client.PingOptions{})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// check with curl
|
|
cmd := exec.Command("curl", "--unix-socket", sockPath, "http://d/v5.0.0/libpod/info")
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
err = cmd.Run()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
}
|
|
checkAPI()
|
|
|
|
// Kill the proxy without giving it a chance to remove its socket, as
|
|
// happens when the host shuts down. The next start must still bring
|
|
// the API back.
|
|
// gvproxy writes its pid file next to the API socket.
|
|
runtimeDir := filepath.Dir(inspectInfo[0].ConnectionInfo.PodmanSocket.Path)
|
|
pid := apiProxyPID(name, runtimeDir)
|
|
proxy, err := os.FindProcess(pid)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(proxy.Kill()).To(Succeed())
|
|
Eventually(func() bool { return processExists(pid) }, 10*time.Second).Should(BeFalse())
|
|
Expect(sockPath).To(BeAnExistingFile())
|
|
|
|
stop := new(stopMachine)
|
|
stopSession, err := mb.setCmd(stop).run()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(stopSession).To(Exit(0))
|
|
|
|
start := new(startMachine)
|
|
startSession, err := mb.setCmd(start).run()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(startSession).To(Exit(0))
|
|
|
|
checkAPI()
|
|
})
|
|
})
|
|
|
|
// gvproxyPID returns the PID recorded in the gvproxy pid file in runtimeDir.
|
|
func gvproxyPID(runtimeDir string) int {
|
|
pidFile, err := define.NewMachineFile(filepath.Join(runtimeDir, "gvproxy.pid"), nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
pid, err := pidFile.ReadPIDFrom()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
return pid
|
|
}
|