github.com/containers/podman/v4@v4.9.4/pkg/specgen/generate/container_create.go (about) 1 //go:build !remote 2 // +build !remote 3 4 package generate 5 6 import ( 7 "context" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "os" 12 "path/filepath" 13 "strings" 14 15 "github.com/containers/common/libimage" 16 "github.com/containers/common/libnetwork/pasta" 17 "github.com/containers/common/libnetwork/slirp4netns" 18 "github.com/containers/podman/v4/libpod" 19 "github.com/containers/podman/v4/libpod/define" 20 "github.com/containers/podman/v4/pkg/namespaces" 21 "github.com/containers/podman/v4/pkg/rootless" 22 "github.com/containers/podman/v4/pkg/specgen" 23 "github.com/containers/podman/v4/pkg/specgenutil" 24 "github.com/containers/podman/v4/pkg/util" 25 "github.com/opencontainers/runtime-spec/specs-go" 26 "github.com/opencontainers/selinux/go-selinux/label" 27 "github.com/sirupsen/logrus" 28 "tags.cncf.io/container-device-interface/pkg/parser" 29 ) 30 31 // MakeContainer creates a container based on the SpecGenerator. 32 // Returns the created, container and any warnings resulting from creating the 33 // container, or an error. 34 func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, clone bool, c *libpod.Container) (*specs.Spec, *specgen.SpecGenerator, []libpod.CtrCreateOption, error) { 35 rtc, err := rt.GetConfigNoCopy() 36 if err != nil { 37 return nil, nil, nil, err 38 } 39 40 rlimits, err := specgenutil.GenRlimits(rtc.Ulimits()) 41 if err != nil { 42 return nil, nil, nil, err 43 } 44 s.Rlimits = append(rlimits, s.Rlimits...) 45 46 if s.OOMScoreAdj == nil { 47 s.OOMScoreAdj = rtc.Containers.OOMScoreAdj 48 } 49 50 if len(rtc.Containers.CgroupConf.Get()) > 0 { 51 if s.ResourceLimits == nil { 52 s.ResourceLimits = &specs.LinuxResources{} 53 } 54 if s.ResourceLimits.Unified == nil { 55 s.ResourceLimits.Unified = make(map[string]string) 56 } 57 for _, cgroupConf := range rtc.Containers.CgroupConf.Get() { 58 cgr := strings.SplitN(cgroupConf, "=", 2) 59 if len(cgr) != 2 { 60 return nil, nil, nil, fmt.Errorf("CgroupConf %q from containers.conf invalid, must be name=value", cgr) 61 } 62 if _, ok := s.ResourceLimits.Unified[cgr[0]]; !ok { 63 s.ResourceLimits.Unified[cgr[0]] = cgr[1] 64 } 65 } 66 } 67 68 // If joining a pod, retrieve the pod for use, and its infra container 69 var pod *libpod.Pod 70 var infra *libpod.Container 71 if s.Pod != "" { 72 pod, err = rt.LookupPod(s.Pod) 73 if err != nil { 74 return nil, nil, nil, fmt.Errorf("retrieving pod %s: %w", s.Pod, err) 75 } 76 if pod.HasInfraContainer() { 77 infra, err = pod.InfraContainer() 78 if err != nil { 79 return nil, nil, nil, err 80 } 81 } 82 } 83 84 options := []libpod.CtrCreateOption{} 85 compatibleOptions := &libpod.InfraInherit{} 86 var infraSpec *specs.Spec 87 if infra != nil { 88 options, infraSpec, compatibleOptions, err = Inherit(infra, s, rt) 89 if err != nil { 90 return nil, nil, nil, err 91 } 92 } 93 94 if err := specgen.FinishThrottleDevices(s); err != nil { 95 return nil, nil, nil, err 96 } 97 98 // Set defaults for unset namespaces 99 if s.PidNS.IsDefault() { 100 defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod) 101 if err != nil { 102 return nil, nil, nil, err 103 } 104 s.PidNS = defaultNS 105 } 106 if s.IpcNS.IsDefault() { 107 defaultNS, err := GetDefaultNamespaceMode("ipc", rtc, pod) 108 if err != nil { 109 return nil, nil, nil, err 110 } 111 s.IpcNS = defaultNS 112 } 113 if s.UtsNS.IsDefault() { 114 defaultNS, err := GetDefaultNamespaceMode("uts", rtc, pod) 115 if err != nil { 116 return nil, nil, nil, err 117 } 118 s.UtsNS = defaultNS 119 } 120 if s.UserNS.IsDefault() { 121 defaultNS, err := GetDefaultNamespaceMode("user", rtc, pod) 122 if err != nil { 123 return nil, nil, nil, err 124 } 125 s.UserNS = defaultNS 126 value := string(s.UserNS.NSMode) 127 if s.UserNS.Value != "" { 128 value = value + ":" + s.UserNS.Value 129 } 130 mappings, err := util.ParseIDMapping(namespaces.UsernsMode(value), nil, nil, "", "") 131 if err != nil { 132 return nil, nil, nil, err 133 } 134 s.IDMappings = mappings 135 } 136 if s.NetNS.IsDefault() { 137 defaultNS, err := GetDefaultNamespaceMode("net", rtc, pod) 138 if err != nil { 139 return nil, nil, nil, err 140 } 141 s.NetNS = defaultNS 142 } 143 if s.CgroupNS.IsDefault() { 144 defaultNS, err := GetDefaultNamespaceMode("cgroup", rtc, pod) 145 if err != nil { 146 return nil, nil, nil, err 147 } 148 s.CgroupNS = defaultNS 149 } 150 151 if s.ContainerCreateCommand != nil { 152 options = append(options, libpod.WithCreateCommand(s.ContainerCreateCommand)) 153 } 154 155 if s.Rootfs != "" { 156 options = append(options, libpod.WithRootFS(s.Rootfs, s.RootfsOverlay, s.RootfsMapping)) 157 } 158 159 newImage, resolvedImageName, imageData, err := getImageFromSpec(ctx, rt, s) 160 if err != nil { 161 return nil, nil, nil, err 162 } 163 164 if imageData != nil { 165 ociRuntimeVariant := rtc.Engine.ImagePlatformToRuntime(imageData.Os, imageData.Architecture) 166 // Don't unnecessarily set and invoke additional libpod 167 // option if OCI runtime is still default. 168 if ociRuntimeVariant != rtc.Engine.OCIRuntime { 169 options = append(options, libpod.WithCtrOCIRuntime(ociRuntimeVariant)) 170 } 171 } 172 173 if newImage != nil { 174 // If the input name changed, we could properly resolve the 175 // image. Otherwise, it must have been an ID where we're 176 // defaulting to the first name or an empty one if no names are 177 // present. 178 if strings.HasPrefix(newImage.ID(), resolvedImageName) { 179 names := newImage.Names() 180 if len(names) > 0 { 181 resolvedImageName = names[0] 182 } 183 } 184 185 options = append(options, libpod.WithRootFSFromImage(newImage.ID(), resolvedImageName, s.RawImageName)) 186 } 187 188 _, err = rt.LookupPod(s.Hostname) 189 if len(s.Hostname) > 0 && !s.UtsNS.IsPrivate() && err == nil { 190 // ok, we are incorrectly setting the pod as the hostname, let's undo that before validation 191 s.Hostname = "" 192 } 193 194 // Set defaults if network info is not provided 195 if s.NetNS.IsPrivate() || s.NetNS.IsDefault() { 196 if rootless.IsRootless() { 197 // when we are rootless we default to default_rootless_network_cmd from containers.conf 198 conf, err := rt.GetConfigNoCopy() 199 if err != nil { 200 return nil, nil, nil, err 201 } 202 switch conf.Network.DefaultRootlessNetworkCmd { 203 case slirp4netns.BinaryName, "": 204 s.NetNS.NSMode = specgen.Slirp 205 case pasta.BinaryName: 206 s.NetNS.NSMode = specgen.Pasta 207 default: 208 return nil, nil, nil, fmt.Errorf("invalid default_rootless_network_cmd option %q", 209 conf.Network.DefaultRootlessNetworkCmd) 210 } 211 } else { 212 // as root default to bridge 213 s.NetNS.NSMode = specgen.Bridge 214 } 215 } 216 217 if err := s.Validate(); err != nil { 218 return nil, nil, nil, fmt.Errorf("invalid config provided: %w", err) 219 } 220 221 finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage) 222 if err != nil { 223 return nil, nil, nil, err 224 } 225 226 if len(s.HostUsers) > 0 { 227 options = append(options, libpod.WithHostUsers(s.HostUsers)) 228 } 229 230 command, err := makeCommand(s, imageData) 231 if err != nil { 232 return nil, nil, nil, err 233 } 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 clone { // the container fails to start if cloned due to missing Linux spec entries 255 if c == nil { 256 return nil, nil, nil, errors.New("the given container could not be retrieved") 257 } 258 conf := c.Config() 259 if conf != nil && conf.Spec != nil && conf.Spec.Linux != nil { 260 out, err := json.Marshal(conf.Spec.Linux) 261 if err != nil { 262 return nil, nil, nil, err 263 } 264 resources := runtimeSpec.Linux.Resources 265 266 // resources get overwritten similarly to pod inheritance, manually assign here if there is a new value 267 marshalRes, err := json.Marshal(resources) 268 if err != nil { 269 return nil, nil, nil, err 270 } 271 272 err = json.Unmarshal(out, runtimeSpec.Linux) 273 if err != nil { 274 return nil, nil, nil, err 275 } 276 277 err = json.Unmarshal(marshalRes, runtimeSpec.Linux.Resources) 278 if err != nil { 279 return nil, nil, nil, err 280 } 281 } 282 if s.ResourceLimits != nil { 283 switch { 284 case s.ResourceLimits.CPU != nil: 285 runtimeSpec.Linux.Resources.CPU = s.ResourceLimits.CPU 286 case s.ResourceLimits.Memory != nil: 287 runtimeSpec.Linux.Resources.Memory = s.ResourceLimits.Memory 288 case s.ResourceLimits.BlockIO != nil: 289 runtimeSpec.Linux.Resources.BlockIO = s.ResourceLimits.BlockIO 290 case s.ResourceLimits.Devices != nil: 291 runtimeSpec.Linux.Resources.Devices = s.ResourceLimits.Devices 292 } 293 } 294 } 295 if len(s.HostDeviceList) > 0 { 296 options = append(options, libpod.WithHostDevice(s.HostDeviceList)) 297 } 298 if infraSpec != nil && infraSpec.Linux != nil { // if we are inheriting Linux info from a pod... 299 // Pass Security annotations 300 if len(infraSpec.Annotations[define.InspectAnnotationLabel]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationLabel]) == 0 { 301 runtimeSpec.Annotations[define.InspectAnnotationLabel] = infraSpec.Annotations[define.InspectAnnotationLabel] 302 } 303 if len(infraSpec.Annotations[define.InspectAnnotationSeccomp]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationSeccomp]) == 0 { 304 runtimeSpec.Annotations[define.InspectAnnotationSeccomp] = infraSpec.Annotations[define.InspectAnnotationSeccomp] 305 } 306 if len(infraSpec.Annotations[define.InspectAnnotationApparmor]) > 0 && len(runtimeSpec.Annotations[define.InspectAnnotationApparmor]) == 0 { 307 runtimeSpec.Annotations[define.InspectAnnotationApparmor] = infraSpec.Annotations[define.InspectAnnotationApparmor] 308 } 309 } 310 return runtimeSpec, s, options, err 311 } 312 func ExecuteCreate(ctx context.Context, rt *libpod.Runtime, runtimeSpec *specs.Spec, s *specgen.SpecGenerator, infra bool, options ...libpod.CtrCreateOption) (*libpod.Container, error) { 313 ctr, err := rt.NewContainer(ctx, runtimeSpec, s, infra, options...) 314 if err != nil { 315 return ctr, err 316 } 317 318 return ctr, rt.PrepareVolumeOnCreateContainer(ctx, ctr) 319 } 320 321 // ExtractCDIDevices process the list of Devices in the spec and determines if any of these are CDI devices. 322 // The CDI devices are added to the list of CtrCreateOptions. 323 // Note that this may modify the device list associated with the spec, which should then only contain non-CDI devices. 324 func ExtractCDIDevices(s *specgen.SpecGenerator) []libpod.CtrCreateOption { 325 devs := make([]specs.LinuxDevice, 0, len(s.Devices)) 326 var cdiDevs []string 327 var options []libpod.CtrCreateOption 328 329 for _, device := range s.Devices { 330 if isCDIDevice(device.Path) { 331 logrus.Debugf("Identified CDI device %v", device.Path) 332 cdiDevs = append(cdiDevs, device.Path) 333 continue 334 } 335 logrus.Debugf("Non-CDI device %v; assuming standard device", device.Path) 336 devs = append(devs, device) 337 } 338 s.Devices = devs 339 if len(cdiDevs) > 0 { 340 options = append(options, libpod.WithCDI(cdiDevs)) 341 } 342 return options 343 } 344 345 // isCDIDevice checks whether the specified device is a CDI device. 346 func isCDIDevice(device string) bool { 347 return parser.IsQualifiedName(device) 348 } 349 350 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) { 351 var options []libpod.CtrCreateOption 352 var err error 353 354 if s.PreserveFDs > 0 { 355 options = append(options, libpod.WithPreserveFDs(s.PreserveFDs)) 356 } 357 358 if s.Stdin { 359 options = append(options, libpod.WithStdin()) 360 } 361 362 if s.Timezone != "" { 363 options = append(options, libpod.WithTimezone(s.Timezone)) 364 } 365 if s.Umask != "" { 366 options = append(options, libpod.WithUmask(s.Umask)) 367 } 368 if s.Volatile { 369 options = append(options, libpod.WithVolatile()) 370 } 371 if s.PasswdEntry != "" { 372 options = append(options, libpod.WithPasswdEntry(s.PasswdEntry)) 373 } 374 if s.GroupEntry != "" { 375 options = append(options, libpod.WithGroupEntry(s.GroupEntry)) 376 } 377 378 if s.Privileged { 379 options = append(options, libpod.WithMountAllDevices()) 380 } 381 382 useSystemd := false 383 switch s.Systemd { 384 case "always": 385 useSystemd = true 386 case "false": 387 break 388 case "", "true": 389 if len(command) == 0 && imageData != nil { 390 command = imageData.Config.Cmd 391 } 392 393 if len(command) > 0 { 394 useSystemdCommands := map[string]bool{ 395 "/sbin/init": true, 396 "/usr/sbin/init": true, 397 "/usr/local/sbin/init": true, 398 } 399 // Grab last command in case this is launched from a shell 400 cmd := command 401 if len(command) > 2 { 402 // Podman build will add "/bin/sh" "-c" to 403 // Entrypoint. Remove and search for systemd 404 if command[0] == "/bin/sh" && command[1] == "-c" { 405 cmd = command[2:] 406 } 407 } 408 if useSystemdCommands[cmd[0]] || (filepath.Base(cmd[0]) == "systemd") { 409 useSystemd = true 410 } 411 } 412 default: 413 return nil, fmt.Errorf("invalid value %q systemd option requires 'true, false, always': %w", s.Systemd, err) 414 } 415 logrus.Debugf("using systemd mode: %t", useSystemd) 416 if useSystemd { 417 // is StopSignal was not set by the user then set it to systemd 418 // expected StopSigal 419 if s.StopSignal == nil { 420 stopSignal, err := util.ParseSignal("RTMIN+3") 421 if err != nil { 422 return nil, fmt.Errorf("parsing systemd signal: %w", err) 423 } 424 s.StopSignal = &stopSignal 425 } 426 427 options = append(options, libpod.WithSystemd()) 428 } 429 if len(s.SdNotifyMode) > 0 { 430 options = append(options, libpod.WithSdNotifyMode(s.SdNotifyMode)) 431 if s.SdNotifyMode != define.SdNotifyModeIgnore { 432 if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok { 433 options = append(options, libpod.WithSdNotifySocket(notify)) 434 } 435 } 436 } 437 438 if pod != nil { 439 logrus.Debugf("adding container to pod %s", pod.Name()) 440 options = append(options, rt.WithPod(pod)) 441 } 442 destinations := []string{} 443 // Take all mount and named volume destinations. 444 for _, mount := range s.Mounts { 445 destinations = append(destinations, mount.Destination) 446 } 447 for _, volume := range volumes { 448 destinations = append(destinations, volume.Dest) 449 } 450 for _, overlayVolume := range overlays { 451 destinations = append(destinations, overlayVolume.Destination) 452 } 453 for _, imageVolume := range s.ImageVolumes { 454 destinations = append(destinations, imageVolume.Destination) 455 } 456 457 if len(destinations) > 0 || !infraVolumes { 458 options = append(options, libpod.WithUserVolumes(destinations)) 459 } 460 461 if len(volumes) != 0 { 462 var vols []*libpod.ContainerNamedVolume 463 for _, v := range volumes { 464 vols = append(vols, &libpod.ContainerNamedVolume{ 465 Name: v.Name, 466 Dest: v.Dest, 467 Options: v.Options, 468 IsAnonymous: v.IsAnonymous, 469 SubPath: v.SubPath, 470 }) 471 } 472 options = append(options, libpod.WithNamedVolumes(vols)) 473 } 474 475 if len(overlays) != 0 { 476 var vols []*libpod.ContainerOverlayVolume 477 for _, v := range overlays { 478 vols = append(vols, &libpod.ContainerOverlayVolume{ 479 Dest: v.Destination, 480 Source: v.Source, 481 Options: v.Options, 482 }) 483 } 484 options = append(options, libpod.WithOverlayVolumes(vols)) 485 } 486 487 if len(s.ImageVolumes) != 0 { 488 var vols []*libpod.ContainerImageVolume 489 for _, v := range s.ImageVolumes { 490 vols = append(vols, &libpod.ContainerImageVolume{ 491 Dest: v.Destination, 492 Source: v.Source, 493 ReadWrite: v.ReadWrite, 494 }) 495 } 496 options = append(options, libpod.WithImageVolumes(vols)) 497 } 498 499 if s.Command != nil { 500 options = append(options, libpod.WithCommand(s.Command)) 501 } 502 if s.Entrypoint != nil { 503 options = append(options, libpod.WithEntrypoint(s.Entrypoint)) 504 } 505 if len(s.ContainerStorageConfig.StorageOpts) > 0 { 506 options = append(options, libpod.WithStorageOpts(s.StorageOpts)) 507 } 508 // If the user did not specify a workdir on the CLI, let's extract it 509 // from the image. 510 if s.WorkDir == "" && imageData != nil { 511 options = append(options, libpod.WithCreateWorkingDir()) 512 s.WorkDir = imageData.Config.WorkingDir 513 } 514 if s.WorkDir == "" { 515 s.WorkDir = "/" 516 } 517 if s.CreateWorkingDir { 518 options = append(options, libpod.WithCreateWorkingDir()) 519 } 520 if s.StopSignal != nil { 521 options = append(options, libpod.WithStopSignal(*s.StopSignal)) 522 } 523 if s.StopTimeout != nil { 524 options = append(options, libpod.WithStopTimeout(*s.StopTimeout)) 525 } 526 if s.Timeout != 0 { 527 options = append(options, libpod.WithTimeout(s.Timeout)) 528 } 529 if s.LogConfiguration != nil { 530 if len(s.LogConfiguration.Path) > 0 { 531 options = append(options, libpod.WithLogPath(s.LogConfiguration.Path)) 532 } 533 if s.LogConfiguration.Size > 0 { 534 options = append(options, libpod.WithMaxLogSize(s.LogConfiguration.Size)) 535 } 536 if len(s.LogConfiguration.Options) > 0 && s.LogConfiguration.Options["tag"] != "" { 537 options = append(options, libpod.WithLogTag(s.LogConfiguration.Options["tag"])) 538 } 539 540 if len(s.LogConfiguration.Driver) > 0 { 541 options = append(options, libpod.WithLogDriver(s.LogConfiguration.Driver)) 542 } 543 } 544 if s.ContainerSecurityConfig.LabelNested { 545 options = append(options, libpod.WithLabelNested(s.ContainerSecurityConfig.LabelNested)) 546 } 547 // Security options 548 if len(s.SelinuxOpts) > 0 { 549 options = append(options, libpod.WithSecLabels(s.SelinuxOpts)) 550 } else if pod != nil && len(compatibleOptions.SelinuxOpts) == 0 { 551 // duplicate the security options from the pod 552 processLabel, err := pod.ProcessLabel() 553 if err != nil { 554 return nil, err 555 } 556 if processLabel != "" { 557 selinuxOpts, err := label.DupSecOpt(processLabel) 558 if err != nil { 559 return nil, err 560 } 561 options = append(options, libpod.WithSecLabels(selinuxOpts)) 562 } 563 } 564 options = append(options, libpod.WithPrivileged(s.Privileged)) 565 options = append(options, libpod.WithReadWriteTmpfs(s.ReadWriteTmpfs)) 566 567 // Get namespace related options 568 namespaceOpts, err := namespaceOptions(s, rt, pod, imageData) 569 if err != nil { 570 return nil, err 571 } 572 options = append(options, namespaceOpts...) 573 574 if len(s.ConmonPidFile) > 0 { 575 options = append(options, libpod.WithConmonPidFile(s.ConmonPidFile)) 576 } 577 options = append(options, libpod.WithLabels(s.Labels)) 578 if s.ShmSize != nil { 579 options = append(options, libpod.WithShmSize(*s.ShmSize)) 580 } 581 if s.ShmSizeSystemd != nil { 582 options = append(options, libpod.WithShmSizeSystemd(*s.ShmSizeSystemd)) 583 } 584 if s.Rootfs != "" { 585 options = append(options, libpod.WithRootFS(s.Rootfs, s.RootfsOverlay, s.RootfsMapping)) 586 } 587 // Default used if not overridden on command line 588 589 var ( 590 restartPolicy string 591 retries uint 592 ) 593 // If the container is running in a pod, use the pod's restart policy for all the containers 594 if pod != nil && !s.IsInitContainer() && s.RestartPolicy == "" { 595 podConfig := pod.ConfigNoCopy() 596 if podConfig.RestartRetries != nil { 597 retries = *podConfig.RestartRetries 598 } 599 restartPolicy = podConfig.RestartPolicy 600 } else if s.RestartPolicy != "" { 601 if s.RestartRetries != nil { 602 retries = *s.RestartRetries 603 } 604 restartPolicy = s.RestartPolicy 605 } 606 options = append(options, libpod.WithRestartRetries(retries), libpod.WithRestartPolicy(restartPolicy)) 607 608 healthCheckSet := false 609 if s.ContainerHealthCheckConfig.HealthConfig != nil { 610 options = append(options, libpod.WithHealthCheck(s.ContainerHealthCheckConfig.HealthConfig)) 611 logrus.Debugf("New container has a health check") 612 healthCheckSet = true 613 } 614 if s.ContainerHealthCheckConfig.StartupHealthConfig != nil { 615 options = append(options, libpod.WithStartupHealthcheck(s.ContainerHealthCheckConfig.StartupHealthConfig)) 616 healthCheckSet = true 617 } 618 619 if s.ContainerHealthCheckConfig.HealthCheckOnFailureAction != define.HealthCheckOnFailureActionNone { 620 options = append(options, libpod.WithHealthCheckOnFailureAction(s.ContainerHealthCheckConfig.HealthCheckOnFailureAction)) 621 } 622 623 if s.SdNotifyMode == define.SdNotifyModeHealthy && !healthCheckSet { 624 return nil, fmt.Errorf("%w: sdnotify policy %q requires a healthcheck to be set", define.ErrInvalidArg, s.SdNotifyMode) 625 } 626 627 if len(s.Secrets) != 0 { 628 manager, err := rt.SecretsManager() 629 if err != nil { 630 return nil, err 631 } 632 var secrs []*libpod.ContainerSecret 633 for _, s := range s.Secrets { 634 secr, err := manager.Lookup(s.Source) 635 if err != nil { 636 return nil, err 637 } 638 secrs = append(secrs, &libpod.ContainerSecret{ 639 Secret: secr, 640 UID: s.UID, 641 GID: s.GID, 642 Mode: s.Mode, 643 Target: s.Target, 644 }) 645 } 646 options = append(options, libpod.WithSecrets(secrs)) 647 } 648 649 if len(s.EnvSecrets) != 0 { 650 options = append(options, libpod.WithEnvSecrets(s.EnvSecrets)) 651 } 652 653 if len(s.DependencyContainers) > 0 { 654 deps := make([]*libpod.Container, 0, len(s.DependencyContainers)) 655 for _, ctr := range s.DependencyContainers { 656 depCtr, err := rt.LookupContainer(ctr) 657 if err != nil { 658 return nil, fmt.Errorf("%q is not a valid container, cannot be used as a dependency: %w", ctr, err) 659 } 660 deps = append(deps, depCtr) 661 } 662 options = append(options, libpod.WithDependencyCtrs(deps)) 663 } 664 if s.PidFile != "" { 665 options = append(options, libpod.WithPidFile(s.PidFile)) 666 } 667 668 if len(s.ChrootDirs) != 0 { 669 options = append(options, libpod.WithChrootDirs(s.ChrootDirs)) 670 } 671 672 options = append(options, libpod.WithSelectedPasswordManagement(s.Passwd)) 673 674 return options, nil 675 } 676 677 func Inherit(infra *libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtime) (opts []libpod.CtrCreateOption, infraS *specs.Spec, compat *libpod.InfraInherit, err error) { 678 inheritSpec := &specgen.SpecGenerator{} 679 _, compatibleOptions, err := ConfigToSpec(rt, inheritSpec, infra.ID()) 680 if err != nil { 681 return nil, nil, nil, err 682 } 683 options := []libpod.CtrCreateOption{} 684 infraConf := infra.Config() 685 infraSpec := infraConf.Spec 686 687 // need to set compatOptions to the currently filled specgenOptions so we do not overwrite 688 compatibleOptions.CapAdd = append(compatibleOptions.CapAdd, s.CapAdd...) 689 compatibleOptions.CapDrop = append(compatibleOptions.CapDrop, s.CapDrop...) 690 compatibleOptions.HostDeviceList = append(compatibleOptions.HostDeviceList, s.HostDeviceList...) 691 compatibleOptions.ImageVolumes = append(compatibleOptions.ImageVolumes, s.ImageVolumes...) 692 compatibleOptions.Mounts = append(compatibleOptions.Mounts, s.Mounts...) 693 compatibleOptions.OverlayVolumes = append(compatibleOptions.OverlayVolumes, s.OverlayVolumes...) 694 compatibleOptions.SelinuxOpts = append(compatibleOptions.SelinuxOpts, s.SelinuxOpts...) 695 compatibleOptions.Volumes = append(compatibleOptions.Volumes, s.Volumes...) 696 697 compatByte, err := json.Marshal(compatibleOptions) 698 if err != nil { 699 return nil, nil, nil, err 700 } 701 err = json.Unmarshal(compatByte, s) 702 if err != nil { 703 return nil, nil, nil, err 704 } 705 706 // podman pod container can override pod ipc NS 707 if !s.IpcNS.IsDefault() { 708 inheritSpec.IpcNS = s.IpcNS 709 } 710 711 // this causes errors when shmSize is the default value, it will still get passed down unless we manually override. 712 if inheritSpec.IpcNS.NSMode == specgen.Host && (compatibleOptions.ShmSize != nil && compatibleOptions.IsDefaultShmSize()) { 713 s.ShmSize = nil 714 } 715 return options, infraSpec, compatibleOptions, nil 716 }