From 5a5d53935329dcfeb99e8733b9bf68ce637cb375 Mon Sep 17 00:00:00 2001 From: Jon Edvald Date: Thu, 19 Sep 2019 11:45:14 +0200 Subject: [PATCH] improvement(k8s): better error logging for kubectl port forwards --- .../src/plugins/kubernetes/port-forward.ts | 28 +++++++++++++++++-- garden-service/src/util/ext-tools.ts | 18 ++++++++++-- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/garden-service/src/plugins/kubernetes/port-forward.ts b/garden-service/src/plugins/kubernetes/port-forward.ts index 6271d5dc13..0ad0d14eab 100644 --- a/garden-service/src/plugins/kubernetes/port-forward.ts +++ b/garden-service/src/plugins/kubernetes/port-forward.ts @@ -22,6 +22,7 @@ import { KubernetesResource } from "./types" import { ForwardablePort } from "../../types/service" import { isBuiltIn } from "./util" import { LogEntry } from "../../logger/log-entry" +import { RuntimeError } from "../../exceptions" // TODO: implement stopPortForward handler @@ -90,8 +91,25 @@ export async function getPortForward( log.silly(`Running 'kubectl ${portForwardArgs.join(" ")}'`) const proc = await kubectl.spawn({ log, provider: k8sCtx.provider, namespace, args: portForwardArgs }) + let output = "" + + return new Promise((resolve, reject) => { + let resolved = false + + const portForward = { targetResource, port, proc, localPort } + + proc.on("close", (code) => { + if (registeredPortForwards[key]) { + delete registeredPortForwards[key] + } + if (!resolved) { + reject(new RuntimeError( + `Port forward exited with code ${code} before establishing connection:\n\n${output}`, + { code, portForward }, + )) + } + }) - return new Promise((resolve) => { proc.on("error", (error) => { !proc.killed && proc.kill() throw error @@ -100,13 +118,19 @@ export async function getPortForward( proc.stdout!.on("data", (line) => { // This is unfortunately the best indication that we have that the connection is up... log.silly(`[${targetResource} port forwarder] ${line}`) + output += line if (line.toString().includes("Forwarding from ")) { - const portForward = { targetResource, port, proc, localPort } registeredPortForwards[key] = portForward + resolved = true resolve(portForward) } }) + + proc.stderr!.on("data", (line) => { + log.silly(`[${targetResource} port forwarder] ${line}`) + output += line + }) }) })) } diff --git a/garden-service/src/util/ext-tools.ts b/garden-service/src/util/ext-tools.ts index d679233d09..91c2b955cb 100644 --- a/garden-service/src/util/ext-tools.ts +++ b/garden-service/src/util/ext-tools.ts @@ -263,11 +263,14 @@ export class BinaryCmd extends Library { if (!args) { args = [] } + if (!cwd) { + cwd = dirname(path) + } - log.debug(`Execing ${path} ${args.join(" ")}`) + log.debug(`Execing '${path} ${args.join(" ")}' in ${cwd}`) const proc = execa(path, args, { - cwd: cwd || dirname(path), + cwd, timeout: this.getTimeout(timeout) * 1000, env, input, @@ -302,7 +305,16 @@ export class BinaryCmd extends Library { async spawn({ args, cwd, env, log }: ExecParams) { const path = await this.getPath(log) - return crossSpawn(path, args || [], { cwd: cwd || dirname(path), env }) + + if (!args) { + args = [] + } + if (!cwd) { + cwd = dirname(path) + } + + log.debug(`Spawning '${path} ${args.join(" ")}' in ${cwd}`) + return crossSpawn(path, args, { cwd, env }) } async spawnAndWait({ args, cwd, env, log, ignoreError, outputStream, timeout, tty }: SpawnParams) {