diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 4971abe5cc..4a0ed76d9d 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -91,6 +91,10 @@ export class Cluster implements ClusterInfo { return this.kubeconfigManager.getPath() } + public proxySocketPath() { + return this.kubeconfigManager.getProxySocketPath() + } + public async init(kc: KubeConfig) { this.contextHandler = new ContextHandler(kc, this) this.contextName = kc.currentContext diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index 9f2977dfc4..828bddd100 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -1,15 +1,12 @@ import { KubeConfig, CoreV1Api } from "@kubernetes/client-node" -import { readFileSync } from "fs" import * as http from "http" import { ServerOptions } from "http-proxy" import * as url from "url" import logger from "./logger" -import { getFreePort } from "./port" import { KubeAuthProxy } from "./kube-auth-proxy" import { Cluster, ClusterPreferences } from "./cluster" import { prometheusProviders } from "../common/prometheus-providers" import { PrometheusService, PrometheusProvider } from "./prometheus/provider-registry" -import { PrometheusLens } from "./prometheus/lens" export class ContextHandler { public contextName: string @@ -148,7 +145,7 @@ export class ContextHandler { "Host": this.clusterUrl.hostname }, target: { - port: await this.resolveProxyPort(), + socketPath: this.cluster.proxySocketPath(), protocol: "http://", host: "localhost", path: this.clusterUrl.path @@ -156,21 +153,6 @@ export class ContextHandler { } } - protected async resolveProxyPort(): Promise { - if (this.proxyPort) return this.proxyPort - - let serverPort: number = null - try { - serverPort = await getFreePort() - } catch(error) { - logger.error(error) - throw(error) - } - this.proxyPort = serverPort - - return serverPort - } - public applyHeaders(req: http.IncomingMessage) { req.headers["authorization"] = `Bearer ${this.id}` } @@ -185,12 +167,11 @@ export class ContextHandler { public async ensureServer() { if (!this.proxyServer) { - const proxyPort = await this.resolveProxyPort() const proxyEnv = Object.assign({}, process.env) if (this.cluster.preferences && this.cluster.preferences.httpsProxy) { proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy } - this.proxyServer = new KubeAuthProxy(this.cluster, proxyPort, proxyEnv) + this.proxyServer = new KubeAuthProxy(this.cluster, proxyEnv) await this.proxyServer.run() } } diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index c6f65f2419..ea920f5481 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -1,26 +1,24 @@ import { spawn, ChildProcess } from "child_process" import logger from "./logger" -import * as tcpPortUsed from "tcp-port-used" import { Kubectl, bundledKubectl } from "./kubectl" import { Cluster } from "./cluster" -import { readFileSync, watch } from "fs" +import { readFileSync, watch, existsSync } from "fs" import { PromiseIpc } from "electron-promise-ipc" import { findMainWebContents } from "./webcontents" import * as url from "url" + export class KubeAuthProxy { public lastError: string protected cluster: Cluster protected env: NodeJS.ProcessEnv = null protected proxyProcess: ChildProcess - protected port: number protected kubectl: Kubectl protected promiseIpc: any - constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) { + constructor(cluster: Cluster, env: NodeJS.ProcessEnv) { this.env = env - this.port = port this.cluster = cluster this.kubectl = bundledKubectl this.promiseIpc = new PromiseIpc({ timeout: 2000 }) @@ -47,9 +45,9 @@ export class KubeAuthProxy { const clusterUrl = url.parse(this.cluster.apiUrl) let args = [ "proxy", - "-p", this.port.toString(), "--kubeconfig", this.cluster.kubeconfigPath(), "--accept-hosts", clusterUrl.hostname, + "-u", this.cluster.proxySocketPath(), ] if (process.env.DEBUG_PROXY === "true") { args = args.concat(["-v", "9"]) @@ -77,7 +75,19 @@ export class KubeAuthProxy { this.sendIpcLogMessage(data.toString(), "stderr") }) - return tcpPortUsed.waitUntilUsed(this.port, 500, 10000) + return await this.waitUnixSocket(this.cluster.proxySocketPath()) + } + + protected waitUnixSocket(socket: string): Promise { + return new Promise((resolve, reject) => { + let done = false + while(!done) { // TODO: fix busy loop + if (existsSync(socket)) { + done = true + resolve() + } + } + }) } protected parseError(data: string) { diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index 0a2473d1c4..28b4de337e 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -7,19 +7,25 @@ export class KubeconfigManager { protected configDir = app.getPath("temp") protected kubeconfig: string protected tempFile: string + protected tempProxySocket: string constructor(kubeconfig: string) { this.kubeconfig = kubeconfig this.tempFile = this.createTemporaryKubeconfig() + this.tempProxySocket = `${this.configDir}${randomFileName("proxy")}.sock` } public getPath() { return this.tempFile } + public getProxySocketPath() { + return this.tempProxySocket + } + protected createTemporaryKubeconfig(): string { ensureDir(this.configDir) - const path = `${this.configDir}/${randomFileName("kubeconfig")}` + const path = `${this.configDir}${randomFileName("kubeconfig")}` logger.debug('Creating temporary kubeconfig: ' + path) fs.writeFileSync(path, this.kubeconfig) return path @@ -28,5 +34,7 @@ export class KubeconfigManager { public unlink() { logger.debug('Deleting temporary kubeconfig: ' + this.tempFile) fs.unlinkSync(this.tempFile) + logger.debug('Deleting temporary proxy socket: ' + this.tempFile) + fs.unlinkSync(this.tempProxySocket) } }