diff options
-rw-r--r-- | cmd/podman/containers/create.go | 1 | ||||
-rw-r--r-- | cmd/podman/pods/create.go | 6 | ||||
-rw-r--r-- | docs/source/markdown/podman-pod-create.1.md | 8 | ||||
-rw-r--r-- | libpod/define/pod_inspect.go | 2 | ||||
-rw-r--r-- | libpod/options.go | 20 | ||||
-rw-r--r-- | libpod/pod.go | 7 | ||||
-rw-r--r-- | libpod/pod_api.go | 1 | ||||
-rw-r--r-- | libpod/runtime_pod_infra_linux.go | 12 | ||||
-rw-r--r-- | libpod/runtime_pod_linux.go | 1 | ||||
-rw-r--r-- | pkg/domain/entities/pods.go | 21 | ||||
-rw-r--r-- | pkg/specgen/generate/pod_create.go | 4 | ||||
-rw-r--r-- | pkg/specgen/podspecgen.go | 4 | ||||
-rw-r--r-- | test/e2e/pod_create_test.go | 61 |
13 files changed, 148 insertions, 0 deletions
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 1e11c53d5..df0fa6f9d 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -293,6 +293,7 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions Hostname: s.ContainerBasicConfig.Hostname, Cpus: cliVals.CPUS, CpusetCpus: cliVals.CPUSetCPUs, + Pid: cliVals.PID, } // Unset config values we passed to the pod to prevent them being used twice for the container and pod. s.ContainerBasicConfig.Hostname = "" diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go index 03e3ffaa0..0d299bb9c 100644 --- a/cmd/podman/pods/create.go +++ b/cmd/podman/pods/create.go @@ -102,6 +102,10 @@ func init() { flags.StringVarP(&createOptions.Hostname, hostnameFlagName, "", "", "Set a hostname to the pod") _ = createCommand.RegisterFlagCompletionFunc(hostnameFlagName, completion.AutocompleteNone) + pidFlagName := "pid" + flags.StringVar(&createOptions.Pid, pidFlagName, "", "PID namespace to use") + _ = createCommand.RegisterFlagCompletionFunc(pidFlagName, common.AutocompleteNamespace) + podIDFileFlagName := "pod-id-file" flags.StringVar(&podIDFile, podIDFileFlagName, "", "Write the pod ID to the file") _ = createCommand.RegisterFlagCompletionFunc(podIDFileFlagName, completion.AutocompleteDefault) @@ -179,6 +183,8 @@ func create(cmd *cobra.Command, args []string) error { defer errorhandling.SyncQuiet(podIDFD) } + createOptions.Pid = cmd.Flag("pid").Value.String() + createOptions.Net, err = common.NetFlagsToNetOptions(cmd, createOptions.Infra) if err != nil { return err diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md index 653b0f6f1..fecdd8494 100644 --- a/docs/source/markdown/podman-pod-create.1.md +++ b/docs/source/markdown/podman-pod-create.1.md @@ -120,6 +120,14 @@ Add a DNS alias for the container. When the container is joined to a CNI network Disable creation of /etc/hosts for the pod. +#### **--pid**=*pid* + +Set the PID mode for the pod. The default is to create a private PID namespace for the pod. Requires the PID namespace to be shared via --share. + + host: use the host’s PID namespace for the pod + ns: join the specified PID namespace + private: create a new namespace for the pod (default) + #### **--pod-id-file**=*path* Write the pod ID to the file. diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go index 67f075b3c..a17304875 100644 --- a/libpod/define/pod_inspect.go +++ b/libpod/define/pod_inspect.go @@ -103,6 +103,8 @@ type InspectPodInfraConfig struct { CPUQuota int64 `json:"cpu_quota,omitempty"` // CPUSetCPUs contains linux specific CPU data for the container CPUSetCPUs string `json:"cpuset_cpus,omitempty"` + // Pid is the PID namespace mode of the pod's infra container + PidNS string `json:"pid_ns,omitempty"` } // InspectPodContainerInfo contains information on a container in a pod. diff --git a/libpod/options.go b/libpod/options.go index b12153512..bc563d60c 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -16,6 +16,7 @@ import ( "github.com/containers/podman/v3/libpod/events" "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" "github.com/containers/storage" "github.com/containers/storage/pkg/idtools" @@ -2397,3 +2398,22 @@ func WithPodCPUSetCPUs(inp string) PodCreateOption { 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 d7a9b15d9..c03059c82 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -7,6 +7,7 @@ import ( "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" @@ -97,6 +98,7 @@ type InfraContainerConfig struct { 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"` @@ -170,6 +172,11 @@ func (p *Pod) CPUQuota() int64 { 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) +} + // Labels returns the pod's labels func (p *Pod) Labels() map[string]string { labels := make(map[string]string) diff --git a/libpod/pod_api.go b/libpod/pod_api.go index d8f5d15f8..1ab012a8b 100644 --- a/libpod/pod_api.go +++ b/libpod/pod_api.go @@ -541,6 +541,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) { infraConfig.CPUPeriod = p.CPUPeriod() infraConfig.CPUQuota = p.CPUQuota() infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus + infraConfig.PidNS = p.PidMode() if len(p.config.InfraContainer.DNSServer) > 0 { infraConfig.DNSServer = make([]string, 0, len(p.config.InfraContainer.DNSServer)) diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 6b002f65a..8342352ec 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -145,6 +145,18 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm 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 + } } g.SetRootReadonly(true) g.SetProcessArgs(infraCtrCommand) diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 4ede23cac..fce3f38a7 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -116,6 +116,7 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po if pod.config.UsePodCgroup { logrus.Debugf("Got pod cgroup as %s", pod.state.CgroupPath) } + if !pod.HasInfraContainer() && pod.SharesNamespaces() { return nil, errors.Errorf("Pods must have an infra container to share namespaces") } diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index 35f940bca..a0a2a1790 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -118,6 +118,7 @@ type PodCreateOptions struct { Name string Net *NetOptions Share []string + Pid string Cpus float64 CpusetCpus string } @@ -146,6 +147,18 @@ func (p *PodCreateOptions) CPULimits() *specs.LinuxCPU { return cpu } +func setNamespaces(p *PodCreateOptions) ([4]specgen.Namespace, error) { + allNS := [4]specgen.Namespace{} + if p.Pid != "" { + pid, err := specgen.ParseNamespace(p.Pid) + if err != nil { + return [4]specgen.Namespace{}, err + } + allNS[0] = pid + } + return allNS, nil +} + func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error { // Basic Config s.Name = p.Name @@ -178,6 +191,14 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error { s.NoManageHosts = p.Net.NoHosts s.HostAdd = p.Net.AddHosts + namespaces, err := setNamespaces(p) + if err != nil { + return err + } + if !namespaces[0].IsDefault() { + s.Pid = namespaces[0] + } + // Cgroup s.CgroupParent = p.CGroupParent diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go index 023ebb41e..4ffd8a37f 100644 --- a/pkg/specgen/generate/pod_create.go +++ b/pkg/specgen/generate/pod_create.go @@ -102,6 +102,10 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod options = append(options, libpod.WithInfraCommand(p.InfraCommand)) } + if !p.Pid.IsDefault() { + options = append(options, libpod.WithPodPidNS(p.Pid)) + } + switch p.NetNS.NSMode { case specgen.Default, "": if p.NoInfra { diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index 000a787ea..319345c71 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -57,6 +57,10 @@ type PodBasicConfig struct { // (e.g. `podman generate systemd --new`). // Optional. PodCreateCommand []string `json:"pod_create_command,omitempty"` + // Pid sets the process id namespace of the pod + // Optional (defaults to private if unset). This sets the PID namespace of the infra container + // This configuration will then be shared with the entire pod if PID namespace sharing is enabled via --share + Pid Namespace `json:"pid,omitempty:"` } // PodNetworkConfig contains networking configuration for a pod. diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 71fec8d21..63f55fb88 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -560,4 +560,65 @@ ENTRYPOINT ["sleep","99999"] podJSON := podInspect.InspectPodToJSON() Expect(podJSON.CPUSetCPUs).To(Equal(in)) }) + + It("podman pod create --pid", func() { + podName := "pidPod" + ns := "ns:/proc/self/ns/" + podCreate := podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", podName}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect.ExitCode()).To(Equal(0)) + podJSON := podInspect.InspectPodToJSON() + Expect(podJSON.InfraConfig.PidNS).To(Equal("path")) + + podName = "pidPod2" + ns = "pod" + + podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podInspect = podmanTest.Podman([]string{"pod", "inspect", podName}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect.ExitCode()).To(Equal(0)) + podJSON = podInspect.InspectPodToJSON() + Expect(podJSON.InfraConfig.PidNS).To(Equal("pod")) + + podName = "pidPod3" + ns = "host" + + podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podInspect = podmanTest.Podman([]string{"pod", "inspect", podName}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect.ExitCode()).To(Equal(0)) + podJSON = podInspect.InspectPodToJSON() + Expect(podJSON.InfraConfig.PidNS).To(Equal("host")) + + podName = "pidPod4" + ns = "private" + + podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podInspect = podmanTest.Podman([]string{"pod", "inspect", podName}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect.ExitCode()).To(Equal(0)) + podJSON = podInspect.InspectPodToJSON() + Expect(podJSON.InfraConfig.PidNS).To(Equal("private")) + + podName = "pidPod5" + ns = "container:randomfakeid" + + podCreate = podmanTest.Podman([]string{"pod", "create", "--pid", ns, "--name", podName, "--share", "pid"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate).Should(ExitWithError()) + + }) }) |