Keep port-forward objects around when not running (#4607)

* adding disabled status to port forwards (WIP)

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* more work

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* almost working

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* working

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* refactoring and bug fixing, still issue with port-forward-dialog

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* further refactoring and bug fixing

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* fixed remaining issues around port-forward dialog, changed port-forward-item id to resource name, etc from local port

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* documentation, more cleanup

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>

* address review comments

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>
This commit is contained in:
Jim Ehrismann authored and GitHub committed 2022-01-10 10:00:10 -05:00
1 parent fa3708c879
commit 446eb5ca43
12 files changed
+405 -162

No files matched your search

@@ -24,13 +24,14 @@ import "./service-port-component.scss";
import React from "react";
import { disposeOnUnmount, observer } from "mobx-react";
import type { Service, ServicePort } from "../../../common/k8s-api/endpoints";
import { observable, makeObservable, reaction } from "mobx";
import { observable, makeObservable, reaction, action } from "mobx";
import { cssNames } from "../../utils";
import { Notifications } from "../notifications";
import { Button } from "../button";
import { aboutPortForwarding, addPortForward, getPortForward, getPortForwards, openPortForward, PortForwardDialog, portForwardStore, predictProtocol, removePortForward } from "../../port-forward";
import { aboutPortForwarding, addPortForward, getPortForward, getPortForwards, notifyErrorPortForwarding, openPortForward, PortForwardDialog, predictProtocol, removePortForward, startPortForward } from "../../port-forward";
import type { ForwardedPort } from "../../port-forward";
import { Spinner } from "../spinner";
import logger from "../../../common/logger";
interface Props {
service: Service;
@@ -42,6 +43,7 @@ export class ServicePortComponent extends React.Component<Props> {
@observable waiting = false;
@observable forwardPort = 0;
@observable isPortForwarded = false;
@observable isActive = false;
constructor(props: Props) {
super(props);
@@ -51,13 +53,14 @@ export class ServicePortComponent extends React.Component<Props> {
componentDidMount() {
disposeOnUnmount(this, [
reaction(() => [portForwardStore.portForwards, this.props.service], () => this.checkExistingPortForwarding()),
reaction(() => this.props.service, () => this.checkExistingPortForwarding()),
]);
}
@action
async checkExistingPortForwarding() {
const { service, port } = this.props;
const portForward: ForwardedPort = {
let portForward: ForwardedPort = {
kind: "service",
name: service.getName(),
namespace: service.getNs(),
@@ -65,57 +68,66 @@ export class ServicePortComponent extends React.Component<Props> {
forwardPort: this.forwardPort,
};
let activePort: number;
try {
activePort = await getPortForward(portForward) ?? 0;
portForward = await getPortForward(portForward);
} catch (error) {
this.isPortForwarded = false;
this.isActive = false;
return;
}
this.forwardPort = activePort;
this.isPortForwarded = activePort ? true : false;
this.forwardPort = portForward.forwardPort;
this.isPortForwarded = true;
this.isActive = portForward.status === "Active";
}
@action
async portForward() {
const { service, port } = this.props;
const portForward: ForwardedPort = {
let portForward: ForwardedPort = {
kind: "service",
name: service.getName(),
namespace: service.getNs(),
port: port.port,
forwardPort: this.forwardPort,
protocol: predictProtocol(port.name),
status: "Active",
};
this.waiting = true;
try {
// determine how many port-forwards are already active
const { length } = await getPortForwards();
// determine how many port-forwards already exist
const { length } = getPortForwards();
this.forwardPort = await addPortForward(portForward);
if (!this.isPortForwarded) {
portForward = await addPortForward(portForward);
} else if (!this.isActive) {
portForward = await startPortForward(portForward);
}
if (this.forwardPort) {
portForward.forwardPort = this.forwardPort;
this.forwardPort = portForward.forwardPort;
if (portForward.status === "Active") {
openPortForward(portForward);
this.isPortForwarded = true;
// if this is the first port-forward show the about notification
if (!length) {
aboutPortForwarding();
}
} else {
notifyErrorPortForwarding(`Error occurred starting port-forward, the local port may not be available or the ${portForward.kind} ${portForward.name} may not be reachable`);
}
} catch (error) {
Notifications.error(`Error occurred starting port-forward, the local port may not be available or the ${portForward.kind} ${portForward.name} may not be reachable`);
this.checkExistingPortForwarding();
logger.error("[SERVICE-PORT-COMPONENT]:", error, portForward);
} finally {
this.checkExistingPortForwarding();
this.waiting = false;
}
}
@action
async stopPortForward() {
const { service, port } = this.props;
const portForward: ForwardedPort = {
@@ -130,11 +142,11 @@ export class ServicePortComponent extends React.Component<Props> {
try {
await removePortForward(portForward);
this.isPortForwarded = false;
} catch (error) {
Notifications.error(`Error occurred stopping the port-forward from port ${portForward.forwardPort}.`);
this.checkExistingPortForwarding();
} finally {
this.checkExistingPortForwarding();
this.forwardPort = 0;
this.waiting = false;
}
}
@@ -142,7 +154,7 @@ export class ServicePortComponent extends React.Component<Props> {
render() {
const { port, service } = this.props;
const portForwardAction = async () => {
const portForwardAction = action(async () => {
if (this.isPortForwarded) {
await this.stopPortForward();
} else {
@@ -155,16 +167,16 @@ export class ServicePortComponent extends React.Component<Props> {
protocol: predictProtocol(port.name),
};
PortForwardDialog.open(portForward, { openInBrowser: true });
PortForwardDialog.open(portForward, { openInBrowser: true, onClose: () => this.checkExistingPortForwarding() });
}
};
});
return (
<div className={cssNames("ServicePortComponent", { waiting: this.waiting })}>
<span title="Open in a browser" onClick={() => this.portForward()}>
{port.toString()}
</span>
<Button primary onClick={() => portForwardAction()}> {this.isPortForwarded ? "Stop" : "Forward..."} </Button>
<Button primary onClick={portForwardAction}> {this.isPortForwarded ? (this.isActive ? "Stop/Remove" : "Remove") : "Forward..."} </Button>
{this.waiting && (
<Spinner />
)}