mirror of
				https://github.com/containers/podman.git
				synced 2025-11-04 08:56:05 +08:00 
			
		
		
		
	- 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
 | 
						|
}
 |