mirror of
https://github.com/containers/podman.git
synced 2025-05-20 00:27:03 +08:00

This adds generic utility to convert file system path into URL structure. Instead of string manipulation it uses URL parsing and building routines. Appending absolute path to `unix:///` URL out of the box correctly handles URL format on Windows platform, where filepath should be prepended by additional `/` before drive letter. Signed-off-by: Arthur Sengileyev <arthur.sengileyev@gmail.com>
128 lines
3.3 KiB
Go
128 lines
3.3 KiB
Go
package sockets
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"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)
|
|
}
|
|
|
|
// ToUnixURL converts `socketLoc` into URL representation
|
|
func ToUnixURL(socketLoc *define.VMFile) (*url.URL, error) {
|
|
p := socketLoc.GetPath()
|
|
if !filepath.IsAbs(p) {
|
|
return nil, fmt.Errorf("socket path must be absolute %q", p)
|
|
}
|
|
s, err := url.Parse("unix:///")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s = s.JoinPath(filepath.ToSlash(p))
|
|
return s, nil
|
|
}
|