mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +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")
|
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
|
Release: v1.26
|
||||||
Testname: Service, same ports with different protocols on a Load Balancer Service
|
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
|
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