mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Inject Host header to k8s client requests (#887)
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
ec4d859ef7
commit
c2afd026cc
6 files changed
+118
-32
No files matched your search
@@ -44,7 +44,7 @@ export class ClusterManager {
|
||||
// lens-server is connecting to 127.0.0.1:<port>/<uid>
|
||||
if (req.headers.host.startsWith("127.0.0.1")) {
|
||||
const clusterId = req.url.split("/")[1]
|
||||
const cluster = clusterStore.getById(clusterId)
|
||||
cluster = clusterStore.getById(clusterId)
|
||||
if (cluster) {
|
||||
// we need to swap path prefix so that request is proxied to kube api
|
||||
req.url = req.url.replace(`/${clusterId}`, apiKubePrefix)
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ export class Cluster implements ClusterModel {
|
||||
async init(port: number) {
|
||||
try {
|
||||
this.contextHandler = new ContextHandler(this);
|
||||
this.kubeconfigManager = new KubeconfigManager(this, this.contextHandler);
|
||||
this.kubeconfigManager = new KubeconfigManager(this, this.contextHandler, port);
|
||||
this.kubeProxyUrl = `http://localhost:${port}${apiKubePrefix}`;
|
||||
this.initialized = true;
|
||||
logger.info(`[CLUSTER]: "${this.contextName}" init success`, {
|
||||
|
||||
@@ -11,7 +11,7 @@ export class KubeconfigManager {
|
||||
protected configDir = app.getPath("temp")
|
||||
protected tempFile: string;
|
||||
|
||||
constructor(protected cluster: Cluster, protected contextHandler: ContextHandler) {
|
||||
constructor(protected cluster: Cluster, protected contextHandler: ContextHandler, protected port: number) {
|
||||
this.init();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ export class KubeconfigManager {
|
||||
return this.tempFile;
|
||||
}
|
||||
|
||||
protected resolveProxyUrl() {
|
||||
return `http://127.0.0.1:${this.port}/${this.cluster.id}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new "temporary" kubeconfig that point to the kubectl-proxy.
|
||||
* This way any user of the config does not need to know anything about the auth etc. details.
|
||||
@@ -42,7 +46,7 @@ export class KubeconfigManager {
|
||||
clusters: [
|
||||
{
|
||||
name: contextName,
|
||||
server: await contextHandler.resolveAuthProxyUrl(),
|
||||
server: this.resolveProxyUrl(),
|
||||
skipTLSVerify: undefined,
|
||||
}
|
||||
],
|
||||
|
||||
+40
-27
@@ -1,13 +1,14 @@
|
||||
import net from "net";
|
||||
import http from "http";
|
||||
import spdy from "spdy";
|
||||
import httpProxy from "http-proxy";
|
||||
import url from "url";
|
||||
import * as WebSocket from "ws"
|
||||
import { apiPrefix, apiKubePrefix } from "../common/vars"
|
||||
import { openShell } from "./node-shell-session";
|
||||
import { Router } from "./router"
|
||||
import { ClusterManager } from "./cluster-manager"
|
||||
import { ContextHandler } from "./context-handler";
|
||||
import { apiKubePrefix } from "../common/vars";
|
||||
import logger from "./logger"
|
||||
|
||||
export class LensProxy {
|
||||
@@ -40,37 +41,49 @@ export class LensProxy {
|
||||
|
||||
protected buildCustomProxy(): http.Server {
|
||||
const proxy = this.createProxy();
|
||||
const customProxy = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
this.handleRequest(proxy, req, res);
|
||||
});
|
||||
customProxy.on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
|
||||
this.handleWsUpgrade(req, socket, head)
|
||||
});
|
||||
customProxy.on("error", (err) => {
|
||||
const spdyProxy = spdy.createServer({
|
||||
spdy: {
|
||||
plain: true,
|
||||
connection: {
|
||||
autoSpdy31: true
|
||||
}
|
||||
}
|
||||
}, (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
this.handleRequest(proxy, req, res)
|
||||
})
|
||||
spdyProxy.on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
|
||||
if (req.url.startsWith(`${apiPrefix}/?`)) {
|
||||
this.handleWsUpgrade(req, socket, head)
|
||||
} else {
|
||||
if (req.headers.upgrade?.startsWith("SPDY")) {
|
||||
this.handleSpdyProxy(proxy, req, socket, head)
|
||||
} else {
|
||||
socket.end()
|
||||
}
|
||||
}
|
||||
})
|
||||
spdyProxy.on("error", (err) => {
|
||||
logger.error("proxy error", err)
|
||||
});
|
||||
return customProxy;
|
||||
})
|
||||
return spdyProxy
|
||||
}
|
||||
|
||||
protected async handleSpdyProxy(proxy: httpProxy, req: http.IncomingMessage, socket: net.Socket, head: Buffer) {
|
||||
const cluster = this.clusterManager.getClusterForRequest(req)
|
||||
if (cluster) {
|
||||
const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, "")
|
||||
const apiUrl = url.parse(cluster.apiUrl)
|
||||
const res = new http.ServerResponse(req)
|
||||
res.assignSocket(socket)
|
||||
res.setHeader("Location", proxyUrl)
|
||||
res.setHeader("Host", apiUrl.hostname)
|
||||
res.statusCode = 302
|
||||
res.end()
|
||||
}
|
||||
}
|
||||
|
||||
protected createProxy(): httpProxy {
|
||||
const proxy = httpProxy.createProxyServer();
|
||||
proxy.on("proxyRes", (proxyRes, req, res) => {
|
||||
if (req.method !== "GET") {
|
||||
return;
|
||||
}
|
||||
if (proxyRes.statusCode === 502) {
|
||||
const cluster = this.clusterManager.getClusterForRequest(req)
|
||||
const proxyError = cluster?.contextHandler.proxyLastError;
|
||||
if (proxyError) {
|
||||
return res.writeHead(502).end(proxyError);
|
||||
}
|
||||
}
|
||||
const reqId = this.getRequestId(req);
|
||||
if (this.retryCounters.has(reqId)) {
|
||||
logger.debug(`Resetting proxy retry cache for url: ${reqId}`);
|
||||
this.retryCounters.delete(reqId)
|
||||
}
|
||||
})
|
||||
proxy.on("error", (error, req, res, target) => {
|
||||
if (this.closed) {
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user