Add TestSuite interface and update the CreateTestArchive function.

pull/6/head
Random-Liu 2016-11-28 17:17:10 -08:00
parent 78df5f7db1
commit 99dc80ccc2
4 changed files with 179 additions and 61 deletions

View File

@ -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")
}

View File

@ -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

View File

@ -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)
}

View File

@ -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
}