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))
// 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))

View File

@ -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()

View File

@ -22,13 +22,13 @@ export class ServicePorts extends React.Component<Props> {
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;
});
try {
await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {})
} catch(error) {
Notifications.error(error);
} finally {
this.waiting = false;
}
}
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 { Badge } from "../badge";
import { ContainerEnvironment } from "./pod-container-env";
import { PodContainerPorts } from "./pod-container-ports";
import { ResourceMetrics } from "../resource-metrics";
import { IMetrics } from "../../api/endpoints/metrics.api";
import { ContainerCharts } from "./container-charts";
@ -63,17 +64,7 @@ export class PodDetailsContainer extends React.Component<Props> {
}
{ports && ports.length > 0 &&
<DrawerItem name={<Trans>Ports</Trans>}>
{
ports.map(port => {
const { name, containerPort, protocol } = port;
const key = `${container.name}-port-${containerPort}-${protocol}`
return (
<div key={key}>
{name ? name + ': ' : ''}{containerPort}/{protocol}
</div>
)
})
}
<PodContainerPorts pod={pod} container={container}/>
</DrawerItem>
}
{<ContainerEnvironment container={container} namespace={pod.getNs()}/>}