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>
		
			
				
	
	
		
			114 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //go:build dragonfly || freebsd || linux || netbsd || openbsd || darwin
 | |
| 
 | |
| package shim
 | |
| 
 | |
| import (
 | |
| 	"io/fs"
 | |
| 	"net"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 
 | |
| 	"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"
 | |
| )
 | |
| 
 | |
| func setupMachineSockets(mc *vmconfigs.MachineConfig, dirs *define.MachineDirs) ([]string, string, machine.APIForwardingState, error) {
 | |
| 	hostSocket, err := mc.APISocket()
 | |
| 	if err != nil {
 | |
| 		return nil, "", 0, err
 | |
| 	}
 | |
| 
 | |
| 	forwardSock, state, err := setupForwardingLinks(hostSocket, dirs.DataDir)
 | |
| 	if err != nil {
 | |
| 		return nil, "", 0, err
 | |
| 	}
 | |
| 	return []string{hostSocket.GetPath()}, forwardSock, state, nil
 | |
| }
 | |
| 
 | |
| func setupForwardingLinks(hostSocket, dataDir *define.VMFile) (string, machine.APIForwardingState, error) {
 | |
| 	// Sets up a cooperative link structure to help a separate privileged
 | |
| 	// service manage /var/run/docker.sock (currently only on MacOS via
 | |
| 	// podman-mac-helper, but potentially other OSs in the future).
 | |
| 	//
 | |
| 	// The linking pattern is:
 | |
| 	//
 | |
| 	// /var/run/docker.sock (link) -> user global sock (link) -> machine sock
 | |
| 	//
 | |
| 	// This allows the helper to only have to maintain one constant target to
 | |
| 	// the user, which can be repositioned without updating docker.sock.
 | |
| 	//
 | |
| 	// Since these link locations are global/shared across multiple machine
 | |
| 	// instances, they must coordinate on the winner. The scheme is first come
 | |
| 	// first serve, whoever is actively answering on the socket first wins. All
 | |
| 	// other machine instances backs off. As soon as the winner is no longer
 | |
| 	// active another machine instance start will become the new active winner.
 | |
| 	// The same applies to a competing container runtime trying to use
 | |
| 	// /var/run/docker.sock, if the socket is in use by another runtime, podman
 | |
| 	// machine will back off. In the start message "Losing" machine instances
 | |
| 	// will instead advertise the direct machine socket, while "winning"
 | |
| 	// instances will simply note they listen on the standard
 | |
| 	// /var/run/docker.sock address. The APIForwardingState return value is
 | |
| 	// returned by this function to indicate how the start message should behave
 | |
| 
 | |
| 	// Skip any OS not supported for helper usage
 | |
| 	if !dockerClaimSupported() {
 | |
| 		return hostSocket.GetPath(), machine.ClaimUnsupported, nil
 | |
| 	}
 | |
| 
 | |
| 	// Verify the helper system service was installed and report back if not
 | |
| 	if !dockerClaimHelperInstalled() {
 | |
| 		return hostSocket.GetPath(), machine.NotInstalled, nil
 | |
| 	}
 | |
| 
 | |
| 	dataPath := filepath.Dir(dataDir.GetPath())
 | |
| 	userGlobalSocket, err := define.NewMachineFile(filepath.Join(dataPath, "podman.sock"), nil)
 | |
| 	if err != nil {
 | |
| 		return "", 0, err
 | |
| 	}
 | |
| 
 | |
| 	// Setup the user global socket if not in use
 | |
| 	// (e.g ~/.local/share/containers/podman/machine/podman.sock)
 | |
| 	if !alreadyLinked(hostSocket.GetPath(), userGlobalSocket.GetPath()) {
 | |
| 		if checkSockInUse(userGlobalSocket.GetPath()) {
 | |
| 			return hostSocket.GetPath(), machine.MachineLocal, nil
 | |
| 		}
 | |
| 
 | |
| 		_ = userGlobalSocket.Delete()
 | |
| 
 | |
| 		if err := os.Symlink(hostSocket.GetPath(), userGlobalSocket.GetPath()); err != nil {
 | |
| 			logrus.Warnf("could not create user global API forwarding link: %s", err.Error())
 | |
| 			return hostSocket.GetPath(), machine.MachineLocal, nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Setup /var/run/docker.sock if not in use
 | |
| 	if !alreadyLinked(userGlobalSocket.GetPath(), dockerSock) {
 | |
| 		if checkSockInUse(dockerSock) {
 | |
| 			return hostSocket.GetPath(), machine.MachineLocal, nil
 | |
| 		}
 | |
| 
 | |
| 		if !claimDockerSock() {
 | |
| 			logrus.Warn("podman helper is installed, but was not able to claim the global docker sock")
 | |
| 			return hostSocket.GetPath(), machine.MachineLocal, nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return dockerSock, machine.DockerGlobal, nil
 | |
| }
 | |
| 
 | |
| func alreadyLinked(target string, link string) bool {
 | |
| 	read, err := os.Readlink(link)
 | |
| 	return err == nil && read == target
 | |
| }
 | |
| 
 | |
| func checkSockInUse(sock string) bool {
 | |
| 	if info, err := os.Stat(sock); err == nil && info.Mode()&fs.ModeSocket == fs.ModeSocket {
 | |
| 		_, err = net.DialTimeout("unix", dockerSock, dockerConnectTimeout)
 | |
| 		return err == nil
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 |