mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
Merge pull request #116333 from aojea/multiport_service
e2e network test for multiple protocol services on same port
This commit is contained in:
commit
7598ff36cf
@ -3618,6 +3618,114 @@ var _ = common.SIGDescribe("Services", func() {
|
||||
|
||||
framework.Logf("Collection of services has been deleted")
|
||||
})
|
||||
|
||||
ginkgo.It("should serve endpoints on same port and different protocols", func(ctx context.Context) {
|
||||
serviceName := "multiprotocol-test"
|
||||
testLabels := map[string]string{"app": "multiport"}
|
||||
ns := f.Namespace.Name
|
||||
containerPort := 80
|
||||
|
||||
svcTCPport := v1.ServicePort{
|
||||
Name: "tcp-port",
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromInt(containerPort),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
}
|
||||
svcUDPport := v1.ServicePort{
|
||||
Name: "udp-port",
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromInt(containerPort),
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}
|
||||
|
||||
ginkgo.By("creating service " + serviceName + " in namespace " + ns)
|
||||
|
||||
testService := v1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: serviceName,
|
||||
Labels: testLabels,
|
||||
},
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeClusterIP,
|
||||
Selector: testLabels,
|
||||
Ports: []v1.ServicePort{svcTCPport, svcUDPport},
|
||||
},
|
||||
}
|
||||
service, err := cs.CoreV1().Services(ns).Create(ctx, &testService, metav1.CreateOptions{})
|
||||
framework.ExpectNoError(err, "failed to create Service")
|
||||
|
||||
containerPorts := []v1.ContainerPort{{
|
||||
Name: svcTCPport.Name,
|
||||
ContainerPort: int32(containerPort),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
}, {
|
||||
Name: svcUDPport.Name,
|
||||
ContainerPort: int32(containerPort),
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}}
|
||||
podname1 := "pod1"
|
||||
ginkgo.By("creating pod " + podname1 + " in namespace " + ns)
|
||||
createPodOrFail(ctx, f, ns, podname1, testLabels, containerPorts, "netexec", "--http-port", strconv.Itoa(containerPort), "--udp-port", strconv.Itoa(containerPort))
|
||||
validateEndpointsPortsWithProtocolsOrFail(cs, ns, serviceName, fullPortsByPodName{podname1: containerPorts})
|
||||
|
||||
ginkgo.By("Checking if the Service forwards traffic to the TCP and UDP port")
|
||||
execPod := e2epod.CreateExecPodOrFail(ctx, cs, ns, "execpod", nil)
|
||||
err = testEndpointReachability(ctx, service.Spec.ClusterIP, 80, v1.ProtocolTCP, execPod, 30*time.Second)
|
||||
if err != nil {
|
||||
framework.Failf("Failed to connect to Service TCP port: %v", err)
|
||||
}
|
||||
err = testEndpointReachability(ctx, service.Spec.ClusterIP, 80, v1.ProtocolUDP, execPod, 30*time.Second)
|
||||
if err != nil {
|
||||
framework.Failf("Failed to connect to Service UDP port: %v", err)
|
||||
}
|
||||
|
||||
ginkgo.By("Checking if the Service forwards traffic to TCP only")
|
||||
service, err = cs.CoreV1().Services(ns).Get(ctx, serviceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("failed to get Service %q: %v", serviceName, err)
|
||||
}
|
||||
service.Spec.Ports = []v1.ServicePort{svcTCPport}
|
||||
_, err = cs.CoreV1().Services(ns).Update(ctx, service, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("failed to get Service %q: %v", serviceName, err)
|
||||
}
|
||||
|
||||
// test reachability
|
||||
err = testEndpointReachability(ctx, service.Spec.ClusterIP, 80, v1.ProtocolTCP, execPod, 30*time.Second)
|
||||
if err != nil {
|
||||
framework.Failf("Failed to connect to Service TCP port: %v", err)
|
||||
}
|
||||
// take into account the NetworkProgrammingLatency
|
||||
// testEndpointReachability tries 3 times every 3 second
|
||||
// we retry again during 30 seconds to check if the port stops forwarding
|
||||
gomega.Eventually(ctx, func() error {
|
||||
return testEndpointReachability(ctx, service.Spec.ClusterIP, 80, v1.ProtocolUDP, execPod, 6*time.Second)
|
||||
}).WithTimeout(30 * time.Second).WithPolling(5 * time.Second).ShouldNot(gomega.BeNil())
|
||||
|
||||
ginkgo.By("Checking if the Service forwards traffic to UDP only")
|
||||
service, err = cs.CoreV1().Services(ns).Get(ctx, serviceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("failed to get Service %q: %v", serviceName, err)
|
||||
}
|
||||
service.Spec.Ports = []v1.ServicePort{svcUDPport}
|
||||
_, err = cs.CoreV1().Services(ns).Update(ctx, service, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
framework.Failf("failed to update Service %q: %v", serviceName, err)
|
||||
}
|
||||
|
||||
// test reachability
|
||||
err = testEndpointReachability(ctx, service.Spec.ClusterIP, 80, v1.ProtocolUDP, execPod, 30*time.Second)
|
||||
if err != nil {
|
||||
framework.Failf("Failed to connect to Service UDP port: %v", err)
|
||||
}
|
||||
// take into account the NetworkProgrammingLatency
|
||||
// testEndpointReachability tries 3 times every 3 second
|
||||
// we retry again during 30 seconds to check if the port stops forwarding
|
||||
gomega.Eventually(ctx, func() error {
|
||||
return testEndpointReachability(ctx, service.Spec.ClusterIP, 80, v1.ProtocolTCP, execPod, 6*time.Second)
|
||||
}).WithTimeout(30 * time.Second).WithPolling(5 * time.Second).ShouldNot(gomega.BeNil())
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.26
|
||||
Testname: Service, same ports with different protocols on a Load Balancer Service
|
||||
|
@ -218,3 +218,34 @@ func createSecondNodePortService(ctx context.Context, f *framework.Framework, co
|
||||
|
||||
return createdService, httpPort
|
||||
}
|
||||
|
||||
// testEndpointReachability tests reachability to endpoints (i.e. IP, ServiceName) and ports. Test request is initiated from specified execPod.
|
||||
// TCP and UDP protocol based service are supported at this moment
|
||||
func testEndpointReachability(ctx context.Context, endpoint string, port int32, protocol v1.Protocol, execPod *v1.Pod, timeout time.Duration) error {
|
||||
cmd := ""
|
||||
switch protocol {
|
||||
case v1.ProtocolTCP:
|
||||
cmd = fmt.Sprintf("echo hostName | nc -v -t -w 2 %s %v", endpoint, port)
|
||||
case v1.ProtocolUDP:
|
||||
cmd = fmt.Sprintf("echo hostName | nc -v -u -w 2 %s %v", endpoint, port)
|
||||
default:
|
||||
return fmt.Errorf("service reachability check is not supported for %v", protocol)
|
||||
}
|
||||
|
||||
err := wait.PollImmediateWithContext(ctx, framework.Poll, timeout, func(ctx context.Context) (bool, error) {
|
||||
stdout, err := e2eoutput.RunHostCmd(execPod.Namespace, execPod.Name, cmd)
|
||||
if err != nil {
|
||||
framework.Logf("Service reachability failing with error: %v\nRetrying...", err)
|
||||
return false, nil
|
||||
}
|
||||
trimmed := strings.TrimSpace(stdout)
|
||||
if trimmed != "" {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("service is not reachable within %v timeout on endpoint %s %d over %s protocol", timeout, endpoint, port, protocol)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user