Skip to content

Commit 63bd1d7

Browse files
authored
Merge pull request kubernetes#80725 from aramase/dualstack-phase2-e2e
E2E tests for dualstack phase2
2 parents aafbb93 + 50e2182 commit 63bd1d7

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

test/e2e/network/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ go_library(
8080
"//vendor/github.com/onsi/gomega:go_default_library",
8181
"//vendor/google.golang.org/api/compute/v0.alpha:go_default_library",
8282
"//vendor/google.golang.org/api/compute/v1:go_default_library",
83+
"//vendor/k8s.io/utils/net:go_default_library",
8384
],
8485
)
8586

test/e2e/network/dual_stack.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ import (
3030
"k8s.io/kubernetes/test/e2e/framework"
3131
e2edeploy "k8s.io/kubernetes/test/e2e/framework/deployment"
3232
e2enode "k8s.io/kubernetes/test/e2e/framework/node"
33+
e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
3334
imageutils "k8s.io/kubernetes/test/utils/image"
35+
netutils "k8s.io/utils/net"
3436
)
3537

3638
// Tests for ipv6 dual stack feature
@@ -204,8 +206,152 @@ var _ = SIGDescribe("[Feature:IPv6DualStackAlphaFeature] [LinuxOnly]", func() {
204206

205207
assertNetworkConnectivity(f, *serverPods, *clientPods, "dualstack-test-client", "80")
206208
})
209+
210+
ginkgo.It("should create service with cluster ip from primary service range [Feature:IPv6DualStackAlphaFeature:Phase2]", func() {
211+
serviceName := "defaultclusterip"
212+
ns := f.Namespace.Name
213+
jig := e2eservice.NewTestJig(cs, serviceName)
214+
215+
defaultIPFamily := v1.IPv4Protocol
216+
if framework.TestContext.ClusterIsIPv6() {
217+
defaultIPFamily = v1.IPv6Protocol
218+
}
219+
220+
t := e2eservice.NewServerTest(cs, ns, serviceName)
221+
defer func() {
222+
defer ginkgo.GinkgoRecover()
223+
if errs := t.Cleanup(); len(errs) != 0 {
224+
framework.Failf("errors in cleanup: %v", errs)
225+
}
226+
}()
227+
228+
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamily not set")
229+
service := createService(t.ServiceName, t.Namespace, t.Labels, nil)
230+
231+
jig.Labels = t.Labels
232+
jig.CreateServicePods(cs, ns, 2)
233+
svc, err := t.CreateService(service)
234+
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
235+
236+
validateNumOfServicePorts(svc, 2)
237+
238+
// check the spec has been set to default ip family
239+
validateServiceAndClusterIPFamily(svc, defaultIPFamily)
240+
241+
// ensure endpoint belong to same ipfamily as service
242+
endpoint, err := cs.CoreV1().Endpoints(svc.Namespace).Get(svc.Name, metav1.GetOptions{})
243+
if err != nil {
244+
framework.Failf("Get endpoints for service %s/%s failed (%s)", svc.Namespace, svc.Name, err)
245+
}
246+
validateEndpointsBelongToIPFamily(svc, endpoint, defaultIPFamily)
247+
})
248+
249+
ginkgo.It("should create service with ipv4 cluster ip [Feature:IPv6DualStackAlphaFeature:Phase2]", func() {
250+
serviceName := "ipv4clusterip"
251+
ns := f.Namespace.Name
252+
ipv4 := v1.IPv4Protocol
253+
254+
jig := e2eservice.NewTestJig(cs, serviceName)
255+
256+
t := e2eservice.NewServerTest(cs, ns, serviceName)
257+
defer func() {
258+
defer ginkgo.GinkgoRecover()
259+
if errs := t.Cleanup(); len(errs) != 0 {
260+
framework.Failf("errors in cleanup: %v", errs)
261+
}
262+
}()
263+
264+
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamily IPv4" + ns)
265+
service := createService(t.ServiceName, t.Namespace, t.Labels, &ipv4)
266+
267+
jig.Labels = t.Labels
268+
jig.CreateServicePods(cs, ns, 2)
269+
svc, err := t.CreateService(service)
270+
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
271+
272+
validateNumOfServicePorts(svc, 2)
273+
274+
// check the spec has been set to IPv4 and cluster ip belong to IPv4 family
275+
validateServiceAndClusterIPFamily(svc, ipv4)
276+
277+
// ensure endpoints belong to same ipfamily as service
278+
endpoint, err := cs.CoreV1().Endpoints(svc.Namespace).Get(svc.Name, metav1.GetOptions{})
279+
if err != nil {
280+
framework.Failf("Get endpoints for service %s/%s failed (%s)", svc.Namespace, svc.Name, err)
281+
}
282+
validateEndpointsBelongToIPFamily(svc, endpoint, ipv4)
283+
})
284+
285+
ginkgo.It("should create service with ipv6 cluster ip [Feature:IPv6DualStackAlphaFeature:Phase2]", func() {
286+
serviceName := "ipv6clusterip"
287+
ns := f.Namespace.Name
288+
ipv6 := v1.IPv6Protocol
289+
290+
jig := e2eservice.NewTestJig(cs, serviceName)
291+
292+
t := e2eservice.NewServerTest(cs, ns, serviceName)
293+
defer func() {
294+
defer ginkgo.GinkgoRecover()
295+
if errs := t.Cleanup(); len(errs) != 0 {
296+
framework.Failf("errors in cleanup: %v", errs)
297+
}
298+
}()
299+
300+
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamily IPv6" + ns)
301+
service := createService(t.ServiceName, t.Namespace, t.Labels, &ipv6)
302+
303+
jig.Labels = t.Labels
304+
jig.CreateServicePods(cs, ns, 2)
305+
svc, err := t.CreateService(service)
306+
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
307+
308+
validateNumOfServicePorts(svc, 2)
309+
310+
// check the spec has been set to IPv6 and cluster ip belongs to IPv6 family
311+
validateServiceAndClusterIPFamily(svc, ipv6)
312+
313+
// ensure endpoints belong to same ipfamily as service
314+
endpoint, err := cs.CoreV1().Endpoints(svc.Namespace).Get(svc.Name, metav1.GetOptions{})
315+
if err != nil {
316+
framework.Failf("Get endpoints for service %s/%s failed (%s)", svc.Namespace, svc.Name, err)
317+
}
318+
validateEndpointsBelongToIPFamily(svc, endpoint, ipv6)
319+
})
207320
})
208321

