podman

Форк
0
/
pod.go 
536 строк · 14.7 Кб
1
//go:build !remote
2

3
package libpod
4

5
import (
6
	"errors"
7
	"fmt"
8
	"sort"
9
	"strings"
10
	"time"
11

12
	"github.com/containers/common/pkg/config"
13
	"github.com/containers/podman/v5/libpod/define"
14
	"github.com/containers/podman/v5/libpod/lock"
15
	"github.com/opencontainers/runtime-spec/specs-go"
16
)
17

18
// Pod represents a group of containers that are managed together.
19
// Any operations on a Pod that access state must begin with a call to
20
// updatePod().
21
// There is no guarantee that state exists in a readable state before this call,
22
// and even if it does its contents will be out of date and must be refreshed
23
// from the database.
24
// Generally, this requirement applies only to top-level functions; helpers can
25
// assume their callers handled this requirement. Generally speaking, if a
26
// function takes the pod lock and accesses any part of state, it should
27
// updatePod() immediately after locking.
28
// Pod represents a group of containers that may share namespaces
29
type Pod struct {
30
	config *PodConfig
31
	state  *podState
32

33
	valid   bool
34
	runtime *Runtime
35
	lock    lock.Locker
36
}
37

38
// PodConfig represents a pod's static configuration
39
type PodConfig struct {
40
	ID   string `json:"id"`
41
	Name string `json:"name"`
42
	// Namespace the pod is in
43
	Namespace string `json:"namespace,omitempty"`
44

45
	Hostname string `json:"hostname,omitempty"`
46

47
	// Labels contains labels applied to the pod
48
	Labels map[string]string `json:"labels"`
49
	// CgroupParent contains the pod's Cgroup parent
50
	CgroupParent string `json:"cgroupParent"`
51
	// UsePodCgroup indicates whether the pod will create its own Cgroup and
52
	// join containers to it.
53
	// If true, all containers joined to the pod will use the pod cgroup as
54
	// their cgroup parent, and cannot set a different cgroup parent
55
	UsePodCgroup bool `json:"sharesCgroup,omitempty"`
56

57
	// The following UsePod{kernelNamespace} indicate whether the containers
58
	// in the pod will inherit the namespace from the first container in the pod.
59
	UsePodPID      bool `json:"sharesPid,omitempty"`
60
	UsePodIPC      bool `json:"sharesIpc,omitempty"`
61
	UsePodNet      bool `json:"sharesNet,omitempty"`
62
	UsePodMount    bool `json:"sharesMnt,omitempty"`
63
	UsePodUser     bool `json:"sharesUser,omitempty"`
64
	UsePodUTS      bool `json:"sharesUts,omitempty"`
65
	UsePodCgroupNS bool `json:"sharesCgroupNS,omitempty"`
66

67
	HasInfra bool `json:"hasInfra,omitempty"`
68

69
	// ServiceContainerID is the main container of a service.  A service
70
	// consists of one or more pods.  The service container is started
71
	// before all pods and is stopped when the last pod stops.
72
	// The service container allows for tracking and managing the entire
73
	// life cycle of service which may be started via `podman-play-kube`.
74
	ServiceContainerID string `json:"serviceContainerID,omitempty"`
75

76
	// Time pod was created
77
	CreatedTime time.Time `json:"created"`
78

79
	// CreateCommand is the full command plus arguments of the process the
80
	// container has been created with.
81
	CreateCommand []string `json:"CreateCommand,omitempty"`
82

83
	// The pod's exit policy.
84
	ExitPolicy config.PodExitPolicy `json:"ExitPolicy,omitempty"`
85

86
	// The pod's restart policy
87
	RestartPolicy string `json:"RestartPolicy,omitempty"`
88

89
	// The max number of retries for a pod based on restart policy
90
	RestartRetries *uint `json:"RestartRetries,omitempty"`
91

92
	// ID of the pod's lock
93
	LockID uint32 `json:"lockID"`
94

95
	// ResourceLimits hold the pod level resource limits
96
	ResourceLimits specs.LinuxResources
97
}
98

99
// podState represents a pod's state
100
type podState struct {
101
	// CgroupPath is the path to the pod's Cgroup
102
	CgroupPath string `json:"cgroupPath"`
103
	// InfraContainerID is the container that holds pod namespace information
104
	// Most often an infra container
105
	InfraContainerID string
106
}
107

108
// ID retrieves the pod's ID
109
func (p *Pod) ID() string {
110
	return p.config.ID
111
}
112

113
// Name retrieves the pod's name
114
func (p *Pod) Name() string {
115
	return p.config.Name
116
}
117

118
// MountLabel returns the SELinux label associated with the pod
119
func (p *Pod) MountLabel() (string, error) {
120
	if !p.HasInfraContainer() {
121
		return "", nil
122
	}
123
	ctr, err := p.infraContainer()
124
	if err != nil {
125
		return "", err
126
	}
127
	return ctr.MountLabel(), nil
128
}
129

