podman

Форк
0
/
container_internal_freebsd.go 
400 строк · 10.3 Кб
1
//go:build !remote
2

3
package libpod
4

5
import (
6
	"fmt"
7
	"os"
8
	"path/filepath"
9
	"strings"
10
	"sync"
11
	"syscall"
12
	"time"
13

14
	"github.com/containers/common/libnetwork/types"
15
	"github.com/containers/podman/v5/pkg/rootless"
16
	spec "github.com/opencontainers/runtime-spec/specs-go"
17
	"github.com/opencontainers/runtime-tools/generate"
18
	"github.com/sirupsen/logrus"
19
	"golang.org/x/sys/unix"
20
)
21

22
var (
23
	bindOptions = []string{}
24
)
25

26
func (c *Container) mountSHM(shmOptions string) error {
27
	return nil
28
}
29

30
func (c *Container) unmountSHM(path string) error {
31
	return nil
32
}
33

34
// prepare mounts the container and sets up other required resources like net
35
// namespaces
36
func (c *Container) prepare() error {
37
	var (
38
		wg                              sync.WaitGroup
39
		ctrNS                           string
40
		networkStatus                   map[string]types.StatusBlock
41
		createNetNSErr, mountStorageErr error
42
		mountPoint                      string
43
		tmpStateLock                    sync.Mutex
44
	)
45

46
	wg.Add(2)
47

48
	go func() {
49
		defer wg.Done()
50
		// Set up network namespace if not already set up
51
		noNetNS := c.state.NetNS == ""
52
		if c.config.CreateNetNS && noNetNS && !c.config.PostConfigureNetNS {
53
			ctrNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
54
			if createNetNSErr != nil {
55
				return
56
			}
57

58
			tmpStateLock.Lock()
59
			defer tmpStateLock.Unlock()
60

61
			// Assign NetNS attributes to container
62
			c.state.NetNS = ctrNS
63
			c.state.NetworkStatus = networkStatus
64
		}
65
	}()
66
	// Mount storage if not mounted
67
	go func() {
68
		defer wg.Done()
69
		mountPoint, mountStorageErr = c.mountStorage()
70

71
		if mountStorageErr != nil {
72
			return
73
		}
74

75
		tmpStateLock.Lock()
76
		defer tmpStateLock.Unlock()
77

78
		// Finish up mountStorage
79
		c.state.Mounted = true
80
		c.state.Mountpoint = mountPoint
81

82
		logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)
83
	}()
84

85
	wg.Wait()
86

87
	var createErr error
88
	if createNetNSErr != nil {
89
		createErr = createNetNSErr
90
	}
91
	if mountStorageErr != nil {
92
		if createErr != nil {
93
			logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
94
		}
95
		createErr = mountStorageErr
96
	}
97

98
	// Only trigger storage cleanup if mountStorage was successful.
99
	// Otherwise, we may mess up mount counters.
100
	if createErr != nil {
101
		if mountStorageErr == nil {
102
			if err := c.cleanupStorage(); err != nil {
103
				// createErr is guaranteed non-nil, so print
104
				// unconditionally
105
				logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
106
				createErr = fmt.Errorf("unmounting storage for container %s after network create failure: %w", c.ID(), err)
107
			}
108
		}
109
		// It's OK to unconditionally trigger network cleanup. If the network
110
		// isn't ready it will do nothing.
111
		if err := c.cleanupNetwork(); err != nil {
112
			logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
113
			createErr = fmt.Errorf("cleaning up container %s network after setup failure: %w", c.ID(), err)
114
		}
115
		return createErr
116
	}
117

118
	// Save changes to container state
119
	if err := c.save(); err != nil {
120
		return err
121
	}
122

123
	return nil
124
}
125

126
// cleanupNetwork unmounts and cleans up the container's network
127
func (c *Container) cleanupNetwork() error {
128
	if c.config.NetNsCtr != "" {
129
		return nil
130
	}
131
	netDisabled, err := c.NetworkDisabled()
132
	if err != nil {
133
		return err
134
	}
135
	if netDisabled {
136
		return nil
137
	}
138

139
	// Stop the container's network namespace (if it has one)
140
	if err := c.runtime.teardownNetNS(c); err != nil {
141
		logrus.Errorf("Unable to cleanup network for container %s: %q", c.ID(), err)
142
	}
143

144
	if c.valid {
145
		return c.save()
146
	}
147

148
	return nil
149
}
150

