diff --git a/test/e2e/network/pod_lifecycle.go b/test/e2e/network/pod_lifecycle.go new file mode 100644 index 00000000000..b2051144af8 --- /dev/null +++ b/test/e2e/network/pod_lifecycle.go @@ -0,0 +1,101 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package network + +import ( + "context" + "fmt" + "net" + "strconv" + "time" + + "github.com/onsi/ginkgo/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/test/e2e/framework" + e2epod "k8s.io/kubernetes/test/e2e/framework/pod" + "k8s.io/kubernetes/test/e2e/network/common" + admissionapi "k8s.io/pod-security-admission/api" +) + +var _ = common.SIGDescribe("Connectivity Pod Lifecycle", func() { + + fr := framework.NewDefaultFramework("podlifecycle") + fr.NamespacePodSecurityEnforceLevel = admissionapi.LevelPrivileged + + var ( + cs clientset.Interface + ns string + podClient *e2epod.PodClient + ) + ginkgo.BeforeEach(func(ctx context.Context) { + cs = fr.ClientSet + ns = fr.Namespace.Name + podClient = e2epod.NewPodClient(fr) + }) + + ginkgo.It("should be able to connect from a Pod to a terminating Pod", func(ctx context.Context) { + ginkgo.By("Creating 1 webserver pod able to serve traffic during the grace period of 300 seconds") + gracePeriod := int64(100) + webserverPod := e2epod.NewAgnhostPod(ns, "webserver-pod", nil, nil, nil, "netexec", "--http-port=80", fmt.Sprintf("--delay-shutdown=%d", gracePeriod)) + webserverPod.Spec.TerminationGracePeriodSeconds = &gracePeriod + webserverPod = podClient.CreateSync(ctx, webserverPod) + + ginkgo.By("Creating 1 client pod that will try to connect to the webserver") + pausePod := e2epod.NewAgnhostPod(ns, "pause-pod-1", nil, nil, nil) + pausePod = podClient.CreateSync(ctx, pausePod) + + ginkgo.By("Try to connect to the webserver") + // Wait until we are able to connect to the Pod + podIPAddress := net.JoinHostPort(webserverPod.Status.PodIP, strconv.Itoa(80)) + execHostnameTest(*pausePod, podIPAddress, webserverPod.Name) + + // webserver should continue to serve traffic after delete + // since will be gracefully terminating + err := cs.CoreV1().Pods(ns).Delete(ctx, webserverPod.Name, metav1.DeleteOptions{}) + framework.ExpectNoError(err, "error deleting webserver pod") + // wait some time to ensure the test hit the pod during the terminating phase + time.Sleep(15 * time.Second) + execHostnameTest(*pausePod, podIPAddress, webserverPod.Name) + }) + + ginkgo.It("should be able to connect to other Pod from a terminating Pod", func(ctx context.Context) { + ginkgo.By("Creating 1 webserver pod able to serve traffic during the grace period of 300 seconds") + gracePeriod := int64(100) + webserverPod := e2epod.NewAgnhostPod(ns, "webserver-pod", nil, nil, nil, "netexec", "--http-port=80", fmt.Sprintf("--delay-shutdown=%d", gracePeriod)) + webserverPod = podClient.CreateSync(ctx, webserverPod) + + ginkgo.By("Creating 1 client pod that will try to connect to the webservers") + pausePod := e2epod.NewAgnhostPod(ns, "pause-pod-1", nil, nil, nil, "netexec", "--http-port=80", fmt.Sprintf("--delay-shutdown=%d", gracePeriod)) + pausePod.Spec.TerminationGracePeriodSeconds = &gracePeriod + pausePod = podClient.CreateSync(ctx, pausePod) + + ginkgo.By("Try to connect to the webserver") + // Wait until we are able to connect to the Pod + podIPAddress := net.JoinHostPort(webserverPod.Status.PodIP, strconv.Itoa(80)) + execHostnameTest(*pausePod, podIPAddress, webserverPod.Name) + + // pod client should continue to connect to the webserver after delete + // since will be gracefully terminating + err := cs.CoreV1().Pods(ns).Delete(ctx, pausePod.Name, metav1.DeleteOptions{}) + framework.ExpectNoError(err, "error deleting client pod") + // wait some time to ensure the test hit the pod during the terminating + time.Sleep(15 * time.Second) + execHostnameTest(*pausePod, podIPAddress, webserverPod.Name) + }) + +})