Files
podman/pkg/machine/shim/networking.go
Jason T. Greene 487219d809 Complete WSL implementation, refactor a few areas
Also addresses a number of issues:
- StopHostNetworking isn't plumbed, win-sshproxy leaks on hyperv
- Wait api and print output doesn't work properly on Windows
- API forwarding doesn't work on WSL
- Terminal corruption with after start/stop on Windows
- Gvproxy is forcefully killed vs gracefully quit
- Switching rootful/rootless does not update /var/run/docker.sock on the guest
- File already closed error on init
- HyperV backend is publishing Unix sockets when it should be named pipes
- User-mode networking doesn't always work
- Stop state outside of lock boundaries
- WSL blocks parallel machined (should be supported)

[NO NEW TESTS NEEDED]

Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
2024-02-11 12:58:11 -06:00

153 lines
4.3 KiB
Go

package shim
import (
"fmt"
"net"
"path/filepath"
"strings"
"time"
"github.com/containers/common/pkg/config"
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/vmconfigs"
"github.com/sirupsen/logrus"
)
const (
dockerSock = "/var/run/docker.sock"
defaultGuestSock = "/run/user/%d/podman/podman.sock"
dockerConnectTimeout = 5 * time.Second
)
func startHostForwarder(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider, dirs *define.MachineDirs, hostSocks []string) error {
forwardUser := mc.SSH.RemoteUsername
// 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 {
guestSock = "/run/podman/podman.sock"
forwardUser = "root"
}
cfg, err := config.Default()
if err != nil {
return err
}
binary, err := cfg.FindHelperBinary(machine.ForwarderBinaryName, false)
if err != nil {
return err
}
cmd := gvproxy.NewGvproxyCommand()
// GvProxy PID file path is now derived
cmd.PidFile = filepath.Join(dirs.RuntimeDir.GetPath(), "gvproxy.pid")
// TODO This can be re-enabled when gvisor-tap-vsock #305 is merged
// debug is set, we dump to a logfile as well
// if logrus.IsLevelEnabled(logrus.DebugLevel) {
// cmd.LogFile = filepath.Join(runDir.GetPath(), "gvproxy.log")
// }
cmd.SSHPort = mc.SSH.Port
// Windows providers listen on multiple sockets since they do not involve links
for _, hostSock := range hostSocks {
cmd.AddForwardSock(hostSock)
cmd.AddForwardDest(guestSock)
cmd.AddForwardUser(forwardUser)
cmd.AddForwardIdentity(mc.SSH.IdentityPath)
}
if logrus.IsLevelEnabled(logrus.DebugLevel) {
cmd.Debug = true
logrus.Debug(cmd)
}
// This allows a provider to perform additional setup as well as
// add in any provider specific options for gvproxy
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) {
// Provider has its own networking code path (e.g. WSL)
if provider.UseProviderNetworkSetup() {
return "", 0, provider.StartNetworking(mc, nil)
}
dirs, err := machine.GetMachineDirs(provider.VMType())
if err != nil {
return "", 0, err
}
hostSocks, forwardSock, forwardingState, err := setupMachineSockets(mc.Name, dirs)
if err != nil {
return "", 0, err
}
if err := startHostForwarder(mc, provider, dirs, hostSocks); err != nil {
return "", 0, err
}
return forwardSock, forwardingState, nil
}
// conductVMReadinessCheck checks to make sure the machine is in the proper state
// and that SSH is up and running
func conductVMReadinessCheck(mc *vmconfigs.MachineConfig, maxBackoffs int, backoff time.Duration, stateF func() (define.Status, error)) (connected bool, sshError error, err error) {
for i := 0; i < maxBackoffs; i++ {
if i > 0 {
time.Sleep(backoff)
backoff *= 2
}
state, err := stateF()
if err != nil {
return false, nil, err
}
if state == define.Running && isListening(mc.SSH.Port) {
// Also make sure that SSH is up and running. The
// ready service's dependencies don't fully make sure
// that clients can SSH into the machine immediately
// after boot.
//
// CoreOS users have reported the same observation but
// the underlying source of the issue remains unknown.
if sshError = machine.CommonSSHSilent(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"true"}); sshError != nil {
logrus.Debugf("SSH readiness check for machine failed: %v", sshError)
continue
}
connected = true
break
}
}
return
}
func isListening(port int) bool {
// Check if we can dial it
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", port), 10*time.Millisecond)
if err != nil {
return false
}
if err := conn.Close(); err != nil {
logrus.Error(err)
}
return true
}