From c66f9323156003bd1a8912239241911995531ab5 Mon Sep 17 00:00:00 2001 From: Chris O'Haver Date: Thu, 10 May 2018 18:01:13 -0400 Subject: [PATCH] dns record scale test --- test/e2e/network/BUILD | 2 + test/e2e/network/dns_common.go | 12 +-- test/e2e/network/dns_configmap.go | 26 +++---- test/e2e/network/dns_scale_records.go | 105 ++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 test/e2e/network/dns_scale_records.go diff --git a/test/e2e/network/BUILD b/test/e2e/network/BUILD index 60ac1f73e08..ac6ae0df02c 100644 --- a/test/e2e/network/BUILD +++ b/test/e2e/network/BUILD @@ -11,6 +11,7 @@ go_library( "dns.go", "dns_common.go", "dns_configmap.go", + "dns_scale_records.go", "doc.go", "example_cluster_dns.go", "firewall.go", @@ -70,6 +71,7 @@ go_library( "//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/tools/cache:go_default_library", "//vendor/k8s.io/client-go/util/flowcontrol:go_default_library", + "//vendor/k8s.io/client-go/util/workqueue:go_default_library", ], ) diff --git a/test/e2e/network/dns_common.go b/test/e2e/network/dns_common.go index 35af935c261..d4696319fb6 100644 --- a/test/e2e/network/dns_common.go +++ b/test/e2e/network/dns_common.go @@ -111,7 +111,7 @@ func (t *dnsTestCommon) runDig(dnsName, target string) []string { cmd = append(cmd, "@"+t.dnsPod.Status.PodIP) case "kube-dns": cmd = append(cmd, "@"+t.dnsPod.Status.PodIP, "-p", "10053") - case "dnsmasq": + case "cluster-dns": break default: panic(fmt.Errorf("invalid target: " + target)) @@ -193,7 +193,7 @@ func (t *dnsTestCommon) deleteConfigMap() { Expect(err).NotTo(HaveOccurred()) } -func (t *dnsTestCommon) createUtilPod() { +func (t *dnsTestCommon) createUtilPodLabel(baseName string) { // Actual port # doesn't matter, just needs to exist. const servicePort = 10101 @@ -203,8 +203,8 @@ func (t *dnsTestCommon) createUtilPod() { }, ObjectMeta: metav1.ObjectMeta{ Namespace: t.f.Namespace.Name, - Labels: map[string]string{"app": "e2e-dns-configmap"}, - GenerateName: "e2e-dns-configmap-", + Labels: map[string]string{"app": baseName}, + GenerateName: baseName + "-", }, Spec: v1.PodSpec{ Containers: []v1.Container{ @@ -232,10 +232,10 @@ func (t *dnsTestCommon) createUtilPod() { }, ObjectMeta: metav1.ObjectMeta{ Namespace: t.f.Namespace.Name, - Name: "e2e-dns-configmap", + Name: baseName, }, Spec: v1.ServiceSpec{ - Selector: map[string]string{"app": "e2e-dns-configmap"}, + Selector: map[string]string{"app": baseName}, Ports: []v1.ServicePort{ { Protocol: "TCP", diff --git a/test/e2e/network/dns_configmap.go b/test/e2e/network/dns_configmap.go index 332b84d590f..c067fc22aab 100644 --- a/test/e2e/network/dns_configmap.go +++ b/test/e2e/network/dns_configmap.go @@ -55,7 +55,7 @@ func (t *dnsFederationsConfigMapTest) run() { t.init() defer t.c.CoreV1().ConfigMaps(t.ns).Delete(t.name, nil) - t.createUtilPod() + t.createUtilPodLabel("e2e-dns-configmap") defer t.deleteUtilPod() t.validate() @@ -149,7 +149,7 @@ type dnsNameserverTest struct { func (t *dnsNameserverTest) run() { t.init() - t.createUtilPod() + t.createUtilPodLabel("e2e-dns-configmap") defer t.deleteUtilPod() originalConfigMapData := t.fetchDNSConfigMapData() defer t.restoreDNSConfigMap(originalConfigMapData) @@ -187,17 +187,17 @@ func (t *dnsNameserverTest) run() { t.checkDNSRecordFrom( "abc.acme.local", func(actual []string) bool { return len(actual) == 1 && actual[0] == "1.1.1.1" }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) t.checkDNSRecordFrom( "def.acme.local", func(actual []string) bool { return len(actual) == 1 && actual[0] == "2.2.2.2" }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) t.checkDNSRecordFrom( "widget.local", func(actual []string) bool { return len(actual) == 1 && actual[0] == "3.3.3.3" }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) t.restoreDNSConfigMap(originalConfigMapData) @@ -206,7 +206,7 @@ func (t *dnsNameserverTest) run() { t.checkDNSRecordFrom( "abc.acme.local", func(actual []string) bool { return len(actual) == 0 }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) } @@ -217,7 +217,7 @@ type dnsPtrFwdTest struct { func (t *dnsPtrFwdTest) run() { t.init() - t.createUtilPod() + t.createUtilPodLabel("e2e-dns-configmap") defer t.deleteUtilPod() originalConfigMapData := t.fetchDNSConfigMapData() defer t.restoreDNSConfigMap(originalConfigMapData) @@ -229,7 +229,7 @@ func (t *dnsPtrFwdTest) run() { t.checkDNSRecordFrom( "8.8.8.8.in-addr.arpa", func(actual []string) bool { return len(actual) == 1 && actual[0] == googleDnsHostname+"." }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) if t.name == "coredns" { @@ -254,14 +254,14 @@ func (t *dnsPtrFwdTest) run() { t.checkDNSRecordFrom( "123.2.0.192.in-addr.arpa", func(actual []string) bool { return len(actual) == 1 && actual[0] == "my.test." }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) t.restoreDNSConfigMap(originalConfigMapData) t.checkDNSRecordFrom( "123.2.0.192.in-addr.arpa", func(actual []string) bool { return len(actual) == 0 }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) } @@ -272,7 +272,7 @@ type dnsExternalNameTest struct { func (t *dnsExternalNameTest) run() { t.init() - t.createUtilPod() + t.createUtilPodLabel("e2e-dns-configmap") defer t.deleteUtilPod() originalConfigMapData := t.fetchDNSConfigMapData() defer t.restoreDNSConfigMap(originalConfigMapData) @@ -306,7 +306,7 @@ func (t *dnsExternalNameTest) run() { func(actual []string) bool { return len(actual) >= 1 && actual[0] == googleDnsHostname+"." }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) if t.name == "coredns" { @@ -333,7 +333,7 @@ func (t *dnsExternalNameTest) run() { func(actual []string) bool { return len(actual) == 2 && actual[0] == fooHostname+"." && actual[1] == "192.0.2.123" }, - "dnsmasq", + "cluster-dns", moreForeverTestTimeout) t.restoreDNSConfigMap(originalConfigMapData) diff --git a/test/e2e/network/dns_scale_records.go b/test/e2e/network/dns_scale_records.go new file mode 100644 index 00000000000..c22cbd7e640 --- /dev/null +++ b/test/e2e/network/dns_scale_records.go @@ -0,0 +1,105 @@ +/* +Copyright 2018 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 ( + "fmt" + "strconv" + "time" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/workqueue" + "k8s.io/kubernetes/test/e2e/framework" + testutils "k8s.io/kubernetes/test/utils" + + . "github.com/onsi/ginkgo" +) + +const ( + parallelCreateServiceWorkers = 1 + maxServicesPerCluster = 10000 + checkServicePercent = 0.05 +) + +var _ = SIGDescribe("[Feature:PerformanceDNS]", func() { + f := framework.NewDefaultFramework("performancedns") + + BeforeEach(func() { + framework.ExpectNoError(framework.WaitForAllNodesSchedulable(f.ClientSet, framework.TestContext.NodeSchedulableTimeout)) + framework.WaitForAllNodesHealthy(f.ClientSet, time.Minute) + + err := framework.CheckTestingNSDeletedExcept(f.ClientSet, f.Namespace.Name) + framework.ExpectNoError(err) + }) + + // answers dns for service - creates the maximum number of services, and then check dns record for one + It("Should answer DNS query for maximum number of services per cluster", func() { + services := generateServicesInNamespace(f.Namespace.Name, maxServicesPerCluster) + createService := func(i int) { + defer GinkgoRecover() + framework.ExpectNoError(testutils.CreateServiceWithRetries(f.ClientSet, f.Namespace.Name, services[i])) + } + framework.Logf("Creating %v test services", maxServicesPerCluster) + workqueue.Parallelize(parallelCreateServiceWorkers, len(services), createService) + dnsTest := dnsTestCommon{ + f: f, + c: f.ClientSet, + ns: f.Namespace.Name, + } + dnsTest.createUtilPodLabel("e2e-dns-scale-records") + defer dnsTest.deleteUtilPod() + framework.Logf("Querying %v%% of service records", checkServicePercent*100) + for i := 0; i < len(services); i++ { + if i%(1/checkServicePercent) != 0 { + continue + } + s := services[i] + svc, err := f.ClientSet.CoreV1().Services(s.Namespace).Get(s.Name, metav1.GetOptions{}) + framework.ExpectNoError(err) + qname := fmt.Sprintf("%v.%v.svc.cluster.local", s.Name, s.Namespace) + framework.Logf("Querying %v expecting %v", qname, svc.Spec.ClusterIP) + dnsTest.checkDNSRecordFrom( + qname, + func(actual []string) bool { + return len(actual) == 1 && actual[0] == svc.Spec.ClusterIP + }, + "cluster-dns", + wait.ForeverTestTimeout, + ) + } + }) +}) + +func generateServicesInNamespace(namespace string, num int) []*v1.Service { + services := make([]*v1.Service, num) + for i := 0; i < num; i++ { + services[i] = &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "svc-" + strconv.Itoa(i), + Namespace: namespace, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{{ + Port: 80, + }}, + }, + } + } + return services +}