podman

Форк
0
/
container_create.go 
737 строк · 23.2 Кб
1
//go:build !remote
2

3
package generate
4

5
import (
6
	"context"
7
	"encoding/json"
8
	"errors"
9
	"fmt"
10
	"os"
11
	"path/filepath"
12
	"strings"
13

14
	"github.com/containers/common/libimage"
15
	"github.com/containers/common/libnetwork/pasta"
16
	"github.com/containers/common/libnetwork/slirp4netns"
17
	"github.com/containers/podman/v5/libpod"
18
	"github.com/containers/podman/v5/libpod/define"
19
	"github.com/containers/podman/v5/pkg/namespaces"
20
	"github.com/containers/podman/v5/pkg/rootless"
21
	"github.com/containers/podman/v5/pkg/specgen"
22
	"github.com/containers/podman/v5/pkg/specgenutil"
23
	"github.com/containers/podman/v5/pkg/util"
24
	"github.com/opencontainers/runtime-spec/specs-go"
25
	"github.com/opencontainers/selinux/go-selinux/label"
26
	"github.com/sirupsen/logrus"
27
	"tags.cncf.io/container-device-interface/pkg/parser"
28
)
29

30
// MakeContainer creates a container based on the SpecGenerator.
31
// Returns the created, container and any warnings resulting from creating the
32
// container, or an error.
33
func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, clone bool, c *libpod.Container) (*specs.Spec, *specgen.SpecGenerator, []libpod.CtrCreateOption, error) {
34
	rtc, err := rt.GetConfigNoCopy()
35
	if err != nil {
36
		return nil, nil, nil, err
37
	}
38

39
	rlimits, err := specgenutil.GenRlimits(rtc.Ulimits())
40
	if err != nil {
41
		return nil, nil, nil, err
42
	}
43
	s.Rlimits = append(rlimits, s.Rlimits...)
44

45
	if s.OOMScoreAdj == nil {
46
		s.OOMScoreAdj = rtc.Containers.OOMScoreAdj
47
	}
48

49
	if len(rtc.Containers.CgroupConf.Get()) > 0 {
50
		if s.ResourceLimits == nil {
51
			s.ResourceLimits = &specs.LinuxResources{}
52
		}
53
		if s.ResourceLimits.Unified == nil {
54
			s.ResourceLimits.Unified = make(map[string]string)
55
		}
56
		for _, cgroupConf := range rtc.Containers.CgroupConf.Get() {
57
			key, val, hasVal := strings.Cut(cgroupConf, "=")
58
			if !hasVal {
59
				return nil, nil, nil, fmt.Errorf("CgroupConf %s from containers.conf invalid, must be name=value", cgroupConf)
60
			}
61
			if _, ok := s.ResourceLimits.Unified[key]; !ok {
62
				s.ResourceLimits.Unified[key] = val
63
			}
64
		}
65
	}
66

67
	// If joining a pod, retrieve the pod for use, and its infra container
68
	var pod *libpod.Pod
69
	var infra *libpod.Container
70
	if s.Pod != "" {
71
		pod, err = rt.LookupPod(s.Pod)
72
		if err != nil {
73
			return nil, nil, nil, fmt.Errorf("retrieving pod %s: %w", s.Pod, err)
74
		}
75
		if pod.HasInfraContainer() {
76
			infra, err = pod.InfraContainer()
77
			if err != nil {
78
				return nil, nil, nil, err
79
			}
80
		}
81
	}
82

83
	options := []libpod.CtrCreateOption{}
84
	compatibleOptions := &libpod.InfraInherit{}
85
	var infraSpec *specs.Spec
86
	if infra != nil {
87
		options, infraSpec, compatibleOptions, err = Inherit(infra, s, rt)
88
		if err != nil {
89
			return nil, nil, nil, err
90
		}
91
	}
92

93
	if err := specgen.FinishThrottleDevices(s); err != nil {
94
		return nil, nil, nil, err
95
	}
96

97
	// Set defaults for unset namespaces
98
	if s.PidNS.IsDefault() {
99
		defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod)
100
		if err != nil {
101
			return nil, nil, nil, err
102
		}
103
		s.PidNS = defaultNS
104
	}
