Single-stepping interactively through a test can be useful to understand what's happening and to investigate the state at each step. Similar support was added early to hack/ginkgo-e2e.sh, so the same env variable is used again.
137 lines
5.1 KiB
Go
137 lines
5.1 KiB
Go
/*
|
|
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 main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"k8s.io/kubernetes/test/e2e_node/builder"
|
|
"k8s.io/kubernetes/test/e2e_node/system"
|
|
"k8s.io/kubernetes/test/utils"
|
|
|
|
"k8s.io/klog/v2"
|
|
)
|
|
|
|
var buildDependencies = flag.Bool("build-dependencies", true, "If true, build all dependencies.")
|
|
var ginkgoFlags = flag.String("ginkgo-flags", "", "Space-separated list of arguments to pass to Ginkgo test runner, with shell-style quoting and escaping.")
|
|
var testFlags = flag.String("test-flags", "", "Space-separated list of arguments to pass to node e2e test, with shell-style quoting and escaping.")
|
|
var systemSpecName = flag.String("system-spec-name", "", fmt.Sprintf("The name of the system spec used for validating the image in the node conformance test. The specs are at %s. If unspecified, the default built-in spec (system.DefaultSpec) will be used.", system.SystemSpecPath))
|
|
var extraEnvs = flag.String("extra-envs", "", "The extra environment variables needed for node e2e tests. Format: a list of key=value pairs, e.g., env1=val1,env2=val2")
|
|
var runtimeConfig = flag.String("runtime-config", "", "The runtime configuration for the API server on the node e2e tests. Format: a list of key=value pairs, e.g., env1=val1,env2=val2")
|
|
var kubeletConfigFile = flag.String("kubelet-config-file", "", "The KubeletConfiguration file that should be applied to the kubelet")
|
|
var debugTool = flag.String("debug-tool", "", "'delve', 'dlv' or 'gdb': run e2e_node.test under that debugger")
|
|
|
|
func main() {
|
|
klog.InitFlags(nil)
|
|
flag.Parse()
|
|
|
|
// Build dependencies - ginkgo, kubelet, e2e_node.test, and mounter.
|
|
if *buildDependencies {
|
|
if err := builder.BuildGo(); err != nil {
|
|
klog.Fatalf("Failed to build the dependencies: %v", err)
|
|
}
|
|
}
|
|
|
|
// Run node e2e test
|
|
outputDir, err := utils.GetK8sBuildOutputDir(builder.IsDockerizedBuild(), builder.GetTargetBuildArch())
|
|
if err != nil {
|
|
klog.Fatalf("Failed to get build output directory: %v", err)
|
|
}
|
|
klog.Infof("Got build output dir: %v", outputDir)
|
|
test := filepath.Join(outputDir, "e2e_node.test")
|
|
interactive := false
|
|
var cmd string
|
|
var args []string
|
|
switch *debugTool {
|
|
case "":
|
|
// No debugger, run gingko directly.
|
|
cmd = filepath.Join(outputDir, "ginkgo")
|
|
args = []string{*ginkgoFlags, test, "--"}
|
|
case "delve", "dlv":
|
|
dlv, err := exec.LookPath("dlv")
|
|
if err != nil {
|
|
klog.Fatalf("'dlv' not found: %v", err)
|
|
}
|
|
interactive = true
|
|
cmd = dlv
|
|
args = []string{"exec", test, "--", addGinkgoArgPrefix(*ginkgoFlags)}
|
|
case "gdb":
|
|
gdb, err := exec.LookPath("gdb")
|
|
if err != nil {
|
|
klog.Fatalf("'gdb' not found: %v", err)
|
|
}
|
|
interactive = true
|
|
cmd = gdb
|
|
args = []string{test, "--", addGinkgoArgPrefix(*ginkgoFlags)}
|
|
}
|
|
|
|
args = append(args, *testFlags, fmt.Sprintf("--runtime-config=%s", *runtimeConfig))
|
|
if *systemSpecName != "" {
|
|
rootDir, err := utils.GetK8sRootDir()
|
|
if err != nil {
|
|
klog.Fatalf("Failed to get k8s root directory: %v", err)
|
|
}
|
|
systemSpecFile := filepath.Join(rootDir, system.SystemSpecPath, *systemSpecName+".yaml")
|
|
args = append(args, fmt.Sprintf("--system-spec-name=%s --system-spec-file=%s --extra-envs=%s", *systemSpecName, systemSpecFile, *extraEnvs))
|
|
}
|
|
if *kubeletConfigFile != "" {
|
|
args = append(args, fmt.Sprintf("--kubelet-config-file=\"%s\"", *kubeletConfigFile))
|
|
}
|
|
if err := runCommand(interactive, cmd, args...); err != nil {
|
|
klog.Exitf("Test failed: %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
func addGinkgoArgPrefix(ginkgoFlags string) string {
|
|
// Warning, hack! This simplistic search/replace assumes that hyphens do not appear
|
|
// inside argument values.
|
|
//
|
|
// The right solution would be to use github.com/anmitsu/go-shlex to split
|
|
// the -ginkgo-flags and -test-flags strings into individual arguments, then invoke
|
|
// exec.Command with the resulting string slice instead of passing a single string
|
|
// to sh. But github.com/anmitsu/go-shlex is not a Kubernetes dependency and not
|
|
// worth adding.
|
|
|
|
ginkgoFlags = regexp.MustCompile(`(^| )--?`).ReplaceAllString(ginkgoFlags, `$1--ginkgo.`)
|
|
return ginkgoFlags
|
|
}
|
|
|
|
func runCommand(interactive bool, name string, args ...string) error {
|
|
klog.Infof("Running command: %v %v", name, strings.Join(args, " "))
|
|
// Using sh is necessary because the args are using POSIX quoting.
|
|
// sh has to parse that.
|
|
cmd := exec.Command("sudo", "sh", "-c", strings.Join(append([]string{name}, args...), " "))
|
|
if interactive {
|
|
// stdin must be a console.
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Stdout = os.Stdin
|
|
cmd.Stderr = os.Stdin
|
|
} else {
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
}
|
|
|
|
return cmd.Run()
|
|
}
|