From 368cd0dd7c99e3e2c21b9c6dcd12da8151a0fdd7 Mon Sep 17 00:00:00 2001 From: "Timothy St. Clair" Date: Fri, 17 Mar 2017 11:24:00 -0500 Subject: [PATCH] Sig-scalability test segregation to allow for assignment and cleaning, and easier refactoring --- test/e2e/BUILD | 8 +- test/e2e/e2e_test.go | 1 + test/e2e/empty.go | 3 +- test/e2e/example_k8petstore.go | 187 --------------------------------- test/e2e/perf/BUILD | 57 ++++++++++ test/e2e/perf/OWNERS | 7 ++ test/e2e/{ => perf}/density.go | 2 +- test/e2e/{ => perf}/load.go | 10 +- 8 files changed, 76 insertions(+), 199 deletions(-) delete mode 100644 test/e2e/example_k8petstore.go create mode 100644 test/e2e/perf/BUILD create mode 100644 test/e2e/perf/OWNERS rename test/e2e/{ => perf}/density.go (99%) rename test/e2e/{ => perf}/load.go (98%) diff --git a/test/e2e/BUILD b/test/e2e/BUILD index 314e47f5fe8..dd9aaaf4050 100644 --- a/test/e2e/BUILD +++ b/test/e2e/BUILD @@ -26,7 +26,6 @@ go_library( "daemon_restart.go", "daemon_set.go", "dashboard.go", - "density.go", "deployment.go", "disruption.go", "dns.go", @@ -39,7 +38,6 @@ go_library( "etcd_failure.go", "events.go", "example_cluster_dns.go", - "example_k8petstore.go", "examples.go", "firewall.go", "garbage_collector.go", @@ -57,7 +55,6 @@ go_library( "kubelet.go", "kubelet_perf.go", "limit_range.go", - "load.go", "logging_soak.go", "monitoring.go", "namespace.go", @@ -151,6 +148,7 @@ go_library( "//test/e2e/common:go_default_library", "//test/e2e/framework:go_default_library", "//test/e2e/generated:go_default_library", + "//test/e2e/perf:go_default_library", "//test/e2e/scheduling:go_default_library", "//test/e2e/upgrades:go_default_library", "//test/e2e_federation:go_default_library", @@ -202,10 +200,8 @@ go_library( "//vendor:k8s.io/client-go/pkg/apis/policy/v1beta1", "//vendor:k8s.io/client-go/rest", "//vendor:k8s.io/client-go/tools/cache", - "//vendor:k8s.io/client-go/transport", "//vendor:k8s.io/client-go/util/flowcontrol", "//vendor:k8s.io/client-go/util/integer", - "//vendor:k8s.io/client-go/util/workqueue", ], ) @@ -226,6 +222,7 @@ go_test( "//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/metrics:go_default_library", "//test/e2e/framework:go_default_library", + "//test/e2e/perf:go_default_library", "//test/e2e/scheduling:go_default_library", "//test/utils:go_default_library", "//vendor:github.com/onsi/ginkgo", @@ -263,6 +260,7 @@ filegroup( "//test/e2e/common:all-srcs", "//test/e2e/framework:all-srcs", "//test/e2e/generated:all-srcs", + "//test/e2e/perf:all-srcs", "//test/e2e/perftype:all-srcs", "//test/e2e/scheduling:all-srcs", "//test/e2e/testing-manifests:all-srcs", diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index d1d32794ffa..92965d81efb 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -20,6 +20,7 @@ import ( "testing" "k8s.io/kubernetes/test/e2e/framework" + _ "k8s.io/kubernetes/test/e2e/perf" _ "k8s.io/kubernetes/test/e2e/scheduling" ) diff --git a/test/e2e/empty.go b/test/e2e/empty.go index a81afc2c7ec..c6437183ffe 100644 --- a/test/e2e/empty.go +++ b/test/e2e/empty.go @@ -22,6 +22,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/perf" . "github.com/onsi/ginkgo" ) @@ -42,7 +43,7 @@ var _ = framework.KubeDescribe("Empty [Feature:Empty]", func() { }) It("starts a pod", func() { - configs, _ := generateConfigsForGroup([]*v1.Namespace{f.Namespace}, "empty-pod", 1, 1, framework.GetPauseImageName(f.ClientSet), []string{}, api.Kind("ReplicationController"), 0) + configs, _ := perf.GenerateConfigsForGroup([]*v1.Namespace{f.Namespace}, "empty-pod", 1, 1, framework.GetPauseImageName(f.ClientSet), []string{}, api.Kind("ReplicationController"), 0) if len(configs) != 1 { framework.Failf("generateConfigs should have generated single config") } diff --git a/test/e2e/example_k8petstore.go b/test/e2e/example_k8petstore.go deleted file mode 100644 index d78c1447d0f..00000000000 --- a/test/e2e/example_k8petstore.go +++ /dev/null @@ -1,187 +0,0 @@ -/* -Copyright 2015 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 e2e - -import ( - "context" - "fmt" - "os" - "os/exec" - "path/filepath" - "strconv" - "syscall" - "time" - - "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" - "k8s.io/kubernetes/test/e2e/framework" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -const ( - k8bpsContainerVersion = "r.2.8.19" // Container version, see the examples/k8petstore dockerfiles for details. - k8bpsThroughputDummy = "0" // Polling time = 0, since we framework.Poll in ginkgo rather than using the shell script tests. - k8bpsRedisSlaves = "1" // Number of redis slaves. - k8bpsDontRunTest = "0" // Don't bother embedded test. - k8bpsStartupTimeout = 30 * time.Second // Amount of elapsed time before petstore transactions are being stored. - k8bpsMinTransactionsOnStartup = 3 // Amount of transactions we expect we should have before data generator starts. - - // Constants for the first test. We can make this a hashmap once we add scale tests to it. - k8bpsSmokeTestFinalTransactions = 50 - k8bpsSmokeTestTimeout = 60 * time.Second -) - -// readTransactions reads # of transactions from the k8petstore web server endpoint. -// for more details see the source of the k8petstore web server. -func readTransactions(c clientset.Interface, ns string) (error, int) { - proxyRequest, errProxy := framework.GetServicesProxyRequest(c, c.Core().RESTClient().Get()) - if errProxy != nil { - return errProxy, -1 - } - - ctx, cancel := context.WithTimeout(context.Background(), framework.SingleCallTimeout) - defer cancel() - - body, err := proxyRequest.Namespace(ns). - Context(ctx). - Name("frontend"). - Suffix("llen"). - DoRaw() - if err != nil { - if ctx.Err() != nil { - framework.Failf("Failed to read petstore transactions: %v", err) - } - return err, -1 - } - - totalTrans, err := strconv.Atoi(string(body)) - return err, totalTrans - -} - -// runK8petstore runs the k8petstore application, bound to external nodeport, and -// polls until finalTransactionsExpected transactions are acquired, in a maximum of maxSeconds. -func runK8petstore(restServers int, loadGenerators int, c clientset.Interface, ns string, finalTransactionsExpected int, maxTime time.Duration) { - - var err error = nil - k8bpsScriptLocation := filepath.Join(framework.TestContext.RepoRoot, "examples/k8petstore/k8petstore-nodeport.sh") - - cmd := exec.Command( - k8bpsScriptLocation, - framework.TestContext.KubectlPath, - k8bpsContainerVersion, - k8bpsThroughputDummy, - strconv.Itoa(restServers), - strconv.Itoa(loadGenerators), - k8bpsRedisSlaves, - k8bpsDontRunTest, // Don't bother embedded test. - ns, - ) - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - framework.Logf("Starting k8petstore application....") - // Run the k8petstore app, and log / fail if it returns any errors. - // This should return quickly, assuming containers are downloaded. - if err = cmd.Start(); err != nil { - framework.Failf("%v", err) - } - // Make sure there are no command errors. - if err = cmd.Wait(); err != nil { - if exiterr, ok := err.(*exec.ExitError); ok { - if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { - framework.Logf("Exit Status: %d", status.ExitStatus()) - } - } - } - Expect(err).NotTo(HaveOccurred()) - framework.Logf("... Done starting k8petstore ") - - totalTransactions := 0 - framework.Logf("Start polling, timeout is %v seconds", maxTime) - - // How long until the FIRST transactions are created. - startupTimeout := time.After(time.Duration(k8bpsStartupTimeout)) - - // Maximum time to wait until we reach the nth transaction. - transactionsCompleteTimeout := time.After(time.Duration(maxTime)) - tick := time.Tick(2 * time.Second) - var ready = false - - framework.Logf("Now waiting %v seconds to see progress (transactions > 3)", k8bpsStartupTimeout) -T: - for { - select { - case <-transactionsCompleteTimeout: - framework.Logf("Completion timeout %v reached, %v transactions not complete. Breaking!", time.Duration(maxTime), finalTransactionsExpected) - break T - case <-tick: - // Don't fail if there's an error. We expect a few failures might happen in the cloud. - err, totalTransactions = readTransactions(c, ns) - if err == nil { - framework.Logf("PetStore : Time: %v, %v = total petstore transactions stored into redis.", time.Now(), totalTransactions) - if totalTransactions >= k8bpsMinTransactionsOnStartup { - ready = true - } - if totalTransactions >= finalTransactionsExpected { - break T - } - } else { - if ready { - framework.Logf("Blip: during polling: %v", err) - } else { - framework.Logf("Not ready yet: %v", err) - } - } - case <-startupTimeout: - if !ready { - framework.Logf("Startup Timeout %v reached: Its been too long and we still haven't started accumulating %v transactions!", startupTimeout, k8bpsMinTransactionsOnStartup) - break T - } - } - } - - // We should have exceeded the finalTransactionsExpected num of transactions. - // If this fails, but there are transactions being created, we may need to recalibrate - // the finalTransactionsExpected value - or else - your cluster is broken/slow ! - Expect(totalTransactions).To(BeNumerically(">", finalTransactionsExpected)) -} - -var _ = framework.KubeDescribe("Pet Store [Feature:Example]", func() { - - BeforeEach(func() { - // The shell scripts in k8petstore break on jenkins... Pure golang rewrite is in progress. - framework.SkipUnlessProviderIs("local") - }) - - // The number of nodes dictates total number of generators/transaction expectations. - var nodeCount int - f := framework.NewDefaultFramework("petstore") - - It(fmt.Sprintf("should scale to persist a nominal number ( %v ) of transactions in %v seconds", k8bpsSmokeTestFinalTransactions, k8bpsSmokeTestTimeout), func() { - nodes := framework.GetReadySchedulableNodesOrDie(f.ClientSet) - nodeCount = len(nodes.Items) - - loadGenerators := nodeCount - restServers := nodeCount - fmt.Printf("load generators / rest servers [ %v / %v ] ", loadGenerators, restServers) - runK8petstore(restServers, loadGenerators, f.ClientSet, f.Namespace.Name, k8bpsSmokeTestFinalTransactions, k8bpsSmokeTestTimeout) - }) - -}) diff --git a/test/e2e/perf/BUILD b/test/e2e/perf/BUILD new file mode 100644 index 00000000000..39ba7df7f29 --- /dev/null +++ b/test/e2e/perf/BUILD @@ -0,0 +1,57 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = [ + "density.go", + "load.go", + ], + tags = ["automanaged"], + deps = [ + "//pkg/api:go_default_library", + "//pkg/api/v1:go_default_library", + "//pkg/apis/batch:go_default_library", + "//pkg/apis/extensions:go_default_library", + "//pkg/client/clientset_generated/clientset:go_default_library", + "//pkg/client/clientset_generated/internalclientset:go_default_library", + "//test/e2e/framework:go_default_library", + "//test/utils:go_default_library", + "//vendor:github.com/onsi/ginkgo", + "//vendor:github.com/onsi/gomega", + "//vendor:k8s.io/apimachinery/pkg/api/resource", + "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", + "//vendor:k8s.io/apimachinery/pkg/fields", + "//vendor:k8s.io/apimachinery/pkg/labels", + "//vendor:k8s.io/apimachinery/pkg/runtime", + "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + "//vendor:k8s.io/apimachinery/pkg/util/intstr", + "//vendor:k8s.io/apimachinery/pkg/util/net", + "//vendor:k8s.io/apimachinery/pkg/util/sets", + "//vendor:k8s.io/apimachinery/pkg/util/uuid", + "//vendor:k8s.io/apimachinery/pkg/watch", + "//vendor:k8s.io/client-go/rest", + "//vendor:k8s.io/client-go/tools/cache", + "//vendor:k8s.io/client-go/transport", + "//vendor:k8s.io/client-go/util/workqueue", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/test/e2e/perf/OWNERS b/test/e2e/perf/OWNERS new file mode 100644 index 00000000000..b6fb0a98d7d --- /dev/null +++ b/test/e2e/perf/OWNERS @@ -0,0 +1,7 @@ +approvers: +- gmarek +- wojtek-t +reviewers: +- gmarek +- wojtek-t +- timothysc diff --git a/test/e2e/density.go b/test/e2e/perf/density.go similarity index 99% rename from test/e2e/density.go rename to test/e2e/perf/density.go index 636f3d4e194..e6e3629f217 100644 --- a/test/e2e/density.go +++ b/test/e2e/perf/density.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package e2e +package perf import ( "fmt" diff --git a/test/e2e/load.go b/test/e2e/perf/load.go similarity index 98% rename from test/e2e/load.go rename to test/e2e/perf/load.go index 6c9dd67411e..20e0a0cb125 100644 --- a/test/e2e/load.go +++ b/test/e2e/perf/load.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package e2e +package perf import ( "fmt" @@ -344,13 +344,13 @@ func generateConfigs( secretConfigs := make([]*testutils.SecretConfig, 0) smallGroupCount, mediumGroupCount, bigGroupCount := computePodCounts(totalPods) - newConfigs, newSecretConfigs := generateConfigsForGroup(nss, smallGroupName, smallGroupSize, smallGroupCount, image, command, kind, secretsPerPod) + newConfigs, newSecretConfigs := GenerateConfigsForGroup(nss, smallGroupName, smallGroupSize, smallGroupCount, image, command, kind, secretsPerPod) configs = append(configs, newConfigs...) secretConfigs = append(secretConfigs, newSecretConfigs...) - newConfigs, newSecretConfigs = generateConfigsForGroup(nss, mediumGroupName, mediumGroupSize, mediumGroupCount, image, command, kind, secretsPerPod) + newConfigs, newSecretConfigs = GenerateConfigsForGroup(nss, mediumGroupName, mediumGroupSize, mediumGroupCount, image, command, kind, secretsPerPod) configs = append(configs, newConfigs...) secretConfigs = append(secretConfigs, newSecretConfigs...) - newConfigs, newSecretConfigs = generateConfigsForGroup(nss, bigGroupName, bigGroupSize, bigGroupCount, image, command, kind, secretsPerPod) + newConfigs, newSecretConfigs = GenerateConfigsForGroup(nss, bigGroupName, bigGroupSize, bigGroupCount, image, command, kind, secretsPerPod) configs = append(configs, newConfigs...) secretConfigs = append(secretConfigs, newSecretConfigs...) @@ -371,7 +371,7 @@ func generateConfigs( return configs, secretConfigs } -func generateConfigsForGroup( +func GenerateConfigsForGroup( nss []*v1.Namespace, groupName string, size, count int,