1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

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

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>
This commit is contained in:
Jim Ehrismann 2020-06-23 18:48:14 -04:00
parent 55687b7d35
commit 548a119945
6 changed files with 102 additions and 29 deletions

View File

@ -123,7 +123,7 @@ export class Router {
this.router.add({ method: "post", path: `${apiBase}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)) this.router.add({ method: "post", path: `${apiBase}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute))
// Port-forward API // 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 // Helm API
this.router.add({ method: "get", path: `${apiHelm}/v2/charts` }, helmApi.listCharts.bind(helmApi)) this.router.add({ method: "get", path: `${apiHelm}/v2/charts` }, helmApi.listCharts.bind(helmApi))

View File

@ -14,7 +14,7 @@ class PortForward {
return PortForward.portForwards.find((pf) => { return PortForward.portForwards.find((pf) => {
return ( return (
pf.clusterId == forward.clusterId && pf.clusterId == forward.clusterId &&
pf.kind == "service" && pf.kind == forward.kind &&
pf.name == forward.name && pf.name == forward.name &&
pf.namespace == forward.namespace && pf.namespace == forward.namespace &&
pf.port == forward.port pf.port == forward.port
@ -42,7 +42,7 @@ class PortForward {
"--kubeconfig", this.kubeConfig, "--kubeconfig", this.kubeConfig,
"port-forward", "port-forward",
"-n", this.namespace, "-n", this.namespace,
`service/${this.name}`, `${this.kind}/${this.name}`,
`${this.localPort}:${this.port}` `${this.localPort}:${this.port}`
] ]
@ -72,21 +72,22 @@ class PortForward {
class PortForwardRoute extends LensApi { class PortForwardRoute extends LensApi {
public async routeServicePortForward(request: LensApiRequest) { public async routePortForward(request: LensApiRequest) {
const { params, response, cluster} = request const { params, response, cluster} = request
const { namespace, port, resourceType, resourceName } = params
let portForward = PortForward.getPortforward({ let portForward = PortForward.getPortforward({
clusterId: cluster.id, kind: "service", name: params.service, clusterId: cluster.id, kind: resourceType, name: resourceName,
namespace: params.namespace, port: params.port namespace: namespace, port: port
}) })
if (!portForward) { 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({ portForward = new PortForward({
clusterId: cluster.id, clusterId: cluster.id,
kind: "service", kind: resourceType,
namespace: params.namespace, namespace: namespace,
name: params.service, name: resourceName,
port: params.port, port: port,
kubeConfig: cluster.proxyKubeconfigPath() kubeConfig: cluster.proxyKubeconfigPath()
}) })
const started = await portForward.start() const started = await portForward.start()

View File

@ -22,13 +22,13 @@ export class ServicePorts extends React.Component<Props> {
async portForward(port: ServicePort) { async portForward(port: ServicePort) {
const { service } = this.props; const { service } = this.props;
this.waiting = true; this.waiting = true;
apiBase.post(`/services/${service.getNs()}/${service.getName()}/port-forward/${port.port}`, {}) try {
.catch(error => { await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {})
Notifications.error(error); } catch(error) {
}) Notifications.error(error);
.finally(() => { } finally {
this.waiting = false; this.waiting = false;
}); }
} }
render() { render() {

View File

@ -0,0 +1,24 @@
.PodContainerPorts {
&.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: static;
}
}

View File

@ -0,0 +1,57 @@
import "./pod-container-ports.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;
container: IPodContainer;
}
@observer
export class PodContainerPorts extends React.Component<Props> {
@observable waiting = false;
async portForward(port: number) {
const { pod } = this.props;
this.waiting = true;
try {
await apiBase.post(`/pods/${pod.getNs()}/pod/${pod.getName()}/port-forward/${port}`, {})
} catch(error) {
Notifications.error(error);
} finally {
this.waiting = false;
}
}
render() {
const { container } = this.props;
return (
<div className={cssNames("PodContainerPorts", { waiting: this.waiting })}>
{
container.ports.map((port) => {
const key = `${container.name}-port-${port.containerPort}-${port.protocol}`
const text = (port.name ? port.name + ': ' : '')+`${port.containerPort}/${port.protocol}`
return(
<p key={key}>
<span title={_i18n._(t`Open in a browser`)} onClick={() => this.portForward(port.containerPort) }>
{text}
{this.waiting && (
<Spinner />
)}
</span>
</p>
);
})}
</div>
);
}
}

View File

@ -8,6 +8,7 @@ import { cssNames } from "../../utils";
import { StatusBrick } from "../status-brick"; import { StatusBrick } from "../status-brick";
import { Badge } from "../badge"; import { Badge } from "../badge";
import { ContainerEnvironment } from "./pod-container-env"; import { ContainerEnvironment } from "./pod-container-env";
import { PodContainerPorts } from "./pod-container-ports";
import { ResourceMetrics } from "../resource-metrics"; import { ResourceMetrics } from "../resource-metrics";
import { IMetrics } from "../../api/endpoints/metrics.api"; import { IMetrics } from "../../api/endpoints/metrics.api";
import { ContainerCharts } from "./container-charts"; import { ContainerCharts } from "./container-charts";
@ -63,17 +64,7 @@ export class PodDetailsContainer extends React.Component<Props> {
} }
{ports && ports.length > 0 && {ports && ports.length > 0 &&
<DrawerItem name={<Trans>Ports</Trans>}> <DrawerItem name={<Trans>Ports</Trans>}>
{ <PodContainerPorts pod={pod} container={container}/>
ports.map(port => {
const { name, containerPort, protocol } = port;
const key = `${container.name}-port-${containerPort}-${protocol}`
return (
<div key={key}>
{name ? name + ': ' : ''}{containerPort}/{protocol}
</div>
)
})
}
</DrawerItem> </DrawerItem>
} }
{<ContainerEnvironment container={container} namespace={pod.getNs()}/>} {<ContainerEnvironment container={container} namespace={pod.getNs()}/>}