11
"github.com/containers/common/pkg/config"
12
gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types"
13
"github.com/containers/podman/v5/pkg/machine"
14
"github.com/containers/podman/v5/pkg/machine/connection"
15
"github.com/containers/podman/v5/pkg/machine/define"
16
"github.com/containers/podman/v5/pkg/machine/env"
17
"github.com/containers/podman/v5/pkg/machine/ports"
18
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
19
"github.com/sirupsen/logrus"
23
dockerSock = "/var/run/docker.sock"
24
defaultGuestSock = "/run/user/%d/podman/podman.sock"
25
dockerConnectTimeout = 5 * time.Second
29
ErrNotRunning = errors.New("machine not in running state")
30
ErrSSHNotListening = errors.New("machine is not listening on ssh port")
33
func startHostForwarder(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider, dirs *define.MachineDirs, hostSocks []string) error {
34
forwardUser := mc.SSH.RemoteUsername
36
// TODO should this go up the stack higher or
37
// the guestSock is "inside" the guest machine
38
guestSock := fmt.Sprintf(defaultGuestSock, mc.HostUser.UID)
39
if mc.HostUser.Rootful {
40
guestSock = "/run/podman/podman.sock"
44
cfg, err := config.Default()
49
binary, err := cfg.FindHelperBinary(machine.ForwarderBinaryName, false)
54
cmd := gvproxy.NewGvproxyCommand()
56
// GvProxy PID file path is now derived
57
runDir := dirs.RuntimeDir
58
cmd.PidFile = filepath.Join(runDir.GetPath(), "gvproxy.pid")
60
if logrus.IsLevelEnabled(logrus.DebugLevel) {
61
cmd.LogFile = filepath.Join(runDir.GetPath(), "gvproxy.log")
64
cmd.SSHPort = mc.SSH.Port
66
// Windows providers listen on multiple sockets since they do not involve links
67
for _, hostSock := range hostSocks {
68
cmd.AddForwardSock(hostSock)
69
cmd.AddForwardDest(guestSock)
70
cmd.AddForwardUser(forwardUser)
71
cmd.AddForwardIdentity(mc.SSH.IdentityPath)
74
if logrus.IsLevelEnabled(logrus.DebugLevel) {
79
// This allows a provider to perform additional setup as well as
80
// add in any provider specific options for gvproxy
81
if err := provider.StartNetworking(mc, &cmd); err != nil {
87
logrus.Debugf("gvproxy command-line: %s %s", binary, strings.Join(cmd.ToCmdline(), " "))
88
if err := c.Start(); err != nil {
89
return fmt.Errorf("unable to execute: %q: %w", cmd.ToCmdline(), err)
95
func startNetworking(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) (string, machine.APIForwardingState, error) {
96
// Check if SSH port is in use, and reassign if necessary
97
if !ports.IsLocalPortAvailable(mc.SSH.Port) {
98
logrus.Warnf("detected port conflict on machine ssh port [%d], reassigning", mc.SSH.Port)
99
if err := reassignSSHPort(mc, provider); err != nil {
104
// Provider has its own networking code path (e.g. WSL)
105
if provider.UseProviderNetworkSetup() {
106
return "", 0, provider.StartNetworking(mc, nil)
109
dirs, err := env.GetMachineDirs(provider.VMType())
114
hostSocks, forwardSock, forwardingState, err := setupMachineSockets(mc, dirs)
119
if err := startHostForwarder(mc, provider, dirs, hostSocks); err != nil {
123
return forwardSock, forwardingState, nil
126
// conductVMReadinessCheck checks to make sure the machine is in the proper state
127
// and that SSH is up and running
128
func conductVMReadinessCheck(mc *vmconfigs.MachineConfig, maxBackoffs int, backoff time.Duration, stateF func() (define.Status, error)) (connected bool, sshError error, err error) {
129
for i := 0; i < maxBackoffs; i++ {
134
state, err := stateF()
136
return false, nil, err
138
if state != define.Running {
139
sshError = ErrNotRunning
142
if !isListening(mc.SSH.Port) {
143
sshError = ErrSSHNotListening
147
// Also make sure that SSH is up and running. The
148
// ready service's dependencies don't fully make sure
149
// that clients can SSH into the machine immediately
152
// CoreOS users have reported the same observation but
153
// the underlying source of the issue remains unknown.
155
if sshError = machine.CommonSSHSilent(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, []string{"true"}); sshError != nil {
156
logrus.Debugf("SSH readiness check for machine failed: %v", sshError)
166
func reassignSSHPort(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) error {
167
newPort, err := ports.AllocateMachinePort()
175
if err := ports.ReleaseMachinePort(newPort); err != nil {
176
logrus.Warnf("could not release port allocation as part of failure rollback (%d): %s", newPort, err.Error())
181
// Write a transient invalid port, to force a retry on failure
182
oldPort := mc.SSH.Port
184
if err := mc.Write(); err != nil {
188
if err := ports.ReleaseMachinePort(oldPort); err != nil {
189
logrus.Warnf("could not release current ssh port allocation (%d): %s", oldPort, err.Error())
192
// Update the backend's settings if relevant (e.g. WSL)
193
if err := provider.UpdateSSHPort(mc, newPort); err != nil {
197
mc.SSH.Port = newPort
198
if err := connection.UpdateConnectionPairPort(mc.Name, newPort, mc.HostUser.UID, mc.SSH.RemoteUsername, mc.SSH.IdentityPath); err != nil {
199
return fmt.Errorf("could not update remote connection configuration: %w", err)
202
// Write updated port back
203
if err := mc.Write(); err != nil {
207
// inform defer routine not to release the port
213
func isListening(port int) bool {
214
// Check if we can dial it
215
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", port), 10*time.Millisecond)
219
if err := conn.Close(); err != nil {