mirror of https://github.com/containers/podman.git
Merge pull request #13750 from baude/refactor3
machine refactor 3: add symlinks for sockets
This commit is contained in:
commit
370821f3e3
|
@ -7,6 +7,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -20,6 +21,9 @@ const (
|
||||||
Next string = "next"
|
Next string = "next"
|
||||||
// Stable FCOS stream
|
// Stable FCOS stream
|
||||||
Stable string = "stable"
|
Stable string = "stable"
|
||||||
|
|
||||||
|
// Max length of fully qualified socket path
|
||||||
|
maxSocketPathLength int = 103
|
||||||
)
|
)
|
||||||
|
|
||||||
type Provider struct{}
|
type Provider struct{}
|
||||||
|
@ -197,8 +201,27 @@ func NewMachineFile(path string, symlink *string) (*MachineFile, error) {
|
||||||
if symlink != nil && len(*symlink) < 1 {
|
if symlink != nil && len(*symlink) < 1 {
|
||||||
return nil, errors.New("invalid symlink path")
|
return nil, errors.New("invalid symlink path")
|
||||||
}
|
}
|
||||||
return &MachineFile{
|
mf := MachineFile{Path: path}
|
||||||
Path: path,
|
if symlink != nil && len(path) > maxSocketPathLength {
|
||||||
Symlink: symlink,
|
if err := mf.makeSymlink(symlink); err != nil && !errors.Is(err, os.ErrExist) {
|
||||||
}, nil
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &mf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeSymlink for macOS creates a symlink in $HOME/.podman/
|
||||||
|
// for a machinefile like a socket
|
||||||
|
func (m *MachineFile) makeSymlink(symlink *string) error {
|
||||||
|
homedir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sl := filepath.Join(homedir, ".podman", *symlink)
|
||||||
|
// make the symlink dir and throw away if it already exists
|
||||||
|
if err := os.MkdirAll(filepath.Dir(sl), 0700); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Symlink = &sl
|
||||||
|
return os.Symlink(m.Path, sl)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package qemu
|
package qemu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containers/podman/v4/test/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMachineFile_GetPath(t *testing.T) {
|
func TestMachineFile_GetPath(t *testing.T) {
|
||||||
|
@ -45,10 +49,30 @@ func TestMachineFile_GetPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewMachineFile(t *testing.T) {
|
func TestNewMachineFile(t *testing.T) {
|
||||||
p := "/var/tmp/podman/my.sock"
|
|
||||||
sym := "/tmp/podman/my.sock"
|
|
||||||
empty := ""
|
empty := ""
|
||||||
|
|
||||||
|
homedir, err := os.MkdirTemp("/tmp", "homedir")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(homedir)
|
||||||
|
longTemp, err := os.MkdirTemp("/tmp", "tmpdir")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(longTemp)
|
||||||
|
oldhome := os.Getenv("HOME")
|
||||||
|
os.Setenv("HOME", homedir) //nolint: tenv
|
||||||
|
defer os.Setenv("HOME", oldhome)
|
||||||
|
|
||||||
|
p := "/var/tmp/podman/my.sock"
|
||||||
|
longp := filepath.Join(longTemp, utils.RandomString(100), "my.sock")
|
||||||
|
os.MkdirAll(filepath.Dir(longp), 0755)
|
||||||
|
f, _ := os.Create(longp)
|
||||||
|
f.Close()
|
||||||
|
sym := "my.sock"
|
||||||
|
longSym := filepath.Join(homedir, ".podman", sym)
|
||||||
|
|
||||||
m := MachineFile{
|
m := MachineFile{
|
||||||
Path: p,
|
Path: p,
|
||||||
Symlink: nil,
|
Symlink: nil,
|
||||||
|
@ -70,9 +94,9 @@ func TestNewMachineFile(t *testing.T) {
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Good with Symlink",
|
name: "Good with short symlink",
|
||||||
args: args{p, &sym},
|
args: args{p, &sym},
|
||||||
want: &MachineFile{p, &sym},
|
want: &MachineFile{p, nil},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -87,6 +111,12 @@ func TestNewMachineFile(t *testing.T) {
|
||||||
want: nil,
|
want: nil,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Good with long symlink",
|
||||||
|
args: args{longp, &sym},
|
||||||
|
want: &MachineFile{longp, &longSym},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -131,10 +131,11 @@ func (p *Provider) NewMachine(opts machine.InitOptions) (machine.VM, error) {
|
||||||
// Add serial port for readiness
|
// Add serial port for readiness
|
||||||
cmd = append(cmd, []string{
|
cmd = append(cmd, []string{
|
||||||
"-device", "virtio-serial",
|
"-device", "virtio-serial",
|
||||||
"-chardev", "socket,path=" + vm.getReadySocket() + ",server=on,wait=off,id=" + vm.Name + "_ready",
|
// qemu needs to establish the long name; other connections can use the symlink'd
|
||||||
|
"-chardev", "socket,path=" + vm.ReadySocket.Path + ",server=on,wait=off,id=" + vm.Name + "_ready",
|
||||||
"-device", "virtserialport,chardev=" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0"}...)
|
"-device", "virtserialport,chardev=" + vm.Name + "_ready" + ",name=org.fedoraproject.port.0"}...)
|
||||||
vm.CmdLine = cmd
|
vm.CmdLine = cmd
|
||||||
if err := vm.setQEMUAndPIDSocket(); err != nil {
|
if err := vm.setPIDSocket(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return vm, nil
|
return vm, nil
|
||||||
|
@ -487,9 +488,6 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := v.setQEMUAndPIDSocket(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// If the qemusocketpath exists and the vm is off/down, we should rm
|
// If the qemusocketpath exists and the vm is off/down, we should rm
|
||||||
// it before the dial as to avoid a segv
|
// it before the dial as to avoid a segv
|
||||||
if err := v.QMPMonitor.Address.Delete(); err != nil {
|
if err := v.QMPMonitor.Address.Delete(); err != nil {
|
||||||
|
@ -700,7 +698,7 @@ func (v *MachineVM) Stop(_ string, _ machine.StopOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(v.getPidFile()); os.IsNotExist(err) {
|
if _, err := os.Stat(v.PidFilePath.GetPath()); os.IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pidString, err := v.PidFilePath.Read()
|
pidString, err := v.PidFilePath.Read()
|
||||||
|
@ -748,7 +746,7 @@ func (v *MachineVM) Stop(_ string, _ machine.StopOptions) error {
|
||||||
waitInternal = waitInternal * 2
|
waitInternal = waitInternal * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return v.ReadySocket.Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewQMPMonitor creates the monitor subsection of our vm
|
// NewQMPMonitor creates the monitor subsection of our vm
|
||||||
|
@ -770,7 +768,7 @@ func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error)
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
timeout = defaultQMPTimeout
|
timeout = defaultQMPTimeout
|
||||||
}
|
}
|
||||||
address, err := NewMachineFile(filepath.Join(rtDir, "qmp+"+name+".sock"), nil)
|
address, err := NewMachineFile(filepath.Join(rtDir, "qmp_"+name+".sock"), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Monitor{}, err
|
return Monitor{}, err
|
||||||
}
|
}
|
||||||
|
@ -807,11 +805,14 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
|
||||||
if !opts.SaveImage {
|
if !opts.SaveImage {
|
||||||
files = append(files, v.getImageFile())
|
files = append(files, v.getImageFile())
|
||||||
}
|
}
|
||||||
socketPath, err := v.getForwardSocketPath()
|
socketPath, err := v.forwardSocketPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
return "", nil, err
|
||||||
}
|
}
|
||||||
files = append(files, socketPath)
|
if socketPath.Symlink != nil {
|
||||||
|
files = append(files, *socketPath.Symlink)
|
||||||
|
}
|
||||||
|
files = append(files, socketPath.Path)
|
||||||
files = append(files, v.archRemovalFiles()...)
|
files = append(files, v.archRemovalFiles()...)
|
||||||
|
|
||||||
if err := machine.RemoveConnection(v.Name); err != nil {
|
if err := machine.RemoveConnection(v.Name); err != nil {
|
||||||
|
@ -831,7 +832,6 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func()
|
||||||
confirmationMessage += msg + "\n"
|
confirmationMessage += msg + "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
//silently try to delete socket and pid file
|
|
||||||
//remove socket and pid file if any: warn at low priority if things fail
|
//remove socket and pid file if any: warn at low priority if things fail
|
||||||
// Remove the pidfile
|
// Remove the pidfile
|
||||||
if err := v.PidFilePath.Delete(); err != nil {
|
if err := v.PidFilePath.Delete(); err != nil {
|
||||||
|
@ -1083,7 +1083,7 @@ func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) {
|
||||||
files := []*os.File{os.Stdin, os.Stdout, os.Stderr}
|
files := []*os.File{os.Stdin, os.Stdout, os.Stderr}
|
||||||
attr.Files = files
|
attr.Files = files
|
||||||
cmd := []string{binary}
|
cmd := []string{binary}
|
||||||
cmd = append(cmd, []string{"-listen-qemu", fmt.Sprintf("unix://%s", v.getQMPMonitorSocket()), "-pid-file", v.getPidFile()}...)
|
cmd = append(cmd, []string{"-listen-qemu", fmt.Sprintf("unix://%s", v.QMPMonitor.Address.GetPath()), "-pid-file", v.PidFilePath.GetPath()}...)
|
||||||
// Add the ssh port
|
// Add the ssh port
|
||||||
cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", v.Port)}...)
|
cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", v.Port)}...)
|
||||||
|
|
||||||
|
@ -1102,7 +1102,7 @@ func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) setupAPIForwarding(cmd []string) ([]string, string, apiForwardingState) {
|
func (v *MachineVM) setupAPIForwarding(cmd []string) ([]string, string, apiForwardingState) {
|
||||||
socket, err := v.getForwardSocketPath()
|
socket, err := v.forwardSocketPath()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmd, "", noForwarding
|
return cmd, "", noForwarding
|
||||||
|
@ -1116,43 +1116,43 @@ func (v *MachineVM) setupAPIForwarding(cmd []string) ([]string, string, apiForwa
|
||||||
forwardUser = "root"
|
forwardUser = "root"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = append(cmd, []string{"-forward-sock", socket}...)
|
cmd = append(cmd, []string{"-forward-sock", socket.GetPath()}...)
|
||||||
cmd = append(cmd, []string{"-forward-dest", destSock}...)
|
cmd = append(cmd, []string{"-forward-dest", destSock}...)
|
||||||
cmd = append(cmd, []string{"-forward-user", forwardUser}...)
|
cmd = append(cmd, []string{"-forward-user", forwardUser}...)
|
||||||
cmd = append(cmd, []string{"-forward-identity", v.IdentityPath}...)
|
cmd = append(cmd, []string{"-forward-identity", v.IdentityPath}...)
|
||||||
link := filepath.Join(filepath.Dir(filepath.Dir(socket)), "podman.sock")
|
link := socket.GetPath()
|
||||||
|
|
||||||
// The linking pattern is /var/run/docker.sock -> user global sock (link) -> machine sock (socket)
|
// The linking pattern is /var/run/docker.sock -> user global sock (link) -> machine sock (socket)
|
||||||
// This allows the helper to only have to maintain one constant target to the user, which can be
|
// This allows the helper to only have to maintain one constant target to the user, which can be
|
||||||
// repositioned without updating docker.sock.
|
// repositioned without updating docker.sock.
|
||||||
if !dockerClaimSupported() {
|
if !dockerClaimSupported() {
|
||||||
return cmd, socket, claimUnsupported
|
return cmd, socket.GetPath(), claimUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
if !dockerClaimHelperInstalled() {
|
if !dockerClaimHelperInstalled() {
|
||||||
return cmd, socket, notInstalled
|
return cmd, socket.GetPath(), notInstalled
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alreadyLinked(socket, link) {
|
if !alreadyLinked(socket.GetPath(), link) {
|
||||||
if checkSockInUse(link) {
|
if checkSockInUse(link) {
|
||||||
return cmd, socket, machineLocal
|
return cmd, socket.GetPath(), machineLocal
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = os.Remove(link)
|
_ = os.Remove(link)
|
||||||
if err = os.Symlink(socket, link); err != nil {
|
if err = os.Symlink(socket.GetPath(), link); err != nil {
|
||||||
logrus.Warnf("could not create user global API forwarding link: %s", err.Error())
|
logrus.Warnf("could not create user global API forwarding link: %s", err.Error())
|
||||||
return cmd, socket, machineLocal
|
return cmd, socket.GetPath(), machineLocal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alreadyLinked(link, dockerSock) {
|
if !alreadyLinked(link, dockerSock) {
|
||||||
if checkSockInUse(dockerSock) {
|
if checkSockInUse(dockerSock) {
|
||||||
return cmd, socket, machineLocal
|
return cmd, socket.GetPath(), machineLocal
|
||||||
}
|
}
|
||||||
|
|
||||||
if !claimDockerSock() {
|
if !claimDockerSock() {
|
||||||
logrus.Warn("podman helper is installed, but was not able to claim the global docker sock")
|
logrus.Warn("podman helper is installed, but was not able to claim the global docker sock")
|
||||||
return cmd, socket, machineLocal
|
return cmd, socket.GetPath(), machineLocal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,13 +1163,14 @@ func (v *MachineVM) isIncompatible() bool {
|
||||||
return v.UID == -1
|
return v.UID == -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) getForwardSocketPath() (string, error) {
|
func (v *MachineVM) forwardSocketPath() (*MachineFile, error) {
|
||||||
|
sockName := "podman.sock"
|
||||||
path, err := machine.GetDataDir(v.Name)
|
path, err := machine.GetDataDir(v.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Resolving data dir: %s", err.Error())
|
logrus.Errorf("Resolving data dir: %s", err.Error())
|
||||||
return "", nil
|
return nil, err
|
||||||
}
|
}
|
||||||
return filepath.Join(path, "podman.sock"), nil
|
return NewMachineFile(filepath.Join(path, sockName), &sockName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) setConfigPath() error {
|
func (v *MachineVM) setConfigPath() error {
|
||||||
|
@ -1187,11 +1188,12 @@ func (v *MachineVM) setConfigPath() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) setReadySocket() error {
|
func (v *MachineVM) setReadySocket() error {
|
||||||
|
readySocketName := v.Name + "_ready.sock"
|
||||||
rtPath, err := getRuntimeDir()
|
rtPath, err := getRuntimeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
virtualSocketPath, err := NewMachineFile(filepath.Join(rtPath, "podman", v.Name+"_ready.sock"), nil)
|
virtualSocketPath, err := NewMachineFile(filepath.Join(rtPath, "podman", readySocketName), &readySocketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1199,7 +1201,7 @@ func (v *MachineVM) setReadySocket() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *MachineVM) setQEMUAndPIDSocket() error {
|
func (v *MachineVM) setPIDSocket() error {
|
||||||
rtPath, err := getRuntimeDir()
|
rtPath, err := getRuntimeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1207,8 +1209,9 @@ func (v *MachineVM) setQEMUAndPIDSocket() error {
|
||||||
if !rootless.IsRootless() {
|
if !rootless.IsRootless() {
|
||||||
rtPath = "/run"
|
rtPath = "/run"
|
||||||
}
|
}
|
||||||
|
pidFileName := fmt.Sprintf("%s.pid", v.Name)
|
||||||
socketDir := filepath.Join(rtPath, "podman")
|
socketDir := filepath.Join(rtPath, "podman")
|
||||||
pidFilePath, err := NewMachineFile(filepath.Join(socketDir, fmt.Sprintf("%s.pid", v.Name)), nil)
|
pidFilePath, err := NewMachineFile(filepath.Join(socketDir, pidFileName), &pidFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1216,7 +1219,7 @@ func (v *MachineVM) setQEMUAndPIDSocket() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: getSocketandPid is being replace by setQEMUAndPIDSocket and
|
// Deprecated: getSocketandPid is being replace by setPIDSocket and
|
||||||
// machinefiles.
|
// machinefiles.
|
||||||
func (v *MachineVM) getSocketandPid() (string, string, error) {
|
func (v *MachineVM) getSocketandPid() (string, string, error) {
|
||||||
rtPath, err := getRuntimeDir()
|
rtPath, err := getRuntimeDir()
|
||||||
|
@ -1342,7 +1345,7 @@ func (v *MachineVM) update() error {
|
||||||
}
|
}
|
||||||
b, err := v.ConfigPath.Read()
|
b, err := v.ConfigPath.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return errors.Wrap(machine.ErrNoSuchVM, v.Name)
|
return errors.Wrap(machine.ErrNoSuchVM, v.Name)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -1377,30 +1380,13 @@ func (v *MachineVM) writeConfig() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPidFile gets the file where the machine pid is stored
|
// getImageFile wrapper returns the path to the image used
|
||||||
func (v *MachineVM) getPidFile() string {
|
|
||||||
return v.PidFilePath.GetPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
// getQMPMonitorSocket gets the socket used by qemu to interact
|
|
||||||
// with the instance
|
|
||||||
func (v *MachineVM) getQMPMonitorSocket() string {
|
|
||||||
return v.QMPMonitor.Address.GetPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
// getReadySocket returns the socket used to communicate
|
|
||||||
// with the machinevm and report when it is booted
|
|
||||||
func (v *MachineVM) getReadySocket() string {
|
|
||||||
return v.ReadySocket.GetPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
// getImageFile returns the path to the image used
|
|
||||||
// to boot the VM
|
// to boot the VM
|
||||||
func (v *MachineVM) getImageFile() string {
|
func (v *MachineVM) getImageFile() string {
|
||||||
return v.ImagePath.GetPath()
|
return v.ImagePath.GetPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
// getIgnitionFile returns the path to the ignition file
|
// getIgnitionFile wrapper returns the path to the ignition file
|
||||||
func (v *MachineVM) getIgnitionFile() string {
|
func (v *MachineVM) getIgnitionFile() string {
|
||||||
return v.IgnitionFilePath.GetPath()
|
return v.IgnitionFilePath.GetPath()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue