From 3082ba8b7b4489ec0be3886450b2681e16aca17e Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Tue, 12 Oct 2021 12:35:55 -0500 Subject: No space in kube annotations for bind mounts Kubernetes fails to deal with an annotation that has a space in it. Trim these strings to remove spaces. Fixes: #11929 Signed-off-by: Brent Baude [NO TESTS NEEDED] --- libpod/kube.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libpod/kube.go') diff --git a/libpod/kube.go b/libpod/kube.go index cb97eb5ab..9e1e3ddfe 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -246,7 +246,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po return nil, err } for k, v := range annotations { - podAnnotations[define.BindMountPrefix+k] = v + podAnnotations[define.BindMountPrefix+k] = strings.TrimSpace(v) } // Since port bindings for the pod are handled by the // infra container, wipe them here. @@ -366,7 +366,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod, return nil, err } for k, v := range annotations { - kubeAnnotations[define.BindMountPrefix+k] = v + kubeAnnotations[define.BindMountPrefix+k] = strings.TrimSpace(v) } if isInit { kubeInitCtrs = append(kubeInitCtrs, kubeCtr) -- cgit v1.2.3-54-g00ecf From 16fb4161a6853c047f40920adce43049cc428243 Mon Sep 17 00:00:00 2001 From: cdoern Date: Mon, 11 Oct 2021 11:01:36 -0400 Subject: Kube Gen run as user/group issues Removed the inclusion of RunAsUser or RunAsGroup unless a container is run with the --user flag. When building from an image the user will be pulled from there anyway resolves #11914 Signed-off-by: cdoern --- libpod/kube.go | 4 ++++ test/e2e/generate_kube_test.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'libpod/kube.go') diff --git a/libpod/kube.go b/libpod/kube.go index 9e1e3ddfe..9c71c8ad6 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -485,6 +485,10 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] kubeContainer.Command = nil } + if imgData.User == c.User() { + kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil + } + kubeContainer.WorkingDir = c.WorkingDir() kubeContainer.Ports = ports // This should not be applicable diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index cb987e139..b84977d0d 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -942,7 +942,7 @@ USER test1` pod := new(v1.Pod) err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) - Expect(*pod.Spec.Containers[0].SecurityContext.RunAsUser).To(Equal(int64(10001))) + Expect(pod.Spec.Containers[0].SecurityContext.RunAsUser).To(BeNil()) }) It("podman generate kube on named volume", func() { -- cgit v1.2.3-54-g00ecf From 92ed439d2252146220922bc1dd8cacfc4090a8c5 Mon Sep 17 00:00:00 2001 From: Urvashi Mohnani Date: Tue, 12 Oct 2021 16:02:47 -0400 Subject: Don't add image entrypoint to the generate kube yaml If no entrypoint or command is set in the podman create command, and the image command or entrypoint is being used as the default, then do not add the image command or entrypoint to the generated kube yaml. Kubernetes knows to default to the image command and/or entrypoint settings when not defined in the kube yaml. Add and modify tests for this case. Signed-off-by: Urvashi Mohnani --- libpod/kube.go | 4 +++- test/e2e/generate_kube_test.go | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 12 deletions(-) (limited to 'libpod/kube.go') diff --git a/libpod/kube.go b/libpod/kube.go index 9c71c8ad6..72d2f8e96 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -481,7 +481,9 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] if err != nil { return kubeContainer, kubeVolumes, nil, annotations, err } - if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) { + // If the user doesn't set a command/entrypoint when creating the container with podman and + // is using the image command or entrypoint from the image, don't add it to the generated kube yaml + if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) || reflect.DeepEqual(imgData.Config.Entrypoint, kubeContainer.Command) { kubeContainer.Command = nil } diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index b84977d0d..8f3d5027d 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -803,7 +803,7 @@ var _ = Describe("Podman generate kube", func() { Expect(containers[0].Args).To(Equal([]string{"10s"})) }) - It("podman generate kube - no command", func() { + It("podman generate kube - use command from image unless explicitly set in the podman command", func() { session := podmanTest.Podman([]string{"create", "--name", "test", ALPINE}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -812,8 +812,8 @@ var _ = Describe("Podman generate kube", func() { kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // Now make sure that the container's command is not set to the - // entrypoint and it's arguments to "10s". + // Now make sure that the container's command in the kube yaml is not set to the + // image command. pod := new(v1.Pod) err := yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) @@ -831,8 +831,8 @@ var _ = Describe("Podman generate kube", func() { kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // Now make sure that the container's command is not set to the - // entrypoint and it's arguments to "10s". + // Now make sure that the container's command in the kube yaml is set to the + // command passed via the cli to podman create. pod = new(v1.Pod) err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) @@ -842,10 +842,10 @@ var _ = Describe("Podman generate kube", func() { Expect(containers[0].Command).To(Equal(cmd)) }) - It("podman generate kube - use entrypoint from image", func() { + It("podman generate kube - use entrypoint from image unless --entrypoint is set", func() { // Build an image with an entrypoint. containerfile := `FROM quay.io/libpod/alpine:latest -ENTRYPOINT /bin/sleep` +ENTRYPOINT ["sleep"]` targetPath, err := CreateTempDirInTempDir() Expect(err).To(BeNil()) @@ -866,17 +866,34 @@ ENTRYPOINT /bin/sleep` kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // Now make sure that the container's command is set to the - // entrypoint and it's arguments to "10s". + // Now make sure that the container's command in the kube yaml is NOT set to the + // entrypoint but the arguments should be set to "10s". pod := new(v1.Pod) err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) containers := pod.Spec.Containers Expect(len(containers)).To(Equal(1)) - - Expect(containers[0].Command).To(Equal([]string{"/bin/sh", "-c", "/bin/sleep"})) Expect(containers[0].Args).To(Equal([]string{"10s"})) + + session = podmanTest.Podman([]string{"create", "--pod", "new:testpod-2", "--entrypoint", "echo", image, "hello"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + kube = podmanTest.Podman([]string{"generate", "kube", "testpod-2"}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Now make sure that the container's command in the kube yaml is set to the + // entrypoint defined by the --entrypoint flag and the arguments should be set to "hello". + pod = new(v1.Pod) + err = yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + + containers = pod.Spec.Containers + Expect(len(containers)).To(Equal(1)) + Expect(containers[0].Command).To(Equal([]string{"echo"})) + Expect(containers[0].Args).To(Equal([]string{"hello"})) }) It("podman generate kube - --privileged container", func() { -- cgit v1.2.3-54-g00ecf From 9168db8bc0b1158389801c2fa53563a4ced3aea5 Mon Sep 17 00:00:00 2001 From: Urvashi Mohnani Date: Thu, 14 Oct 2021 15:03:18 -0400 Subject: Do not add TCP to protocol in generated kube yaml As the default protocol in k8s is TCP, don't add it to the generate yaml when using protocol. Add UDP to the protocol of the generated yaml when udp is being used. Add tests for this as well. Signed-off-by: Urvashi Mohnani --- libpod/kube.go | 3 ++- test/e2e/generate_kube_test.go | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'libpod/kube.go') diff --git a/libpod/kube.go b/libpod/kube.go index 72d2f8e96..ad70dd2cf 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -578,7 +578,8 @@ func ocicniPortMappingToContainerPort(portMappings []ocicni.PortMapping) ([]v1.C var protocol v1.Protocol switch strings.ToUpper(p.Protocol) { case "TCP": - protocol = v1.ProtocolTCP + // do nothing as it is the default protocol in k8s, there is no need to explicitly + // add it to the generated yaml case "UDP": protocol = v1.ProtocolUDP default: diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 8f3d5027d..7b0ed144d 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -451,6 +451,10 @@ var _ = Describe("Podman generate kube", func() { foundOtherPort := 0 for _, ctr := range pod.Spec.Containers { for _, port := range ctr.Ports { + // Since we are using tcp here, the generated kube yaml shouldn't + // have anything for protocol under the ports as tcp is the default + // for k8s + Expect(port.Protocol).To(BeEmpty()) if port.HostPort == 4000 { foundPort4000 = foundPort4000 + 1 } else if port.HostPort == 5000 { @@ -463,6 +467,24 @@ var _ = Describe("Podman generate kube", func() { Expect(foundPort4000).To(Equal(1)) Expect(foundPort5000).To(Equal(1)) Expect(foundOtherPort).To(Equal(0)) + + // Create container with UDP port and check the generated kube yaml + ctrWithUDP := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "6666:66/udp", ALPINE, "top"}) + ctrWithUDP.WaitWithDefaultTimeout() + Expect(ctrWithUDP).Should(Exit(0)) + + kube = podmanTest.Podman([]string{"generate", "kube", "test-pod"}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + pod = new(v1.Pod) + err = yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + + containers := pod.Spec.Containers + Expect(len(containers)).To(Equal(1)) + Expect(len(containers[0].Ports)).To(Equal(1)) + Expect(containers[0].Ports[0].Protocol).To(Equal(v1.ProtocolUDP)) }) It("podman generate and reimport kube on pod", func() { -- cgit v1.2.3-54-g00ecf From d39e4128342635a9385b29f3be64c69a4ce0ea32 Mon Sep 17 00:00:00 2001 From: Urvashi Mohnani Date: Thu, 14 Oct 2021 16:58:27 -0400 Subject: Set targetPort to the port value in the kube yaml When the targetPort is not defined, it is supposed to be set to the port value according to the k8s docs. Add tests for targetPort. Update tests to be able to check the Service yaml that is generated. Signed-off-by: Urvashi Mohnani --- libpod/kube.go | 10 +++++---- test/e2e/generate_kube_test.go | 50 ++++++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 21 deletions(-) (limited to 'libpod/kube.go') diff --git a/libpod/kube.go b/libpod/kube.go index ad70dd2cf..f5291ce60 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -25,6 +25,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" v12 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) // GenerateForKube takes a slice of libpod containers and generates @@ -196,10 +197,11 @@ func containerPortsToServicePorts(containerPorts []v1.ContainerPort) []v1.Servic for _, cp := range containerPorts { nodePort := 30000 + rand.Intn(32767-30000+1) servicePort := v1.ServicePort{ - Protocol: cp.Protocol, - Port: cp.ContainerPort, - NodePort: int32(nodePort), - Name: strconv.Itoa(int(cp.ContainerPort)), + Protocol: cp.Protocol, + Port: cp.ContainerPort, + NodePort: int32(nodePort), + Name: strconv.Itoa(int(cp.ContainerPort)), + TargetPort: intstr.Parse(strconv.Itoa(int(cp.ContainerPort))), } sps = append(sps, servicePort) } diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 7b0ed144d..07515fe7b 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "github.com/containers/podman/v3/libpod/define" @@ -119,20 +120,28 @@ var _ = Describe("Podman generate kube", func() { Expect(kube.OutputToString()).To(ContainSubstring("type: foo_bar_t")) }) - It("podman generate service kube on container", func() { - session := podmanTest.RunTopContainer("top") + It("podman generate service kube on container - targetPort should match port name", func() { + session := podmanTest.Podman([]string{"create", "--name", "test-ctr", "-p", "3890:3890", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - kube := podmanTest.Podman([]string{"generate", "kube", "-s", "top"}) + kube := podmanTest.Podman([]string{"generate", "kube", "-s", "test-ctr"}) kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // TODO - test generated YAML - service produces multiple - // structs. - // pod := new(v1.Pod) - // err := yaml.Unmarshal([]byte(kube.OutputToString()), pod) - // Expect(err).To(BeNil()) + // Separate out the Service and Pod yaml + arr := strings.Split(string(kube.Out.Contents()), "---") + Expect(len(arr)).To(Equal(2)) + + svc := new(v1.Service) + err := yaml.Unmarshal([]byte(arr[0]), svc) + Expect(err).To(BeNil()) + Expect(len(svc.Spec.Ports)).To(Equal(1)) + Expect(svc.Spec.Ports[0].TargetPort.IntValue()).To(Equal(3890)) + + pod := new(v1.Pod) + err = yaml.Unmarshal([]byte(arr[1]), pod) + Expect(err).To(BeNil()) }) It("podman generate kube on pod", func() { @@ -315,21 +324,28 @@ var _ = Describe("Podman generate kube", func() { }) It("podman generate service kube on pod", func() { - _, rc, _ := podmanTest.CreatePod(map[string][]string{"--name": {"toppod"}}) - Expect(rc).To(Equal(0)) - - session := podmanTest.RunTopContainerInPod("topcontainer", "toppod") + session := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "4000:4000/udp", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - kube := podmanTest.Podman([]string{"generate", "kube", "-s", "toppod"}) + kube := podmanTest.Podman([]string{"generate", "kube", "-s", "test-pod"}) kube.WaitWithDefaultTimeout() Expect(kube).Should(Exit(0)) - // TODO: How do we test unmarshal with a service? We have two - // structs that need to be unmarshalled... - // _, err := yaml.Marshal(kube.OutputToString()) - // Expect(err).To(BeNil()) + // Separate out the Service and Pod yaml + arr := strings.Split(string(kube.Out.Contents()), "---") + Expect(len(arr)).To(Equal(2)) + + svc := new(v1.Service) + err := yaml.Unmarshal([]byte(arr[0]), svc) + Expect(err).To(BeNil()) + Expect(len(svc.Spec.Ports)).To(Equal(1)) + Expect(svc.Spec.Ports[0].TargetPort.IntValue()).To(Equal(4000)) + Expect(svc.Spec.Ports[0].Protocol).To(Equal(v1.ProtocolUDP)) + + pod := new(v1.Pod) + err = yaml.Unmarshal([]byte(arr[1]), pod) + Expect(err).To(BeNil()) }) It("podman generate kube on pod with restartPolicy", func() { -- cgit v1.2.3-54-g00ecf