mirror of https://github.com/containers/podman.git
				
				
				
			
		
			
				
	
	
		
			113 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
| package sockets
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"path/filepath"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/containers/podman/v5/pkg/machine/define"
 | |
| 	"github.com/containers/storage/pkg/fileutils"
 | |
| 	"github.com/sirupsen/logrus"
 | |
| )
 | |
| 
 | |
| // SetSocket creates a new machine file for the socket and assigns it to
 | |
| // `socketLoc`
 | |
| func SetSocket(socketLoc *define.VMFile, path string, symlink *string) error {
 | |
| 	socket, err := define.NewMachineFile(path, symlink)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	*socketLoc = *socket
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // ReadySocketPath returns the filepath for the ready socket
 | |
| func ReadySocketPath(runtimeDir, machineName string) string {
 | |
| 	return filepath.Join(runtimeDir, fmt.Sprintf("%s_ready.sock", machineName))
 | |
| }
 | |
| 
 | |
| // ListenAndWaitOnSocket waits for a new connection to the listener and sends
 | |
| // any error back through the channel. ListenAndWaitOnSocket is intended to be
 | |
| // used as a goroutine
 | |
| func ListenAndWaitOnSocket(errChan chan<- error, listener net.Listener) {
 | |
| 	conn, err := listener.Accept()
 | |
| 	if err != nil {
 | |
| 		logrus.Debug("failed to connect to ready socket")
 | |
| 		errChan <- err
 | |
| 		return
 | |
| 	}
 | |
| 	_, err = bufio.NewReader(conn).ReadString('\n')
 | |
| 	logrus.Debug("ready ack received")
 | |
| 
 | |
| 	if closeErr := conn.Close(); closeErr != nil {
 | |
| 		errChan <- closeErr
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	errChan <- err
 | |
| }
 | |
| 
 | |
| // DialSocketWithBackoffs attempts to connect to the socket in maxBackoffs attempts
 | |
| func DialSocketWithBackoffs(maxBackoffs int, backoff time.Duration, socketPath string) (conn net.Conn, err error) {
 | |
| 	for i := 0; i < maxBackoffs; i++ {
 | |
| 		if i > 0 {
 | |
| 			time.Sleep(backoff)
 | |
| 			backoff *= 2
 | |
| 		}
 | |
| 		conn, err = net.Dial("unix", socketPath)
 | |
| 		if err == nil {
 | |
| 			return conn, nil
 | |
| 		}
 | |
| 	}
 | |
| 	return nil, err
 | |
| }
 | |
| 
 | |
| // DialSocketWithBackoffsAndProcCheck attempts to connect to the socket in
 | |
| // maxBackoffs attempts. After every failure to connect, it makes sure the
 | |
| // specified process is alive
 | |
| func DialSocketWithBackoffsAndProcCheck(
 | |
| 	maxBackoffs int,
 | |
| 	backoff time.Duration,
 | |
| 	socketPath string,
 | |
| 	checkProccessStatus func(string, int, *bytes.Buffer) error,
 | |
| 	procHint string,
 | |
| 	procPid int,
 | |
| 	errBuf *bytes.Buffer,
 | |
| ) (conn net.Conn, err error) {
 | |
| 	for i := 0; i < maxBackoffs; i++ {
 | |
| 		if i > 0 {
 | |
| 			time.Sleep(backoff)
 | |
| 			backoff *= 2
 | |
| 		}
 | |
| 		conn, err = net.Dial("unix", socketPath)
 | |
| 		if err == nil {
 | |
| 			return conn, nil
 | |
| 		}
 | |
| 
 | |
| 		// check to make sure process denoted by procHint is alive
 | |
| 		err = checkProccessStatus(procHint, procPid, errBuf)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 	return nil, err
 | |
| }
 | |
| 
 | |
| // WaitForSocketWithBackoffs attempts to discover listening socket in maxBackoffs attempts
 | |
| func WaitForSocketWithBackoffs(maxBackoffs int, backoff time.Duration, socketPath string, name string) error {
 | |
| 	backoffWait := backoff
 | |
| 	logrus.Debugf("checking that %q socket is ready", name)
 | |
| 	for i := 0; i < maxBackoffs; i++ {
 | |
| 		err := fileutils.Exists(socketPath)
 | |
| 		if err == nil {
 | |
| 			return nil
 | |
| 		}
 | |
| 		time.Sleep(backoffWait)
 | |
| 		backoffWait *= 2
 | |
| 	}
 | |
| 	return fmt.Errorf("unable to connect to %q socket at %q", name, socketPath)
 | |
| }
 |