Skip to content

Commit

Permalink
Node e2e export test artifacts to jenkins.
Browse files Browse the repository at this point in the history
- Add junit test reported
- Write etcd.log, kubelet.log and kube-apiserver.log to files instead of stdout
- Scp artifacts to the jenkins WORKSPACE

Fixes kubernetes#25966
  • Loading branch information
pwittrock committed May 24, 2016
1 parent e958c0c commit eae1961
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 73 deletions.
3 changes: 2 additions & 1 deletion hack/e2e-node-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"

focus=${FOCUS:-""}
skip=${SKIP:-""}
report=${REPORT:-"/tmp/"}

ginkgo=$(kube::util::find-binary "ginkgo")
if [[ -z "${ginkgo}" ]]; then
Expand All @@ -27,6 +28,6 @@ if [[ -z "${ginkgo}" ]]; then
fi

# Provided for backwards compatibility
"${ginkgo}" --focus=$focus --skip=$skip "${KUBE_ROOT}/test/e2e_node/" -- --alsologtostderr --v 2 --node-name $(hostname) --build-services=true --start-services=true --stop-services=true
"${ginkgo}" --focus=$focus --skip=$skip "${KUBE_ROOT}/test/e2e_node/" --report-dir=${report} -- --alsologtostderr --v 2 --node-name $(hostname) --build-services=true --start-services=true --stop-services=true