105
	if s.IpcNS.IsDefault() {
106
		defaultNS, err := GetDefaultNamespaceMode("ipc", rtc, pod)
107
		if err != nil {
108
			return nil, nil, nil, err
109
		}
110
		s.IpcNS = defaultNS
111
	}
112
	if s.UtsNS.IsDefault() {
113
		defaultNS, err := GetDefaultNamespaceMode("uts", rtc, pod)
114
		if err != nil {
115
			return nil, nil, nil, err
116
		}
117
		s.UtsNS = defaultNS
118
	}
119
	if s.UserNS.IsDefault() {
120
		defaultNS, err := GetDefaultNamespaceMode("user", rtc, pod)
121
		if err != nil {
122
			return nil, nil, nil, err
123
		}
124
		s.UserNS = defaultNS
125
		value := string(s.UserNS.NSMode)
126
		if s.UserNS.Value != "" {
127
			value = value + ":" + s.UserNS.Value
128
		}
129
		mappings, err := util.ParseIDMapping(namespaces.UsernsMode(value), nil, nil, "", "")
130
		if err != nil {
131
			return nil, nil, nil, err
132
		}
133
		s.IDMappings = mappings
134
	}
135
	if s.NetNS.IsDefault() {
136
		defaultNS, err := GetDefaultNamespaceMode("net", rtc, pod)
137
		if err != nil {
138
			return nil, nil, nil, err
139
		}
140
		s.NetNS = defaultNS
141
	}
142
	if s.CgroupNS.IsDefault() {
143
		defaultNS, err := GetDefaultNamespaceMode("cgroup", rtc, pod)
144
		if err != nil {
145
			return nil, nil, nil, err
146
		}
147
		s.CgroupNS = defaultNS
148
	}
149

150
	if s.ContainerCreateCommand != nil {
151
		options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand))
152
	}
153

154
	if s.Rootfs != "" {
155
		rootfsOverlay := false
156
		if s.RootfsOverlay != nil {
157
			rootfsOverlay = *s.RootfsOverlay
158
		}
159
		options = append(options, libpod.WithRootFS(s.Rootfs, rootfsOverlay, s.RootfsMapping))
160
	}
161

162
	newImage, resolvedImageName, imageData, err := getImageFromSpec(ctx, rt, s)
163
	if err != nil {
164
		return nil, nil, nil, err
165
	}
166

167
	if imageData != nil {
168
		ociRuntimeVariant := rtc.Engine.ImagePlatformToRuntime(imageData.Os, imageData.Architecture)
169
		// Don't unnecessarily set and invoke additional libpod
170
		// option if OCI runtime is still default.
171
		if ociRuntimeVariant != rtc.Engine.OCIRuntime {
172
			options = append(options, libpod.WithCtrOCIRuntime(ociRuntimeVariant))
173
		}
174
	}
175

176
	if newImage != nil {
177
		// If the input name changed, we could properly resolve the
178
		// image. Otherwise, it must have been an ID where we're
179
		// defaulting to the first name or an empty one if no names are
180
		// present.
181
		if strings.HasPrefix(newImage.ID(), resolvedImageName) {
182
			names := newImage.Names()
183
			if len(names) > 0 {
184
				resolvedImageName = names[0]
185
			}
186
		}
187

188
		options = append(options, libpod.WithRootFSFromImage(newImage.ID(), resolvedImageName, s.RawImageName))
189
	}
190

191
	_, err = rt.LookupPod(s.Hostname)
192
	if len(s.Hostname) > 0 && !s.UtsNS.IsPrivate() && err == nil {
193
		// ok, we are incorrectly setting the pod as the hostname, let's undo that before validation
194
		s.Hostname = ""
195
	}
