From 8081d35f9c24a1070abb4fc0f8047b29149e5c31 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 23 Nov 2021 14:34:37 -0500 Subject: [PATCH] Broadcast cluster's disconnected state before stopping KubeAuthProxy (#4273) --- integration/__tests__/cluster-pages.tests.ts | 5 +++- integration/helpers/utils.ts | 15 ++++++------ src/main/__test__/cluster.test.ts | 21 +++++++++++++++++ .../__test__/kubeconfig-sync.test.ts | 1 + src/main/cluster.ts | 23 ++++++++----------- src/main/kube-auth-proxy.ts | 4 ++-- .../components/cluster-manager/lens-views.ts | 2 ++ 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index 64ca60380d..930c852fe8 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -328,6 +328,8 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => { }, 10*60*1000); afterEach(async () => { + await frame.click(`[data-testid="sidebar-cluster-dropdown"]`); + await frame.click(`.Menu >> text="Disconnect"`); await cleanup(); }, 10*60*1000); @@ -337,6 +339,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => { await frame.waitForSelector(`.Menu >> text="Settings"`); await frame.waitForSelector(`.Menu >> text="Disconnect"`); await frame.waitForSelector(`.Menu >> text="Delete"`); + await frame.click(`[data-testid="sidebar-cluster-dropdown"]`); }); it("should navigate around common cluster pages", async () => { @@ -370,7 +373,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => { } }, 10*60*1000); - + it("show logs and highlight the log search entries", async () => { await frame.click(`a[href="/workloads"]`); diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index ad140d346e..783111d0fd 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -72,7 +72,12 @@ export async function start() { ...process.env, }, timeout: 100_000, - } as Parameters[0]); + }); + + const cleanup = async () => { + await app.close(); + await remove(CICD).catch(noop); + }; try { const window = await getMainWindow(app); @@ -80,14 +85,10 @@ export async function start() { return { app, window, - cleanup: async () => { - await app.close(); - await remove(CICD).catch(noop); - }, + cleanup, }; } catch (error) { - await app.close(); - await remove(CICD).catch(noop); + await cleanup(); throw error; } } diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index ffd77da3d2..d2853b63d8 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -36,6 +36,8 @@ jest.mock("winston", () => ({ label: jest.fn(), timestamp: jest.fn(), printf: jest.fn(), + padLevels: jest.fn(), + ms: jest.fn(), }, createLogger: jest.fn().mockReturnValue(logger), transports: { @@ -49,12 +51,31 @@ jest.mock("../context-handler"); jest.mock("request"); jest.mock("request-promise-native"); +jest.mock("electron", () => ({ + app: { + getVersion: () => "99.99.99", + getName: () => "lens", + setName: jest.fn(), + setPath: jest.fn(), + getPath: () => "tmp", + getLocale: () => "en", + setLoginItemSettings: jest.fn(), + }, + ipcMain: { + on: jest.fn(), + once: jest.fn(), + handle: jest.fn(), + }, +})); + import { Console } from "console"; import mockFs from "mock-fs"; +import { AppPaths } from "../../common/app-paths"; import { Cluster } from "../cluster"; import { Kubectl } from "../kubectl"; console = new Console(process.stdout, process.stderr); // fix mockFS +AppPaths.init(); describe("create clusters", () => { beforeEach(() => { diff --git a/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts b/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts index 5c3a7094ae..de18704049 100644 --- a/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts +++ b/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts @@ -42,6 +42,7 @@ jest.mock("electron", () => ({ }, ipcMain: { on: jest.fn(), + once: jest.fn(), handle: jest.fn(), }, })); diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 1cbf4f980c..0ffb175a02 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -34,7 +34,7 @@ import { DetectorRegistry } from "./cluster-detectors/detector-registry"; import plimit from "p-limit"; import type { ClusterState, ClusterRefreshOptions, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate } from "../common/cluster-types"; import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus } from "../common/cluster-types"; -import { storedKubeConfigFolder, toJS } from "../common/utils"; +import { disposer, storedKubeConfigFolder, toJS } from "../common/utils"; import type { Response } from "request"; /** @@ -53,7 +53,7 @@ export class Cluster implements ClusterModel, ClusterState { */ public contextHandler: ContextHandler; protected kubeconfigManager: KubeconfigManager; - protected eventDisposers: Function[] = []; + protected eventDisposers = disposer(); protected activated = false; private resourceAccessStatuses: Map = new Map(); @@ -324,15 +324,6 @@ export class Cluster implements ClusterModel, ClusterState { this.getProxyKubeconfig(); } - /** - * internal - */ - protected unbindEvents() { - logger.info(`[CLUSTER]: unbind events`, this.getMeta()); - this.eventDisposers.forEach(dispose => dispose()); - this.eventDisposers.length = 0; - } - /** * @param force force activation * @internal @@ -395,8 +386,13 @@ export class Cluster implements ClusterModel, ClusterState { * @internal */ @action disconnect() { - this.unbindEvents(); - this.contextHandler?.stopServer(); + logger.info(`[CLUSTER]: disconnecting cluster`, { id: this.id }); + + ipcMain.once(`cluster:${this.id}:frame-removed`, () => { + this.contextHandler?.stopServer(); + }); + + this.eventDisposers(); this.disconnected = true; this.online = false; this.accessible = false; @@ -405,7 +401,6 @@ export class Cluster implements ClusterModel, ClusterState { this.allowedNamespaces = []; this.resourceAccessStatuses.clear(); this.pushState(); - logger.info(`[CLUSTER]: disconnect`, this.getMeta()); } /** diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index c52f97d4b1..e79c356ef7 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -129,11 +129,11 @@ export class KubeAuthProxy { this.ready = false; if (this.proxyProcess) { - logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()); + logger.info("[KUBE-AUTH]: stopping local proxy", { clusterId: this.cluster.id }); + this.proxyProcess.kill(); this.proxyProcess.removeAllListeners(); this.proxyProcess.stderr.removeAllListeners(); this.proxyProcess.stdout.removeAllListeners(); - this.proxyProcess.kill(); this.proxyProcess = null; } } diff --git a/src/renderer/components/cluster-manager/lens-views.ts b/src/renderer/components/cluster-manager/lens-views.ts index 784e645e59..c63c2645f4 100644 --- a/src/renderer/components/cluster-manager/lens-views.ts +++ b/src/renderer/components/cluster-manager/lens-views.ts @@ -21,6 +21,7 @@ import { action, IReactionDisposer, makeObservable, observable, when } from "mobx"; import logger from "../../../main/logger"; +import { broadcastMessage } from "../../../common/ipc"; import { clusterVisibilityHandler } from "../../../common/cluster-ipc"; import { ClusterStore } from "../../../common/cluster-store"; import type { ClusterId } from "../../../common/cluster-types"; @@ -88,6 +89,7 @@ export class ClusterFrameHandler extends Singleton { logger.info(`[LENS-VIEW]: remove dashboard, clusterId=${clusterId}`); this.views.delete(clusterId); iframe.parentNode.removeChild(iframe); + broadcastMessage(`cluster:${clusterId}:frame-removed`); dispose(); }, );