Merge pull request #76488 from atoato88/fix-golint-e2e-framework-util-go-part2

Fix golint failures of e2e/framework/util.go - part2
This commit is contained in:
Kubernetes Prow Robot 2019-04-23 14:02:12 -07:00 committed by GitHub
commit 4098347433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 39 deletions

View File

@ -164,7 +164,7 @@ func TestReplicationControllerServeImageOrFail(f *framework.Framework, test stri
retryTimeout := 2 * time.Minute retryTimeout := 2 * time.Minute
retryInterval := 5 * time.Second retryInterval := 5 * time.Second
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name})) label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
err = wait.Poll(retryInterval, retryTimeout, framework.PodProxyResponseChecker(f.ClientSet, f.Namespace.Name, label, name, true, pods).CheckAllResponses) err = wait.Poll(retryInterval, retryTimeout, framework.NewPodProxyResponseChecker(f.ClientSet, f.Namespace.Name, label, name, true, pods).CheckAllResponses)
if err != nil { if err != nil {
framework.Failf("Did not get expected responses within the timeout period of %.2f seconds.", retryTimeout.Seconds()) framework.Failf("Did not get expected responses within the timeout period of %.2f seconds.", retryTimeout.Seconds())
} }

View File

@ -166,7 +166,7 @@ func testReplicaSetServeImageOrFail(f *framework.Framework, test string, image s
retryTimeout := 2 * time.Minute retryTimeout := 2 * time.Minute
retryInterval := 5 * time.Second retryInterval := 5 * time.Second
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name})) label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
err = wait.Poll(retryInterval, retryTimeout, framework.PodProxyResponseChecker(f.ClientSet, f.Namespace.Name, label, name, true, pods).CheckAllResponses) err = wait.Poll(retryInterval, retryTimeout, framework.NewPodProxyResponseChecker(f.ClientSet, f.Namespace.Name, label, name, true, pods).CheckAllResponses)
if err != nil { if err != nil {
framework.Failf("Did not get expected responses within the timeout period of %.2f seconds.", retryTimeout.Seconds()) framework.Failf("Did not get expected responses within the timeout period of %.2f seconds.", retryTimeout.Seconds())
} }

View File

