diff --git a/src/main/router.ts b/src/main/router.ts index 50175aa9de..16fed03734 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -180,7 +180,9 @@ export class Router { this.router.add({ method: "get", path: `${apiPrefix}/metrics/providers` }, MetricsRoute.routeMetricsProviders); // Port-forward API - this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, PortForwardRoute.routePortForward); + this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}/{forwardPort}` }, PortForwardRoute.routePortForward); + this.router.add({ method: "get", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}/{forwardPort}` }, PortForwardRoute.routeCurrentPortForward); + this.router.add({ method: "delete", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}/{forwardPort}` }, PortForwardRoute.routeCurrentPortForwardStop); // Helm API this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, HelmApiRoute.listCharts); diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index e97b4171cb..c9e3036e86 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -34,6 +34,7 @@ interface PortForwardArgs { namespace: string; name: string; port: string; + forwardPort: string; } const internalPortRegex = /^forwarding from (?
.+) ->/i; @@ -58,6 +59,7 @@ class PortForward { public name: string; public port: string; public internalPort?: number; + public forwardPort?: string; constructor(public kubeConfig: string, args: PortForwardArgs) { this.clusterId = args.clusterId; @@ -65,6 +67,7 @@ class PortForward { this.namespace = args.namespace; this.name = args.name; this.port = args.port; + this.forwardPort = args.forwardPort; } public async start() { @@ -74,7 +77,7 @@ class PortForward { "port-forward", "-n", this.namespace, `${this.kind}/${this.name}`, - `:${this.port}` + `${this.forwardPort??""}:${this.port}` ]; this.process = spawn(kubectlBin, args, { @@ -104,6 +107,10 @@ class PortForward { } } + public async stop() { + this.process.kill(); + } + public open() { shell.openExternal(`http://localhost:${this.internalPort}`) .catch(error => logger.error(`[PORT-FORWARD]: failed to open external shell: ${error}`, { @@ -118,44 +125,74 @@ class PortForward { export class PortForwardRoute { static async routePortForward(request: LensApiRequest) { - const { params, response, cluster} = request; - const { namespace, port, resourceType, resourceName } = params; - let portForward = PortForward.getPortforward({ - clusterId: cluster.id, kind: resourceType, name: resourceName, - namespace, port - }); + const { params, response, cluster } = request; + const { namespace, port, forwardPort, resourceType, resourceName } = params; - if (!portForward) { - logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`); - portForward = new PortForward(await cluster.getProxyKubeconfigPath(), { - clusterId: cluster.id, - kind: resourceType, - namespace, - name: resourceName, - port, + try { + let portForward = PortForward.getPortforward({ + clusterId: cluster.id, kind: resourceType, name: resourceName, + namespace, port, forwardPort, }); - try { + if (!portForward) { + logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`); + portForward = new PortForward(await cluster.getProxyKubeconfigPath(), { + clusterId: cluster.id, + kind: resourceType, + namespace, + name: resourceName, + port, + forwardPort + }); + const started = await portForward.start(); if (!started) { - logger.warn("[PORT-FORWARD-ROUTE]: failed to start a port-forward", { namespace, port, resourceType, resourceName }); + logger.error("[PORT-FORWARD-ROUTE]: failed to start a port-forward", { namespace, port, resourceType, resourceName }); return respondJson(response, { - message: "Failed to open port-forward" + message: `Failed to forward port ${port}` }, 400); } - } catch (error) { - logger.warn(`[PORT-FORWARD-ROUTE]: failed to open a port-forward: ${error}`, { namespace, port, resourceType, resourceName }); - - return respondJson(response, { - message: error?.toString() || "Failed to open port-forward", - }, 400); } + + portForward.open(); + respondJson(response, {port: portForward.internalPort}); + } catch (error) { + logger.error(`[PORT-FORWARD-ROUTE]: failed to open a port-forward: ${error}`, { namespace, port, resourceType, resourceName }); + + return respondJson(response, { + message: `Failed to forward port ${port}` + }, 400); } + } - portForward.open(); + static async routeCurrentPortForward(request: LensApiRequest) { + const { params, response, cluster} = request; + const { namespace, port, forwardPort, resourceType, resourceName } = params; - respondJson(response, {}); + const portForward = PortForward.getPortforward({ + clusterId: cluster.id, kind: resourceType, name: resourceName, + namespace, port, forwardPort + }); + + respondJson(response, {port: portForward?.internalPort?? null}); + } + + static async routeCurrentPortForwardStop(request: LensApiRequest) { + const { params, response, cluster} = request; + const { namespace, port, forwardPort, resourceType, resourceName } = params; + + const portForward = PortForward.getPortforward({ + clusterId: cluster.id, kind: resourceType, name: resourceName, + namespace, port, forwardPort, + }); + + try { + await portForward.stop(); + respondJson(response, {status: true}); + } catch (error) { + logger.error(error); + } } } diff --git a/src/renderer/components/+network-services/service-port-component.scss b/src/renderer/components/+network-services/service-port-component.scss index 89369f560f..579edc7c2c 100644 --- a/src/renderer/components/+network-services/service-port-component.scss +++ b/src/renderer/components/+network-services/service-port-component.scss @@ -35,9 +35,10 @@ text-decoration: underline; } - .Spinner { - --spinner-size: #{$unit * 2}; - margin-left: $margin; - position: absolute; + .portInput { + display: inline-block !important; + width: 70px; + margin-left: 10px; + margin-right: 10px; } } diff --git a/src/renderer/components/+network-services/service-port-component.tsx b/src/renderer/components/+network-services/service-port-component.tsx index 96bb7385cb..6ad22a9dd3 100644 --- a/src/renderer/components/+network-services/service-port-component.tsx +++ b/src/renderer/components/+network-services/service-port-component.tsx @@ -28,20 +28,46 @@ import { apiBase } from "../../api"; import { observable, makeObservable } from "mobx"; import { cssNames } from "../../utils"; import { Notifications } from "../notifications"; -import { Spinner } from "../spinner"; +import { Input } from "../input"; +import { Button } from "../button"; interface Props { service: Service; port: ServicePort; } +interface PortForwardResult { + port: number; +} + @observer export class ServicePortComponent extends React.Component