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  }