130
// Namespace returns the pod's libpod namespace.
131
// Namespaces are used to logically separate containers and pods in the state.
132
func (p *Pod) Namespace() string {
133
	return p.config.Namespace
134
}
135

136
// ResourceLim returns the cpuset resource limits for the pod
137
func (p *Pod) ResourceLim() *specs.LinuxResources {
138
	resCopy := &specs.LinuxResources{}
139
	empty := &specs.LinuxResources{
140
		CPU: &specs.LinuxCPU{},
141
	}
142
	if err := JSONDeepCopy(p.config.ResourceLimits, resCopy); err != nil {
143
		return nil
144
	}
145
	if resCopy.CPU != nil {
146
		return resCopy
147
	}
148

149
	return empty
150
}
151

152
// CPUPeriod returns the pod CPU period
153
func (p *Pod) CPUPeriod() uint64 {
154
	resLim := p.ResourceLim()
155
	if resLim.CPU == nil || resLim.CPU.Period == nil {
156
		return 0
157
	}
158
	return *resLim.CPU.Period
159
}
160

161
// CPUQuota returns the pod CPU quota
162
func (p *Pod) CPUQuota() int64 {
163
	resLim := p.ResourceLim()
164
	if resLim.CPU == nil || resLim.CPU.Quota == nil {
165
		return 0
166
	}
167
	return *resLim.CPU.Quota
168
}
169

170
// MemoryLimit returns the pod Memory Limit
171
func (p *Pod) MemoryLimit() uint64 {
172
	resLim := p.ResourceLim()
173
	if resLim.Memory == nil || resLim.Memory.Limit == nil {
174
		return 0
175
	}
176
	return uint64(*resLim.Memory.Limit)
177
}
178

179
// MemorySwap returns the pod Memory swap limit
180
func (p *Pod) MemorySwap() uint64 {
181
	resLim := p.ResourceLim()
182
	if resLim.Memory == nil || resLim.Memory.Swap == nil {
183
		return 0
184
	}
185
	return uint64(*resLim.Memory.Swap)
186
}
187

188
// BlkioWeight returns the pod blkio weight
189
func (p *Pod) BlkioWeight() uint64 {
190
	resLim := p.ResourceLim()
191
	if resLim.BlockIO == nil || resLim.BlockIO.Weight == nil {
192
		return 0
193
	}
194
	return uint64(*resLim.BlockIO.Weight)
195
}
196

197
// CPUSetMems returns the pod CPUSet memory nodes
198
func (p *Pod) CPUSetMems() string {
199
	resLim := p.ResourceLim()
200
	if resLim.CPU == nil {
201
		return ""
202
	}
203
	return resLim.CPU.Mems
204
}
205

206
// CPUShares returns the pod cpu shares
207
func (p *Pod) CPUShares() uint64 {
208
	resLim := p.ResourceLim()
209
	if resLim.CPU == nil || resLim.CPU.Shares == nil {
210
		return 0
211
	}
212
	return *resLim.CPU.Shares
213
}
214

215
// BlkiThrottleReadBps returns the pod  throttle devices
216
func (p *Pod) BlkiThrottleReadBps() []define.InspectBlkioThrottleDevice {
217
	resLim := p.ResourceLim()
218
	if resLim.BlockIO == nil || resLim.BlockIO.ThrottleReadBpsDevice == nil {
219
		return []define.InspectBlkioThrottleDevice{}
220
	}
221
	devs, err := blkioDeviceThrottle(nil, resLim.BlockIO.ThrottleReadBpsDevice)
222
	if err != nil {
223
		return []define.InspectBlkioThrottleDevice{}
224
	}
225
	return devs
226
}
227

228
// BlkiThrottleWriteBps returns the pod  throttle devices
229
func (p *Pod) BlkiThrottleWriteBps() []define.InspectBlkioThrottleDevice {
230
	resLim := p.ResourceLim()
231
	if resLim.BlockIO == nil || resLim.BlockIO.ThrottleWriteBpsDevice == nil {
232
		return []define.InspectBlkioThrottleDevice{}
233
	}
234
	devs, err := blkioDeviceThrottle(nil, resLim.BlockIO.ThrottleWriteBpsDevice)
235
	if err != nil {
236
		return []define.InspectBlkioThrottleDevice{}
237
	}
238
	return devs
239
}
240

241
// NetworkMode returns the Network mode given by the user ex: pod, private...
242
func (p *Pod) NetworkMode() string {
243
	infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
244
	if err != nil {
245
		return ""
246
	}
247
	return infra.NetworkMode()
248
}
249

