diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_internal.go | 3 | ||||
-rw-r--r-- | libpod/kube.go | 4 | ||||
-rw-r--r-- | libpod/networking_linux.go | 1 | ||||
-rw-r--r-- | libpod/options.go | 480 | ||||
-rw-r--r-- | libpod/pod.go | 169 | ||||
-rw-r--r-- | libpod/pod_api.go | 53 | ||||
-rw-r--r-- | libpod/pod_internal.go | 2 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 26 | ||||
-rw-r--r-- | libpod/runtime_pod_infra_linux.go | 284 | ||||
-rw-r--r-- | libpod/runtime_pod_linux.go | 57 |
10 files changed, 224 insertions, 855 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 3f7a4807d..6717ada59 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -972,11 +972,12 @@ func (c *Container) checkDependenciesRunning() ([]string, error) { } // Check the status + conf := depCtr.Config() state, err := depCtr.State() if err != nil { return nil, errors.Wrapf(err, "error retrieving state of dependency %s of container %s", dep, c.ID()) } - if state != define.ContainerStateRunning { + if state != define.ContainerStateRunning && !conf.IsInfra { notRunning = append(notRunning, dep) } depCtrs[dep] = depCtr diff --git a/libpod/kube.go b/libpod/kube.go index a3f49bfe8..fff040adb 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -10,6 +10,8 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/lookup" + "github.com/containers/podman/v3/pkg/namespaces" + "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/util" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/opencontainers/runtime-spec/specs-go" @@ -72,7 +74,7 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) { return nil, servicePorts, err } servicePorts = containerPortsToServicePorts(ports) - hostNetwork = p.config.InfraContainer.HostNetwork + hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host)) } pod, err := p.podWithContainers(allContainers, ports, hostNetwork) if err != nil { diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index dbe2274d3..5ade0849d 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -632,7 +632,6 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re } podName := getCNIPodName(ctr) - networks, _, err := ctr.networks() if err != nil { return nil, err diff --git a/libpod/options.go b/libpod/options.go index 0bcd1e3a6..4cbd2b5e2 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -14,6 +14,7 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/events" + netTypes "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/namespaces" "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/specgen" @@ -21,7 +22,6 @@ import ( "github.com/containers/storage" "github.com/containers/storage/pkg/idtools" "github.com/cri-o/ocicni/pkg/ocicni" - "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -713,7 +713,6 @@ func (r *Runtime) WithPod(pod *Pod) CtrCreateOption { if pod == nil { return define.ErrInvalidArg } - ctr.config.Pod = pod.ID() return nil @@ -1430,20 +1429,6 @@ func WithRestartRetries(tries uint) CtrCreateOption { } } -// withIsInfra sets the container to be an infra container. This means the container will be sometimes hidden -// and expected to be the first container in the pod. -func withIsInfra() CtrCreateOption { - return func(ctr *Container) error { - if ctr.valid { - return define.ErrCtrFinalized - } - - ctr.config.IsInfra = true - - return nil - } -} - // WithNamedVolumes adds the given named volumes to the container. func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption { return func(ctr *Container) error { @@ -1541,6 +1526,20 @@ func WithCreateCommand(cmd []string) CtrCreateOption { } } +// withIsInfra allows us to dfferentiate between infra containers and regular containers +// within the container config +func withIsInfra() CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return define.ErrCtrFinalized + } + + ctr.config.IsInfra = true + + return nil + } +} + // WithCreateWorkingDir tells Podman to create the container's working directory // if it does not exist. func WithCreateWorkingDir() CtrCreateOption { @@ -1812,45 +1811,14 @@ func WithInitCtrType(containerType string) CtrCreateOption { // Pod Creation Options -// WithInfraImage sets the infra image for libpod. -// An infra image is used for inter-container kernel -// namespace sharing within a pod. Typically, an infra -// container is lightweight and is there to reap -// zombie processes within its pid namespace. -func WithInfraImage(img string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - pod.config.InfraContainer.InfraImage = img - - return nil - } -} - -// WithInfraCommand sets the command to -// run on pause container start up. -func WithInfraCommand(cmd []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - pod.config.InfraContainer.InfraCommand = cmd - return nil - } -} - -// WithInfraName sets the infra container name for a single pod. -func WithInfraName(name string) PodCreateOption { +// WithPodCreateCommand adds the full command plus arguments of the current +// process to the pod config. +func WithPodCreateCommand(createCmd []string) PodCreateOption { return func(pod *Pod) error { if pod.valid { return define.ErrPodFinalized } - - pod.config.InfraContainer.InfraName = name - + pod.config.CreateCommand = createCmd return nil } } @@ -1891,26 +1859,14 @@ func WithPodHostname(hostname string) PodCreateOption { } } -// WithPodCreateCommand adds the full command plus arguments of the current -// process to the pod config. -func WithPodCreateCommand(createCmd []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - pod.config.CreateCommand = createCmd - return nil - } -} - // WithInfraConmonPidFile sets the path to a custom conmon PID file for the // infra container. -func WithInfraConmonPidFile(path string) PodCreateOption { +func WithInfraConmonPidFile(path string, infraSpec *specgen.SpecGenerator) PodCreateOption { return func(pod *Pod) error { if pod.valid { return define.ErrPodFinalized } - pod.config.InfraContainer.ConmonPidFile = path + infraSpec.ConmonPidFile = path return nil } } @@ -2099,320 +2055,25 @@ func WithInfraContainer() PodCreateOption { if pod.valid { return define.ErrPodFinalized } - - pod.config.InfraContainer.HasInfraContainer = true + pod.config.HasInfra = true return nil } } // WithInfraContainerPorts tells the pod to add port bindings to the pause container -func WithInfraContainerPorts(bindings []ocicni.PortMapping) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot set pod ports as no infra container is being created") - } - pod.config.InfraContainer.PortBindings = bindings - return nil - } -} - -// WithPodStaticIP sets a static IP for the pod. -func WithPodStaticIP(ip net.IP) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot set pod static IP as no infra container is being created") - } - - if pod.config.InfraContainer.HostNetwork { - return errors.Wrapf(define.ErrInvalidArg, "cannot set static IP if host network is specified") - } - - if len(pod.config.InfraContainer.Networks) > 1 { - return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining more than 1 CNI network") - } - - pod.config.InfraContainer.StaticIP = ip - - return nil - } -} - -// WithPodStaticMAC sets a static MAC address for the pod. -func WithPodStaticMAC(mac net.HardwareAddr) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot set pod static MAC as no infra container is being created") - } - - if pod.config.InfraContainer.HostNetwork { - return errors.Wrapf(define.ErrInvalidArg, "cannot set static MAC if host network is specified") - } - - if len(pod.config.InfraContainer.Networks) > 1 { - return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining more than 1 CNI network") - } - - pod.config.InfraContainer.StaticMAC = mac - - return nil - } -} - -// WithPodUseImageResolvConf sets a pod to use an image's resolv.conf and not -// create its own. -func WithPodUseImageResolvConf() PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created") - } - - if len(pod.config.InfraContainer.DNSServer) != 0 || - len(pod.config.InfraContainer.DNSSearch) != 0 || - len(pod.config.InfraContainer.DNSOption) != 0 { - return errors.Wrapf(define.ErrInvalidArg, "requested use of image resolv.conf conflicts with already-configured DNS settings") - } - - pod.config.InfraContainer.UseImageResolvConf = true - - return nil - } -} - -// WithPodDNS sets the DNS Servers for a pod. -func WithPodDNS(dnsServer []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created") - } - - if pod.config.InfraContainer.UseImageResolvConf { - return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS servers if pod will not create /etc/resolv.conf") - } - - pod.config.InfraContainer.DNSServer = dnsServer - - return nil - } -} - -// WithPodDNSSearch sets the DNS Search domains for a pod. -func WithPodDNSSearch(dnsSearch []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created") - } - - if pod.config.InfraContainer.UseImageResolvConf { - return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS search domains if pod will not create /etc/resolv.conf") - } - - pod.config.InfraContainer.DNSSearch = dnsSearch - - return nil - } -} - -// WithPodDNSOption sets DNS Options for a pod. -func WithPodDNSOption(dnsOption []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod DNS as no infra container is being created") - } - - if pod.config.InfraContainer.UseImageResolvConf { - return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS options if pod will not create /etc/resolv.conf") - } - - pod.config.InfraContainer.DNSOption = dnsOption - - return nil - } -} - -// WithPodUseImageHosts tells the pod not to create /etc/hosts and instead to -// use the one provided by the image. -func WithPodUseImageHosts() PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod hosts as no infra container is being created") - } - - if len(pod.config.InfraContainer.HostAdd) != 0 { - return errors.Wrapf(define.ErrInvalidArg, "not creating /etc/hosts conflicts with adding to the hosts file") - } - - pod.config.InfraContainer.UseImageHosts = true - - return nil - } -} - -// WithPodHosts adds additional entries to the pod's /etc/hosts -func WithPodHosts(hosts []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod hosts as no infra container is being created") - } - - if pod.config.InfraContainer.UseImageHosts { - return errors.Wrapf(define.ErrInvalidArg, "cannot add to /etc/hosts if container is using image hosts") - } - - pod.config.InfraContainer.HostAdd = hosts - - return nil - } -} - -// WithPodNetworks sets additional CNI networks for the pod to join. -func WithPodNetworks(networks []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod CNI networks as no infra container is being created") - } - - if (pod.config.InfraContainer.StaticIP != nil || pod.config.InfraContainer.StaticMAC != nil) && - len(networks) > 1 { - return errors.Wrapf(define.ErrInvalidArg, "cannot join more than one CNI network if setting a static IP or MAC address") - } - - if pod.config.InfraContainer.HostNetwork { - return errors.Wrapf(define.ErrInvalidArg, "cannot join pod to CNI networks if host network is specified") - } - - pod.config.InfraContainer.Networks = networks - - return nil - } -} - -// WithPodNoNetwork tells the pod to disable external networking. -func WithPodNoNetwork() PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot disable pod networking as no infra container is being created") - } - - if len(pod.config.InfraContainer.PortBindings) > 0 || - pod.config.InfraContainer.StaticIP != nil || - pod.config.InfraContainer.StaticMAC != nil || - len(pod.config.InfraContainer.Networks) > 0 || - pod.config.InfraContainer.HostNetwork { - return errors.Wrapf(define.ErrInvalidArg, "cannot disable pod network if network-related configuration is specified") - } - - pod.config.InfraContainer.NoNetwork = true - - return nil - } -} - -// WithPodHostNetwork tells the pod to use the host's network namespace. -func WithPodHostNetwork() PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod host networking as no infra container is being created") - } - - if len(pod.config.InfraContainer.PortBindings) > 0 || - pod.config.InfraContainer.StaticIP != nil || - pod.config.InfraContainer.StaticMAC != nil || - len(pod.config.InfraContainer.Networks) > 0 || - pod.config.InfraContainer.NoNetwork { - return errors.Wrapf(define.ErrInvalidArg, "cannot set host network if network-related configuration is specified") - } - - pod.config.InfraContainer.HostNetwork = true - - return nil - } -} - -// WithPodInfraExitCommand sets an exit command for the pod's infra container. -// Semantics are identical to WithExitCommand() above - the ID of the container -// will be appended to the end of the provided command (note that this will -// specifically be the ID of the infra container *and not the pod's id*. -func WithPodInfraExitCommand(exitCmd []string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod infra container exit command as no infra container is being created") - } - - pod.config.InfraContainer.ExitCommand = exitCmd - - return nil - } -} - -// WithPodSlirp4netns tells the pod to use slirp4netns. -func WithPodSlirp4netns(networkOptions map[string][]string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod networking as no infra container is being created") - } - if pod.config.InfraContainer.HostNetwork { - return errors.Wrapf(define.ErrInvalidArg, "cannot set both HostNetwork and Slirp4netns") - } - pod.config.InfraContainer.Slirp4netns = true - pod.config.InfraContainer.NetworkOptions = networkOptions - - return nil +func WithInfraContainerPorts(bindings []ocicni.PortMapping, infraSpec *specgen.SpecGenerator) []netTypes.PortMapping { + bindingSpec := []netTypes.PortMapping{} + for _, bind := range bindings { + currBind := netTypes.PortMapping{} + currBind.ContainerPort = uint16(bind.ContainerPort) + currBind.HostIP = bind.HostIP + currBind.HostPort = uint16(bind.HostPort) + currBind.Protocol = bind.Protocol + bindingSpec = append(bindingSpec, currBind) } + infraSpec.PortMappings = bindingSpec + return infraSpec.PortMappings } // WithVolatile sets the volatile flag for the container storage. @@ -2428,78 +2089,3 @@ func WithVolatile() CtrCreateOption { return nil } } - -// WithPodUserns sets the userns for the infra container in a pod. -func WithPodUserns(userns specgen.Namespace) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - - if !pod.config.InfraContainer.HasInfraContainer { - return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod userns as no infra container is being created") - } - - pod.config.InfraContainer.Userns = userns - - return nil - } -} - -// WithPodCPUPAQ takes the given cpu period and quota and inserts them in the proper place. -func WithPodCPUPAQ(period uint64, quota int64) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - if pod.CPUPeriod() != 0 && pod.CPUQuota() != 0 { - pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{ - Period: &period, - Quota: "a, - } - } else { - pod.config.InfraContainer.ResourceLimits = &specs.LinuxResources{} - pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{ - Period: &period, - Quota: "a, - } - } - return nil - } -} - -// WithPodCPUSetCPUS computes and sets the Cpus linux resource string which determines the amount of cores, from those available, we are allowed to execute on -func WithPodCPUSetCPUs(inp string) PodCreateOption { - return func(pod *Pod) error { - if pod.valid { - return define.ErrPodFinalized - } - if pod.ResourceLim().CPU.Period != nil { - pod.config.InfraContainer.ResourceLimits.CPU.Cpus = inp - } else { - pod.config.InfraContainer.ResourceLimits = &specs.LinuxResources{} - pod.config.InfraContainer.ResourceLimits.CPU = &specs.LinuxCPU{} - pod.config.InfraContainer.ResourceLimits.CPU.Cpus = inp - } - return nil - } -} - -func WithPodPidNS(inp specgen.Namespace) PodCreateOption { - return func(p *Pod) error { - if p.valid { - return define.ErrPodFinalized - } - if p.config.UsePodPID { - switch inp.NSMode { - case "container": - return errors.Wrap(define.ErrInvalidArg, "Cannot take container in a different NS as an argument") - case "host": - p.config.UsePodPID = false - } - p.config.InfraContainer.PidNS = inp - } - - return nil - } -} diff --git a/libpod/pod.go b/libpod/pod.go index 7df15df7b..e4516b354 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -2,14 +2,12 @@ package libpod import ( "context" - "net" + "fmt" "sort" "time" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/lock" - "github.com/containers/podman/v3/pkg/specgen" - "github.com/cri-o/ocicni/pkg/ocicni" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) @@ -63,7 +61,7 @@ type PodConfig struct { UsePodUTS bool `json:"sharesUts,omitempty"` UsePodCgroupNS bool `json:"sharesCgroupNS,omitempty"` - InfraContainer *InfraContainerConfig `json:"infraConfig"` + HasInfra bool `json:"hasInfra,omitempty"` // Time pod was created CreatedTime time.Time `json:"created"` @@ -85,41 +83,6 @@ type podState struct { InfraContainerID string } -// InfraContainerConfig is the configuration for the pod's infra container. -// Generally speaking, these are equivalent to container configuration options -// you will find in container_config.go (and even named identically), save for -// HasInfraContainer (which determines if an infra container is even created - -// if it is false, no other options in this struct will be used) and HostNetwork -// (this involves the created OCI spec, and as such is not represented directly -// in container_config.go). -// Generally speaking, aside from those two exceptions, these options will set -// the equivalent field in the container's configuration. -type InfraContainerConfig struct { - ConmonPidFile string `json:"conmonPidFile"` - HasInfraContainer bool `json:"makeInfraContainer"` - NoNetwork bool `json:"noNetwork,omitempty"` - HostNetwork bool `json:"infraHostNetwork,omitempty"` - PidNS specgen.Namespace `json:"infraPid,omitempty"` - PortBindings []ocicni.PortMapping `json:"infraPortBindings"` - StaticIP net.IP `json:"staticIP,omitempty"` - StaticMAC net.HardwareAddr `json:"staticMAC,omitempty"` - UseImageResolvConf bool `json:"useImageResolvConf,omitempty"` - DNSServer []string `json:"dnsServer,omitempty"` - DNSSearch []string `json:"dnsSearch,omitempty"` - DNSOption []string `json:"dnsOption,omitempty"` - UseImageHosts bool `json:"useImageHosts,omitempty"` - HostAdd []string `json:"hostsAdd,omitempty"` - Networks []string `json:"networks,omitempty"` - ExitCommand []string `json:"exitCommand,omitempty"` - InfraImage string `json:"infraImage,omitempty"` - InfraCommand []string `json:"infraCommand,omitempty"` - InfraName string `json:"infraName,omitempty"` - Slirp4netns bool `json:"slirp4netns,omitempty"` - NetworkOptions map[string][]string `json:"network_options,omitempty"` - ResourceLimits *specs.LinuxResources `json:"resource_limits,omitempty"` - Userns specgen.Namespace `json:"userns,omitempty"` -} - // ID retrieves the pod's ID func (p *Pod) ID() string { return p.config.ID @@ -139,45 +102,104 @@ func (p *Pod) Namespace() string { // ResourceLim returns the cpuset resource limits for the pod func (p *Pod) ResourceLim() *specs.LinuxResources { resCopy := &specs.LinuxResources{} - if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil { + empty := &specs.LinuxResources{ + CPU: &specs.LinuxCPU{}, + } + infra, err := p.runtime.GetContainer(p.state.InfraContainerID) + if err != nil { + return empty + } + conf := infra.config.Spec + if err != nil { + return empty + } + if conf.Linux == nil || conf.Linux.Resources == nil { + return empty + } + if err = JSONDeepCopy(conf.Linux.Resources, resCopy); err != nil { return nil } - if resCopy != nil && resCopy.CPU != nil { + if resCopy.CPU != nil { return resCopy } - empty := &specs.LinuxResources{ - CPU: &specs.LinuxCPU{}, - } + return empty } // CPUPeriod returns the pod CPU period func (p *Pod) CPUPeriod() uint64 { - resCopy := &specs.LinuxResources{} - if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil { + if p.state.InfraContainerID == "" { return 0 } - if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Period != nil { - return *resCopy.CPU.Period + infra, err := p.runtime.GetContainer(p.state.InfraContainerID) + if err != nil { + return 0 + } + conf := infra.config.Spec + if conf != nil && conf.Linux != nil && conf.Linux.Resources != nil && conf.Linux.Resources.CPU != nil && conf.Linux.Resources.CPU.Period != nil { + return *conf.Linux.Resources.CPU.Period } return 0 } // CPUQuota returns the pod CPU quota func (p *Pod) CPUQuota() int64 { - resCopy := &specs.LinuxResources{} - if err := JSONDeepCopy(p.config.InfraContainer.ResourceLimits, resCopy); err != nil { + if p.state.InfraContainerID == "" { + return 0 + } + infra, err := p.runtime.GetContainer(p.state.InfraContainerID) + if err != nil { return 0 } - if resCopy != nil && resCopy.CPU != nil && resCopy.CPU.Quota != nil { - return *resCopy.CPU.Quota + conf := infra.config.Spec + if conf != nil && conf.Linux != nil && conf.Linux.Resources != nil && conf.Linux.Resources.CPU != nil && conf.Linux.Resources.CPU.Quota != nil { + return *conf.Linux.Resources.CPU.Quota } return 0 } // PidMode returns the PID mode given by the user ex: pod, private... func (p *Pod) PidMode() string { - return string(p.config.InfraContainer.PidNS.NSMode) + infra, err := p.runtime.GetContainer(p.state.InfraContainerID) + if err != nil { + return "" + } + conf := infra.Config() + ctrSpec := conf.Spec + if ctrSpec != nil && ctrSpec.Linux != nil { + for _, ns := range ctrSpec.Linux.Namespaces { + if ns.Type == specs.PIDNamespace { + if ns.Path != "" { + return fmt.Sprintf("ns:%s", ns.Path) + } + return "private" + } + } + return "host" + } + return "" +} + +// PidMode returns the PID mode given by the user ex: pod, private... +func (p *Pod) UserNSMode() string { + infra, err := p.infraContainer() + if err != nil { + return "" + } + conf := infra.Config() + ctrSpec := conf.Spec + if ctrSpec != nil && ctrSpec.Linux != nil { + for _, ns := range ctrSpec.Linux.Namespaces { + if ns.Type == specs.UserNamespace { + if ns.Path != "" { + return fmt.Sprintf("ns:%s", ns.Path) + } + return "private" + } + } + return "host" + } + return "" } // Labels returns the pod's labels @@ -263,20 +285,24 @@ func (p *Pod) CgroupPath() (string, error) { if p.state.CgroupPath != "" { return p.state.CgroupPath, nil } - if !p.HasInfraContainer() { + if p.state.InfraContainerID == "" { return "", errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container") } - id := p.state.InfraContainerID + id, err := p.infraContainerID() + if err != nil { + return "", err + } if id != "" { - ctr, err := p.runtime.state.Container(id) + ctr, err := p.infraContainer() if err != nil { return "", errors.Wrapf(err, "could not get infra") } if ctr != nil { - ctr.Start(context.Background(), false) + ctr.Start(context.Background(), true) cgroupPath, err := ctr.CGroupPath() + fmt.Println(cgroupPath) if err != nil { return "", errors.Wrapf(err, "could not get container cgroup") } @@ -325,7 +351,7 @@ func (p *Pod) allContainers() ([]*Container, error) { // HasInfraContainer returns whether the pod will create an infra container func (p *Pod) HasInfraContainer() bool { - return p.config.InfraContainer.HasInfraContainer + return p.config.HasInfra } // SharesNamespaces checks if the pod has any kernel namespaces set as shared. An infra container will not be @@ -350,19 +376,26 @@ func (p *Pod) InfraContainerID() (string, error) { return p.infraContainerID() } -// InfraContainer returns the infra container. -func (p *Pod) InfraContainer() (*Container, error) { - if !p.HasInfraContainer() { - return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container") - } - id, err := p.InfraContainerID() +// infraContainer is the unlocked versio of InfraContainer which returns the infra container +func (p *Pod) infraContainer() (*Container, error) { + id, err := p.infraContainerID() if err != nil { return nil, err } + if id == "" { + return nil, errors.Wrap(define.ErrNoSuchCtr, "pod has no infra container") + } return p.runtime.state.Container(id) } +// InfraContainer returns the infra container. +func (p *Pod) InfraContainer() (*Container, error) { + p.lock.Lock() + defer p.lock.Unlock() + return p.infraContainer() +} + // TODO add pod batching // Lock pod to avoid lock contention // Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale) @@ -412,13 +445,7 @@ func (p *Pod) ProcessLabel() (string, error) { if !p.HasInfraContainer() { return "", nil } - - id, err := p.InfraContainerID() - if err != nil { - return "", err - } - - ctr, err := p.runtime.state.Container(id) + ctr, err := p.infraContainer() if err != nil { return "", err } diff --git a/libpod/pod_api.go b/libpod/pod_api.go index 53fb9538f..5f4d983b9 100644 --- a/libpod/pod_api.go +++ b/libpod/pod_api.go @@ -582,41 +582,46 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { // Infra config contains detailed information on the pod's infra // container. var infraConfig *define.InspectPodInfraConfig - if p.config.InfraContainer != nil && p.config.InfraContainer.HasInfraContainer { + if p.state.InfraContainerID != "" { + infra, err := p.runtime.GetContainer(p.state.InfraContainerID) + if err != nil { + return nil, err + } infraConfig = new(define.InspectPodInfraConfig) - infraConfig.HostNetwork = p.config.InfraContainer.HostNetwork - infraConfig.StaticIP = p.config.InfraContainer.StaticIP - infraConfig.StaticMAC = p.config.InfraContainer.StaticMAC.String() - infraConfig.NoManageResolvConf = p.config.InfraContainer.UseImageResolvConf - infraConfig.NoManageHosts = p.config.InfraContainer.UseImageHosts + infraConfig.HostNetwork = !infra.Config().ContainerNetworkConfig.UseImageHosts + infraConfig.StaticIP = infra.Config().ContainerNetworkConfig.StaticIP + infraConfig.NoManageResolvConf = infra.Config().UseImageResolvConf + infraConfig.NoManageHosts = infra.Config().UseImageHosts infraConfig.CPUPeriod = p.CPUPeriod() infraConfig.CPUQuota = p.CPUQuota() infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus infraConfig.PidNS = p.PidMode() - infraConfig.UserNS = p.config.InfraContainer.Userns.String() + infraConfig.UserNS = p.UserNSMode() - if len(p.config.InfraContainer.DNSServer) > 0 { - infraConfig.DNSServer = make([]string, 0, len(p.config.InfraContainer.DNSServer)) - infraConfig.DNSServer = append(infraConfig.DNSServer, p.config.InfraContainer.DNSServer...) + if len(infra.Config().ContainerNetworkConfig.DNSServer) > 0 { + infraConfig.DNSServer = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSServer)) + for _, entry := range infra.Config().ContainerNetworkConfig.DNSServer { + infraConfig.DNSServer = append(infraConfig.DNSServer, entry.String()) + } } - if len(p.config.InfraContainer.DNSSearch) > 0 { - infraConfig.DNSSearch = make([]string, 0, len(p.config.InfraContainer.DNSSearch)) - infraConfig.DNSSearch = append(infraConfig.DNSSearch, p.config.InfraContainer.DNSSearch...) + if len(infra.Config().ContainerNetworkConfig.DNSSearch) > 0 { + infraConfig.DNSSearch = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSSearch)) + infraConfig.DNSSearch = append(infraConfig.DNSSearch, infra.Config().ContainerNetworkConfig.DNSSearch...) } - if len(p.config.InfraContainer.DNSOption) > 0 { - infraConfig.DNSOption = make([]string, 0, len(p.config.InfraContainer.DNSOption)) - infraConfig.DNSOption = append(infraConfig.DNSOption, p.config.InfraContainer.DNSOption...) + if len(infra.Config().ContainerNetworkConfig.DNSOption) > 0 { + infraConfig.DNSOption = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSOption)) + infraConfig.DNSOption = append(infraConfig.DNSOption, infra.Config().ContainerNetworkConfig.DNSOption...) } - if len(p.config.InfraContainer.HostAdd) > 0 { - infraConfig.HostAdd = make([]string, 0, len(p.config.InfraContainer.HostAdd)) - infraConfig.HostAdd = append(infraConfig.HostAdd, p.config.InfraContainer.HostAdd...) + if len(infra.Config().HostAdd) > 0 { + infraConfig.HostAdd = make([]string, 0, len(infra.Config().HostAdd)) + infraConfig.HostAdd = append(infraConfig.HostAdd, infra.Config().HostAdd...) } - if len(p.config.InfraContainer.Networks) > 0 { - infraConfig.Networks = make([]string, 0, len(p.config.InfraContainer.Networks)) - infraConfig.Networks = append(infraConfig.Networks, p.config.InfraContainer.Networks...) + if len(infra.Config().ContainerNetworkConfig.Networks) > 0 { + infraConfig.Networks = make([]string, 0, len(infra.Config().ContainerNetworkConfig.Networks)) + infraConfig.Networks = append(infraConfig.Networks, infra.Config().ContainerNetworkConfig.Networks...) } - infraConfig.NetworkOptions = p.config.InfraContainer.NetworkOptions - infraConfig.PortBindings = makeInspectPortBindings(p.config.InfraContainer.PortBindings, nil) + infraConfig.NetworkOptions = infra.Config().ContainerNetworkConfig.NetworkOptions + infraConfig.PortBindings = makeInspectPortBindings(infra.Config().ContainerNetworkConfig.PortMappings, nil) } inspectData := define.InspectPodData{ diff --git a/libpod/pod_internal.go b/libpod/pod_internal.go index e81bd7b16..079b631a0 100644 --- a/libpod/pod_internal.go +++ b/libpod/pod_internal.go @@ -20,7 +20,7 @@ func newPod(runtime *Runtime) *Pod { pod.config.ID = stringid.GenerateNonCryptoID() pod.config.Labels = make(map[string]string) pod.config.CreatedTime = time.Now() - pod.config.InfraContainer = new(InfraContainerConfig) + // pod.config.InfraContainer = new(ContainerConfig) pod.state = new(podState) pod.runtime = runtime diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 52072b0f3..7d3891f6e 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -17,6 +17,7 @@ import ( "github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/podman/v3/pkg/domain/entities/reports" "github.com/containers/podman/v3/pkg/rootless" + "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/storage" "github.com/containers/storage/pkg/stringid" "github.com/docker/go-units" @@ -38,12 +39,15 @@ type CtrCreateOption func(*Container) error type ContainerFilter func(*Container) bool // NewContainer creates a new container from a given OCI config. -func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (*Container, error) { +func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, spec *specgen.SpecGenerator, infra bool, options ...CtrCreateOption) (*Container, error) { r.lock.Lock() defer r.lock.Unlock() if !r.valid { return nil, define.ErrRuntimeStopped } + if infra { + options = append(options, withIsInfra()) + } return r.newContainer(ctx, rSpec, options...) } @@ -172,6 +176,7 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf } ctr.config.ShmSize = size ctr.config.StopSignal = 15 + ctr.config.StopTimeout = r.config.Engine.StopTimeout } else { // This is a restore from an imported checkpoint @@ -211,7 +216,11 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf } func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (*Container, error) { - ctr, err := r.initContainerVariables(rSpec, nil) + var ctr *Container + var err error + + ctr, err = r.initContainerVariables(rSpec, nil) + if err != nil { return nil, errors.Wrapf(err, "error initializing container variables") } @@ -230,7 +239,9 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai if err := ctr.validate(); err != nil { return nil, err } - + if ctr.config.IsInfra { + ctr.config.StopTimeout = 10 + } // normalize the networks to names // ocicni only knows about cni names so we have to make // sure we do not use ids internally @@ -327,7 +338,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai switch r.config.Engine.CgroupManager { case config.CgroupfsCgroupsManager: if ctr.config.CgroupParent == "" { - if pod != nil && pod.config.UsePodCgroup { + if pod != nil && pod.config.UsePodCgroup && !ctr.IsInfra() { podCgroup, err := pod.CgroupPath() if err != nil { return nil, errors.Wrapf(err, "error retrieving pod %s cgroup", pod.ID()) @@ -348,7 +359,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai case config.SystemdCgroupsManager: if ctr.config.CgroupParent == "" { switch { - case pod != nil && pod.config.UsePodCgroup: + case pod != nil && pod.config.UsePodCgroup && !ctr.IsInfra(): podCgroup, err := pod.CgroupPath() if err != nil { return nil, errors.Wrapf(err, "error retrieving pod %s cgroup", pod.ID()) @@ -833,7 +844,10 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol return id, err } - infraID := pod.state.InfraContainerID + infraID, err := pod.infraContainerID() + if err != nil { + return "", err + } if c.ID() == infraID { return id, errors.Errorf("container %s is the infra container of pod %s and cannot be removed without removing the pod", c.ID(), pod.ID()) } diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go deleted file mode 100644 index 9236fb1f5..000000000 --- a/libpod/runtime_pod_infra_linux.go +++ /dev/null @@ -1,284 +0,0 @@ -// +build linux - -package libpod - -import ( - "context" - "strings" - - "github.com/containers/common/pkg/config" - "github.com/containers/podman/v3/libpod/define" - "github.com/containers/podman/v3/pkg/namespaces" - "github.com/containers/podman/v3/pkg/rootless" - "github.com/containers/podman/v3/pkg/specgen" - "github.com/containers/podman/v3/pkg/util" - v1 "github.com/opencontainers/image-spec/specs-go/v1" - spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/opencontainers/runtime-tools/generate" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -const ( - // IDTruncLength is the length of the pod's id that will be used to make the - // infra container name - IDTruncLength = 12 -) - -func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawImageName, imgID string, config *v1.ImageConfig) (*Container, error) { - // Set up generator for infra container defaults - g, err := generate.New("linux") - if err != nil { - return nil, err - } - - // Set Pod hostname - g.Config.Hostname = p.config.Hostname - - var options []CtrCreateOption - - // Command: If user-specified, use that preferentially. - // If not set and the config file is set, fall back to that. - var infraCtrCommand []string - if p.config.InfraContainer.InfraCommand != nil { - logrus.Debugf("User-specified infra container entrypoint %v", p.config.InfraContainer.InfraCommand) - infraCtrCommand = p.config.InfraContainer.InfraCommand - } else if r.config.Engine.InfraCommand != "" { - logrus.Debugf("Config-specified infra container entrypoint %s", r.config.Engine.InfraCommand) - infraCtrCommand = []string{r.config.Engine.InfraCommand} - } - // Only if set by the user or containers.conf, we set entrypoint for the - // infra container. - // This is only used by commit, so it shouldn't matter... But someone - // may eventually want to commit an infra container? - // TODO: Should we actually do this if set by containers.conf? - if infraCtrCommand != nil { - // Need to duplicate the array - we are going to add Cmd later - // so the current array will be changed. - newArr := make([]string, 0, len(infraCtrCommand)) - newArr = append(newArr, infraCtrCommand...) - options = append(options, WithEntrypoint(newArr)) - } - - isRootless := rootless.IsRootless() - - // I've seen circumstances where config is being passed as nil. - // Let's err on the side of safety and make sure it's safe to use. - if config != nil { - if infraCtrCommand == nil { - // If we have no entrypoint and command from the image, - // we can't go on - the infra container has no command. - if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 { - return nil, errors.Errorf("infra container has no command") - } - if len(config.Entrypoint) > 0 { - infraCtrCommand = config.Entrypoint - } else { - // Use the Docker default "/bin/sh -c" - // entrypoint, as we're overriding command. - // If an image doesn't want this, it can - // override entrypoint too. - infraCtrCommand = []string{"/bin/sh", "-c"} - } - } - if len(config.Cmd) > 0 { - infraCtrCommand = append(infraCtrCommand, config.Cmd...) - } - - if len(config.Env) > 0 { - for _, nameValPair := range config.Env { - nameValSlice := strings.Split(nameValPair, "=") - if len(nameValSlice) < 2 { - return nil, errors.Errorf("Invalid environment variable structure in pause image") - } - g.AddProcessEnv(nameValSlice[0], nameValSlice[1]) - } - } - - switch { - case p.config.InfraContainer.HostNetwork: - if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil { - return nil, errors.Wrapf(err, "error removing network namespace from pod %s infra container", p.ID()) - } - case p.config.InfraContainer.NoNetwork: - // Do nothing - we have a network namespace by default, - // but should not configure slirp. - default: - // Since user namespace sharing is not implemented, we only need to check if it's rootless - netmode := "bridge" - if p.config.InfraContainer.Slirp4netns { - netmode = "slirp4netns" - if len(p.config.InfraContainer.NetworkOptions) != 0 { - options = append(options, WithNetworkOptions(p.config.InfraContainer.NetworkOptions)) - } - } - // FIXME allow pods to have exposed ports - options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, nil, !p.config.InfraContainer.Userns.IsHost(), netmode, p.config.InfraContainer.Networks)) - } - - // For each option in InfraContainerConfig - if set, pass into - // the infra container we're creating with the appropriate - // With... option. - if p.config.InfraContainer.StaticIP != nil { - options = append(options, WithStaticIP(p.config.InfraContainer.StaticIP)) - } - if p.config.InfraContainer.StaticMAC != nil { - options = append(options, WithStaticMAC(p.config.InfraContainer.StaticMAC)) - } - if p.config.InfraContainer.UseImageResolvConf { - options = append(options, WithUseImageResolvConf()) - } - if len(p.config.InfraContainer.DNSServer) > 0 { - options = append(options, WithDNS(p.config.InfraContainer.DNSServer)) - } - if len(p.config.InfraContainer.DNSSearch) > 0 { - options = append(options, WithDNSSearch(p.config.InfraContainer.DNSSearch)) - } - if len(p.config.InfraContainer.DNSOption) > 0 { - options = append(options, WithDNSOption(p.config.InfraContainer.DNSOption)) - } - if p.config.InfraContainer.UseImageHosts { - options = append(options, WithUseImageHosts()) - } - if len(p.config.InfraContainer.HostAdd) > 0 { - options = append(options, WithHosts(p.config.InfraContainer.HostAdd)) - } - if len(p.config.InfraContainer.ExitCommand) > 0 { - options = append(options, WithExitCommand(p.config.InfraContainer.ExitCommand)) - } - - if p.config.UsePodPID && p.config.InfraContainer.PidNS.NSMode != "host" { - g.AddOrReplaceLinuxNamespace(string(spec.LinuxNamespaceType("pid")), p.config.InfraContainer.PidNS.Value) - } else if p.config.InfraContainer.PidNS.NSMode == "host" { - newNS := []spec.LinuxNamespace{} - for _, entry := range g.Config.Linux.Namespaces { - if entry.Type != spec.LinuxNamespaceType("pid") { - newNS = append(newNS, entry) - } - } - g.Config.Linux.Namespaces = newNS - } - } - - for _, ctl := range r.config.Containers.DefaultSysctls { - sysctl := strings.SplitN(ctl, "=", 2) - if len(sysctl) < 2 { - return nil, errors.Errorf("invalid default sysctl %s", ctl) - } - - // Ignore net sysctls if --net=host - if p.config.InfraContainer.HostNetwork && strings.HasPrefix(sysctl[0], "net.") { - logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctl[0], sysctl[1]) - continue - } - - g.AddLinuxSysctl(sysctl[0], sysctl[1]) - } - - g.SetRootReadonly(true) - g.SetProcessArgs(infraCtrCommand) - - logrus.Debugf("Using %q as infra container command", infraCtrCommand) - - mapopt, err := util.ParseIDMapping(namespaces.UsernsMode(p.config.InfraContainer.Userns.String()), []string{}, []string{}, "", "") - if err != nil { - return nil, err - } - user, err := specgen.SetupUserNS(mapopt, p.config.InfraContainer.Userns, &g) - if err != nil { - return nil, err - } - if user != "" { - options = append(options, WithUser(user)) - } - - g.RemoveMount("/dev/shm") - if isRootless { - g.RemoveMount("/dev/pts") - devPts := spec.Mount{ - Destination: "/dev/pts", - Type: "devpts", - Source: "devpts", - Options: []string{"private", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"}, - } - g.AddMount(devPts) - } - - // Add default sysctls from containers.conf - defaultSysctls, err := util.ValidateSysctls(r.config.Sysctls()) - if err != nil { - return nil, err - } - for sysctlKey, sysctlVal := range defaultSysctls { - // Ignore mqueue sysctls if not sharing IPC - if !p.config.UsePodIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") { - logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace for pod is unused", sysctlKey, sysctlVal) - continue - } - - // Ignore net sysctls if host network or not sharing network - if (p.config.InfraContainer.HostNetwork || !p.config.UsePodNet) && strings.HasPrefix(sysctlKey, "net.") { - logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace for pod is unused", sysctlKey, sysctlVal) - continue - } - - // Ignore uts sysctls if not sharing UTS - if !p.config.UsePodUTS && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) { - logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace for pod is unused", sysctlKey, sysctlVal) - continue - } - g.AddLinuxSysctl(sysctlKey, sysctlVal) - } - - containerName := p.config.InfraContainer.InfraName - if containerName == "" { - containerName = p.ID()[:IDTruncLength] + "-infra" - } - logrus.Infof("Infra container name %s", containerName) - options = append(options, r.WithPod(p)) - options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName)) - options = append(options, WithName(containerName)) - options = append(options, withIsInfra()) - options = append(options, WithIDMappings(*mapopt)) - if len(p.config.InfraContainer.ConmonPidFile) > 0 { - options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile)) - } - newRes := new(spec.LinuxResources) - newRes.CPU = new(spec.LinuxCPU) - newRes.CPU = p.ResourceLim().CPU - g.Config.Linux.Resources.CPU = newRes.CPU - - return r.newContainer(ctx, g.Config, options...) -} - -// createInfraContainer wrap creates an infra container for a pod. -// An infra container becomes the basis for kernel namespace sharing between -// containers in the pod. -func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container, error) { - if !r.valid { - return nil, define.ErrRuntimeStopped - } - imageName := p.config.InfraContainer.InfraImage - if imageName == "" { - imageName = r.config.Engine.InfraImage - } - - pulledImages, err := r.LibimageRuntime().Pull(ctx, imageName, config.PullPolicyMissing, nil) - if err != nil { - return nil, errors.Wrap(err, "error pulling infra-container image") - } - - newImage := pulledImages[0] - data, err := newImage.Inspect(ctx, false) - if err != nil { - return nil, err - } - - imageName = "none" - if len(newImage.Names()) > 0 { - imageName = newImage.Names()[0] - } - imageID := data.ID - - return r.makeInfraContainer(ctx, p, imageName, r.config.Engine.InfraImage, imageID, data.Config) -} diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index fce3f38a7..7571fdfff 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -14,13 +14,14 @@ import ( "github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/podman/v3/pkg/rootless" + "github.com/containers/podman/v3/pkg/specgen" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) // NewPod makes a new, empty pod -func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Pod, deferredErr error) { +func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, options ...PodCreateOption) (_ *Pod, deferredErr error) { r.lock.Lock() defer r.lock.Unlock() @@ -50,8 +51,8 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po pod.config.Name = name } - if pod.config.Hostname == "" { - pod.config.Hostname = pod.config.Name + if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" { + p.InfraContainerSpec.Hostname = pod.config.Name } // Allocate a lock for the pod @@ -88,6 +89,9 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po // launch should do it for us if pod.config.UsePodCgroup { pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID()) + if p.InfraContainerSpec != nil { + p.InfraContainerSpec.CgroupParent = pod.state.CgroupPath + } } } case config.SystemdCgroupsManager: @@ -108,6 +112,9 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po return nil, errors.Wrapf(err, "unable to create pod cgroup for pod %s", pod.ID()) } pod.state.CgroupPath = cgroupPath + if p.InfraContainerSpec != nil { + p.InfraContainerSpec.CgroupParent = pod.state.CgroupPath + } } default: return nil, errors.Wrapf(define.ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.Engine.CgroupManager) @@ -127,28 +134,40 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po if err := r.state.AddPod(pod); err != nil { return nil, errors.Wrapf(err, "error adding pod to state") } - defer func() { - if deferredErr != nil { - if err := r.removePod(ctx, pod, true, true); err != nil { - logrus.Errorf("Error removing pod after pause container creation failure: %v", err) - } - } - }() + return pod, nil +} - if pod.HasInfraContainer() { - ctr, err := r.createInfraContainer(ctx, pod) - if err != nil { - return nil, errors.Wrapf(err, "error adding Infra Container") - } - pod.state.InfraContainerID = ctr.ID() - if err := pod.save(); err != nil { - return nil, err - } +// AddInfra adds the created infra container to the pod state +func (r *Runtime) AddInfra(ctx context.Context, pod *Pod, infraCtr *Container) (*Pod, error) { + r.lock.Lock() + defer r.lock.Unlock() + + if !r.valid { + return nil, define.ErrRuntimeStopped + } + pod.state.InfraContainerID = infraCtr.ID() + if err := pod.save(); err != nil { + return nil, err } pod.newPodEvent(events.Create) return pod, nil } +// SavePod is a helper function to save the pod state from outside of libpod +func (r *Runtime) SavePod(pod *Pod) error { + r.lock.Lock() + defer r.lock.Unlock() + + if !r.valid { + return define.ErrRuntimeStopped + } + if err := pod.save(); err != nil { + return err + } + pod.newPodEvent(events.Create) + return nil +} + func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) error { if err := p.updatePod(); err != nil { return err |