322+
func validateNumOfServicePorts(svc *v1.Service, expectedNumOfPorts int) {
323+
if len(svc.Spec.Ports) != expectedNumOfPorts {
324+
framework.Failf("got unexpected len(Spec.Ports) for service: %v", svc)
325+
}
326+
}
327+
328+
func validateServiceAndClusterIPFamily(svc *v1.Service, expectedIPFamily v1.IPFamily) {
329+
if svc.Spec.IPFamily == nil {
330+
framework.Failf("service ip family nil for service %s/%s", svc.Namespace, svc.Name)
331+
}
332+
if *svc.Spec.IPFamily != expectedIPFamily {
333+
framework.Failf("ip family mismatch for service: %s/%s, expected: %s, actual: %s", svc.Namespace, svc.Name, expectedIPFamily, *svc.Spec.IPFamily)
334+
}
335+
336+
isIPv6ClusterIP := netutils.IsIPv6String(svc.Spec.ClusterIP)
337+
if (expectedIPFamily == v1.IPv4Protocol && isIPv6ClusterIP) || (expectedIPFamily == v1.IPv6Protocol && !isIPv6ClusterIP) {
338+
framework.Failf("got unexpected service ip %s, should belong to %s ip family", svc.Spec.ClusterIP, expectedIPFamily)
339+
}
340+
}
341+
342+
func validateEndpointsBelongToIPFamily(svc *v1.Service, endpoint *v1.Endpoints, expectedIPFamily v1.IPFamily) {
343+
if len(endpoint.Subsets) == 0 {
344+
framework.Failf("Endpoint has no subsets, cannot determine service ip family matches endpoints ip family for service %s/%s", svc.Namespace, svc.Name)
345+
}
346+
for _, ss := range endpoint.Subsets {
347+
for _, e := range ss.Addresses {
348+
if (expectedIPFamily == v1.IPv6Protocol && isIPv4(e.IP)) || (expectedIPFamily == v1.IPv4Protocol && netutils.IsIPv6String(e.IP)) {
349+
framework.Failf("service endpoint %s doesn't belong to %s ip family", e.IP, expectedIPFamily)
350+
}
351+
}
352+
}
353+
}
354+
209355
func assertNetworkConnectivity(f *framework.Framework, serverPods v1.PodList, clientPods v1.PodList, containerName, port string) {
210356
// curl from each client pod to all server pods to assert connectivity
211357
duration := "10s"
@@ -256,3 +402,30 @@ func isIPv4CIDR(cidr string) bool {
256402
framework.ExpectNoError(err)
257403
return isIPv4(ip.String())
258404
}
405+
406+
// createService returns a service spec with defined arguments
407+
func createService(name, ns string, labels map[string]string, ipFamily *v1.IPFamily) *v1.Service {
408+
return &v1.Service{
409+
ObjectMeta: metav1.ObjectMeta{
410+
Name: name,
411+
Namespace: ns,
412+
},
413+
Spec: v1.ServiceSpec{
414+
Selector: labels,
415+
Type: v1.ServiceTypeNodePort,
416+
IPFamily: ipFamily,
417+
Ports: []v1.ServicePort{
418+
{
419+
Name: "tcp-port",
420+
Port: 53,
421+
Protocol: v1.ProtocolTCP,
422+
},
423+
{
424+
Name: "udp-port",
425+
Port: 53,
426+
Protocol: v1.ProtocolUDP,
427+
},
428+
},
429+
},
430+
}
431+
}

0 commit comments

Comments
 (0)