From 08186d7dd7a884bd5834ebafdd91a9b583de49d9 Mon Sep 17 00:00:00 2001 From: danishprakash Date: Mon, 23 Jan 2023 11:04:50 +0530 Subject: [PATCH] kube-play: add support for HostIPC in pod.Spec * play_kube_test: add tests Signed-off-by: danishprakash --- docs/kubernetes_support.md | 2 +- pkg/domain/entities/pods.go | 7 ++++++ pkg/domain/infra/abi/play.go | 3 ++- pkg/specgen/generate/kube/kube.go | 8 ++++++ pkg/specgen/podspecgen.go | 3 +++ test/e2e/play_kube_test.go | 42 +++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/docs/kubernetes_support.md b/docs/kubernetes_support.md index 1f80dc45ee..366d26c8cc 100644 --- a/docs/kubernetes_support.md +++ b/docs/kubernetes_support.md @@ -48,7 +48,7 @@ Note: **N/A** means that the option cannot be supported in a single-node Podman | dnsPolicy | | | hostNetwork | ✅ | | hostPID | ✅ | -| hostIPC | | +| hostIPC | ✅ | | shareProcessNamespace | ✅ | | serviceAccountName | | | automountServiceAccountToken | | diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index 36676d56d2..1ee975da39 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -129,6 +129,7 @@ type PodCreateOptions struct { InfraName string `json:"container_name,omitempty"` InfraCommand *string `json:"container_command,omitempty"` InfraConmonPidFile string `json:"container_conmon_pidfile,omitempty"` + Ipc string `json:"ipc,omitempty"` Labels map[string]string `json:"labels,omitempty"` Name string `json:"name,omitempty"` Net *NetOptions `json:"net,omitempty"` @@ -349,6 +350,12 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod return nil, err } s.Pid = out + + out, err = specgen.ParseNamespace(p.Ipc) + if err != nil { + return nil, err + } + s.Ipc = out s.Hostname = p.Hostname s.ExitPolicy = p.ExitPolicy s.Labels = p.Labels diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 70fe4329c4..355cb2f072 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -710,10 +710,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY ConfigMaps: configMaps, Container: container, Image: pulledImage, + IpcNSIsHost: p.Ipc.IsHost(), Labels: labels, LogDriver: options.LogDriver, LogOptions: options.LogOptions, NetNSIsHost: p.NetNS.IsHost(), + PidNSIsHost: p.Pid.IsHost(), PodID: pod.ID(), PodInfraID: podInfraID, PodName: podName, @@ -722,7 +724,6 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY RestartPolicy: ctrRestartPolicy, SeccompPaths: seccompPaths, SecretsManager: secretsManager, - PidNSIsHost: p.Pid.IsHost(), UserNSIsHost: p.Userns.IsHost(), Volumes: volumes, } diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index b3098aa099..1e6314fb76 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -56,6 +56,9 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, if podYAML.Spec.HostPID { p.Pid = "host" } + if podYAML.Spec.HostIPC { + p.Ipc = "host" + } p.Hostname = podYAML.Spec.Hostname if p.Hostname == "" { p.Hostname = podName @@ -114,6 +117,8 @@ type CtrSpecGenOptions struct { Container v1.Container // Image available to use (pulled or found local) Image *libimage.Image + // IPCNSIsHost tells the container to use the host ipcns + IpcNSIsHost bool // Volumes for all containers Volumes map[string]*KubeVolume // PodID of the parent pod @@ -470,6 +475,9 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener if opts.PidNSIsHost { s.PidNS.NSMode = specgen.Host } + if opts.IpcNSIsHost { + s.IpcNS.NSMode = specgen.Host + } // Add labels that come from kube if len(s.Labels) == 0 { diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index faeeb2ed6a..cc5fc8d762 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -53,6 +53,9 @@ type PodBasicConfig struct { // Conflicts with NoInfra=true. // Optional. InfraName string `json:"infra_name,omitempty"` + // Ipc sets the IPC namespace of the pod, set to private by default. + // This configuration will then be shared with the entire pod if PID namespace sharing is enabled via --share + Ipc Namespace `json:"ipcns,omitempty"` // SharedNamespaces instructs the pod to share a set of namespaces. // Shared namespaces will be joined (by default) by every container // which joins the pod. diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 12db9e4ab9..106b5df647 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -11,6 +11,7 @@ import ( "net/http" "net/url" "os" + "os/exec" "os/user" "path/filepath" "strconv" @@ -953,6 +954,19 @@ spec: command: ['sh', '-c', 'echo $$'] ` +var podWithHostIPCDefined = ` +apiVersion: v1 +kind: Pod +metadata: + name: test-hostipc +spec: + hostIPC: true + containers: + - name: alpine + image: quay.io/libpod/alpine:latest + command: ['sh', '-c', 'ls -l /proc/self/ns/ipc'] +` + var ( defaultCtrName = "testCtr" defaultCtrCmd = []string{"top"} @@ -4964,4 +4978,32 @@ spec: Expect(inspect.OutputToString()).To(Equal("host")) }) + It("podman play kube test with hostIPC", func() { + err := writeYaml(podWithHostIPCDefined, kubeYaml) + Expect(err).ToNot(HaveOccurred()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + inspect := podmanTest.Podman([]string{"inspect", "test-hostipc-alpine", "--format", "{{ .HostConfig.IpcMode }}"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(Equal("shareable")) + + cmd := exec.Command("ls", "-l", "/proc/self/ns/ipc") + res, err := cmd.Output() + Expect(err).ToNot(HaveOccurred()) + fields := strings.Split(string(res), " ") + hostIpcNS := strings.TrimSuffix(fields[len(fields)-1], "\n") + + logs := podmanTest.Podman([]string{"pod", "logs", "-c", "test-hostipc-alpine", "test-hostipc"}) + logs.WaitWithDefaultTimeout() + Expect(logs).Should(Exit(0)) + fields = strings.Split(logs.OutputToString(), " ") + ctrIpcNS := strings.TrimSuffix(fields[len(fields)-1], "\n") + + Expect(hostIpcNS).To(Equal(ctrIpcNS)) + }) + })