196

197
	// Set defaults if network info is not provided
198
	if s.NetNS.IsPrivate() || s.NetNS.IsDefault() {
199
		if rootless.IsRootless() {
200
			// when we are rootless we default to default_rootless_network_cmd from containers.conf
201
			conf, err := rt.GetConfigNoCopy()
202
			if err != nil {
203
				return nil, nil, nil, err
204
			}
205
			switch conf.Network.DefaultRootlessNetworkCmd {
206
			case slirp4netns.BinaryName, "":
207
				s.NetNS.NSMode = specgen.Slirp
208
			case pasta.BinaryName:
209
				s.NetNS.NSMode = specgen.Pasta
210
			default:
211
				return nil, nil, nil, fmt.Errorf("invalid default_rootless_network_cmd option %q",
212
					conf.Network.DefaultRootlessNetworkCmd)
213
			}
214
		} else {
215
			// as root default to bridge
216
			s.NetNS.NSMode = specgen.Bridge
217
		}
218
	}
219

220
	if err := s.Validate(); err != nil {
221
		return nil, nil, nil, fmt.Errorf("invalid config provided: %w", err)
222
	}
223

224
	finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage)
225
	if err != nil {
226
		return nil, nil, nil, err
227
	}
228

229
	if len(s.HostUsers) > 0 {
230
		options = append(options, libpod.WithHostUsers(s.HostUsers))
231
	}
232

233
	command := makeCommand(s, imageData)
234

235
	infraVol := len(compatibleOptions.Mounts) > 0 || len(compatibleOptions.Volumes) > 0 || len(compatibleOptions.ImageVolumes) > 0 || len(compatibleOptions.OverlayVolumes) > 0
236
	opts, err := createContainerOptions(rt, s, pod, finalVolumes, finalOverlays, imageData, command, infraVol, *compatibleOptions)
237
	if err != nil {
238
		return nil, nil, nil, err
239
	}
240
	options = append(options, opts...)
241

242
	if containerType := s.InitContainerType; len(containerType) > 0 {
243
		options = append(options, libpod.WithInitCtrType(containerType))
244
	}
245
	if len(s.Name) > 0 {
246
		logrus.Debugf("setting container name %s", s.Name)
247
		options = append(options, libpod.WithName(s.Name))
248
	}
249
	if len(s.Devices) > 0 {
250
		opts = ExtractCDIDevices(s)
251
		options = append(options, opts...)
252
	}
253
	runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command, compatibleOptions)
254
	if err != nil {
255
		return nil, nil, nil, err
256
	}
257
	if clone { // the container fails to start if cloned due to missing Linux spec entries
258
		if c == nil {
259
			return nil, nil, nil, errors.New("the given container could not be retrieved")
260
		}
261
		conf := c.Config()
262
		if conf != nil && conf.Spec != nil && conf.Spec.Linux != nil {
263
			out, err := json.Marshal(conf.Spec.Linux)
264
			if err != nil {
265
				return nil, nil, nil, err
266
			}
267
			resources := runtimeSpec.Linux.Resources
268

269
			// resources get overwritten similarly to pod inheritance, manually assign here if there is a new value
270
			marshalRes, err := json.Marshal(resources)
271
			if err != nil {
272
				return nil, nil, nil, err
273
			}
274

275
			err = json.Unmarshal(out, runtimeSpec.Linux)
276
			if err != nil {
277
				return nil, nil, nil, err
278
			}
279

280
			err = json.Unmarshal(marshalRes, runtimeSpec.Linux.Resources)
281
			if err != nil {
282
				return nil, nil, nil, err
283
			}
284
		}
285
		if s.ResourceLimits != nil {
286
			switch {
287
			case s.ResourceLimits.CPU != nil:
288
				runtimeSpec.Linux.Resources.CPU = s.ResourceLimits.CPU
289
			case s.ResourceLimits.Memory != nil:
290
				runtimeSpec.Linux.Resources.Memory = s.ResourceLimits.Memory
291
			case s.ResourceLimits.BlockIO != nil:
292
				runtimeSpec.Linux.Resources.BlockIO = s.ResourceLimits.BlockIO
293
			case s.ResourceLimits.Devices != nil:
294
				runtimeSpec.Linux.Resources.Devices = s.ResourceLimits.Devices
295
			}
296
		}
297
	}