151
// reloadNetwork reloads the network for the given container, recreating
152
// firewall rules.
153
func (c *Container) reloadNetwork() error {
154
	result, err := c.runtime.reloadContainerNetwork(c)
155
	if err != nil {
156
		return err
157
	}
158

159
	c.state.NetworkStatus = result
160

161
	return c.save()
162
}
163

164
// Add an existing container's network jail
165
func (c *Container) addNetworkContainer(g *generate.Generator, ctr string) error {
166
	nsCtr, err := c.runtime.state.Container(ctr)
167
	if err != nil {
168
		return fmt.Errorf("retrieving dependency %s of container %s from state: %w", ctr, c.ID(), err)
169
	}
170
	c.runtime.state.UpdateContainer(nsCtr)
171
	if nsCtr.state.NetNS != "" {
172
		g.AddAnnotation("org.freebsd.parentJail", nsCtr.state.NetNS)
173
	}
174
	return nil
175
}
176

177
func isRootlessCgroupSet(cgroup string) bool {
178
	return false
179
}
180

181
func (c *Container) expectPodCgroup() (bool, error) {
182
	return false, nil
183
}
184

185
func (c *Container) getOCICgroupPath() (string, error) {
186
	return "", nil
187
}
188

189
func openDirectory(path string) (fd int, err error) {
190
	const O_PATH = 0x00400000
191
	return unix.Open(path, unix.O_RDONLY|O_PATH|unix.O_CLOEXEC, 0)
192
}
193

194
func (c *Container) addNetworkNamespace(g *generate.Generator) error {
195
	if c.config.CreateNetNS {
196
		// If PostConfigureNetNS is set (which is true on FreeBSD 13.3
197
		// and later), we can manage a container's network settings
198
		// without an extra parent jail to own the vnew.
199
		//
200
		// In this case, the OCI runtime creates a new vnet for the
201
		// container jail, otherwise it creates the container jail as a
202
		// child of the jail owning the vnet.
203
		if c.config.PostConfigureNetNS {
204
			g.AddAnnotation("org.freebsd.jail.vnet", "new")
205
		} else {
206
			g.AddAnnotation("org.freebsd.parentJail", c.state.NetNS)
207
		}
208
	}
209
	return nil
210
}
211

212
func (c *Container) addSystemdMounts(g *generate.Generator) error {
213
	return nil
214
}
215

216
func (c *Container) addSharedNamespaces(g *generate.Generator) error {
217
	if c.config.NetNsCtr != "" {
218
		if err := c.addNetworkContainer(g, c.config.NetNsCtr); err != nil {
219
			return err
220
		}
221
	}
222

223
	availableUIDs, availableGIDs, err := rootless.GetAvailableIDMaps()
224
	if err != nil {
225
		if os.IsNotExist(err) {
226
			// The kernel-provided files only exist if user namespaces are supported
227
			logrus.Debugf("User or group ID mappings not available: %s", err)
228
		} else {
229
			return err
230
		}
231
	} else {
232
		g.Config.Linux.UIDMappings = rootless.MaybeSplitMappings(g.Config.Linux.UIDMappings, availableUIDs)
233
		g.Config.Linux.GIDMappings = rootless.MaybeSplitMappings(g.Config.Linux.GIDMappings, availableGIDs)
234
	}
235

236
	// Hostname handling:
237
	// If we have a UTS namespace, set Hostname in the OCI spec.
238
	// Set the HOSTNAME environment variable unless explicitly overridden by
239
	// the user (already present in OCI spec). If we don't have a UTS ns,
240
	// set it to the host's hostname instead.
241
	hostname := c.Hostname()
242
	foundUTS := false
243

244
	// TODO: make this optional, needs progress on adding FreeBSD section to the spec
245
	foundUTS = true
246
	g.SetHostname(hostname)
247

248
	if !foundUTS {
249
		tmpHostname, err := os.Hostname()
250
		if err != nil {
251
			return err
252
		}
253
		hostname = tmpHostname
254
	}
255
	needEnv := true
256
	for _, checkEnv := range g.Config.Process.Env {
257
		if strings.HasPrefix(checkEnv, "HOSTNAME=") {
258
			needEnv = false
259
			break
260
		}
261
	}
262
	if needEnv {
263
		g.AddProcessEnv("HOSTNAME", hostname)
264
	}
265
	return nil
266
}
267

268
func (c *Container) addRootPropagation(g *generate.Generator, mounts []spec.Mount) error {
269
	return nil
270
}
271

272
func (c *Container) setProcessLabel(g *generate.Generator) {
273
}
274

