Cleanup 'Cluster' to remove environment specific details (#6951)

- requestNamespaceListPermissions is infallable so no need to have the extra try/catch

- Refactor isMetricHidden method away from Cluster

- Refactor shouldShowResource out of Cluster

- Refactor isInLocalKubeconfig out of Cluster

- Remove depecrated and unused workspace from Cluster

- Refactor out kubectl as a dependency of Cluster

- Remove from cluster getter used only once

- Split out ClusterConnection from Cluster

- Also split out KubeAuthProxyServer from ContextHandler

- Rename ContextHandler to PrometheusHandler

- Cleanup onNetworkOffline/Online impls within ClusterManager

- Remove annotations from ClusterConnection

- Remove mobx annotations from Cluster

- Rename loadConfigFromFileInjectable

- Remove all uses of dead createClusterInjectionToken

- Fix type errors related to broadcastConnectionUpdate

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton authored and GitHub committed 2023-03-10 09:37:39 +02:00
1 parent e6d6d1d8f7
commit ad9bafe2a5
133 files changed
+2544 -1961

No files matched your search

@@ -4,7 +4,6 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { LensProxy } from "./lens-proxy";
import { kubeApiUpgradeRequest } from "./proxy-functions";
import routerInjectable from "../router/router.injectable";
import httpProxy from "http-proxy";
import shellApiRequestInjectable from "./proxy-functions/shell-api-request.injectable";
@@ -14,6 +13,8 @@ import emitAppEventInjectable from "../../common/app-event-bus/emit-event.inject
import loggerInjectable from "../../common/logger.injectable";
import lensProxyCertificateInjectable from "../../common/certificate/lens-proxy-certificate.injectable";
import getClusterForRequestInjectable from "./get-cluster-for-request.injectable";
import kubeAuthProxyServerInjectable from "../cluster/kube-auth-proxy-server.injectable";
import kubeApiUpgradeRequestInjectable from "./proxy-functions/kube-api-upgrade-request.injectable";
const lensProxyInjectable = getInjectable({
id: "lens-proxy",
@@ -21,7 +22,7 @@ const lensProxyInjectable = getInjectable({
instantiate: (di) => new LensProxy({
router: di.inject(routerInjectable),
proxy: httpProxy.createProxy(),
kubeApiUpgradeRequest,
kubeApiUpgradeRequest: di.inject(kubeApiUpgradeRequestInjectable),
shellApiRequest: di.inject(shellApiRequestInjectable),
getClusterForRequest: di.inject(getClusterForRequestInjectable),
lensProxyPort: di.inject(lensProxyPortInjectable),
@@ -29,6 +30,7 @@ const lensProxyInjectable = getInjectable({
emitAppEvent: di.inject(emitAppEventInjectable),
logger: di.inject(loggerInjectable),
certificate: di.inject(lensProxyCertificateInjectable).get(),
getKubeAuthProxyServer: (cluster) => di.inject(kubeAuthProxyServerInjectable, cluster),
}),
});
@@ -9,7 +9,6 @@ import type http from "http";
import type httpProxy from "http-proxy";
import { apiPrefix, apiKubePrefix } from "../../common/vars";
import type { Router } from "../router/router";
import type { ClusterContextHandler } from "../context-handler/context-handler";
import type { Cluster } from "../../common/cluster/cluster";
import type { ProxyApiRequestArgs } from "./proxy-functions";
import { getBoolean } from "../utils/parse-query";
@@ -18,6 +17,7 @@ import type { SetRequired } from "type-fest";
import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable";
import type { Logger } from "../../common/logger";
import type { SelfSignedCert } from "selfsigned";
import type { KubeAuthProxyServer } from "../cluster/kube-auth-proxy-server.injectable";
export type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | undefined;
export type ServerIncomingMessage = SetRequired<http.IncomingMessage, "url" | "method">;
@@ -28,6 +28,7 @@ interface Dependencies {
shellApiRequest: LensProxyApiRequest;
kubeApiUpgradeRequest: LensProxyApiRequest;
emitAppEvent: EmitAppEvent;
getKubeAuthProxyServer: (cluster: Cluster) => KubeAuthProxyServer;
readonly router: Router;
readonly proxy: httpProxy;
readonly lensProxyPort: { set: (portNumber: number) => void };
@@ -220,15 +221,6 @@ export class LensProxy {
return proxy;
}
protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ClusterContextHandler): Promise<httpProxy.ServerOptions | void> {
if (req.url?.startsWith(apiKubePrefix)) {
delete req.headers.authorization;
req.url = req.url.replace(apiKubePrefix, "");
return contextHandler.getApiTarget(isLongRunningRequest(req.url));
}
}
protected getRequestId(req: http.IncomingMessage): string {
assert(req.headers.host);
@@ -238,8 +230,12 @@ export class LensProxy {
protected async handleRequest(req: ServerIncomingMessage, res: http.ServerResponse) {
const cluster = this.dependencies.getClusterForRequest(req);
if (cluster) {
const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler);
if (cluster && req.url.startsWith(apiKubePrefix)) {
delete req.headers.authorization;
req.url = req.url.replace(apiKubePrefix, "");
const kubeAuthProxyServer = this.dependencies.getKubeAuthProxyServer(cluster);
const proxyTarget = await kubeAuthProxyServer.getApiTarget(isLongRunningRequest(req.url));
if (proxyTarget) {
return this.dependencies.proxy.web(req, res, proxyTarget);
@@ -2,5 +2,4 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export * from "./kube-api-upgrade-request";
export * from "./types";
@@ -0,0 +1,78 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { chunk } from "lodash";
import type { ConnectionOptions } from "tls";
import { connect } from "tls";
import url, { URL } from "url";
import { apiKubePrefix } from "../../../common/vars";
import { getInjectable } from "@ogre-tools/injectable";
import type { LensProxyApiRequest } from "../lens-proxy";
import kubeAuthProxyServerInjectable from "../../cluster/kube-auth-proxy-server.injectable";
import kubeAuthProxyCertificateInjectable from "../../kube-auth-proxy/kube-auth-proxy-certificate.injectable";
const skipRawHeaders = new Set(["Host", "Authorization"]);
const kubeApiUpgradeRequestInjectable = getInjectable({
id: "kube-api-upgrade-request",
instantiate: (di): LensProxyApiRequest => async ({ req, socket, head, cluster }) => {
const clusterUrl = new URL(cluster.apiUrl.get());
const kubeAuthProxyServer = di.inject(kubeAuthProxyServerInjectable, cluster);
const kubeAuthProxyCertificate = di.inject(kubeAuthProxyCertificateInjectable, clusterUrl.hostname);
const proxyUrl = await kubeAuthProxyServer.ensureAuthProxyUrl() + req.url.replace(apiKubePrefix, "");
const apiUrl = url.parse(cluster.apiUrl.get());
const pUrl = url.parse(proxyUrl);
const connectOpts: ConnectionOptions = {
port: pUrl.port ? parseInt(pUrl.port) : undefined,
host: pUrl.hostname ?? undefined,
ca: kubeAuthProxyCertificate.cert,
};
const proxySocket = connect(connectOpts, () => {
proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`);
proxySocket.write(`Host: ${apiUrl.host}\r\n`);
for (const [key, value] of chunk(req.rawHeaders, 2)) {
if (skipRawHeaders.has(key)) {
continue;
}
proxySocket.write(`${key}: ${value}\r\n`);
}
proxySocket.write("\r\n");
proxySocket.write(head);
});
proxySocket.setKeepAlive(true);
socket.setKeepAlive(true);
proxySocket.setTimeout(0);
socket.setTimeout(0);
proxySocket.on("data", function (chunk) {
socket.write(chunk);
});
proxySocket.on("end", function () {
socket.end();
});
proxySocket.on("error", function () {
socket.write(`HTTP/${req.httpVersion} 500 Connection error\r\n\r\n`);
socket.end();
});
socket.on("data", function (chunk) {
proxySocket.write(chunk);
});
socket.on("end", function () {
proxySocket.end();
});
socket.on("error", function () {
proxySocket.end();
});
},
});
export default kubeApiUpgradeRequestInjectable;
@@ -1,66 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { chunk } from "lodash";
import type { ConnectionOptions } from "tls";
import { connect } from "tls";
import url from "url";
import { apiKubePrefix } from "../../../common/vars";
import type { ProxyApiRequestArgs } from "./types";
const skipRawHeaders = new Set(["Host", "Authorization"]);
export async function kubeApiUpgradeRequest({ req, socket, head, cluster }: ProxyApiRequestArgs) {
const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, "");
const proxyCa = cluster.contextHandler.resolveAuthProxyCa();
const apiUrl = url.parse(cluster.apiUrl);
const pUrl = url.parse(proxyUrl);
const connectOpts: ConnectionOptions = {
port: pUrl.port ? parseInt(pUrl.port) : undefined,
host: pUrl.hostname ?? undefined,
ca: proxyCa,
};
const proxySocket = connect(connectOpts, () => {
proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`);
proxySocket.write(`Host: ${apiUrl.host}\r\n`);
for (const [key, value] of chunk(req.rawHeaders, 2)) {
if (skipRawHeaders.has(key)) {
continue;
}
proxySocket.write(`${key}: ${value}\r\n`);
}
proxySocket.write("\r\n");
proxySocket.write(head);
});
proxySocket.setKeepAlive(true);
socket.setKeepAlive(true);
proxySocket.setTimeout(0);
socket.setTimeout(0);
proxySocket.on("data", function (chunk) {
socket.write(chunk);
});
proxySocket.on("end", function () {
socket.end();
});
proxySocket.on("error", function () {
socket.write(`HTTP/${req.httpVersion} 500 Connection error\r\n\r\n`);
socket.end();
});
socket.on("data", function (chunk) {
proxySocket.write(chunk);
});
socket.on("end", function () {
proxySocket.end();
});
socket.on("error", function () {
proxySocket.end();
});
}