250
// Namespace Mode returns the given NS mode provided by the user ex: host, private...
251
func (p *Pod) NamespaceMode(kind specs.LinuxNamespaceType) string {
252
	infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
253
	if err != nil {
254
		return ""
255
	}
256
	ctrSpec := infra.config.Spec
257
	if ctrSpec != nil && ctrSpec.Linux != nil {
258
		for _, ns := range ctrSpec.Linux.Namespaces {
259
			if ns.Type == kind {
260
				if ns.Path != "" {
261
					return fmt.Sprintf("ns:%s", ns.Path)
262
				}
263
				return "private"
264
			}
265
		}
266
		return "host"
267
	}
268
	return ""
269
}
270

271
// CPUQuota returns the pod CPU quota
272
func (p *Pod) VolumesFrom() []string {
273
	if p.state.InfraContainerID == "" {
274
		return nil
275
	}
276
	infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
277
	if err != nil {
278
		return nil
279
	}
280
	if ctrs, ok := infra.config.Spec.Annotations[define.VolumesFromAnnotation]; ok {
281
		return strings.Split(ctrs, ";")
282
	}
283
	return nil
284
}
285

286
// Labels returns the pod's labels
287
func (p *Pod) Labels() map[string]string {
288
	labels := make(map[string]string)
289
	for key, value := range p.config.Labels {
290
		labels[key] = value
291
	}
292

293
	return labels
294
}
295

296
// CreatedTime gets the time when the pod was created
297
func (p *Pod) CreatedTime() time.Time {
298
	return p.config.CreatedTime
299
}
300

301
// CreateCommand returns the os.Args of the process with which the pod has been
302
// created.
303
func (p *Pod) CreateCommand() []string {
304
	return p.config.CreateCommand
305
}
306

307
// CgroupParent returns the pod's Cgroup parent
308
func (p *Pod) CgroupParent() string {
309
	return p.config.CgroupParent
310
}
311

312
// SharesPID returns whether containers in pod
313
// default to use PID namespace of first container in pod
314
func (p *Pod) SharesPID() bool {
315
	return p.config.UsePodPID
316
}
317

318
// SharesIPC returns whether containers in pod
319
// default to use IPC namespace of first container in pod
320
func (p *Pod) SharesIPC() bool {
321
	return p.config.UsePodIPC
322
}
323

324
// SharesNet returns whether containers in pod
325
// default to use network namespace of first container in pod
326
func (p *Pod) SharesNet() bool {
327
	return p.config.UsePodNet
328
}
329

330
// SharesMount returns whether containers in pod
331
// default to use PID namespace of first container in pod
332
func (p *Pod) SharesMount() bool {
333
	return p.config.UsePodMount
334
}
335

336
// SharesUser returns whether containers in pod
337
// default to use user namespace of first container in pod
338
func (p *Pod) SharesUser() bool {
339
	return p.config.UsePodUser
340
}
341

342
// SharesUTS returns whether containers in pod
343
// default to use UTS namespace of first container in pod
344
func (p *Pod) SharesUTS() bool {
345
	return p.config.UsePodUTS
346
}
347

348
// SharesCgroup returns whether containers in the pod will default to this pod's
349
// cgroup instead of the default libpod parent
350
func (p *Pod) SharesCgroup() bool {
351
	return p.config.UsePodCgroupNS
352
}
353

354
// Hostname returns the hostname of the pod.
355
func (p *Pod) Hostname() string {
356
	return p.config.Hostname
357
}
358

359
// CgroupPath returns the path to the pod's Cgroup
360
func (p *Pod) CgroupPath() (string, error) {
361
	p.lock.Lock()
362
	defer p.lock.Unlock()
363
	if err := p.updatePod(); err != nil {
364
		return "", err
365
	}
366
	return p.state.CgroupPath, nil
367
}
368

369
// HasContainer checks if a container is present in the pod
370
func (p *Pod) HasContainer(id string) (bool, error) {
371
	if !p.valid {
372
		return false, define.ErrPodRemoved
373
	}
374

375
	return p.runtime.state.PodHasContainer(p, id)
376
}
377

378
// AllContainersByID returns the container IDs of all the containers in the pod
379
func (p *Pod) AllContainersByID() ([]string, error) {
380
	p.lock.Lock()
381
	defer p.lock.Unlock()
382

383
	if !p.valid {
384
		return nil, define.ErrPodRemoved
385
	}
386

387
	return p.runtime.state.PodContainersByID(p)
388
}
389

390
// AllContainers retrieves the containers in the pod
391
func (p *Pod) AllContainers() ([]*Container, error) {
392
	if !p.valid {
393
		return nil, define.ErrPodRemoved
394
	}
395
	p.lock.Lock()
396
	defer p.lock.Unlock()
397
	return p.allContainers()
398
}
399

400
func (p *Pod) allContainers() ([]*Container, error) {
401
	return p.runtime.state.PodContainers(p)
402
}
403