298
	if len(s.HostDeviceList) > 0 {
299
		options = append(options, libpod.WithHostDevice(s.HostDeviceList))
300
	}
301
	if infraSpec != nil && infraSpec.Linux != nil { // if we are inheriting Linux info from a pod...
302
		// Pass Security annotations
303
		if len(infraSpec.Annotations[define.InspectAnnotationLabel]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationLabel]) == 0 {
304
			runtimeSpec.Annotations[define.InspectAnnotationLabel] = infraSpec.Annotations[define.InspectAnnotationLabel]
305
		}
306
		if len(infraSpec.Annotations[define.InspectAnnotationSeccomp]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationSeccomp]) == 0 {
307
			runtimeSpec.Annotations[define.InspectAnnotationSeccomp] = infraSpec.Annotations[define.InspectAnnotationSeccomp]
308
		}
309
		if len(infraSpec.Annotations[define.InspectAnnotationApparmor]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationApparmor]) == 0 {
310
			runtimeSpec.Annotations[define.InspectAnnotationApparmor] = infraSpec.Annotations[define.InspectAnnotationApparmor]
311
		}
312
	}
313
	return runtimeSpec, s, options, err
314
}
315
func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *specs.Spec, s *specgen.SpecGenerator, infra bool, options ...libpod.CtrCreateOption) (*libpod.Container, error) {
316
	ctr, err := rt.NewContainer(ctx, runtimeSpec, s, infra, options...)
317
	if err != nil {
318
		return ctr, err
319
	}
320

321
	return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr)
322
}
323

324
// ExtractCDIDevices process the list of Devices in the spec and determines if any of these are CDI devices.
325
// The CDI devices are added to the list of CtrCreateOptions.
326
// Note that this may modify the device list associated with the spec, which should then only contain non-CDI devices.
327
func ExtractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption {
328
	devs := make([]specs.LinuxDevice, 0, len(s.Devices))
329
	var cdiDevs []string
330
	var options []libpod.CtrCreateOption
331

332
	for _, device := range s.Devices {
333
		if isCDIDevice(device.Path) {
334
			logrus.Debugf("Identified CDI device %v", device.Path)
335
			cdiDevs = append(cdiDevs, device.Path)
336
			continue
337
		}
338
		logrus.Debugf("Non-CDI device %v; assuming standard device", device.Path)
339
		devs = append(devs, device)
340
	}
341
	s.Devices = devs
342
	if len(cdiDevs) > 0 {
343
		options = append(options, libpod.WithCDI(cdiDevs))
344
	}
345
	return options
346
}
347

348
// isCDIDevice checks whether the specified device is a CDI device.
349
func isCDIDevice(device string) bool {
350
	return parser.IsQualifiedName(device)
351
}
352

