mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Restructure to monorepo (#6907)
* wip: restructure to monorepo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor create-release-pr to a package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * github workflow fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix typo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * add webpack-env types to core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix github workflows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor/fix integration tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * lint fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * yarn run dev Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * eslint settings for vscode Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * move templates to right package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * open-lens build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * integration test fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix nx task dependencies Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * use bash shell for unit tests in test workflow Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix test:unit for windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix build:app on windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove ELECTRON_BUILDER_EXTRA_ARGS Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * sync src/ from master Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove Makefile from core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
0066ca4ea2
commit
2657df2293
3321 files changed
+28699
-11447
No files matched your search
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import clusterFrameContextForNamespacedResourcesInjectable from "../cluster-frame-context/for-namespaced-resources.injectable";
|
||||
import { KubeWatchApi } from "./kube-watch-api";
|
||||
|
||||
const kubeWatchApiInjectable = getInjectable({
|
||||
id: "kube-watch-api",
|
||||
|
||||
instantiate: (di) => new KubeWatchApi({
|
||||
clusterContext: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default kubeWatchApiInjectable;
|
||||
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { comparer, reaction } from "mobx";
|
||||
import type { Disposer } from "../../common/utils";
|
||||
import { disposer, getOrInsert, noop, WrappedAbortController } from "../../common/utils";
|
||||
import { once } from "lodash";
|
||||
import type { Logger } from "../../common/logger";
|
||||
import type { KubeObjectStoreLoadAllParams, KubeObjectStoreSubscribeParams } from "../../common/k8s-api/kube-object.store";
|
||||
import AbortController from "abort-controller";
|
||||
import type { ClusterContext } from "../cluster-frame-context/cluster-frame-context";
|
||||
|
||||
// Kubernetes watch-api client
|
||||
// API: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams
|
||||
|
||||
interface SubscribeStoreParams {
|
||||
store: SubscribableStore;
|
||||
parent: AbortController;
|
||||
namespaces: string[] | undefined;
|
||||
onLoadFailure?: (err: any) => void;
|
||||
}
|
||||
|
||||
interface WatchCountDependencies {
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
class WatchCount {
|
||||
readonly #data = new Map<SubscribableStore, number>();
|
||||
|
||||
constructor(private readonly dependencies: WatchCountDependencies) {}
|
||||
|
||||
public inc(store: SubscribableStore): number {
|
||||
const newCount = getOrInsert(this.#data, store, 0) + 1;
|
||||
|
||||
this.dependencies.logger.info(`[KUBE-WATCH-API]: inc() count for ${store.api.apiBase} is now ${newCount}`);
|
||||
this.#data.set(store, newCount);
|
||||
|
||||
return newCount;
|
||||
}
|
||||
|
||||
public dec(store: SubscribableStore): number {
|
||||
const oldCount = this.#data.get(store);
|
||||
|
||||
if (oldCount === undefined) {
|
||||
throw new Error(`Cannot dec count for store that has never been inc: ${store.api.kind}`);
|
||||
}
|
||||
|
||||
const newCount = oldCount - 1;
|
||||
|
||||
if (newCount < 0) {
|
||||
throw new Error(`Cannot dec count more times than it has been inc: ${store.api.kind}`);
|
||||
}
|
||||
|
||||
this.dependencies.logger.info(`[KUBE-WATCH-API]: dec() count for ${store.api.apiBase} is now ${newCount}`);
|
||||
this.#data.set(store, newCount);
|
||||
|
||||
return newCount;
|
||||
}
|
||||
}
|
||||
|
||||
export interface KubeWatchSubscribeStoreOptions {
|
||||
/**
|
||||
* The namespaces to watch
|
||||
* @default all selected namespaces
|
||||
*/
|
||||
namespaces?: string[];
|
||||
|
||||
/**
|
||||
* A function that is called when listing fails. If set then blocks errors
|
||||
* from rejecting promises
|
||||
*/
|
||||
onLoadFailure?: (err: any) => void;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
readonly clusterContext: ClusterContext;
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export interface SubscribableStore {
|
||||
readonly api: {
|
||||
readonly isNamespaced: boolean;
|
||||
readonly apiBase: string;
|
||||
readonly kind: string;
|
||||
};
|
||||
loadAll(opts?: KubeObjectStoreLoadAllParams): Promise<unknown>;
|
||||
subscribe(opts?: KubeObjectStoreSubscribeParams): Disposer;
|
||||
}
|
||||
|
||||
export type SubscribeStores = (stores: SubscribableStore[], opts?: KubeWatchSubscribeStoreOptions) => Disposer;
|
||||
|
||||
export class KubeWatchApi {
|
||||
readonly #watch = new WatchCount(this.dependencies);
|
||||
|
||||
constructor(private readonly dependencies: Dependencies) {}
|
||||
|
||||
private subscribeStore({ store, parent, namespaces, onLoadFailure }: SubscribeStoreParams): Disposer {
|
||||
const isNamespaceFilterWatch = !namespaces;
|
||||
|
||||
if (isNamespaceFilterWatch && this.#watch.inc(store) > 1) {
|
||||
// don't load or subscribe to a store more than once
|
||||
return () => this.#watch.dec(store);
|
||||
}
|
||||
|
||||
namespaces ??= this.dependencies.clusterContext?.contextNamespaces ?? [];
|
||||
|
||||
let childController = new WrappedAbortController(parent);
|
||||
const unsubscribe = disposer();
|
||||
|
||||
const loadThenSubscribe = async (namespaces: string[] | undefined) => {
|
||||
try {
|
||||
await store.loadAll({ namespaces, reqInit: { signal: childController.signal }, onLoadFailure });
|
||||
unsubscribe.push(store.subscribe({ onLoadFailure, abortController: childController }));
|
||||
} catch (error) {
|
||||
if (!(error instanceof DOMException)) {
|
||||
this.log(new Error("Loading stores has failed", { cause: error }), {
|
||||
meta: { store, namespaces },
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* We don't want to wait because we want to start reacting to namespace
|
||||
* selection changes ASAP
|
||||
*/
|
||||
loadThenSubscribe(namespaces).catch(noop);
|
||||
|
||||
const cancelReloading = isNamespaceFilterWatch && store.api.isNamespaced
|
||||
? reaction(
|
||||
// Note: must slice because reaction won't fire if it isn't there
|
||||
() => [this.dependencies.clusterContext.contextNamespaces.slice(), this.dependencies.clusterContext.hasSelectedAll] as const,
|
||||
([namespaces, curSelectedAll], [prevNamespaces, prevSelectedAll]) => {
|
||||
if (curSelectedAll && prevSelectedAll) {
|
||||
const action = namespaces.length > prevNamespaces.length ? "created" : "deleted";
|
||||
|
||||
return console.debug(`[KUBE-WATCH-API]: Not changing watch for ${store.api.apiBase} because a new namespace was ${action} but all namespaces are selected`);
|
||||
}
|
||||
|
||||
console.log(`[KUBE-WATCH-API]: changing watch ${store.api.apiBase}`, namespaces);
|
||||
childController.abort();
|
||||
unsubscribe();
|
||||
childController = new WrappedAbortController(parent);
|
||||
loadThenSubscribe(namespaces).catch(noop);
|
||||
},
|
||||
{
|
||||
equals: comparer.shallow,
|
||||
},
|
||||
)
|
||||
: noop; // don't watch namespaces if namespaces were provided
|
||||
|
||||
return () => {
|
||||
if (isNamespaceFilterWatch && this.#watch.dec(store) === 0) {
|
||||
// only stop the subcribe if this is the last one
|
||||
cancelReloading();
|
||||
childController.abort();
|
||||
unsubscribe();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
subscribeStores: SubscribeStores = (stores, { namespaces, onLoadFailure } = {}) => {
|
||||
const parent = new AbortController();
|
||||
const unsubscribe = disposer(
|
||||
...stores.map(store => this.subscribeStore({
|
||||
store,
|
||||
parent,
|
||||
namespaces,
|
||||
onLoadFailure,
|
||||
})),
|
||||
);
|
||||
|
||||
// unsubscribe
|
||||
return once(() => {
|
||||
parent.abort();
|
||||
unsubscribe();
|
||||
});
|
||||
};
|
||||
|
||||
protected log(message: any, meta: any) {
|
||||
const log = message instanceof Error
|
||||
? this.dependencies.logger.error
|
||||
: this.dependencies.logger.debug;
|
||||
|
||||
log("[KUBE-WATCH-API]:", message, {
|
||||
time: new Date().toLocaleString(),
|
||||
...meta,
|
||||
});
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import subscribeStoresInjectable from "./subscribe-stores.injectable";
|
||||
|
||||
export default getGlobalOverride(
|
||||
subscribeStoresInjectable,
|
||||
() => () => () => {},
|
||||
);
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import kubeWatchApiInjectable from "./kube-watch-api.injectable";
|
||||
|
||||
const subscribeStoresInjectable = getInjectable({
|
||||
id: "subscribe-stores",
|
||||
instantiate: (di) => di.inject(kubeWatchApiInjectable).subscribeStores,
|
||||
});
|
||||
|
||||
export default subscribeStoresInjectable;
|
||||
Reference in new issue
Block a user