404
// HasInfraContainer returns whether the pod will create an infra container
405
func (p *Pod) HasInfraContainer() bool {
406
	return p.config.HasInfra
407
}
408

409
// SharesNamespaces checks if the pod has any kernel namespaces set as shared. An infra container will not be
410
// created if no kernel namespaces are shared.
411
func (p *Pod) SharesNamespaces() bool {
412
	return p.SharesPID() || p.SharesIPC() || p.SharesNet() || p.SharesMount() || p.SharesUser() || p.SharesUTS()
413
}
414

415
// infraContainerID returns the infra ID without a lock
416
func (p *Pod) infraContainerID() (string, error) {
417
	if err := p.updatePod(); err != nil {
418
		return "", err
419
	}
420
	return p.state.InfraContainerID, nil
421
}
422

423
// InfraContainerID returns the infra container ID for a pod.
424
// If the container returned is "", the pod has no infra container.
425
func (p *Pod) InfraContainerID() (string, error) {
426
	p.lock.Lock()
427
	defer p.lock.Unlock()
428
	return p.infraContainerID()
429
}
430

431
// infraContainer is the unlocked version of InfraContainer which returns the infra container
432
func (p *Pod) infraContainer() (*Container, error) {
433
	id, err := p.infraContainerID()
434
	if err != nil {
435
		return nil, err
436
	}
437
	if id == "" {
438
		return nil, fmt.Errorf("pod has no infra container: %w", define.ErrNoSuchCtr)
439
	}
440

441
	return p.runtime.state.Container(id)
442
}
443

444
// InfraContainer returns the infra container.
445
func (p *Pod) InfraContainer() (*Container, error) {
446
	p.lock.Lock()
447
	defer p.lock.Unlock()
448
	return p.infraContainer()
449
}
450

451
// TODO add pod batching
452
// Lock pod to avoid lock contention
453
// Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale)
454

455
// PodContainerStats is an organization struct for pods and their containers
456
type PodContainerStats struct {
457
	Pod            *Pod
458
	ContainerStats map[string]*define.ContainerStats
459
}
460

461
// GetPodStats returns the stats for each of its containers
462
func (p *Pod) GetPodStats(previousContainerStats map[string]*define.ContainerStats) (map[string]*define.ContainerStats, error) {
463
	p.lock.Lock()
464
	defer p.lock.Unlock()
465

466
	if err := p.updatePod(); err != nil {
467
		return nil, err
468
	}
469
	containers, err := p.runtime.state.PodContainers(p)
470
	if err != nil {
471
		return nil, err
472
	}
473
	newContainerStats := make(map[string]*define.ContainerStats)
474
	for _, c := range containers {
475
		newStats, err := c.GetContainerStats(previousContainerStats[c.ID()])
476
		// If the container wasn't running, don't include it
477
		// but also suppress the error
478
		if err != nil && !errors.Is(err, define.ErrCtrStateInvalid) {
479
			return nil, err
480
		}
481
		if err == nil {
482
			newContainerStats[c.ID()] = newStats
483
		}
484
	}
485
	return newContainerStats, nil
486
}
487

488
// ProcessLabel returns the SELinux label associated with the pod
489
func (p *Pod) ProcessLabel() (string, error) {
490
	if !p.HasInfraContainer() {
491
		return "", nil
492
	}
493
	ctr, err := p.infraContainer()
494
	if err != nil {
495
		return "", err
496
	}
497
	return ctr.ProcessLabel(), nil
498
}
499

500
// initContainers returns the list of initcontainers
501
// in a pod sorted by create time
502
func (p *Pod) initContainers() ([]*Container, error) {
503
	initCons := make([]*Container, 0)
504
	// the pod is already locked when this is called
505
	cons, err := p.allContainers()
506
	if err != nil {
507
		return nil, err
508
	}
509
	// Sort the pod containers by created time
510
	sort.Slice(cons, func(i, j int) bool { return cons[i].CreatedTime().Before(cons[j].CreatedTime()) })
511
	// Iterate sorted containers and add ids for any init containers
512
	for _, c := range cons {
513
		if len(c.config.InitContainerType) > 0 {
514
			initCons = append(initCons, c)
515
		}
516
	}
517
	return initCons, nil
518
}
519

520
func (p *Pod) Config() (*PodConfig, error) {
521
	p.lock.Lock()
522
	defer p.lock.Unlock()
523

524
	conf := &PodConfig{}
525

526
	err := JSONDeepCopy(p.config, conf)
527

528
	return conf, err
529
}
530

531
// ConfigNoCopy returns the configuration used by the pod.
532
// Note that the returned value is not a copy and must hence
533
// only be used in a reading fashion.
534
func (p *Pod) ConfigNoCopy() *PodConfig {
535
	return p.config
536
}
537

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

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

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

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