275
func (c *Container) setMountLabel(g *generate.Generator) {
276
}
277

278
func (c *Container) setCgroupsPath(g *generate.Generator) error {
279
	return nil
280
}
281

282
func (c *Container) addSpecialDNS(nameservers []string) []string {
283
	return nameservers
284
}
285

286
func (c *Container) isSlirp4netnsIPv6() bool {
287
	return false
288
}
289

290
// check for net=none
291
func (c *Container) hasNetNone() bool {
292
	return c.state.NetNS == ""
293
}
294

295
func setVolumeAtime(mountPoint string, st os.FileInfo) error {
296
	stat := st.Sys().(*syscall.Stat_t)
297
	atime := time.Unix(int64(stat.Atimespec.Sec), int64(stat.Atimespec.Nsec)) //nolint: unconvert
298
	if err := os.Chtimes(mountPoint, atime, st.ModTime()); err != nil {
299
		return err
300
	}
301
	return nil
302
}
303

304
func (c *Container) makePlatformBindMounts() error {
305
	return nil
306
}
307

308
func (c *Container) getConmonPidFd() int {
309
	// Note: kqueue(2) could be used here but that would require
310
	// factoring out the call to unix.PollFd from WaitForExit so
311
	// keeping things simple for now.
312
	return -1
313
}
314

315
func (c *Container) jailName() (string, error) {
316
	// If this container is in a pod, get the vnet name from the
317
	// corresponding infra container
318
	var ic *Container
319
	if c.config.Pod != "" && c.config.Pod != c.ID() {
320
		// Get the pod from state
321
		pod, err := c.runtime.state.Pod(c.config.Pod)
322
		if err != nil {
323
			return "", fmt.Errorf("cannot find infra container for pod %s: %w", c.config.Pod, err)
324
		}
325
		ic, err = pod.InfraContainer()
326
		if err != nil {
327
			return "", fmt.Errorf("getting infra container for pod %s: %w", pod.ID(), err)
328
		}
329
		if ic.ID() != c.ID() {
330
			ic.lock.Lock()
331
			defer ic.lock.Unlock()
332
			if err := ic.syncContainer(); err != nil {
333
				return "", err
334
			}
335
		}
336
	} else {
337
		ic = c
338
	}
339

340
	if ic.state.NetNS != "" {
341
		return ic.state.NetNS + "." + c.ID(), nil
342
	} else {
343
		return c.ID(), nil
344
	}
345
}
346

347
type safeMountInfo struct {
348
	// mountPoint is the mount point.
349
	mountPoint string
350
}
351

352
// Close releases the resources allocated with the safe mount info.
353
func (s *safeMountInfo) Close() {
354
}
355

356
// safeMountSubPath securely mounts a subpath inside a volume to a new temporary location.
357
// The function checks that the subpath is a valid subpath within the volume and that it
358
// does not escape the boundaries of the mount point (volume).
359
//
360
// The caller is responsible for closing the file descriptor and unmounting the subpath
361
// when it's no longer needed.
362
func (c *Container) safeMountSubPath(mountPoint, subpath string) (s *safeMountInfo, err error) {
363
	return &safeMountInfo{mountPoint: filepath.Join(mountPoint, subpath)}, nil
364
}
365

366
func (c *Container) makePlatformMtabLink(etcInTheContainerFd, rootUID, rootGID int) error {
367
	// /etc/mtab does not exist on FreeBSD
368
	return nil
369
}
370

371
func (c *Container) getPlatformRunPath() (string, error) {
372
	// If we have a linux image, use "/run", otherwise use "/var/run" for
373
	// consistency with FreeBSD path conventions.
374
	runPath := "/var/run"
375
	if c.config.RootfsImageID != "" {
376
		image, _, err := c.runtime.libimageRuntime.LookupImage(c.config.RootfsImageID, nil)
377
		if err != nil {
378
			return "", err
379
		}
380
		inspectData, err := image.Inspect(nil, nil)
381
		if err != nil {
382
			return "", err
383
		}
384
		if inspectData.Os == "linux" {
385
			runPath = "/run"
386
		}
387
	}
388
	return runPath, nil
389
}
390

391
func (c *Container) addMaskedPaths(g *generate.Generator) {
392
	// There are currently no FreeBSD-specific masked paths
393
}
394

395
func (c *Container) hasPrivateUTS() bool {
396
	// Currently we always use a private UTS namespace on FreeBSD. This
397
	// should be optional but needs a FreeBSD section in the OCI runtime
398
	// specification.
399
	return true
400
}
401

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

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

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

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