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

Catch metadata being undefined at KubeObject creation (#3960)

Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>
This commit is contained in:
Sebastian Malton 2021-10-07 10:09:21 -04:00 committed by Jim Ehrismann
parent b27a2654e4
commit 7c9e367db5
4 changed files with 59 additions and 48 deletions

View File

@ -98,6 +98,12 @@ export interface KubeObjectStatus {
export type KubeMetaField = keyof KubeObjectMetadata; export type KubeMetaField = keyof KubeObjectMetadata;
export class KubeCreationError extends Error {
constructor(message: string, public data: any) {
super(message);
}
}
export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata, Status = any, Spec = any> implements ItemObject { export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata, Status = any, Spec = any> implements ItemObject {
static readonly kind: string; static readonly kind: string;
static readonly namespaced: boolean; static readonly namespaced: boolean;
@ -209,10 +215,14 @@ export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata
]); ]);
constructor(data: KubeJsonApiData) { constructor(data: KubeJsonApiData) {
if (typeof data !== "object") { if (typeof data !== "object") {
throw new TypeError(`Cannot create a KubeObject from ${typeof data}`); throw new TypeError(`Cannot create a KubeObject from ${typeof data}`);
} }
if (!data.metadata || typeof data.metadata !== "object") {
throw new KubeCreationError(`Cannot create a KubeObject from an object without metadata`, data);
}
Object.assign(this, data); Object.assign(this, data);
autoBind(this); autoBind(this);
} }
@ -274,7 +284,7 @@ export class KubeObject<Metadata extends KubeObjectMetadata = KubeObjectMetadata
} }
getOwnerRefs() { getOwnerRefs() {
const refs = this.metadata?.ownerReferences || []; const refs = this.metadata.ownerReferences || [];
const namespace = this.getNs(); const namespace = this.getNs();
return refs.map(ownerRef => ({ ...ownerRef, namespace })); return refs.map(ownerRef => ({ ...ownerRef, namespace }));

View File

@ -25,9 +25,11 @@ import { Pod } from "../../../../common/k8s-api/endpoints";
import { ThemeStore } from "../../../theme.store"; import { ThemeStore } from "../../../theme.store";
import { dockStore } from "../dock.store"; import { dockStore } from "../dock.store";
import { logTabStore } from "../log-tab.store"; import { logTabStore } from "../log-tab.store";
import { TerminalStore } from "../terminal.store";
import { deploymentPod1, deploymentPod2, deploymentPod3, dockerPod } from "./pod.mock"; import { deploymentPod1, deploymentPod2, deploymentPod3, dockerPod } from "./pod.mock";
import fse from "fs-extra"; import fse from "fs-extra";
import { mockWindow } from "../../../../../__mocks__/windowMock";
mockWindow();
jest.mock("react-monaco-editor", () => null); jest.mock("react-monaco-editor", () => null);
@ -45,7 +47,6 @@ describe("log tab store", () => {
beforeEach(() => { beforeEach(() => {
UserStore.createInstance(); UserStore.createInstance();
ThemeStore.createInstance(); ThemeStore.createInstance();
TerminalStore.createInstance();
}); });
afterEach(() => { afterEach(() => {
@ -53,7 +54,6 @@ describe("log tab store", () => {
dockStore.reset(); dockStore.reset();
UserStore.resetInstance(); UserStore.resetInstance();
ThemeStore.resetInstance(); ThemeStore.resetInstance();
TerminalStore.resetInstance();
fse.remove("tmp"); fse.remove("tmp");
}); });
@ -135,11 +135,11 @@ describe("log tab store", () => {
}); });
// FIXME: this is failed when it's not .only == depends on something above // FIXME: this is failed when it's not .only == depends on something above
it.only("closes tab if no pods left in store", () => { it.only("closes tab if no pods left in store", async () => {
const selectedPod = new Pod(deploymentPod1); const selectedPod = new Pod(deploymentPod1);
const selectedContainer = selectedPod.getInitContainers()[0]; const selectedContainer = selectedPod.getInitContainers()[0];
logTabStore.createPodTab({ const id = logTabStore.createPodTab({
selectedPod, selectedPod,
selectedContainer selectedContainer
}); });
@ -147,6 +147,7 @@ describe("log tab store", () => {
podsStore.items.clear(); podsStore.items.clear();
expect(logTabStore.getData(dockStore.selectedTabId)).toBeUndefined(); expect(logTabStore.getData(dockStore.selectedTabId)).toBeUndefined();
expect(dockStore.getTabById(dockStore.selectedTabId)).toBeUndefined(); expect(logTabStore.getData(id)).toBeUndefined();
expect(dockStore.getTabById(id)).toBeUndefined();
}); });
}); });

View File

@ -160,7 +160,7 @@ export class DockStore implements DockStorageState {
window.addEventListener("resize", throttle(this.adjustHeight, 250)); window.addEventListener("resize", throttle(this.adjustHeight, 250));
// create monaco models // create monaco models
this.whenReady.then(() => {this.tabs.forEach(tab => { this.whenReady.then(() => {this.tabs.forEach(tab => {
if (this.usesMonacoEditor(tab)) { if (this.usesMonacoEditor(tab)) {
monacoModelsManager.addModel(tab.id); monacoModelsManager.addModel(tab.id);
} }
});}); });});
@ -274,7 +274,7 @@ export class DockStore implements DockStorageState {
title title
}; };
// add monaco model // add monaco model
if (this.usesMonacoEditor(tab)) { if (this.usesMonacoEditor(tab)) {
monacoModelsManager.addModel(id); monacoModelsManager.addModel(id);
} }
@ -287,14 +287,14 @@ export class DockStore implements DockStorageState {
} }
@action @action
async closeTab(tabId: TabId) { closeTab(tabId: TabId) {
const tab = this.getTabById(tabId); const tab = this.getTabById(tabId);
if (!tab || tab.pinned) { if (!tab || tab.pinned) {
return; return;
} }
// remove monaco model // remove monaco model
if (this.usesMonacoEditor(tab)) { if (this.usesMonacoEditor(tab)) {
monacoModelsManager.removeModel(tabId); monacoModelsManager.removeModel(tabId);
} }
@ -305,12 +305,6 @@ export class DockStore implements DockStorageState {
if (this.tabs.length) { if (this.tabs.length) {
const newTab = this.tabs.slice(-1)[0]; // last const newTab = this.tabs.slice(-1)[0]; // last
if (newTab?.kind === TabKind.TERMINAL) {
// close the dock when selected sibling inactive terminal tab
const { TerminalStore } = await import("./terminal.store");
if (!TerminalStore.getInstance(false)?.isConnected(newTab.id)) this.close();
}
this.selectTab(newTab.id); this.selectTab(newTab.id);
} else { } else {
this.selectedTabId = null; this.selectedTabId = null;

View File

@ -25,6 +25,7 @@ import { podsStore } from "../+workloads-pods/pods.store";
import { IPodContainer, Pod } from "../../../common/k8s-api/endpoints"; import { IPodContainer, Pod } from "../../../common/k8s-api/endpoints";
import type { WorkloadKubeObject } from "../../../common/k8s-api/workload-kube-object"; import type { WorkloadKubeObject } from "../../../common/k8s-api/workload-kube-object";
import logger from "../../../common/logger";
import { DockTabStore } from "./dock-tab.store"; import { DockTabStore } from "./dock-tab.store";
import { dockStore, DockTabCreateSpecific, TabKind } from "./dock.store"; import { dockStore, DockTabCreateSpecific, TabKind } from "./dock.store";
@ -51,17 +52,15 @@ export class LogTabStore extends DockTabStore<LogTabData> {
storageKey: "pod_logs" storageKey: "pod_logs"
}); });
reaction(() => podsStore.items.length, () => { reaction(() => podsStore.items.length, () => this.updateTabsData());
this.updateTabsData();
});
} }
createPodTab({ selectedPod, selectedContainer }: PodLogsTabData): void { createPodTab({ selectedPod, selectedContainer }: PodLogsTabData): string {
const podOwner = selectedPod.getOwnerRefs()[0]; const podOwner = selectedPod.getOwnerRefs()[0];
const pods = podsStore.getPodsByOwnerId(podOwner?.uid); const pods = podsStore.getPodsByOwnerId(podOwner?.uid);
const title = `Pod ${selectedPod.getName()}`; const title = `Pod ${selectedPod.getName()}`;
this.createLogsTab(title, { return this.createLogsTab(title, {
pods: pods.length ? pods : [selectedPod], pods: pods.length ? pods : [selectedPod],
selectedPod, selectedPod,
selectedContainer selectedContainer
@ -95,9 +94,9 @@ export class LogTabStore extends DockTabStore<LogTabData> {
...tabParams, ...tabParams,
kind: TabKind.POD_LOGS, kind: TabKind.POD_LOGS,
}, false); }, false);
} }
private createLogsTab(title: string, data: LogTabData) { private createLogsTab(title: string, data: LogTabData): string {
const id = uniqueId("log-tab-"); const id = uniqueId("log-tab-");
this.createDockTab({ id, title }); this.createDockTab({ id, title });
@ -106,38 +105,45 @@ export class LogTabStore extends DockTabStore<LogTabData> {
showTimestamps: false, showTimestamps: false,
previous: false previous: false
}); });
return id;
} }
private async updateTabsData() { private updateTabsData() {
const promises: Promise<void>[] = [];
for (const [tabId, tabData] of this.data) { for (const [tabId, tabData] of this.data) {
const pod = new Pod(tabData.selectedPod); try {
const pods = podsStore.getPodsByOwnerId(pod.getOwnerRefs()[0]?.uid); if (!tabData.selectedPod) {
const isSelectedPodInList = pods.find(item => item.getId() == pod.getId()); tabData.selectedPod = tabData.pods[0];
const selectedPod = isSelectedPodInList ? pod : pods[0]; }
const selectedContainer = isSelectedPodInList ? tabData.selectedContainer : pod.getAllContainers()[0];
if (pods.length) { const pod = new Pod(tabData.selectedPod);
this.setData(tabId, { const pods = podsStore.getPodsByOwnerId(pod.getOwnerRefs()[0]?.uid);
...tabData, const isSelectedPodInList = pods.find(item => item.getId() == pod.getId());
selectedPod, const selectedPod = isSelectedPodInList ? pod : pods[0];
selectedContainer, const selectedContainer = isSelectedPodInList ? tabData.selectedContainer : pod.getAllContainers()[0];
pods
}); if (pods.length > 0) {
this.setData(tabId, {
this.renameTab(tabId); ...tabData,
} else { selectedPod,
promises.push(this.closeTab(tabId)); selectedContainer,
pods
});
this.renameTab(tabId);
} else {
this.closeTab(tabId);
}
} catch (error) {
logger.error(`[LOG-TAB-STORE]: failed to set data for tabId=${tabId} deleting`, error,);
this.data.delete(tabId);
} }
} }
await Promise.all(promises);
} }
private async closeTab(tabId: string) { private closeTab(tabId: string) {
this.clearData(tabId); this.clearData(tabId);
await dockStore.closeTab(tabId); dockStore.closeTab(tabId);
} }
} }