From 936e30f68be0a13f1452aaa65993debeee162c85 Mon Sep 17 00:00:00 2001 From: Urvashi Mohnani Date: Tue, 17 Oct 2023 11:27:24 -0400 Subject: [PATCH] Use node hostname in kube play when hostNetwork=true When the hostNetwork option is set to true in the k8s yaml, set the pod's hostname to the name of the machine/node as is done in k8s. Also set the utsns to host. Signed-off-by: Urvashi Mohnani --- pkg/domain/entities/pods.go | 7 +++ pkg/domain/infra/abi/play.go | 2 + pkg/specgen/generate/kube/kube.go | 11 +++++ test/e2e/play_kube_test.go | 81 +++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index c6bdc0f553..0baff93a66 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -146,6 +146,7 @@ type PodCreateOptions struct { VolumesFrom []string `json:"volumes_from,omitempty"` SecurityOpt []string `json:"security_opt,omitempty"` Sysctl []string `json:"sysctl,omitempty"` + Uts string `json:"uts,omitempty"` } // PodLogsOptions describes the options to extract pod logs. @@ -362,6 +363,12 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod return nil, err } s.Ipc = out + + out, err = specgen.ParseNamespace(p.Uts) + if err != nil { + return nil, err + } + s.UtsNs = 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 6d9e67a377..0bfb12d1e8 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -789,6 +789,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY SecretsManager: secretsManager, UserNSIsHost: p.Userns.IsHost(), Volumes: volumes, + UtsNSIsHost: p.UtsNs.IsHost(), } specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { @@ -858,6 +859,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY SecretsManager: secretsManager, UserNSIsHost: p.Userns.IsHost(), Volumes: volumes, + UtsNSIsHost: p.UtsNs.IsHost(), } if podYAML.Spec.TerminationGracePeriodSeconds != nil { diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index bff697979e..a9b742ebe2 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -69,6 +69,12 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions, } if podYAML.Spec.HostNetwork { p.Net.Network = specgen.Namespace{NSMode: "host"} + nodeHostName, err := os.Hostname() + if err != nil { + return p, err + } + p.Hostname = nodeHostName + p.Uts = "host" } if podYAML.Spec.HostAliases != nil { if p.Net.NoHosts { @@ -156,6 +162,8 @@ type CtrSpecGenOptions struct { UserNSIsHost bool // PidNSIsHost tells the container to use the host pidns PidNSIsHost bool + // UtsNSIsHost tells the container to use the host utsns + UtsNSIsHost bool // SecretManager to access the secrets SecretsManager *secrets.SecretsManager // LogDriver which should be used for the container @@ -563,6 +571,9 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener if opts.IpcNSIsHost { s.IpcNS.NSMode = specgen.Host } + if opts.UtsNSIsHost { + s.UtsNS.NSMode = specgen.Host + } // Add labels that come from kube if len(s.Labels) == 0 { diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index a8102f650e..38139e159c 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -6256,4 +6256,85 @@ EXPOSE 2004-2005/tcp`, CITEST_IMAGE) Expect(inspect).Should(ExitCleanly()) Expect(inspect.OutputToString()).To(Equal("20")) }) + + It("hostname should be node name when hostNetwork=true", func() { + netYaml := ` +apiVersion: v1 +kind: Pod +metadata: + name: test-pod +spec: + hostNetwork: true + hostname: blah + containers: + - name: alpine + image: alpine + command: + - sleep + - "100" +` + + err := writeYaml(netYaml, kubeYaml) + Expect(err).ToNot(HaveOccurred()) + kube := podmanTest.Podman([]string{"kube", "play", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(ExitCleanly()) + + // Get the name of the host + hostname, err := os.Hostname() + Expect(err).ToNot(HaveOccurred()) + + exec := podmanTest.Podman([]string{"exec", "test-pod-alpine", "hostname"}) + exec.WaitWithDefaultTimeout() + Expect(exec).Should(ExitCleanly()) + Expect(exec.OutputToString()).To(Equal(hostname)) + + // Check that the UTS namespace is set to host also + hostUts := SystemExec("ls", []string{"-l", "/proc/self/ns/uts"}) + Expect(hostUts).Should(ExitCleanly()) + arr := strings.Split(hostUts.OutputToString(), " ") + exec = podmanTest.Podman([]string{"exec", "test-pod-alpine", "ls", "-l", "/proc/self/ns/uts"}) + exec.WaitWithDefaultTimeout() + Expect(exec).Should(ExitCleanly()) + execArr := strings.Split(exec.OutputToString(), " ") + Expect(execArr[len(execArr)-1]).To(ContainSubstring(arr[len(arr)-1])) + }) + + It("hostname should be pod name when hostNetwork=false", func() { + netYaml := ` +apiVersion: v1 +kind: Pod +metadata: + name: test-pod +spec: + containers: + - name: alpine + image: alpine + command: + - sleep + - "100" +` + + err := writeYaml(netYaml, kubeYaml) + Expect(err).ToNot(HaveOccurred()) + kube := podmanTest.Podman([]string{"kube", "play", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(ExitCleanly()) + + exec := podmanTest.Podman([]string{"exec", "test-pod-alpine", "hostname"}) + exec.WaitWithDefaultTimeout() + Expect(exec).Should(ExitCleanly()) + Expect(exec.OutputToString()).To(Equal("test-pod")) + + // Check that the UTS namespace is set to host also + hostUts := SystemExec("ls", []string{"-l", "/proc/self/ns/uts"}) + Expect(hostUts).Should(ExitCleanly()) + arr := strings.Split(hostUts.OutputToString(), " ") + exec = podmanTest.Podman([]string{"exec", "test-pod-alpine", "ls", "-l", "/proc/self/ns/uts"}) + exec.WaitWithDefaultTimeout() + Expect(exec).Should(ExitCleanly()) + execArr := strings.Split(exec.OutputToString(), " ") + Expect(execArr[len(execArr)-1]).To(Not(ContainSubstring(arr[len(arr)-1]))) + }) + })