podman

Форк
0
/
networking.go 
223 строки · 6.1 Кб
1
package shim
2

3
import (
4
	"errors"
5
	"fmt"
6
	"net"
7
	"path/filepath"
8
	"strings"
9
	"time"
10

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"
20
)
21

22
const (
23
	dockerSock           = "/var/run/docker.sock"
24
	defaultGuestSock     = "/run/user/%d/podman/podman.sock"
25
	dockerConnectTimeout = 5 * time.Second
26
)
27

28
var (
29
	ErrNotRunning      = errors.New("machine not in running state")
30
	ErrSSHNotListening = errors.New("machine is not listening on ssh port")
31
)
32

33
func startHostForwarder(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider, dirs *define.MachineDirs, hostSocks []string) error {
34
	forwardUser := mc.SSH.RemoteUsername
35

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"
41
		forwardUser = "root"
42
	}
43

44
	cfg, err := config.Default()
45
	if err != nil {
46
		return err
47
	}
48

49
	binary, err := cfg.FindHelperBinary(machine.ForwarderBinaryName, false)
50
	if err != nil {
51
		return err
52
	}
53

54
	cmd := gvproxy.NewGvproxyCommand()
55

56
	// GvProxy PID file path is now derived
57
	runDir := dirs.RuntimeDir
58
	cmd.PidFile = filepath.Join(runDir.GetPath(), "gvproxy.pid")
59

60
	if logrus.IsLevelEnabled(logrus.DebugLevel) {
61
		cmd.LogFile = filepath.Join(runDir.GetPath(), "gvproxy.log")
62
	}
63

64
	cmd.SSHPort = mc.SSH.Port
65

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)
72
	}
73

74
	if logrus.IsLevelEnabled(logrus.DebugLevel) {
75
		cmd.Debug = true
76
		logrus.Debug(cmd)
77
	}
78

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 {
82
		return err
83
	}
84

85
	c := cmd.Cmd(binary)
86

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)
90
	}
91

92
	return nil
93
}
94

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 {
100
			return "", 0, err
101
		}
102
	}
103

104
	// Provider has its own networking code path (e.g. WSL)
105
	if provider.UseProviderNetworkSetup() {
106
		return "", 0, provider.StartNetworking(mc, nil)
107
	}
108

109
	dirs, err := env.GetMachineDirs(provider.VMType())
110
	if err != nil {
111
		return "", 0, err
112
	}
113

114
	hostSocks, forwardSock, forwardingState, err := setupMachineSockets(mc, dirs)
115
	if err != nil {
116
		return "", 0, err
117
	}
118

119
	if err := startHostForwarder(mc, provider, dirs, hostSocks); err != nil {
120
		return "", 0, err
121
	}
122

123
	return forwardSock, forwardingState, nil
124
}
125

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++ {
130
		if i > 0 {
131
			time.Sleep(backoff)
132
			backoff *= 2
133
		}
134
		state, err := stateF()
135
		if err != nil {
136
			return false, nil, err
137
		}
138
		if state != define.Running {
139
			sshError = ErrNotRunning
140
			continue
141
		}
142
		if !isListening(mc.SSH.Port) {
143
			sshError = ErrSSHNotListening
144
			continue
145
		}
146

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
150
		// after boot.
151
		//
152
		// CoreOS users have reported the same observation but
153
		// the underlying source of the issue remains unknown.
154

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)
157
			continue
158
		}
159
		connected = true
160
		sshError = nil
161
		break
162
	}
163
	return
164
}
165

166
func reassignSSHPort(mc *vmconfigs.MachineConfig, provider vmconfigs.VMProvider) error {
167
	newPort, err := ports.AllocateMachinePort()
168
	if err != nil {
169
		return err
170
	}
171

172
	success := false
173
	defer func() {
174
		if !success {
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())
177
			}
178
		}
179
	}()
180

181
	// Write a transient invalid port, to force a retry on failure
182
	oldPort := mc.SSH.Port
183
	mc.SSH.Port = 0
184
	if err := mc.Write(); err != nil {
185
		return err
186
	}
187

188
	if err := ports.ReleaseMachinePort(oldPort); err != nil {
189
		logrus.Warnf("could not release current ssh port allocation (%d): %s", oldPort, err.Error())
190
	}
191

192
	// Update the backend's settings if relevant (e.g. WSL)
193
	if err := provider.UpdateSSHPort(mc, newPort); err != nil {
194
		return err
195
	}
196

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)
200
	}
201

202
	// Write updated port back
203
	if err := mc.Write(); err != nil {
204
		return err
205
	}
206

207
	// inform defer routine not to release the port
208
	success = true
209

210
	return nil
211
}
212

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)
216
	if err != nil {
217
		return false
218
	}
219
	if err := conn.Close(); err != nil {
220
		logrus.Error(err)
221
	}
222
	return true
223
}
224

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.