mirror of
				https://github.com/containers/podman.git
				synced 2025-10-31 10:00:01 +08:00 
			
		
		
		
	 e58cb97de1
			
		
	
	e58cb97de1
	
	
	
		
			
			- Fixes conflicts such as removal of second machine deleting a socket of a the first machine while it's running - Move API socket into runtime directory for consistency - Add API and gvproxy sockets to removal list - Cleanup related logic Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
		
			
				
	
	
		
			224 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package shim
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"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/connection"
 | |
| 	"github.com/containers/podman/v5/pkg/machine/define"
 | |
| 	"github.com/containers/podman/v5/pkg/machine/env"
 | |
| 	"github.com/containers/podman/v5/pkg/machine/ports"
 | |
| 	"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
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	ErrNotRunning      = errors.New("machine not in running state")
 | |
| 	ErrSSHNotListening = errors.New("machine is not listening on ssh port")
 | |
| )
 | |
| 
 | |
| 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
 | |
| 	runDir := dirs.RuntimeDir
 | |
| 	cmd.PidFile = filepath.Join(runDir.GetPath(), "gvproxy.pid")
 | |
| 
 | |
| 	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) {
 | |
| 	// Check if SSH port is in use, and reassign if necessary
 | |
| 	if !ports.IsLocalPortAvailable(mc.SSH.Port) {
 | |
| 		logrus.Warnf("detected port conflict on machine ssh port [%d], reassigning", mc.SSH.Port)
 | |
| 		if err := reassignSSHPort(mc, provider); err != nil {
 | |
| 			return "", 0, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Provider has its own networking code path (e.g. WSL)
 | |
| 	if provider.UseProviderNetworkSetup() {
 | |
| 		return "", 0, provider.StartNetworking(mc, nil)
 | |
| 	}
 | |
| 
 | |
| 	dirs, err := env.GetMachineDirs(provider.VMType())
 | |
| 	if err != nil {
 | |
| 		return "", 0, err
 | |
| 	}
 | |
| 
 | |
| 	hostSocks, forwardSock, forwardingState, err := setupMachineSockets(mc, 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 {
 | |
| 			sshError = ErrNotRunning
 | |
| 			continue
 | |
| 		}
 | |
| 		if !isListening(mc.SSH.Port) {
 | |
| 			sshError = ErrSSHNotListening
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		// 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
 | |
| 		sshError = nil
 | |
| 		break
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func reassignSSHPort(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) error {
 | |
| 	newPort, err := ports.AllocateMachinePort()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	success := false
 | |
| 	defer func() {
 | |
| 		if !success {
 | |
| 			if err := ports.ReleaseMachinePort(newPort); err != nil {
 | |
| 				logrus.Warnf("could not release port allocation as part of failure rollback (%d): %s", newPort, err.Error())
 | |
| 			}
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	// Write a transient invalid port, to force a retry on failure
 | |
| 	oldPort := mc.SSH.Port
 | |
| 	mc.SSH.Port = 0
 | |
| 	if err := mc.Write(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if err := ports.ReleaseMachinePort(oldPort); err != nil {
 | |
| 		logrus.Warnf("could not release current ssh port allocation (%d): %s", oldPort, err.Error())
 | |
| 	}
 | |
| 
 | |
| 	// Update the backend's settings if relevant (e.g. WSL)
 | |
| 	if err := provider.UpdateSSHPort(mc, newPort); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	mc.SSH.Port = newPort
 | |
| 	if err := connection.UpdateConnectionPairPort(mc.Name, newPort, mc.HostUser.UID, mc.SSH.RemoteUsername, mc.SSH.IdentityPath); err != nil {
 | |
| 		return fmt.Errorf("could not update remote connection configuration: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// Write updated port back
 | |
| 	if err := mc.Write(); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// inform defer routine not to release the port
 | |
| 	success = true
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| 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
 | |
| }
 |