353
func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, imageData *libimage.ImageData, command []string, infraVolumes bool, compatibleOptions libpod.InfraInherit) ([]libpod.CtrCreateOption, error) {
354
	var options []libpod.CtrCreateOption
355
	var err error
356

357
	if s.PreserveFDs > 0 {
358
		options = append(options, libpod.WithPreserveFDs(s.PreserveFDs))
359
	}
360

361
	if s.PreserveFD != nil {
362
		options = append(options, libpod.WithPreserveFD(s.PreserveFD))
363
	}
364

365
	if s.Stdin != nil && *s.Stdin {
366
		options = append(options, libpod.WithStdin())
367
	}
368

369
	if s.Timezone != "" {
370
		options = append(options, libpod.WithTimezone(s.Timezone))
371
	}
372
	if s.Umask != "" {
373
		options = append(options, libpod.WithUmask(s.Umask))
374
	}
375
	if s.Volatile != nil && *s.Volatile {
376
		options = append(options, libpod.WithVolatile())
377
	}
378
	if s.PasswdEntry != "" {
379
		options = append(options, libpod.WithPasswdEntry(s.PasswdEntry))
380
	}
381
	if s.GroupEntry != "" {
382
		options = append(options, libpod.WithGroupEntry(s.GroupEntry))
383
	}
384
	if s.BaseHostsFile != "" {
385
		options = append(options, libpod.WithBaseHostsFile(s.BaseHostsFile))
386
	}
387

388
	if s.IsPrivileged() {
389
		options = append(options, libpod.WithMountAllDevices())
390
	}
391

392
	useSystemd := false
393
	switch s.Systemd {
394
	case "always":
395
		useSystemd = true
396
	case "false":
397
		break
398
	case "", "true":
399
		if len(command) == 0 && imageData != nil {
400
			command = imageData.Config.Cmd
401
		}
402

403
		if len(command) > 0 {
404
			useSystemdCommands := map[string]bool{
405
				"/sbin/init":           true,
406
				"/usr/sbin/init":       true,
407
				"/usr/local/sbin/init": true,
408
			}
409
			// Grab last command in case this is launched from a shell
410
			cmd := command
411
			if len(command) > 2 {
412
				// Podman build will add "/bin/sh" "-c" to
413
				// Entrypoint. Remove and search for systemd
414
				if command[0] == "/bin/sh" && command[1] == "-c" {
415
					cmd = command[2:]
416
				}
417
			}
418
			if useSystemdCommands[cmd[0]] || (filepath.Base(cmd[0]) == "systemd") {
419
				useSystemd = true
420
			}
421
		}
422
	default:
423
		return nil, fmt.Errorf("invalid value %q systemd option requires 'true, false, always': %w", s.Systemd, err)
424
	}
425
	logrus.Debugf("using systemd mode: %t", useSystemd)
426
	if useSystemd {
427
		// is StopSignal was not set by the user then set it to systemd
428
		// expected StopSigal
429
		if s.StopSignal == nil {
430
			stopSignal, err := util.ParseSignal("RTMIN+3")
431
			if err != nil {
432
				return nil, fmt.Errorf("parsing systemd signal: %w", err)
433
			}
434
			s.StopSignal = &stopSignal
435
		}
436

437
		options = append(options, libpod.WithSystemd())
438
	}
439
	if len(s.SdNotifyMode) > 0 {
440
		options = append(options, libpod.WithSdNotifyMode(s.SdNotifyMode))
441
		if s.SdNotifyMode != define.SdNotifyModeIgnore {
442
			if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
443
				options = append(options, libpod.WithSdNotifySocket(notify))
444
			}
445
		}
446
	}
447

448
	if pod != nil {
449
		logrus.Debugf("adding container to pod %s", pod.Name())
450
		options = append(options, rt.WithPod(pod))
451
	}
452
	destinations := []string{}
453
	// Take all mount and named volume destinations.
454
	for _, mount := range s.Mounts {
455
		destinations = append(destinations, mount.Destination)
456
	}
457
	for _, volume := range volumes {
458
		destinations = append(destinations, volume.Dest)
459
	}
460
	for _, overlayVolume := range overlays {
461
		destinations = append(destinations, overlayVolume.Destination)
462
	}
463
	for _, imageVolume := range s.ImageVolumes {
464
		destinations = append(destinations, imageVolume.Destination)
465
	}
466

467
	if len(destinations) > 0 || !infraVolumes {
468
		options = append(options, libpod.WithUserVolumes(destinations))
469
	}
470

