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:
parent
e21e0b577b
commit
2baa85b2c3
@ -91,6 +91,10 @@ export class Cluster implements ClusterInfo {
|
|||||||
return this.kubeconfigManager.getPath()
|
return this.kubeconfigManager.getPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public proxySocketPath() {
|
||||||
|
return this.kubeconfigManager.getProxySocketPath()
|
||||||
|
}
|
||||||
|
|
||||||
public async init(kc: KubeConfig) {
|
public async init(kc: KubeConfig) {
|
||||||
this.contextHandler = new ContextHandler(kc, this)
|
this.contextHandler = new ContextHandler(kc, this)
|
||||||
this.contextName = kc.currentContext
|
this.contextName = kc.currentContext
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
import { KubeConfig, CoreV1Api } from "@kubernetes/client-node"
|
import { KubeConfig, CoreV1Api } from "@kubernetes/client-node"
|
||||||
import { readFileSync } from "fs"
|
|
||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
import { ServerOptions } from "http-proxy"
|
import { ServerOptions } from "http-proxy"
|
||||||
import * as url from "url"
|
import * as url from "url"
|
||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
import { getFreePort } from "./port"
|
|
||||||
import { KubeAuthProxy } from "./kube-auth-proxy"
|
import { KubeAuthProxy } from "./kube-auth-proxy"
|
||||||
import { Cluster, ClusterPreferences } from "./cluster"
|
import { Cluster, ClusterPreferences } from "./cluster"
|
||||||
import { prometheusProviders } from "../common/prometheus-providers"
|
import { prometheusProviders } from "../common/prometheus-providers"
|
||||||
import { PrometheusService, PrometheusProvider } from "./prometheus/provider-registry"
|
import { PrometheusService, PrometheusProvider } from "./prometheus/provider-registry"
|
||||||
import { PrometheusLens } from "./prometheus/lens"
|
|
||||||
|
|
||||||
export class ContextHandler {
|
export class ContextHandler {
|
||||||
public contextName: string
|
public contextName: string
|
||||||
@ -148,7 +145,7 @@ export class ContextHandler {
|
|||||||
"Host": this.clusterUrl.hostname
|
"Host": this.clusterUrl.hostname
|
||||||
},
|
},
|
||||||
target: {
|
target: {
|
||||||
port: await this.resolveProxyPort(),
|
socketPath: this.cluster.proxySocketPath(),
|
||||||
protocol: "http://",
|
protocol: "http://",
|
||||||
host: "localhost",
|
host: "localhost",
|
||||||
path: this.clusterUrl.path
|
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) {
|
public applyHeaders(req: http.IncomingMessage) {
|
||||||
req.headers["authorization"] = `Bearer ${this.id}`
|
req.headers["authorization"] = `Bearer ${this.id}`
|
||||||
}
|
}
|
||||||
@ -185,12 +167,11 @@ export class ContextHandler {
|
|||||||
|
|
||||||
public async ensureServer() {
|
public async ensureServer() {
|
||||||
if (!this.proxyServer) {
|
if (!this.proxyServer) {
|
||||||
const proxyPort = await this.resolveProxyPort()
|
|
||||||
const proxyEnv = Object.assign({}, process.env)
|
const proxyEnv = Object.assign({}, process.env)
|
||||||
if (this.cluster.preferences && this.cluster.preferences.httpsProxy) {
|
if (this.cluster.preferences && this.cluster.preferences.httpsProxy) {
|
||||||
proxyEnv.HTTPS_PROXY = 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()
|
await this.proxyServer.run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,26 +1,24 @@
|
|||||||
import { spawn, ChildProcess } from "child_process"
|
import { spawn, ChildProcess } from "child_process"
|
||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
import * as tcpPortUsed from "tcp-port-used"
|
|
||||||
import { Kubectl, bundledKubectl } from "./kubectl"
|
import { Kubectl, bundledKubectl } from "./kubectl"
|
||||||
import { Cluster } from "./cluster"
|
import { Cluster } from "./cluster"
|
||||||
import { readFileSync, watch } from "fs"
|
import { readFileSync, watch, existsSync } from "fs"
|
||||||
import { PromiseIpc } from "electron-promise-ipc"
|
import { PromiseIpc } from "electron-promise-ipc"
|
||||||
import { findMainWebContents } from "./webcontents"
|
import { findMainWebContents } from "./webcontents"
|
||||||
import * as url from "url"
|
import * as url from "url"
|
||||||
|
|
||||||
|
|
||||||
export class KubeAuthProxy {
|
export class KubeAuthProxy {
|
||||||
public lastError: string
|
public lastError: string
|
||||||
|
|
||||||
protected cluster: Cluster
|
protected cluster: Cluster
|
||||||
protected env: NodeJS.ProcessEnv = null
|
protected env: NodeJS.ProcessEnv = null
|
||||||
protected proxyProcess: ChildProcess
|
protected proxyProcess: ChildProcess
|
||||||
protected port: number
|
|
||||||
protected kubectl: Kubectl
|
protected kubectl: Kubectl
|
||||||
protected promiseIpc: any
|
protected promiseIpc: any
|
||||||
|
|
||||||
constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) {
|
constructor(cluster: Cluster, env: NodeJS.ProcessEnv) {
|
||||||
this.env = env
|
this.env = env
|
||||||
this.port = port
|
|
||||||
this.cluster = cluster
|
this.cluster = cluster
|
||||||
this.kubectl = bundledKubectl
|
this.kubectl = bundledKubectl
|
||||||
this.promiseIpc = new PromiseIpc({ timeout: 2000 })
|
this.promiseIpc = new PromiseIpc({ timeout: 2000 })
|
||||||
@ -47,9 +45,9 @@ export class KubeAuthProxy {
|
|||||||
const clusterUrl = url.parse(this.cluster.apiUrl)
|
const clusterUrl = url.parse(this.cluster.apiUrl)
|
||||||
let args = [
|
let args = [
|
||||||
"proxy",
|
"proxy",
|
||||||
"-p", this.port.toString(),
|
|
||||||
"--kubeconfig", this.cluster.kubeconfigPath(),
|
"--kubeconfig", this.cluster.kubeconfigPath(),
|
||||||
"--accept-hosts", clusterUrl.hostname,
|
"--accept-hosts", clusterUrl.hostname,
|
||||||
|
"-u", this.cluster.proxySocketPath(),
|
||||||
]
|
]
|
||||||
if (process.env.DEBUG_PROXY === "true") {
|
if (process.env.DEBUG_PROXY === "true") {
|
||||||
args = args.concat(["-v", "9"])
|
args = args.concat(["-v", "9"])
|
||||||
@ -77,7 +75,19 @@ export class KubeAuthProxy {
|
|||||||
this.sendIpcLogMessage(data.toString(), "stderr")
|
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) {
|
protected parseError(data: string) {
|
||||||
|
|||||||
@ -7,19 +7,25 @@ export class KubeconfigManager {
|
|||||||
protected configDir = app.getPath("temp")
|
protected configDir = app.getPath("temp")
|
||||||
protected kubeconfig: string
|
protected kubeconfig: string
|
||||||
protected tempFile: string
|
protected tempFile: string
|
||||||
|
protected tempProxySocket: string
|
||||||
|
|
||||||
constructor(kubeconfig: string) {
|
constructor(kubeconfig: string) {
|
||||||
this.kubeconfig = kubeconfig
|
this.kubeconfig = kubeconfig
|
||||||
this.tempFile = this.createTemporaryKubeconfig()
|
this.tempFile = this.createTemporaryKubeconfig()
|
||||||
|
this.tempProxySocket = `${this.configDir}${randomFileName("proxy")}.sock`
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPath() {
|
public getPath() {
|
||||||
return this.tempFile
|
return this.tempFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getProxySocketPath() {
|
||||||
|
return this.tempProxySocket
|
||||||
|
}
|
||||||
|
|
||||||
protected createTemporaryKubeconfig(): string {
|
protected createTemporaryKubeconfig(): string {
|
||||||
ensureDir(this.configDir)
|
ensureDir(this.configDir)
|
||||||
const path = `${this.configDir}/${randomFileName("kubeconfig")}`
|
const path = `${this.configDir}${randomFileName("kubeconfig")}`
|
||||||
logger.debug('Creating temporary kubeconfig: ' + path)
|
logger.debug('Creating temporary kubeconfig: ' + path)
|
||||||
fs.writeFileSync(path, this.kubeconfig)
|
fs.writeFileSync(path, this.kubeconfig)
|
||||||
return path
|
return path
|
||||||
@ -28,5 +34,7 @@ export class KubeconfigManager {
|
|||||||
public unlink() {
|
public unlink() {
|
||||||
logger.debug('Deleting temporary kubeconfig: ' + this.tempFile)
|
logger.debug('Deleting temporary kubeconfig: ' + this.tempFile)
|
||||||
fs.unlinkSync(this.tempFile)
|
fs.unlinkSync(this.tempFile)
|
||||||
|
logger.debug('Deleting temporary proxy socket: ' + this.tempFile)
|
||||||
|
fs.unlinkSync(this.tempProxySocket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user