1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

kubectl proxy: switch to unix sockets

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen 2020-05-11 15:48:53 +03:00
parent e21e0b577b
commit 2baa85b2c3
4 changed files with 32 additions and 29 deletions

View File

@ -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

View File

@ -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<number> {
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()
}
}

View File

@ -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<void> {
return new Promise((resolve, reject) => {
let done = false
while(!done) { // TODO: fix busy loop
if (existsSync(socket)) {
done = true
resolve()
}
}
})
}
protected parseError(data: string) {

View File

@ -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)
}
}