471
	if len(volumes) != 0 {
472
		var vols []*libpod.ContainerNamedVolume
473
		for _, v := range volumes {
474
			vols = append(vols, &libpod.ContainerNamedVolume{
475
				Name:        v.Name,
476
				Dest:        v.Dest,
477
				Options:     v.Options,
478
				IsAnonymous: v.IsAnonymous,
479
				SubPath:     v.SubPath,
480
			})
481
		}
482
		options = append(options, libpod.WithNamedVolumes(vols))
483
	}
484

485
	if len(overlays) != 0 {
486
		var vols []*libpod.ContainerOverlayVolume
487
		for _, v := range overlays {
488
			vols = append(vols, &libpod.ContainerOverlayVolume{
489
				Dest:    v.Destination,
490
				Source:  v.Source,
491
				Options: v.Options,
492
			})
493
		}
494
		options = append(options, libpod.WithOverlayVolumes(vols))
495
	}
496

497
	if len(s.ImageVolumes) != 0 {
498
		var vols []*libpod.ContainerImageVolume
499
		for _, v := range s.ImageVolumes {
500
			vols = append(vols, &libpod.ContainerImageVolume{
501
				Dest:      v.Destination,
502
				Source:    v.Source,
503
				ReadWrite: v.ReadWrite,
504
			})
505
		}
506
		options = append(options, libpod.WithImageVolumes(vols))
507
	}
508

509
	if s.Command != nil {
510
		options = append(options, libpod.WithCommand(s.Command))
511
	}
512
	if s.Entrypoint != nil {
513
		options = append(options, libpod.WithEntrypoint(s.Entrypoint))
514
	}
515
	if len(s.ContainerStorageConfig.StorageOpts) > 0 {
516
		options = append(options, libpod.WithStorageOpts(s.StorageOpts))
517
	}
518
	// If the user did not specify a workdir on the CLI, let's extract it
519
	// from the image.
520
	if s.WorkDir == "" && imageData != nil {
521
		options = append(options, libpod.WithCreateWorkingDir())
522
		s.WorkDir = imageData.Config.WorkingDir
523
	}
524
	if s.WorkDir == "" {
525
		s.WorkDir = "/"
526
	}
527
	if s.CreateWorkingDir != nil && *s.CreateWorkingDir {
528
		options = append(options, libpod.WithCreateWorkingDir())
529
	}
530
	if s.StopSignal != nil {
531
		options = append(options, libpod.WithStopSignal(*s.StopSignal))
532
	}
533
	if s.StopTimeout != nil {
534
		options = append(options, libpod.WithStopTimeout(*s.StopTimeout))
535
	}
536
	if s.Timeout != 0 {
537
		options = append(options, libpod.WithTimeout(s.Timeout))
538
	}
539
	if s.LogConfiguration != nil {
540
		if len(s.LogConfiguration.Path) > 0 {
541
			options = append(options, libpod.WithLogPath(s.LogConfiguration.Path))
542
		}
543
		if s.LogConfiguration.Size > 0 {
544
			options = append(options, libpod.WithMaxLogSize(s.LogConfiguration.Size))
545
		}
546
		if len(s.LogConfiguration.Options) > 0 && s.LogConfiguration.Options["tag"] != "" {
547
			options = append(options, libpod.WithLogTag(s.LogConfiguration.Options["tag"]))
548
		}
549

550
		if len(s.LogConfiguration.Driver) > 0 {
551
			options = append(options, libpod.WithLogDriver(s.LogConfiguration.Driver))
552
		}
553
	}
554
	if s.LabelNested != nil {
555
		options = append(options, libpod.WithLabelNested(*s.LabelNested))
556
	}
557
	// Security options
558
	if len(s.SelinuxOpts) > 0 {
559
		options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
560
	} else if pod != nil && len(compatibleOptions.SelinuxOpts) == 0 {
561
		// duplicate the security options from the pod
562
		processLabel, err := pod.ProcessLabel()
563
		if err != nil {
564
			return nil, err
565
		}
566
		if processLabel != "" {
567
			selinuxOpts, err := label.DupSecOpt(processLabel)
568
			if err != nil {
569
				return nil, err
570
			}
571
			options = append(options, libpod.WithSecLabels(selinuxOpts))
572
		}
573
	}
