k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/network/no_snat.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package network 18 19 import ( 20 "context" 21 "fmt" 22 "net" 23 "time" 24 25 "github.com/onsi/ginkgo/v2" 26 "github.com/onsi/gomega" 27 v1 "k8s.io/api/core/v1" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/util/wait" 30 admissionapi "k8s.io/pod-security-admission/api" 31 32 "k8s.io/kubernetes/test/e2e/feature" 33 "k8s.io/kubernetes/test/e2e/framework" 34 e2enode "k8s.io/kubernetes/test/e2e/framework/node" 35 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 36 "k8s.io/kubernetes/test/e2e/network/common" 37 imageutils "k8s.io/kubernetes/test/utils/image" 38 ) 39 40 const ( 41 testPodPort = "8080" 42 noSNATTestName = "no-snat-test" 43 ) 44 45 var ( 46 testPod = v1.Pod{ 47 ObjectMeta: metav1.ObjectMeta{ 48 GenerateName: noSNATTestName, 49 Labels: map[string]string{ 50 noSNATTestName: "", 51 }, 52 }, 53 Spec: v1.PodSpec{ 54 Containers: []v1.Container{ 55 { 56 Name: noSNATTestName, 57 Image: imageutils.GetE2EImage(imageutils.Agnhost), 58 Args: []string{"netexec", "--http-port", testPodPort}, 59 }, 60 }, 61 }, 62 } 63 ) 64 65 // This test verifies that a Pod on each node in a cluster can talk to Pods on every other node without SNAT. 66 // We use the [Feature:NoSNAT] tag so that most jobs will skip this test by default. 67 var _ = common.SIGDescribe("NoSNAT", feature.NoSNAT, framework.WithSlow(), func() { 68 f := framework.NewDefaultFramework("no-snat-test") 69 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 70 ginkgo.It("Should be able to send traffic between Pods without SNAT", func(ctx context.Context) { 71 cs := f.ClientSet 72 pc := cs.CoreV1().Pods(f.Namespace.Name) 73 74 ginkgo.By("creating a test pod on each Node") 75 nodes, err := e2enode.GetReadySchedulableNodes(ctx, cs) 76 framework.ExpectNoError(err) 77 gomega.Expect(nodes.Items).ToNot(gomega.BeEmpty(), "no Nodes in the cluster") 78 79 for _, node := range nodes.Items { 80 // target Pod at Node 81 nodeSelection := e2epod.NodeSelection{Name: node.Name} 82 e2epod.SetNodeSelection(&testPod.Spec, nodeSelection) 83 _, err = pc.Create(ctx, &testPod, metav1.CreateOptions{}) 84 framework.ExpectNoError(err) 85 } 86 87 ginkgo.By("waiting for all of the no-snat-test pods to be scheduled and running") 88 err = wait.PollImmediate(10*time.Second, 1*time.Minute, func() (bool, error) { 89 pods, err := pc.List(ctx, metav1.ListOptions{LabelSelector: noSNATTestName}) 90 if err != nil { 91 return false, err 92 } 93 94 // check all pods are running 95 for _, pod := range pods.Items { 96 if pod.Status.Phase != v1.PodRunning { 97 if pod.Status.Phase != v1.PodPending { 98 return false, fmt.Errorf("expected pod to be in phase \"Pending\" or \"Running\"") 99 } 100 return false, nil // pod is still pending 101 } 102 } 103 return true, nil // all pods are running 104 }) 105 framework.ExpectNoError(err) 106 107 ginkgo.By("sending traffic from each pod to the others and checking that SNAT does not occur") 108 pods, err := pc.List(ctx, metav1.ListOptions{LabelSelector: noSNATTestName}) 109 framework.ExpectNoError(err) 110 111 // hit the /clientip endpoint on every other Pods to check if source ip is preserved 112 // this test is O(n^2) but it doesn't matter because we only run this test on small clusters (~3 nodes) 113 for _, sourcePod := range pods.Items { 114 for _, targetPod := range pods.Items { 115 if targetPod.Name == sourcePod.Name { 116 continue 117 } 118 targetAddr := net.JoinHostPort(targetPod.Status.PodIP, testPodPort) 119 sourceIP, execPodIP := execSourceIPTest(sourcePod, targetAddr) 120 ginkgo.By("Verifying the preserved source ip") 121 gomega.Expect(sourceIP).To(gomega.Equal(execPodIP)) 122 } 123 } 124 }) 125 })