exit $?
2 changes: 2 additions & 0 deletions hack/verify-flags/known-flags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ ir-password
ir-user
jenkins-host
jenkins-jobs
junit-file-number
k8s-bin-dir
k8s-build-output
keep-gogoproto
Expand Down Expand Up @@ -366,6 +367,7 @@ resolv-conf
resource-container
resource-quota-sync-period
resource-version
results-dir
retry_time
rkt-api-endpoint
rkt-path
Expand Down
2 changes: 1 addition & 1 deletion test/e2e_node/container_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func PrePullAllImages() error {
for _, image := range ImageRegistry {
output, err := exec.Command("docker", "pull", image).CombinedOutput()
if err != nil {
glog.Warning("Could not pre-pull image %s %v output: %s", image, err, output)
glog.Warningf("Could not pre-pull image %s %v output: %s", image, err, output)
return err
}
}
Expand Down
54 changes: 17 additions & 37 deletions test/e2e_node/e2e_node_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,41 @@ import (
"fmt"
"io/ioutil"
"math/rand"
"os"
"os/exec"
"path"
"strings"
"testing"
"time"

"github.com/golang/glog"
. "github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/types"
more_reporters "github.com/onsi/ginkgo/reporters"
. "github.com/onsi/gomega"
)

var e2es *e2eService

var prePullImages = flag.Bool("prepull-images", true, "If true, prepull images so image pull failures do not cause test failures.")
var junitFileNumber = flag.Int("junit-file-number", 1, "Used to create junit filename - e.g. junit_01.xml.")

func TestE2eNode(t *testing.T) {
flag.Parse()

rand.Seed(time.Now().UTC().UnixNano())
RegisterFailHandler(Fail)
reporters := []Reporter{&LogReporter{}}
reporters := []Reporter{}
if *reportDir != "" {
// Create the directory if it doesn't already exists
if err := os.MkdirAll(*reportDir, 0755); err != nil {
glog.Errorf("Failed creating report directory: %v", err)
} else {
// Configure a junit reporter to write to the directory
junitFile := fmt.Sprintf("junit_%02d.xml", *junitFileNumber)
junitPath := path.Join(*reportDir, junitFile)
reporters = append(reporters, more_reporters.NewJUnitReporter(junitPath))
}
}
RunSpecsWithDefaultAndCustomReporters(t, "E2eNode Suite", reporters)
}

Expand Down Expand Up @@ -94,40 +108,6 @@ var _ = AfterSuite(func() {
glog.Infof("Tests Finished")
})

var _ Reporter = &LogReporter{}

type LogReporter struct{}

func (lr *LogReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
b := &bytes.Buffer{}
b.WriteString("******************************************************\n")
glog.Infof(b.String())
}

func (lr *LogReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {}

func (lr *LogReporter) SpecWillRun(specSummary *types.SpecSummary) {}

func (lr *LogReporter) SpecDidComplete(specSummary *types.SpecSummary) {}

func (lr *LogReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {}

func (lr *LogReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
// Only log the binary output if the suite failed.
b := &bytes.Buffer{}
if e2es != nil && !summary.SuiteSucceeded {
b.WriteString(fmt.Sprintf("Process Log For Failed Suite On %s\n", *nodeName))
b.WriteString("-------------------------------------------------------------\n")
b.WriteString(fmt.Sprintf("kubelet output:\n%s\n", e2es.kubeletCombinedOut.String()))
b.WriteString("-------------------------------------------------------------\n")
b.WriteString(fmt.Sprintf("apiserver output:\n%s\n", e2es.apiServerCombinedOut.String()))
b.WriteString("-------------------------------------------------------------\n")
b.WriteString(fmt.Sprintf("etcd output:\n%s\n", e2es.etcdCombinedOut.String()))
}
b.WriteString("******************************************************\n")
glog.Infof(b.String())
}

func maskLocksmithdOnCoreos() {
data, err := ioutil.ReadFile("/etc/os-release")
if err != nil {
Expand Down
28 changes: 26 additions & 2 deletions test/e2e_node/e2e_remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ import (
"strings"

"github.com/golang/glog"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
)

var sshOptions = flag.String("ssh-options", "", "Commandline options passed to ssh.")
var sshEnv = flag.String("ssh-env", "", "Use predefined ssh options for environment. Options: gce")
var testTimeoutSeconds = flag.Int("test-timeout", 45*60, "How long (in seconds) to wait for ginkgo tests to complete.")
var resultsDir = flag.String("results-dir", "/tmp/", "Directory to scp test results to.")

var sshOptionsMap map[string]string

Expand Down Expand Up @@ -119,7 +121,7 @@ func CreateTestArchive() string {
}

// RunRemote copies the archive file to a /tmp file on host, unpacks it, and runs the e2e_node.test
func RunRemote(archive string, host string, cleanup bool) (string, error) {
func RunRemote(archive string, host string, cleanup bool, junitFileNumber int) (string, error) {
// Create the temp staging directory
glog.Infof("Staging test binaries on %s", host)
tmp := fmt.Sprintf("/tmp/gcloud-e2e-%d", rand.Int31())
Expand Down Expand Up @@ -158,17 +160,39 @@ func RunRemote(archive string, host string, cleanup bool) (string, error) {
cmd = getSshCommand(" && ",
fmt.Sprintf("cd %s", tmp),
fmt.Sprintf("tar -xzvf ./%s", archiveName),
fmt.Sprintf("timeout -k 30s %ds ./e2e_node.test --logtostderr --v 2 --build-services=false --stop-services=%t --node-name=%s", *testTimeoutSeconds, cleanup, host),
fmt.Sprintf("timeout -k 30s %ds ./e2e_node.test --logtostderr --v 2 --build-services=false --stop-services=%t --node-name=%s --report-dir=%s/results --junit-file-number=%d", *testTimeoutSeconds, cleanup, host, tmp, junitFileNumber),
)
glog.Infof("Starting tests on %s", host)
output, err := RunSshCommand("ssh", host, "--", "sh", "-c", cmd)

if err != nil {
scpErr := getTestArtifacts(host, tmp)

// Return both the testing and scp error
if scpErr != nil {
return "", utilerrors.NewAggregate([]error{err, scpErr})
}
return "", err
}

err = getTestArtifacts(host, tmp)
return output, nil
}

func getTestArtifacts(host, testDir string) error {
_, err := RunSshCommand("scp", "-r", fmt.Sprintf("%s:%s/results/", host, testDir), fmt.Sprintf("%s/%s", *resultsDir, host))
if err != nil {
return err
}

// Copy junit to the top of artifacts
_, err = RunSshCommand("scp", fmt.Sprintf("%s:%s/results/junit*", host, testDir), fmt.Sprintf("%s/", *resultsDir))
if err != nil {
return err
}
return nil
}

// getSshCommand handles proper quoting so that multiple commands are executed in the same shell over ssh
func getSshCommand(sep string, args ...string) string {
return fmt.Sprintf("'%s'", strings.Join(args, sep))
Expand Down
59 changes: 36 additions & 23 deletions test/e2e_node/e2e_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,29 @@ limitations under the License.
package e2e_node

import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path"
"strings"
"time"

"github.com/golang/glog"
)

var serverStartTimeout = flag.Duration("server-start-timeout", time.Second*120, "Time to wait for each server to become healthy.")
var reportDir = flag.String("report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.")

type e2eService struct {
etcdCmd *exec.Cmd
etcdCombinedOut bytes.Buffer
etcdDataDir string
apiServerCmd *exec.Cmd
apiServerCombinedOut bytes.Buffer
kubeletCmd *exec.Cmd
kubeletCombinedOut bytes.Buffer
kubeletStaticPodDir string
nodeName string
etcdCmd *exec.Cmd
etcdDataDir string
apiServerCmd *exec.Cmd
kubeletCmd *exec.Cmd
kubeletStaticPodDir string
nodeName string
}

func newE2eService(nodeName string) *e2eService {
Expand Down Expand Up @@ -123,23 +121,23 @@ func (es *e2eService) startEtcd() (*exec.Cmd, error) {
hcc := newHealthCheckCommand(
"http://127.0.0.1:4001/v2/keys/", // Trailing slash is required,
cmd,
&es.etcdCombinedOut)
"etcd.log")
return cmd, es.startServer(hcc)
}

func (es *e2eService) startApiServer() (*exec.Cmd, error) {
cmd := exec.Command("sudo", getApiServerBin(),
"--v", "2", "--logtostderr", "--log_dir", "./",
"--etcd-servers", "http://127.0.0.1:4001",
"--insecure-bind-address", "0.0.0.0",
"--service-cluster-ip-range", "10.0.0.1/24",
"--kubelet-port", "10250",
"--allow-privileged", "true",
"--v", "8", "--logtostderr",
)
hcc := newHealthCheckCommand(
"http://127.0.0.1:8080/healthz",
cmd,
&es.apiServerCombinedOut)
"kube-apiserver.log")
return cmd, es.startServer(hcc)
}

Expand All @@ -150,7 +148,6 @@ func (es *e2eService) startKubeletServer() (*exec.Cmd, error) {
}
es.kubeletStaticPodDir = dataDir
cmd := exec.Command("sudo", getKubeletServerBin(),
"--v", "2", "--logtostderr", "--log_dir", "./",
"--api-servers", "http://127.0.0.1:8080",
"--address", "0.0.0.0",
"--port", "10250",
Expand All @@ -160,22 +157,40 @@ func (es *e2eService) startKubeletServer() (*exec.Cmd, error) {
"--serialize-image-pulls", "false",
"--config", es.kubeletStaticPodDir,
"--file-check-frequency", "10s", // Check file frequently so tests won't wait too long
"--v", "8", "--logtostderr",
)
hcc := newHealthCheckCommand(
"http://127.0.0.1:10255/healthz",
cmd,
&es.kubeletCombinedOut)
"kubelet.log")
return cmd, es.startServer(hcc)
}

func (es *e2eService) startServer(cmd *healthCheckCommand) error {
cmdErrorChan := make(chan error)
go func() {
err := cmd.Run()
defer close(cmdErrorChan)

// Create the output filename
outPath := path.Join(*reportDir, cmd.outputFilename)
outfile, err := os.Create(outPath)
if err != nil {
cmdErrorChan <- fmt.Errorf("Failed to create file %s for `%s` %v.", outPath, cmd, err)
return
}
defer outfile.Close()
defer outfile.Sync()

// Set the command to write the output file
cmd.Cmd.Stdout = outfile
cmd.Cmd.Stderr = outfile

// Run the command
err = cmd.Run()
if err != nil {
cmdErrorChan <- fmt.Errorf("%s Failed with error \"%v\". Command output:\n%s", cmd, err, cmd.OutputBuffer)
cmdErrorChan <- fmt.Errorf("%s Failed with error \"%v\". Output written to: %s", cmd, err, outPath)
return
}
close(cmdErrorChan)
}()

endTime := time.Now().Add(*serverStartTimeout)
Expand All @@ -196,16 +211,14 @@ func (es *e2eService) startServer(cmd *healthCheckCommand) error {
type healthCheckCommand struct {
*exec.Cmd
HealthCheckUrl string
OutputBuffer *bytes.Buffer
outputFilename string
}

func newHealthCheckCommand(healthCheckUrl string, cmd *exec.Cmd, combinedOutput *bytes.Buffer) *healthCheckCommand {
cmd.Stdout = combinedOutput
cmd.Stderr = combinedOutput
func newHealthCheckCommand(healthCheckUrl string, cmd *exec.Cmd, filename string) *healthCheckCommand {
return &healthCheckCommand{
HealthCheckUrl: healthCheckUrl,
Cmd: cmd,
OutputBuffer: combinedOutput,
outputFilename: filename,
}
}

Expand Down
25 changes: 25 additions & 0 deletions test/e2e_node/jenkins/copy-e2e-image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

# Copyright 2016 The Kubernetes Authors All rights reserved.
#
# 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.

# Usage: copy-e2e-image.sh <image-name> <from-project-name> <to-project-name>

set -e
set -x

echo "Copying image $1 from project $2 to project $3..."
gcloud compute --project $3 disks create $1 --image=https://www.googleapis.com/compute/v1/projects/$2/global/images/$1
gcloud compute --project $3 images create $1 --source-disk=$1
gcloud compute --project $3 disks delete $1
5 changes: 4 additions & 1 deletion test/e2e_node/jenkins/e2e-node-jenkins.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ if [ "$INSTALL_GODEP" = true ] ; then
fi

go build test/e2e_node/environment/conformance.go
ARTIFACTS=${WORKSPACE}/_artifacts
mkdir -p ${ARTIFACTS}
go run test/e2e_node/runner/run_e2e.go --logtostderr --vmodule=*=2 --ssh-env="gce" \
--zone="$GCE_ZONE" --project="$GCE_PROJECT" \
--hosts="$GCE_HOSTS" --images="$GCE_IMAGES" --cleanup="$CLEANUP"
--hosts="$GCE_HOSTS" --images="$GCE_IMAGES" --cleanup="$CLEANUP" \
--results-dir="$ARTIFACTS"
Loading

0 comments on commit eae1961

Please sign in to comment.