574
	options = append(options, libpod.WithPrivileged(s.IsPrivileged()))
575
	if s.ReadWriteTmpfs != nil {
576
		options = append(options, libpod.WithReadWriteTmpfs(*s.ReadWriteTmpfs))
577
	}
578

579
	// Get namespace related options
580
	namespaceOpts, err := namespaceOptions(s, rt, pod, imageData)
581
	if err != nil {
582
		return nil, err
583
	}
584
	options = append(options, namespaceOpts...)
585

586
	if len(s.ConmonPidFile) > 0 {
587
		options = append(options, libpod.WithConmonPidFile(s.ConmonPidFile))
588
	}
589
	options = append(options, libpod.WithLabels(s.Labels))
590
	if s.ShmSize != nil {
591
		options = append(options, libpod.WithShmSize(*s.ShmSize))
592
	}
593
	if s.ShmSizeSystemd != nil {
594
		options = append(options, libpod.WithShmSizeSystemd(*s.ShmSizeSystemd))
595
	}
596
	if s.Rootfs != "" {
597
		rootfsOverlay := false
598
		if s.RootfsOverlay != nil {
599
			rootfsOverlay = *s.RootfsOverlay
600
		}
601
		options = append(options, libpod.WithRootFS(s.Rootfs, rootfsOverlay, s.RootfsMapping))
602
	}
603
	// Default used if not overridden on command line
604

605
	var (
606
		restartPolicy string
607
		retries       uint
608
	)
609
	// If the container is running in a pod, use the pod's restart policy for all the containers
610
	if pod != nil && !s.IsInitContainer() && s.RestartPolicy == "" {
611
		podConfig := pod.ConfigNoCopy()
612
		if podConfig.RestartRetries != nil {
613
			retries = *podConfig.RestartRetries
614
		}
615
		restartPolicy = podConfig.RestartPolicy
616
	} else if s.RestartPolicy != "" {
617
		if s.RestartRetries != nil {
618
			retries = *s.RestartRetries
619
		}
620
		restartPolicy = s.RestartPolicy
621
	}
622
	if restartPolicy != "" {
623
		options = append(options, libpod.WithRestartPolicy(restartPolicy))
624
	}
625
	if retries != 0 {
626
		options = append(options, libpod.WithRestartRetries(retries))
627
	}
628

629
	healthCheckSet := false
630
	if s.ContainerHealthCheckConfig.HealthConfig != nil {
631
		options = append(options, libpod.WithHealthCheck(s.ContainerHealthCheckConfig.HealthConfig))
632
		logrus.Debugf("New container has a health check")
633
		healthCheckSet = true
634
	}
635
	if s.ContainerHealthCheckConfig.StartupHealthConfig != nil {
636
		options = append(options, libpod.WithStartupHealthcheck(s.ContainerHealthCheckConfig.StartupHealthConfig))
637
		healthCheckSet = true
638
	}
639

640
	if s.ContainerHealthCheckConfig.HealthCheckOnFailureAction != define.HealthCheckOnFailureActionNone {
641
		options = append(options, libpod.WithHealthCheckOnFailureAction(s.ContainerHealthCheckConfig.HealthCheckOnFailureAction))
642
	}
643

644
	if s.SdNotifyMode == define.SdNotifyModeHealthy && !healthCheckSet {
645
		return nil, fmt.Errorf("%w: sdnotify policy %q requires a healthcheck to be set", define.ErrInvalidArg, s.SdNotifyMode)
646
	}
647