@ -1392,7 +1392,7 @@ func CheckInvariants(events []watch.Event, fns ...InvariantFunc) error {
return nil return nil
} }
// Waits default amount of time (PodStartTimeout) for the specified pod to become running. // WaitForPodRunningInNamespace waits default amount of time (PodStartTimeout) for the specified pod to become running.
// Returns an error if timeout occurs first, or pod goes in to failed state. // Returns an error if timeout occurs first, or pod goes in to failed state.
func WaitForPodRunningInNamespace(c clientset.Interface, pod *v1.Pod) error { func WaitForPodRunningInNamespace(c clientset.Interface, pod *v1.Pod) error {
if pod.Status.Phase == v1.PodRunning { if pod.Status.Phase == v1.PodRunning {
@ -1401,19 +1401,20 @@ func WaitForPodRunningInNamespace(c clientset.Interface, pod *v1.Pod) error {
return WaitTimeoutForPodRunningInNamespace(c, pod.Name, pod.Namespace, PodStartTimeout) return WaitTimeoutForPodRunningInNamespace(c, pod.Name, pod.Namespace, PodStartTimeout)
} }
// Waits default amount of time (PodStartTimeout) for the specified pod to become running. // WaitForPodNameRunningInNamespace waits default amount of time (PodStartTimeout) for the specified pod to become running.
// Returns an error if timeout occurs first, or pod goes in to failed state. // Returns an error if timeout occurs first, or pod goes in to failed state.
func WaitForPodNameRunningInNamespace(c clientset.Interface, podName, namespace string) error { func WaitForPodNameRunningInNamespace(c clientset.Interface, podName, namespace string) error {
return WaitTimeoutForPodRunningInNamespace(c, podName, namespace, PodStartTimeout) return WaitTimeoutForPodRunningInNamespace(c, podName, namespace, PodStartTimeout)
} }
// Waits an extended amount of time (slowPodStartTimeout) for the specified pod to become running. // waitForPodRunningInNamespaceSlow waits an extended amount of time (slowPodStartTimeout) for the specified pod to become running.
// The resourceVersion is used when Watching object changes, it tells since when we care // The resourceVersion is used when Watching object changes, it tells since when we care
// about changes to the pod. Returns an error if timeout occurs first, or pod goes in to failed state. // about changes to the pod. Returns an error if timeout occurs first, or pod goes in to failed state.
func waitForPodRunningInNamespaceSlow(c clientset.Interface, podName, namespace string) error { func waitForPodRunningInNamespaceSlow(c clientset.Interface, podName, namespace string) error {
return WaitTimeoutForPodRunningInNamespace(c, podName, namespace, slowPodStartTimeout) return WaitTimeoutForPodRunningInNamespace(c, podName, namespace, slowPodStartTimeout)
} }
// WaitTimeoutForPodRunningInNamespace waits the given timeout duration for the specified pod to become running.
func WaitTimeoutForPodRunningInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error { func WaitTimeoutForPodRunningInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error {
return wait.PollImmediate(Poll, timeout, podRunning(c, podName, namespace)) return wait.PollImmediate(Poll, timeout, podRunning(c, podName, namespace))
} }
@ -1434,7 +1435,7 @@ func podRunning(c clientset.Interface, podName, namespace string) wait.Condition
} }
} }
// WaitTimeoutForPodEvent waits for an event to occur for a pod // WaitTimeoutForPodEvent waits the given timeout duration for a pod event to occur.
func WaitTimeoutForPodEvent(c clientset.Interface, podName, namespace, eventSelector, msg string, timeout time.Duration) error { func WaitTimeoutForPodEvent(c clientset.Interface, podName, namespace, eventSelector, msg string, timeout time.Duration) error {
return wait.PollImmediate(Poll, timeout, eventOccurred(c, podName, namespace, eventSelector, msg)) return wait.PollImmediate(Poll, timeout, eventOccurred(c, podName, namespace, eventSelector, msg))
} }
@ -1455,12 +1456,13 @@ func eventOccurred(c clientset.Interface, podName, namespace, eventSelector, msg
} }
} }
// Waits default amount of time (DefaultPodDeletionTimeout) for the specified pod to stop running. // WaitForPodNoLongerRunningInNamespace waits default amount of time (DefaultPodDeletionTimeout) for the specified pod to stop running.
// Returns an error if timeout occurs first. // Returns an error if timeout occurs first.
func WaitForPodNoLongerRunningInNamespace(c clientset.Interface, podName, namespace string) error { func WaitForPodNoLongerRunningInNamespace(c clientset.Interface, podName, namespace string) error {
return WaitTimeoutForPodNoLongerRunningInNamespace(c, podName, namespace, DefaultPodDeletionTimeout) return WaitTimeoutForPodNoLongerRunningInNamespace(c, podName, namespace, DefaultPodDeletionTimeout)
} }
// WaitTimeoutForPodNoLongerRunningInNamespace waits the given timeout duration for the specified pod to stop.
func WaitTimeoutForPodNoLongerRunningInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error { func WaitTimeoutForPodNoLongerRunningInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error {
return wait.PollImmediate(Poll, timeout, podCompleted(c, podName, namespace)) return wait.PollImmediate(Poll, timeout, podCompleted(c, podName, namespace))
} }
@ -1533,9 +1535,8 @@ func waitForPodTerminatedInNamespace(c clientset.Interface, podName, reason, nam
if pod.Status.Phase == v1.PodFailed { if pod.Status.Phase == v1.PodFailed {
if pod.Status.Reason == reason { // short-circuit waitForPodCondition's loop if pod.Status.Reason == reason { // short-circuit waitForPodCondition's loop
return true, nil return true, nil
} else {
return true, fmt.Errorf("Expected pod %q in namespace %q to be terminated with reason %q, got reason: %q", podName, namespace, reason, pod.Status.Reason)
} }
return true, fmt.Errorf("Expected pod %q in namespace %q to be terminated with reason %q, got reason: %q", podName, namespace, reason, pod.Status.Reason)
} }
return false, nil return false, nil
}) })
@ -1618,6 +1619,7 @@ func WaitForRCToStabilize(c clientset.Interface, ns, name string, timeout time.D
return err return err
} }
// WaitForPodToDisappear waits the given timeout duration for the specified pod to disappear.
func WaitForPodToDisappear(c clientset.Interface, ns, podName string, label labels.Selector, interval, timeout time.Duration) error { func WaitForPodToDisappear(c clientset.Interface, ns, podName string, label labels.Selector, interval, timeout time.Duration) error {
return wait.PollImmediate(interval, timeout, func() (bool, error) { return wait.PollImmediate(interval, timeout, func() (bool, error) {
Logf("Waiting for pod %s to disappear", podName) Logf("Waiting for pod %s to disappear", podName)
@ -1746,6 +1748,7 @@ func countEndpointsNum(e *v1.Endpoints) int {
return num return num
} }
// WaitForEndpoint waits for the specified endpoint to be ready.
func WaitForEndpoint(c clientset.Interface, ns, name string) error { func WaitForEndpoint(c clientset.Interface, ns, name string) error {
for t := time.Now(); time.Since(t) < EndpointRegisterTimeout; time.Sleep(Poll) { for t := time.Now(); time.Since(t) < EndpointRegisterTimeout; time.Sleep(Poll) {
endpoint, err := c.CoreV1().Endpoints(ns).Get(name, metav1.GetOptions{}) endpoint, err := c.CoreV1().Endpoints(ns).Get(name, metav1.GetOptions{})
@ -1764,9 +1767,9 @@ func WaitForEndpoint(c clientset.Interface, ns, name string) error {
return fmt.Errorf("Failed to get endpoints for %s/%s", ns, name) return fmt.Errorf("Failed to get endpoints for %s/%s", ns, name)
} }
// Context for checking pods responses by issuing GETs to them (via the API // PodProxyResponseChecker is a context for checking pods responses by issuing GETs to them (via the API
// proxy) and verifying that they answer with their own pod name. // proxy) and verifying that they answer with their own pod name.
type podProxyResponseChecker struct { type PodProxyResponseChecker struct {
c clientset.Interface c clientset.Interface
ns string ns string
label labels.Selector label labels.Selector
@ -1775,13 +1778,14 @@ type podProxyResponseChecker struct {
pods *v1.PodList pods *v1.PodList
} }
func PodProxyResponseChecker(c clientset.Interface, ns string, label labels.Selector, controllerName string, respondName bool, pods *v1.PodList) podProxyResponseChecker { // NewPodProxyResponseChecker returns a context for checking pods responses.
return podProxyResponseChecker{c, ns, label, controllerName, respondName, pods} func NewPodProxyResponseChecker(c clientset.Interface, ns string, label labels.Selector, controllerName string, respondName bool, pods *v1.PodList) PodProxyResponseChecker {
return PodProxyResponseChecker{c, ns, label, controllerName, respondName, pods}
} }
// CheckAllResponses issues GETs to all pods in the context and verify they // CheckAllResponses issues GETs to all pods in the context and verify they
// reply with their own pod name. // reply with their own pod name.
func (r podProxyResponseChecker) CheckAllResponses() (done bool, err error) { func (r PodProxyResponseChecker) CheckAllResponses() (done bool, err error) {
successes := 0 successes := 0
options := metav1.ListOptions{LabelSelector: r.label.String()} options := metav1.ListOptions{LabelSelector: r.label.String()}
currentPods, err := r.c.CoreV1().Pods(r.ns).List(options) currentPods, err := r.c.CoreV1().Pods(r.ns).List(options)
@ -1873,17 +1877,20 @@ func KubectlVersion() (*utilversion.Version, error) {
return utilversion.ParseSemantic(matches[1]) return utilversion.ParseSemantic(matches[1])
} }
// PodsResponding waits for the pods to response.
func PodsResponding(c clientset.Interface, ns, name string, wantName bool, pods *v1.PodList) error { func PodsResponding(c clientset.Interface, ns, name string, wantName bool, pods *v1.PodList) error {
ginkgo.By("trying to dial each unique pod") ginkgo.By("trying to dial each unique pod")
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name})) label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
return wait.PollImmediate(Poll, podRespondingTimeout, PodProxyResponseChecker(c, ns, label, name, wantName, pods).CheckAllResponses) return wait.PollImmediate(Poll, podRespondingTimeout, NewPodProxyResponseChecker(c, ns, label, name, wantName, pods).CheckAllResponses)
} }
// PodsCreated returns a pod list matched by the given name.
func PodsCreated(c clientset.Interface, ns, name string, replicas int32) (*v1.PodList, error) { func PodsCreated(c clientset.Interface, ns, name string, replicas int32) (*v1.PodList, error) {
label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name})) label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
return PodsCreatedByLabel(c, ns, name, replicas, label) return PodsCreatedByLabel(c, ns, name, replicas, label)
} }
// PodsCreatedByLabel returns a created pod list matched by the given label.
func PodsCreatedByLabel(c clientset.Interface, ns, name string, replicas int32, label labels.Selector) (*v1.PodList, error) { func PodsCreatedByLabel(c clientset.Interface, ns, name string, replicas int32, label labels.Selector) (*v1.PodList, error) {
timeout := 2 * time.Minute timeout := 2 * time.Minute
for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) { for start := time.Now(); time.Since(start) < timeout; time.Sleep(5 * time.Second) {
@ -1917,16 +1924,16 @@ func podsRunning(c clientset.Interface, pods *v1.PodList) []error {
// are running so non-running pods cause a timeout for this test. // are running so non-running pods cause a timeout for this test.
ginkgo.By("ensuring each pod is running") ginkgo.By("ensuring each pod is running")
e := []error{} e := []error{}
error_chan := make(chan error) errorChan := make(chan error)
for _, pod := range pods.Items { for _, pod := range pods.Items {
go func(p v1.Pod) { go func(p v1.Pod) {
error_chan <- WaitForPodRunningInNamespace(c, &p) errorChan <- WaitForPodRunningInNamespace(c, &p)
}(pod) }(pod)
} }
for range pods.Items { for range pods.Items {
err := <-error_chan err := <-errorChan
if err != nil { if err != nil {
e = append(e, err) e = append(e, err)
} }
@ -1935,10 +1942,12 @@ func podsRunning(c clientset.Interface, pods *v1.PodList) []error {
return e return e
} }
// VerifyPods checks if the specified pod is responding.
func VerifyPods(c clientset.Interface, ns, name string, wantName bool, replicas int32) error { func VerifyPods(c clientset.Interface, ns, name string, wantName bool, replicas int32) error {
return podRunningMaybeResponding(c, ns, name, wantName, replicas, true) return podRunningMaybeResponding(c, ns, name, wantName, replicas, true)
} }
// VerifyPodsRunning checks if the specified pod is running.
func VerifyPodsRunning(c clientset.Interface, ns, name string, wantName bool, replicas int32) error { func VerifyPodsRunning(c clientset.Interface, ns, name string, wantName bool, replicas int32) error {
return podRunningMaybeResponding(c, ns, name, wantName, replicas, false) return podRunningMaybeResponding(c, ns, name, wantName, replicas, false)
} }
@ -1961,6 +1970,7 @@ func podRunningMaybeResponding(c clientset.Interface, ns, name string, wantName
return nil return nil
} }
// ServiceResponding waits for the service to be responding.
func ServiceResponding(c clientset.Interface, ns, name string) error { func ServiceResponding(c clientset.Interface, ns, name string) error {
ginkgo.By(fmt.Sprintf("trying to dial the service %s.%s via the proxy", ns, name)) ginkgo.By(fmt.Sprintf("trying to dial the service %s.%s via the proxy", ns, name))
@ -1997,6 +2007,7 @@ func ServiceResponding(c clientset.Interface, ns, name string) error {
}) })
} }
// RestclientConfig returns a config holds the information needed to build connection to kubernetes clusters.
func RestclientConfig(kubeContext string) (*clientcmdapi.Config, error) { func RestclientConfig(kubeContext string) (*clientcmdapi.Config, error) {
Logf(">>> kubeConfig: %s", TestContext.KubeConfig) Logf(">>> kubeConfig: %s", TestContext.KubeConfig)
if TestContext.KubeConfig == "" { if TestContext.KubeConfig == "" {
@ -2013,8 +2024,10 @@ func RestclientConfig(kubeContext string) (*clientcmdapi.Config, error) {
return c, nil return c, nil
} }
// ClientConfigGetter is a func that returns getter to return a config.
type ClientConfigGetter func() (*restclient.Config, error) type ClientConfigGetter func() (*restclient.Config, error)
// LoadConfig returns a config for a rest client.
func LoadConfig() (*restclient.Config, error) { func LoadConfig() (*restclient.Config, error) {
if TestContext.NodeE2E { if TestContext.NodeE2E {
// This is a node e2e test, apply the node e2e configuration // This is a node e2e test, apply the node e2e configuration
@ -2024,14 +2037,14 @@ func LoadConfig() (*restclient.Config, error) {
if err != nil { if err != nil {
if TestContext.KubeConfig == "" { if TestContext.KubeConfig == "" {
return restclient.InClusterConfig() return restclient.InClusterConfig()
} else {
return nil, err
} }
return nil, err
} }
return clientcmd.NewDefaultClientConfig(*c, &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: TestContext.Host}}).ClientConfig() return clientcmd.NewDefaultClientConfig(*c, &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: TestContext.Host}}).ClientConfig()
} }
// LoadClientset returns clientset for connecting to kubernetes clusters.
func LoadClientset() (*clientset.Clientset, error) { func LoadClientset() (*clientset.Clientset, error) {
config, err := LoadConfig() config, err := LoadConfig()
if err != nil { if err != nil {
@ -2040,7 +2053,7 @@ func LoadClientset() (*clientset.Clientset, error) {
return clientset.NewForConfig(config) return clientset.NewForConfig(config)
} }
// randomSuffix provides a random string to append to pods,services,rcs. // RandomSuffix provides a random string to append to pods,services,rcs.
// TODO: Allow service names to have the same form as names // TODO: Allow service names to have the same form as names
// for pods and replication controllers so we don't // for pods and replication controllers so we don't
// need to use such a function and can instead // need to use such a function and can instead
@ -2050,6 +2063,7 @@ func RandomSuffix() string {
return strconv.Itoa(r.Int() % 10000) return strconv.Itoa(r.Int() % 10000)
} }
// ExpectNoError checks if "err" is set, and if so, fails assertion while logging the error.
func ExpectNoError(err error, explain ...interface{}) { func ExpectNoError(err error, explain ...interface{}) {
ExpectNoErrorWithOffset(1, err, explain...) ExpectNoErrorWithOffset(1, err, explain...)
} }
@ -2063,6 +2077,7 @@ func ExpectNoErrorWithOffset(offset int, err error, explain ...interface{}) {
gomega.ExpectWithOffset(1+offset, err).NotTo(gomega.HaveOccurred(), explain...) gomega.ExpectWithOffset(1+offset, err).NotTo(gomega.HaveOccurred(), explain...)
} }
// ExpectNoErrorWithRetries checks if an error occurs with the given retry count.
func ExpectNoErrorWithRetries(fn func() error, maxRetries int, explain ...interface{}) { func ExpectNoErrorWithRetries(fn func() error, maxRetries int, explain ...interface{}) {
var err error var err error
for i := 0; i < maxRetries; i++ { for i := 0; i < maxRetries; i++ {
@ -2075,7 +2090,7 @@ func ExpectNoErrorWithRetries(fn func() error, maxRetries int, explain ...interf
gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred(), explain...) gomega.ExpectWithOffset(1, err).NotTo(gomega.HaveOccurred(), explain...)
} }
// Stops everything from filePath from namespace ns and checks if everything matching selectors from the given namespace is correctly stopped. // Cleanup stops everything from filePath from namespace ns and checks if everything matching selectors from the given namespace is correctly stopped.
func Cleanup(filePath, ns string, selectors ...string) { func Cleanup(filePath, ns string, selectors ...string) {
ginkgo.By("using delete to clean up resources") ginkgo.By("using delete to clean up resources")
var nsArg string var nsArg string
@ -2086,7 +2101,7 @@ func Cleanup(filePath, ns string, selectors ...string) {
AssertCleanup(ns, selectors...) AssertCleanup(ns, selectors...)
} }
// Asserts that cleanup of a namespace wrt selectors occurred. // AssertCleanup asserts that cleanup of a namespace wrt selectors occurred.
func AssertCleanup(ns string, selectors ...string) { func AssertCleanup(ns string, selectors ...string) {
var nsArg string var nsArg string
if ns != "" { if ns != "" {
@ -2150,40 +2165,46 @@ func KubectlCmd(args ...string) *exec.Cmd {
return cmd return cmd
} }
// kubectlBuilder is used to build, customize and execute a kubectl Command. // KubectlBuilder is used to build, customize and execute a kubectl Command.
// Add more functions to customize the builder as needed. // Add more functions to customize the builder as needed.
type kubectlBuilder struct { type KubectlBuilder struct {
cmd *exec.Cmd cmd *exec.Cmd
timeout <-chan time.Time timeout <-chan time.Time
} }
func NewKubectlCommand(args ...string) *kubectlBuilder { // NewKubectlCommand returns a KubectlBuilder for running kubectl.
b := new(kubectlBuilder) func NewKubectlCommand(args ...string) *KubectlBuilder {
b := new(KubectlBuilder)
b.cmd = KubectlCmd(args...) b.cmd = KubectlCmd(args...)
return b return b
} }
func (b *kubectlBuilder) WithEnv(env []string) *kubectlBuilder { // WithEnv sets the given environment and returns itself.
func (b *KubectlBuilder) WithEnv(env []string) *KubectlBuilder {
b.cmd.Env = env b.cmd.Env = env
return b return b
} }
func (b *kubectlBuilder) WithTimeout(t <-chan time.Time) *kubectlBuilder { // WithTimeout sets the given timeout and returns itself.
func (b *KubectlBuilder) WithTimeout(t <-chan time.Time) *KubectlBuilder {
b.timeout = t b.timeout = t
return b return b
} }
func (b kubectlBuilder) WithStdinData(data string) *kubectlBuilder { // WithStdinData sets the given data to stdin and returns itself.
func (b KubectlBuilder) WithStdinData(data string) *KubectlBuilder {
b.cmd.Stdin = strings.NewReader(data) b.cmd.Stdin = strings.NewReader(data)
return &b return &b
} }
func (b kubectlBuilder) WithStdinReader(reader io.Reader) *kubectlBuilder { // WithStdinReader sets the given reader and returns itself.
func (b KubectlBuilder) WithStdinReader(reader io.Reader) *KubectlBuilder {
b.cmd.Stdin = reader b.cmd.Stdin = reader
return &b return &b
} }
func (b kubectlBuilder) ExecOrDie() string { // ExecOrDie runs the kubectl executable or dies if error occurs.
func (b KubectlBuilder) ExecOrDie() string {
str, err := b.Exec() str, err := b.Exec()
// In case of i/o timeout error, try talking to the apiserver again after 2s before dying. // In case of i/o timeout error, try talking to the apiserver again after 2s before dying.
// Note that we're still dying after retrying so that we can get visibility to triage it further. // Note that we're still dying after retrying so that we can get visibility to triage it further.
@ -2212,14 +2233,15 @@ func isTimeout(err error) bool {
return false return false
} }
func (b kubectlBuilder) Exec() (string, error) { // Exec runs the kubectl executable.
func (b KubectlBuilder) Exec() (string, error) {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
cmd := b.cmd cmd := b.cmd
cmd.Stdout, cmd.Stderr = &stdout, &stderr cmd.Stdout, cmd.Stderr = &stdout, &stderr
Logf("Running '%s %s'", cmd.Path, strings.Join(cmd.Args[1:], " ")) // skip arg[0] as it is printed separately Logf("Running '%s %s'", cmd.Path, strings.Join(cmd.Args[1:], " ")) // skip arg[0] as it is printed separately
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return "", fmt.Errorf("error starting %v:\nCommand stdout:\n%v\nstderr:\n%v\nerror:\n%v\n", cmd, cmd.Stdout, cmd.Stderr, err) return "", fmt.Errorf("error starting %v:\nCommand stdout:\n%v\nstderr:\n%v\nerror:\n%v", cmd, cmd.Stdout, cmd.Stderr, err)
} }
errCh := make(chan error, 1) errCh := make(chan error, 1)
go func() { go func() {
@ -2228,19 +2250,19 @@ func (b kubectlBuilder) Exec() (string, error) {
select { select {
case err := <-errCh: case err := <-errCh:
if err != nil { if err != nil {
var rc int = 127 var rc = 127
if ee, ok := err.(*exec.ExitError); ok { if ee, ok := err.(*exec.ExitError); ok {
rc = int(ee.Sys().(syscall.WaitStatus).ExitStatus()) rc = int(ee.Sys().(syscall.WaitStatus).ExitStatus())
Logf("rc: %d", rc) Logf("rc: %d", rc)
} }
return "", uexec.CodeExitError{ return "", uexec.CodeExitError{
Err: fmt.Errorf("error running %v:\nCommand stdout:\n%v\nstderr:\n%v\nerror:\n%v\n", cmd, cmd.Stdout, cmd.Stderr, err), Err: fmt.Errorf("error running %v:\nCommand stdout:\n%v\nstderr:\n%v\nerror:\n%v", cmd, cmd.Stdout, cmd.Stderr, err),
Code: rc, Code: rc,
} }
} }
case <-b.timeout: case <-b.timeout:
b.cmd.Process.Kill() b.cmd.Process.Kill()
return "", fmt.Errorf("timed out waiting for command %v:\nCommand stdout:\n%v\nstderr:\n%v\n", cmd, cmd.Stdout, cmd.Stderr) return "", fmt.Errorf("timed out waiting for command %v:\nCommand stdout:\n%v\nstderr:\n%v", cmd, cmd.Stdout, cmd.Stderr)
} }
Logf("stderr: %q", stderr.String()) Logf("stderr: %q", stderr.String())
Logf("stdout: %q", stdout.String()) Logf("stdout: %q", stdout.String())
@ -2280,13 +2302,14 @@ func RunKubemciWithKubeconfig(args ...string) (string, error) {
func RunKubemciCmd(args ...string) (string, error) { func RunKubemciCmd(args ...string) (string, error) {
// kubemci is assumed to be in PATH. // kubemci is assumed to be in PATH.
kubemci := "kubemci" kubemci := "kubemci"
b := new(kubectlBuilder) b := new(KubectlBuilder)
args = append(args, "--gcp-project="+TestContext.CloudConfig.ProjectID) args = append(args, "--gcp-project="+TestContext.CloudConfig.ProjectID)
b.cmd = exec.Command(kubemci, args...) b.cmd = exec.Command(kubemci, args...)
return b.Exec() return b.Exec()
} }
// StartCmdAndStreamOutput returns stdout and stderr after starting the given cmd.
func StartCmdAndStreamOutput(cmd *exec.Cmd) (stdout, stderr io.ReadCloser, err error) { func StartCmdAndStreamOutput(cmd *exec.Cmd) (stdout, stderr io.ReadCloser, err error) {
stdout, err = cmd.StdoutPipe() stdout, err = cmd.StdoutPipe()
if err != nil { if err != nil {
@ -2301,7 +2324,7 @@ func StartCmdAndStreamOutput(cmd *exec.Cmd) (stdout, stderr io.ReadCloser, err e
return return
} }
// Rough equivalent of ctrl+c for cleaning up processes. Intended to be run in defer. // TryKill is rough equivalent of ctrl+c for cleaning up processes. Intended to be run in defer.
func TryKill(cmd *exec.Cmd) { func TryKill(cmd *exec.Cmd) {
if err := cmd.Process.Kill(); err != nil { if err := cmd.Process.Kill(); err != nil {
Logf("ERROR failed to kill command %v! The process may leak", cmd) Logf("ERROR failed to kill command %v! The process may leak", cmd)