diff --git a/test/e2e_node/remote/node_e2e.go b/test/e2e_node/remote/node_e2e.go new file mode 100644 index 00000000000..ad778aec959 --- /dev/null +++ b/test/e2e_node/remote/node_e2e.go @@ -0,0 +1,100 @@ +/* +Copyright 2016 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 remote + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "time" + + "k8s.io/kubernetes/test/e2e_node/builder" +) + +type NodeE2ERemote struct{} + +func InitNodeE2ERemote() TestSuite { + // TODO: Register flags. + return &NodeE2ERemote{} +} + +const ( + localGCIMounterPath = "cluster/gce/gci/mounter/mounter" + CNIRelease = "07a8a28637e97b22eb8dfe710eeae1344f69d16e" + CNIDirectory = "cni" + CNIURL = "https://storage.googleapis.com/kubernetes-release/network-plugins/cni-" + CNIRelease + ".tar.gz" +) + +// SetupTestPackage sets up the test package with binaries k8s required for node e2e tests +func (n *NodeE2ERemote) SetupTestPackage(tardir string) error { + // Build the executables + if err := builder.BuildGo(); err != nil { + return fmt.Errorf("failed to build the depedencies: %v", err) + } + + // Make sure we can find the newly built binaries + buildOutputDir, err := builder.GetK8sBuildOutputDir() + if err != nil { + return fmt.Errorf("failed to locate kubernetes build output directory %v", err) + } + + // Copy binaries + requiredBins := []string{"kubelet", "e2e_node.test", "ginkgo"} + for _, bin := range requiredBins { + source := filepath.Join(buildOutputDir, bin) + if _, err := os.Stat(source); err != nil { + return fmt.Errorf("failed to locate test binary %s: %v", bin, err) + } + out, err := exec.Command("cp", source, filepath.Join(tardir, bin)).CombinedOutput() + if err != nil { + return fmt.Errorf("failed to copy %q: %v Output: %q", bin, err, out) + } + } + + // Include the GCI mounter artifacts in the deployed tarball + k8sDir, err := builder.GetK8sRootDir() + if err != nil { + return fmt.Errorf("Could not find K8s root dir! Err: %v", err) + } + localSource := "cluster/gce/gci/mounter/mounter" + source := filepath.Join(k8sDir, localSource) + + // Require the GCI mounter script, we want to make sure the remote test runner stays up to date if the mounter file moves + if _, err := os.Stat(source); err != nil { + return fmt.Errorf("Could not find GCI mounter script at %q! If this script has been (re)moved, please update the e2e node remote test runner accordingly! Err: %v", source, err) + } + + bindir := "cluster/gce/gci/mounter" + bin := "mounter" + destdir := filepath.Join(tardir, bindir) + dest := filepath.Join(destdir, bin) + out, err := exec.Command("mkdir", "-p", filepath.Join(tardir, bindir)).CombinedOutput() + if err != nil { + return fmt.Errorf("failed to create directory %q for GCI mounter script. Err: %v. Output:\n%s", destdir, err, out) + } + out, err = exec.Command("cp", source, dest).CombinedOutput() + if err != nil { + return fmt.Errorf("failed to copy GCI mounter script to the archive bin. Err: %v. Output:\n%s", err, out) + } + return nil +} + +// RunTest runs test on the node. +func (n *NodeE2ERemote) RunTest(host, workspace, results, junitFilePrefix, testArgs, ginkgoFlags string, timeout time.Duration) (string, error) { + return "", fmt.Errorf("not implemented") +} diff --git a/test/e2e_node/remote/remote.go b/test/e2e_node/remote/remote.go index be02298dfdd..e9cfd62db34 100644 --- a/test/e2e_node/remote/remote.go +++ b/test/e2e_node/remote/remote.go @@ -34,28 +34,9 @@ import ( var testTimeoutSeconds = flag.Duration("test-timeout", 45*time.Minute, "How long (in golang duration format) to wait for ginkgo tests to complete.") var resultsDir = flag.String("results-dir", "/tmp/", "Directory to scp test results to.") -const ( - archiveName = "e2e_node_test.tar.gz" - CNIRelease = "07a8a28637e97b22eb8dfe710eeae1344f69d16e" - CNIDirectory = "cni" -) - -var CNIURL = fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/network-plugins/cni-%s.tar.gz", CNIRelease) - -// CreateTestArchive builds the local source and creates a tar archive e2e_node_test.tar.gz containing -// the binaries k8s required for node e2e tests -func CreateTestArchive() (string, error) { - // Build the executables - if err := builder.BuildGo(); err != nil { - return "", fmt.Errorf("failed to build the depedencies: %v", err) - } - - // Make sure we can find the newly built binaries - buildOutputDir, err := builder.GetK8sBuildOutputDir() - if err != nil { - return "", fmt.Errorf("failed to locate kubernetes build output directory %v", err) - } +const archiveName = "e2e_node_test.tar.gz" +func CreateTestArchive(suite TestSuite) (string, error) { glog.Infof("Building archive...") tardir, err := ioutil.TempDir("", "node-e2e-archive") if err != nil { @@ -63,47 +44,14 @@ func CreateTestArchive() (string, error) { } defer os.RemoveAll(tardir) - // Copy binaries - requiredBins := []string{"kubelet", "e2e_node.test", "ginkgo"} - for _, bin := range requiredBins { - source := filepath.Join(buildOutputDir, bin) - if _, err := os.Stat(source); err != nil { - return "", fmt.Errorf("failed to locate test binary %s: %v", bin, err) - } - out, err := exec.Command("cp", source, filepath.Join(tardir, bin)).CombinedOutput() - if err != nil { - return "", fmt.Errorf("failed to copy %q: %v Output: %q", bin, err, out) - } - } - - // Include the GCI mounter artifacts in the deployed tarball - k8sDir, err := builder.GetK8sRootDir() + // Call the suite function to setup the test package. + err = suite.SetupTestPackage(tardir) if err != nil { - return "", fmt.Errorf("Could not find K8s root dir! Err: %v", err) - } - localSource := "cluster/gce/gci/mounter/mounter" - source := filepath.Join(k8sDir, localSource) - - // Require the GCI mounter script, we want to make sure the remote test runner stays up to date if the mounter file moves - if _, err := os.Stat(source); err != nil { - return "", fmt.Errorf("Could not find GCI mounter script at %q! If this script has been (re)moved, please update the e2e node remote test runner accordingly! Err: %v", source, err) - } - - bindir := "cluster/gce/gci/mounter" - bin := "mounter" - destdir := filepath.Join(tardir, bindir) - dest := filepath.Join(destdir, bin) - out, err := exec.Command("mkdir", "-p", filepath.Join(tardir, bindir)).CombinedOutput() - if err != nil { - return "", fmt.Errorf("failed to create directory %q for GCI mounter script. Err: %v. Output:\n%s", destdir, err, out) - } - out, err = exec.Command("cp", source, dest).CombinedOutput() - if err != nil { - return "", fmt.Errorf("failed to copy GCI mounter script to the archive bin. Err: %v. Output:\n%s", err, out) + return "", fmt.Errorf("failed to setup test package %q: %v", tardir, err) } // Build the tar - out, err = exec.Command("tar", "-zcvf", archiveName, "-C", tardir, ".").CombinedOutput() + out, err := exec.Command("tar", "-zcvf", archiveName, "-C", tardir, ".").CombinedOutput() if err != nil { return "", fmt.Errorf("failed to build tar %v. Output:\n%s", err, out) } @@ -115,6 +63,12 @@ func CreateTestArchive() (string, error) { return filepath.Join(dir, archiveName), nil } +const ( + CNIRelease = "07a8a28637e97b22eb8dfe710eeae1344f69d16e" + CNIDirectory = "cni" + CNIURL = "https://storage.googleapis.com/kubernetes-release/network-plugins/cni-" + CNIRelease + ".tar.gz" +) + // Returns the command output, whether the exit was ok, and any errors func RunRemote(archive string, host string, cleanup bool, junitFilePrefix string, testArgs string, ginkgoFlags string) (string, bool, error) { // Create the temp staging directory diff --git a/test/e2e_node/remote/types.go b/test/e2e_node/remote/types.go new file mode 100644 index 00000000000..52b80a54222 --- /dev/null +++ b/test/e2e_node/remote/types.go @@ -0,0 +1,45 @@ +/* +Copyright 2016 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 remote + +import ( + "time" +) + +// TestSuite is the interface of a test suite, such as node e2e, node conformance, +// node soaking, cri validation etc. +type TestSuite interface { + // SetupTestPackage setup the test package in the given directory. TestSuite + // should put all necessary binaries and dependencies into the path. The caller + // will: + // * create a tarball with the directory. + // * deploy the tarball to the testing host. + // * untar the tarball to the testing workspace on the testing host. + SetupTestPackage(path string) error + // RunTest runs test on the node in the given workspace and returns test output + // and test error if there is any. + // * host is the target node to run the test. + // * workspace is the directory on the testing host the test is running in. Note + // that the test package is unpacked in the workspace before running the test. + // * results is the directory the test should write result into. All logs should be + // saved as *.log, all junit file should start with junit*. + // * junitFilePrefix is the prefix of output junit file. + // * testArgs is the arguments passed to test. + // * ginkgoArgs is the arguments passed to ginkgo. + // * timeout is the test timeout. + RunTest(host, workspace, results, junitFilePrefix, testArgs, ginkgoArgs string, timeout time.Duration) (string, error) +} diff --git a/test/e2e_node/runner/remote/run_remote.go b/test/e2e_node/runner/remote/run_remote.go index 7f1b95e6f98..c3fa9dcfc77 100644 --- a/test/e2e_node/runner/remote/run_remote.go +++ b/test/e2e_node/runner/remote/run_remote.go @@ -66,6 +66,7 @@ const ( var ( computeService *compute.Service arc Archive + suite remote.TestSuite ) type Archive struct { @@ -125,12 +126,30 @@ type internalGCEImage struct { tests []string } +// parseFlags parse subcommands and flags +func parseFlags() { + if len(os.Args) <= 1 { + glog.Fatalf("Too few flags specified: %v", os.Args) + } + // Parse subcommand. + subcommand := os.Args[1] + switch subcommand { + // TODO: Add subcommand for node soaking, node conformance, cri validation. + default: + // Use node e2e suite by default if no subcommand is specified. + suite = remote.InitNodeE2ERemote() + } + // Parse test flags. + flag.CommandLine.Parse(os.Args[2:]) +} + func main() { - flag.Parse() + parseFlags() + rand.Seed(time.Now().UTC().UnixNano()) if *buildOnly { // Build the archive and exit - remote.CreateTestArchive() + remote.CreateTestArchive(suite) return } @@ -301,7 +320,7 @@ func callGubernator(gubernator bool) { } func (a *Archive) getArchive() (string, error) { - a.Do(func() { a.path, a.err = remote.CreateTestArchive() }) + a.Do(func() { a.path, a.err = remote.CreateTestArchive(suite) }) return a.path, a.err }