648
	if len(s.Secrets) != 0 {
649
		manager, err := rt.SecretsManager()
650
		if err != nil {
651
			return nil, err
652
		}
653
		var secrs []*libpod.ContainerSecret
654
		for _, s := range s.Secrets {
655
			secr, err := manager.Lookup(s.Source)
656
			if err != nil {
657
				return nil, err
658
			}
659
			secrs = append(secrs, &libpod.ContainerSecret{
660
				Secret: secr,
661
				UID:    s.UID,
662
				GID:    s.GID,
663
				Mode:   s.Mode,
664
				Target: s.Target,
665
			})
666
		}
667
		options = append(options, libpod.WithSecrets(secrs))
668
	}
669

670
	if len(s.EnvSecrets) != 0 {
671
		options = append(options, libpod.WithEnvSecrets(s.EnvSecrets))
672
	}
673

674
	if len(s.DependencyContainers) > 0 {
675
		deps := make([]*libpod.Container, 0, len(s.DependencyContainers))
676
		for _, ctr := range s.DependencyContainers {
677
			depCtr, err := rt.LookupContainer(ctr)
678
			if err != nil {
679
				return nil, fmt.Errorf("%q is not a valid container, cannot be used as a dependency: %w", ctr, err)
680
			}
681
			deps = append(deps, depCtr)
682
		}
683
		options = append(options, libpod.WithDependencyCtrs(deps))
684
	}
685
	if s.PidFile != "" {
686
		options = append(options, libpod.WithPidFile(s.PidFile))
687
	}
688

689
	if len(s.ChrootDirs) != 0 {
690
		options = append(options, libpod.WithChrootDirs(s.ChrootDirs))
691
	}
692

693
	options = append(options, libpod.WithSelectedPasswordManagement(s.Passwd))
694

695
	return options, nil
696
}
697

698
func Inherit(infra *libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtime) (opts []libpod.CtrCreateOption, infraS *specs.Spec, compat *libpod.InfraInherit, err error) {
699
	inheritSpec := &specgen.SpecGenerator{}
700
	_, compatibleOptions, err := ConfigToSpec(rt, inheritSpec, infra.ID())
701
	if err != nil {
702
		return nil, nil, nil, err
703
	}
704
	options := []libpod.CtrCreateOption{}
705
	infraConf := infra.Config()
706
	infraSpec := infraConf.Spec
707

708
	// need to set compatOptions to the currently filled specgenOptions so we do not overwrite
709
	compatibleOptions.CapAdd = append(compatibleOptions.CapAdd, s.CapAdd...)
710
	compatibleOptions.CapDrop = append(compatibleOptions.CapDrop, s.CapDrop...)
711
	compatibleOptions.HostDeviceList = append(compatibleOptions.HostDeviceList, s.HostDeviceList...)
712
	compatibleOptions.ImageVolumes = append(compatibleOptions.ImageVolumes, s.ImageVolumes...)
713
	compatibleOptions.Mounts = append(compatibleOptions.Mounts, s.Mounts...)
714
	compatibleOptions.OverlayVolumes = append(compatibleOptions.OverlayVolumes, s.OverlayVolumes...)
715
	compatibleOptions.SelinuxOpts = append(compatibleOptions.SelinuxOpts, s.SelinuxOpts...)
716
	compatibleOptions.Volumes = append(compatibleOptions.Volumes, s.Volumes...)
717

718
	compatByte, err := json.Marshal(compatibleOptions)
719
	if err != nil {
720
		return nil, nil, nil, err
721
	}
722
	err = json.Unmarshal(compatByte, s)
723
	if err != nil {
724
		return nil, nil, nil, err
725
	}
726

727
	// podman pod container can override pod ipc NS
728
	if !s.IpcNS.IsDefault() {
729
		inheritSpec.IpcNS = s.IpcNS
730
	}
731

732
	// this causes errors when shmSize is the default value, it will still get passed down unless we manually override.
733
	if inheritSpec.IpcNS.NSMode == specgen.Host && (compatibleOptions.ShmSize != nil && compatibleOptions.IsDefaultShmSize()) {
734
		s.ShmSize = nil
735
	}
736
	return options, infraSpec, compatibleOptions, nil
737
}
738

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

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

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

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