From 693017d2ec87a971d35a9dc1e628e507737f3e4d Mon Sep 17 00:00:00 2001
From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com>
Date: Fri, 7 Aug 2020 11:30:37 -0400
Subject: [PATCH] adding port-forward for containers in pods (#528)
* adding port-forward for containers in pods
address review comments
use more idiomatic approach for async code
move some files in advance of merge conflict with Lens restructure work
* Separate the port forward links in the UI (so they don't all spin when one link is clicked)
* minor fixes
* addressed review comments (replaced
with
, moved key attribute to proper element)
* fix lint issue
* removed extraneous
from pod container port details
Signed-off-by: Jim Ehrismann
---
src/main/router.ts | 2 +-
src/main/routes/port-forward.ts | 21 ++++----
.../+network-services/service-details.tsx | 10 +++-
.../service-port-component.scss | 22 ++++++++
.../service-port-component.tsx | 48 +++++++++++++++++
.../+network-services/service-ports.scss | 24 ---------
.../+network-services/service-ports.tsx | 54 -------------------
.../+workloads-pods/pod-container-port.scss | 23 ++++++++
.../+workloads-pods/pod-container-port.tsx | 54 +++++++++++++++++++
.../+workloads-pods/pod-details-container.tsx | 12 ++---
10 files changed, 172 insertions(+), 98 deletions(-)
create mode 100644 src/renderer/components/+network-services/service-port-component.scss
create mode 100644 src/renderer/components/+network-services/service-port-component.tsx
delete mode 100644 src/renderer/components/+network-services/service-ports.scss
delete mode 100644 src/renderer/components/+network-services/service-ports.tsx
create mode 100644 src/renderer/components/+workloads-pods/pod-container-port.scss
create mode 100644 src/renderer/components/+workloads-pods/pod-container-port.tsx
diff --git a/src/main/router.ts b/src/main/router.ts
index 9ee3a47c73..3381fa139d 100644
--- a/src/main/router.ts
+++ b/src/main/router.ts
@@ -123,7 +123,7 @@ export class Router {
this.router.add({ method: "post", path: `${apiBase}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute))
// Port-forward API
- this.router.add({ method: "post", path: `${apiBase}/services/{namespace}/{service}/port-forward/{port}` }, portForwardRoute.routeServicePortForward.bind(portForwardRoute))
+ this.router.add({ method: "post", path: `${apiBase}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute))
// Helm API
this.router.add({ method: "get", path: `${apiHelm}/v2/charts` }, helmApi.listCharts.bind(helmApi))
diff --git a/src/main/routes/port-forward.ts b/src/main/routes/port-forward.ts
index 27b1158700..ca222596a1 100644
--- a/src/main/routes/port-forward.ts
+++ b/src/main/routes/port-forward.ts
@@ -14,7 +14,7 @@ class PortForward {
return PortForward.portForwards.find((pf) => {
return (
pf.clusterId == forward.clusterId &&
- pf.kind == "service" &&
+ pf.kind == forward.kind &&
pf.name == forward.name &&
pf.namespace == forward.namespace &&
pf.port == forward.port
@@ -42,7 +42,7 @@ class PortForward {
"--kubeconfig", this.kubeConfig,
"port-forward",
"-n", this.namespace,
- `service/${this.name}`,
+ `${this.kind}/${this.name}`,
`${this.localPort}:${this.port}`
]
@@ -72,21 +72,22 @@ class PortForward {
class PortForwardRoute extends LensApi {
- public async routeServicePortForward(request: LensApiRequest) {
+ public async routePortForward(request: LensApiRequest) {
const { params, response, cluster} = request
+ const { namespace, port, resourceType, resourceName } = params
let portForward = PortForward.getPortforward({
- clusterId: cluster.id, kind: "service", name: params.service,
- namespace: params.namespace, port: params.port
+ clusterId: cluster.id, kind: resourceType, name: resourceName,
+ namespace: namespace, port: port
})
if (!portForward) {
- logger.info(`Creating a new port-forward ${params.namespace}/${params.service}:${params.port}`)
+ logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`)
portForward = new PortForward({
clusterId: cluster.id,
- kind: "service",
- namespace: params.namespace,
- name: params.service,
- port: params.port,
+ kind: resourceType,
+ namespace: namespace,
+ name: resourceName,
+ port: port,
kubeConfig: cluster.proxyKubeconfigPath()
})
const started = await portForward.start()
diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx
index 0c158c9e6b..df37d6238e 100644
--- a/src/renderer/components/+network-services/service-details.tsx
+++ b/src/renderer/components/+network-services/service-details.tsx
@@ -11,7 +11,7 @@ import { Service, serviceApi, endpointApi } from "../../api/endpoints";
import { _i18n } from "../../i18n";
import { apiManager } from "../../api/api-manager";
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
-import { ServicePorts } from "./service-ports";
+import { ServicePortComponent } from "./service-port-component";
import { endpointStore } from "../+network-endpoints/endpoints.store";
import { ServiceDetailsEndpoint } from "./service-details-endpoint";
@@ -61,7 +61,13 @@ export class ServiceDetails extends React.Component {
)}
Ports}>
-
+
+ {
+ service.getPorts().map((port) => (
+
+ ))
+ }
+
{spec.type === "LoadBalancer" && spec.loadBalancerIP && (
diff --git a/src/renderer/components/+network-services/service-port-component.scss b/src/renderer/components/+network-services/service-port-component.scss
new file mode 100644
index 0000000000..0e9945631d
--- /dev/null
+++ b/src/renderer/components/+network-services/service-port-component.scss
@@ -0,0 +1,22 @@
+.ServicePortComponent {
+ &.waiting {
+ opacity: 0.5;
+ pointer-events: none;
+ }
+
+ &:not(:last-child) {
+ margin-bottom: $margin;
+ }
+
+ span {
+ cursor: pointer;
+ color: $primary;
+ text-decoration: underline;
+ }
+
+ .Spinner {
+ --spinner-size: #{$unit * 2};
+ margin-left: $margin;
+ position: absolute;
+ }
+}
diff --git a/src/renderer/components/+network-services/service-port-component.tsx b/src/renderer/components/+network-services/service-port-component.tsx
new file mode 100644
index 0000000000..252bf8eb16
--- /dev/null
+++ b/src/renderer/components/+network-services/service-port-component.tsx
@@ -0,0 +1,48 @@
+import "./service-port-component.scss"
+
+import React from "react";
+import { observer } from "mobx-react";
+import { t } from "@lingui/macro";
+import { Service, ServicePort } from "../../api/endpoints";
+import { _i18n } from "../../i18n";
+import { apiBase } from "../../api"
+import { observable } from "mobx";
+import { cssNames } from "../../utils";
+import { Notifications } from "../notifications";
+import { Spinner } from "../spinner"
+
+interface Props {
+ service: Service;
+ port: ServicePort;
+}
+
+@observer
+export class ServicePortComponent extends React.Component {
+ @observable waiting = false;
+
+ async portForward() {
+ const { service, port } = this.props;
+ this.waiting = true;
+ try {
+ await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {})
+ } catch(error) {
+ Notifications.error(error);
+ } finally {
+ this.waiting = false;
+ }
+ }
+
+ render() {
+ const { port } = this.props;
+ return (
+
+ this.portForward() }>
+ {port.toString()}
+ {this.waiting && (
+
+ )}
+
+
+ );
+ }
+}
diff --git a/src/renderer/components/+network-services/service-ports.scss b/src/renderer/components/+network-services/service-ports.scss
deleted file mode 100644
index 5a683af86c..0000000000
--- a/src/renderer/components/+network-services/service-ports.scss
+++ /dev/null
@@ -1,24 +0,0 @@
-.ServicePorts {
- &.waiting {
- opacity: 0.5;
- pointer-events: none;
- }
-
- p {
- &:not(:last-child) {
- margin-bottom: $margin;
- }
-
- span {
- cursor: pointer;
- color: $primary;
- text-decoration: underline;
- }
- }
-
- .Spinner {
- --spinner-size: #{$unit * 2};
- margin-left: $margin;
- position: absolute;
- }
-}
diff --git a/src/renderer/components/+network-services/service-ports.tsx b/src/renderer/components/+network-services/service-ports.tsx
deleted file mode 100644
index 3335be6907..0000000000
--- a/src/renderer/components/+network-services/service-ports.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import "./service-ports.scss"
-
-import React from "react";
-import { observer } from "mobx-react";
-import { t } from "@lingui/macro";
-import { Service, ServicePort } from "../../api/endpoints";
-import { _i18n } from "../../i18n";
-import { apiBase } from "../../api"
-import { observable } from "mobx";
-import { cssNames } from "../../utils";
-import { Notifications } from "../notifications";
-import { Spinner } from "../spinner"
-
-interface Props {
- service: Service;
-}
-
-@observer
-export class ServicePorts extends React.Component {
- @observable waiting = false;
-
- async portForward(port: ServicePort) {
- const { service } = this.props;
- this.waiting = true;
- apiBase.post(`/services/${service.getNs()}/${service.getName()}/port-forward/${port.port}`, {})
- .catch(error => {
- Notifications.error(error);
- })
- .finally(() => {
- this.waiting = false;
- });
- }
-
- render() {
- const { service } = this.props;
- return (
-
- {
- service.getPorts().map((port) => {
- return(
-
- this.portForward(port) }>
- {port.toString()}
- {this.waiting && (
-
- )}
-
-
- );
- })}
-
- );
- }
-}
diff --git a/src/renderer/components/+workloads-pods/pod-container-port.scss b/src/renderer/components/+workloads-pods/pod-container-port.scss
new file mode 100644
index 0000000000..081f0b1090
--- /dev/null
+++ b/src/renderer/components/+workloads-pods/pod-container-port.scss
@@ -0,0 +1,23 @@
+.PodContainerPort {
+ &.waiting {
+ opacity: 0.5;
+ pointer-events: none;
+ }
+
+ &:not(:last-child) {
+ margin-bottom: $margin;
+ }
+
+ span {
+ cursor: pointer;
+ color: $primary;
+ text-decoration: underline;
+ position: relative;
+ }
+
+ .Spinner {
+ --spinner-size: #{$unit * 2};
+ margin-left: $margin;
+ position: absolute;
+ }
+}
\ No newline at end of file
diff --git a/src/renderer/components/+workloads-pods/pod-container-port.tsx b/src/renderer/components/+workloads-pods/pod-container-port.tsx
new file mode 100644
index 0000000000..9ebaed4fd7
--- /dev/null
+++ b/src/renderer/components/+workloads-pods/pod-container-port.tsx
@@ -0,0 +1,54 @@
+import "./pod-container-port.scss"
+
+import React from "react";
+import { observer } from "mobx-react";
+import { t } from "@lingui/macro";
+import { Pod, IPodContainer } from "../../api/endpoints";
+import { _i18n } from "../../i18n";
+import { apiBase } from "../../api"
+import { observable } from "mobx";
+import { cssNames } from "../../utils";
+import { Notifications } from "../notifications";
+import { Spinner } from "../spinner"
+
+interface Props {
+ pod: Pod;
+ port: {
+ name?: string;
+ containerPort: number;
+ protocol: string;
+ }
+}
+
+@observer
+export class PodContainerPort extends React.Component {
+ @observable waiting = false;
+
+ async portForward() {
+ const { pod, port } = this.props;
+ this.waiting = true;
+ try {
+ await apiBase.post(`/pods/${pod.getNs()}/pod/${pod.getName()}/port-forward/${port.containerPort}`, {})
+ } catch(error) {
+ Notifications.error(error);
+ } finally {
+ this.waiting = false;
+ }
+ }
+
+ render() {
+ const { port } = this.props;
+ const { name, containerPort, protocol } = port;
+ const text = (name ? name + ': ' : '')+`${containerPort}/${protocol}`
+ return (
+
+ this.portForward() }>
+ {text}
+ {this.waiting && (
+
+ )}
+
+
+ )
+ }
+}
diff --git a/src/renderer/components/+workloads-pods/pod-details-container.tsx b/src/renderer/components/+workloads-pods/pod-details-container.tsx
index a5cdcc1fbd..79180b1130 100644
--- a/src/renderer/components/+workloads-pods/pod-details-container.tsx
+++ b/src/renderer/components/+workloads-pods/pod-details-container.tsx
@@ -8,6 +8,7 @@ import { cssNames } from "../../utils";
import { StatusBrick } from "../status-brick";
import { Badge } from "../badge";
import { ContainerEnvironment } from "./pod-container-env";
+import { PodContainerPort } from "./pod-container-port";
import { ResourceMetrics } from "../resource-metrics";
import { IMetrics } from "../../api/endpoints/metrics.api";
import { ContainerCharts } from "./container-charts";
@@ -64,13 +65,10 @@ export class PodDetailsContainer extends React.Component {
{ports && ports.length > 0 &&
Ports}>
{
- ports.map(port => {
- const { name, containerPort, protocol } = port;
- const key = `${container.name}-port-${containerPort}-${protocol}`
- return (
-
- {name ? name + ': ' : ''}{containerPort}/{protocol}
-
+ ports.map((port) => {
+ const key = `${container.name}-port-${port.containerPort}-${port.protocol}`
+ return(
+
)
})
}