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

Fix ClusterScoped kube APIs not subscribing (#2706)

* Fix ClusterScoped kube APIs not subscribing

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove debug

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2021-05-06 02:10:52 -04:00 committed by GitHub
parent 768e1d14ca
commit 7b1b8e6321
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 25 deletions

View File

@ -1,31 +1,61 @@
import { splitArray } from "../splitArray"; import { bifurcateArray, splitArray } from "../splitArray";
describe("split array on element tests", () => { describe("split array on element tests", () => {
test("empty array", () => { it("empty array", () => {
expect(splitArray([], 10)).toStrictEqual([[], [], false]); expect(splitArray([], 10)).toStrictEqual([[], [], false]);
}); });
test("one element, not in array", () => { it("one element, not in array", () => {
expect(splitArray([1], 10)).toStrictEqual([[1], [], false]); expect(splitArray([1], 10)).toStrictEqual([[1], [], false]);
}); });
test("ten elements, not in array", () => { it("ten elements, not in array", () => {
expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 10)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [], false]); expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 10)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [], false]);
}); });
test("one elements, in array", () => { it("one elements, in array", () => {
expect(splitArray([1], 1)).toStrictEqual([[], [], true]); expect(splitArray([1], 1)).toStrictEqual([[], [], true]);
}); });
test("ten elements, in front array", () => { it("ten elements, in front array", () => {
expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0)).toStrictEqual([[], [1, 2, 3, 4, 5, 6, 7, 8, 9], true]); expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0)).toStrictEqual([[], [1, 2, 3, 4, 5, 6, 7, 8, 9], true]);
}); });
test("ten elements, in middle array", () => { it("ten elements, in middle array", () => {
expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4)).toStrictEqual([[0, 1, 2, 3], [5, 6, 7, 8, 9], true]); expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4)).toStrictEqual([[0, 1, 2, 3], [5, 6, 7, 8, 9], true]);
}); });
test("ten elements, in end array", () => { it("ten elements, in end array", () => {
expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 9)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8], [], true]); expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 9)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8], [], true]);
}); });
}); });
describe("bifurcateArray", () => {
it("should return tuple of empty arrays from empty array", () => {
const [left, right] = bifurcateArray([], () => true);
expect(left).toStrictEqual([]);
expect(right).toStrictEqual([]);
});
it("should return all true condition returning items in the right array", () => {
const [left, right] = bifurcateArray([1, 2, 3], () => true);
expect(left).toStrictEqual([]);
expect(right).toStrictEqual([1, 2, 3]);
});
it("should return all false condition returning items in the right array", () => {
const [left, right] = bifurcateArray([1, 2, 3], () => false);
expect(left).toStrictEqual([1, 2, 3]);
expect(right).toStrictEqual([]);
});
it("should split array as specified", () => {
const [left, right] = bifurcateArray([1, 2, 3], (i) => Boolean(i % 2));
expect(left).toStrictEqual([2]);
expect(right).toStrictEqual([1, 3]);
});
});

View File

@ -1,4 +1,3 @@
// Moved from dashboard/client/utils/arrays.ts
/** /**
* This function splits an array into two sub arrays on the first instance of * This function splits an array into two sub arrays on the first instance of
* element (from the left). If the array does not contain the element. The * element (from the left). If the array does not contain the element. The
@ -19,3 +18,20 @@ export function splitArray<T>(array: T[], element: T): [T[], T[], boolean] {
return [array.slice(0, index), array.slice(index + 1, array.length), true]; return [array.slice(0, index), array.slice(index + 1, array.length), true];
} }
/**
* Splits an array into two parts based on the outcome of `condition`. If `true`
* the value will be returned as part of the right array. If `false` then part of
* the left array.
* @param src the full array to bifurcate
* @param condition the function to determine which set each is in
*/
export function bifurcateArray<T>(src: T[], condition: (item: T) => boolean): [falses: T[], trues: T[]] {
const res: [T[], T[]] = [[], []];
for (const item of src) {
res[+condition(item)].push(item);
}
return res;
}

View File

@ -50,6 +50,7 @@ import { ReplicaSetScaleDialog } from "./+workloads-replicasets/replicaset-scale
import { CommandContainer } from "./command-palette/command-container"; import { CommandContainer } from "./command-palette/command-container";
import { KubeObjectStore } from "../kube-object.store"; import { KubeObjectStore } from "../kube-object.store";
import { clusterContext } from "./context"; import { clusterContext } from "./context";
import { namespaceStore } from "./+namespaces/namespace.store";
@observer @observer
export class App extends React.Component { export class App extends React.Component {
@ -84,7 +85,7 @@ export class App extends React.Component {
componentDidMount() { componentDidMount() {
disposeOnUnmount(this, [ disposeOnUnmount(this, [
kubeWatchApi.subscribeStores([podsStore, nodesStore, eventStore], { kubeWatchApi.subscribeStores([podsStore, nodesStore, eventStore, namespaceStore], {
preload: true, preload: true,
}) })
]); ]);

View File

@ -1,7 +1,7 @@
import type { ClusterContext } from "./components/context"; import type { ClusterContext } from "./components/context";
import { action, computed, observable, reaction, when } from "mobx"; import { action, computed, observable, reaction, when } from "mobx";
import { autobind, noop, rejectPromiseBy } from "./utils"; import { autobind, bifurcateArray, noop, rejectPromiseBy } from "./utils";
import { KubeObject, KubeStatus } from "./api/kube-object"; import { KubeObject, KubeStatus } from "./api/kube-object";
import { IKubeWatchEvent } from "./api/kube-watch-api"; import { IKubeWatchEvent } from "./api/kube-watch-api";
import { ItemStore } from "./item.store"; import { ItemStore } from "./item.store";
@ -281,21 +281,36 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
subscribe(apis = this.getSubscribeApis()) { subscribe(apis = this.getSubscribeApis()) {
const abortController = new AbortController(); const abortController = new AbortController();
const [clusterScopedApis, namespaceScopedApis] = bifurcateArray(apis, api => api.isNamespaced);
for (const api of namespaceScopedApis) {
const store = apiManager.getStore(api);
// This waits for the context and namespaces to be ready or fails fast if the disposer is called // This waits for the context and namespaces to be ready or fails fast if the disposer is called
Promise.race([rejectPromiseBy(abortController.signal), Promise.all([this.contextReady, this.namespacesReady])]) Promise.race([rejectPromiseBy(abortController.signal), Promise.all([store.contextReady, store.namespacesReady])])
.then(() => { .then(() => {
if (this.context.cluster.isGlobalWatchEnabled && this.loadedNamespaces.length === 0) { if (
apis.forEach(api => this.watchNamespace(api, "", abortController)); store.context.cluster.isGlobalWatchEnabled
} else { && store.loadedNamespaces.length === 0
apis.forEach(api => { ) {
this.loadedNamespaces.forEach((namespace) => { return store.watchNamespace(api, "", abortController);
this.watchNamespace(api, namespace, abortController); }
});
}); for (const namespace of this.loadedNamespaces) {
store.watchNamespace(api, namespace, abortController);
} }
}) })
.catch(noop); // ignore DOMExceptions .catch(noop); // ignore DOMExceptions
}
for (const api of clusterScopedApis) {
/**
* if the api is cluster scoped then we will never assign to `loadedNamespaces`
* and thus `store.namespacesReady` will never resolve. Futhermore, we don't care
* about watching namespaces.
*/
apiManager.getStore(api).watchNamespace(api, "", abortController);
}
return () => { return () => {
abortController.abort(); abortController.abort();