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,289 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "../../common/ipc/cluster";
|
||||
import type { IObservableValue, ObservableSet } from "mobx";
|
||||
import { action, makeObservable, observe, reaction, toJS } from "mobx";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import { isErrnoException } from "../../common/utils";
|
||||
import type { KubernetesClusterPrometheusMetrics } from "../../common/catalog-entities/kubernetes-cluster";
|
||||
import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../../common/catalog-entities/kubernetes-cluster";
|
||||
import { ipcMainOn } from "../../common/ipc";
|
||||
import { once } from "lodash";
|
||||
import type { ClusterStore } from "../../common/cluster-store/cluster-store";
|
||||
import type { ClusterId } from "../../common/cluster-types";
|
||||
import type { CatalogEntityRegistry } from "../catalog";
|
||||
import type { Logger } from "../../common/logger";
|
||||
|
||||
const logPrefix = "[CLUSTER-MANAGER]:";
|
||||
|
||||
const lensSpecificClusterStatuses: Set<string> = new Set(Object.values(LensKubernetesClusterStatus));
|
||||
|
||||
interface Dependencies {
|
||||
readonly store: ClusterStore;
|
||||
readonly catalogEntityRegistry: CatalogEntityRegistry;
|
||||
readonly clustersThatAreBeingDeleted: ObservableSet<ClusterId>;
|
||||
readonly visibleCluster: IObservableValue<ClusterId | null>;
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export class ClusterManager {
|
||||
constructor(private readonly dependencies: Dependencies) {
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
init = once(() => {
|
||||
// reacting to every cluster's state change and total amount of items
|
||||
reaction(
|
||||
() => this.dependencies.store.clustersList.map(c => c.getState()),
|
||||
() => this.updateCatalog(this.dependencies.store.clustersList),
|
||||
{ fireImmediately: false },
|
||||
);
|
||||
|
||||
// reacting to every cluster's preferences change and total amount of items
|
||||
reaction(
|
||||
() => this.dependencies.store.clustersList.map(c => toJS(c.preferences)),
|
||||
() => this.updateCatalog(this.dependencies.store.clustersList),
|
||||
{ fireImmediately: false },
|
||||
);
|
||||
|
||||
reaction(
|
||||
() => this.dependencies.catalogEntityRegistry.filterItemsByPredicate(isKubernetesCluster),
|
||||
entities => this.syncClustersFromCatalog(entities),
|
||||
);
|
||||
|
||||
reaction(() => [
|
||||
this.dependencies.catalogEntityRegistry.filterItemsByPredicate(isKubernetesCluster),
|
||||
this.dependencies.visibleCluster.get(),
|
||||
] as const, ([entities, visibleCluster]) => {
|
||||
for (const entity of entities) {
|
||||
if (entity.getId() === visibleCluster) {
|
||||
entity.status.active = true;
|
||||
} else {
|
||||
entity.status.active = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observe(this.dependencies.clustersThatAreBeingDeleted, change => {
|
||||
if (change.type === "add") {
|
||||
this.updateEntityStatus(this.dependencies.catalogEntityRegistry.findById(change.newValue) as KubernetesCluster);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMainOn("network:offline", this.onNetworkOffline);
|
||||
ipcMainOn("network:online", this.onNetworkOnline);
|
||||
});
|
||||
|
||||
@action
|
||||
protected updateCatalog(clusters: Cluster[]) {
|
||||
this.dependencies.logger.debug("[CLUSTER-MANAGER]: updating catalog from cluster store");
|
||||
|
||||
for (const cluster of clusters) {
|
||||
this.updateEntityFromCluster(cluster);
|
||||
}
|
||||
}
|
||||
|
||||
protected updateEntityFromCluster(cluster: Cluster) {
|
||||
const index = this.dependencies.catalogEntityRegistry.items.findIndex((entity) => entity.getId() === cluster.id);
|
||||
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entity = this.dependencies.catalogEntityRegistry.items[index] as KubernetesCluster;
|
||||
|
||||
this.updateEntityStatus(entity, cluster);
|
||||
|
||||
entity.metadata.labels = {
|
||||
...entity.metadata.labels,
|
||||
...cluster.labels,
|
||||
};
|
||||
entity.metadata.distro = cluster.distribution;
|
||||
entity.metadata.kubeVersion = cluster.version;
|
||||
|
||||
if (cluster.preferences?.clusterName) {
|
||||
/**
|
||||
* Only set the name if the it is overriden in preferences. If it isn't
|
||||
* set then the name of the entity has been explicitly set by its source
|
||||
*/
|
||||
entity.metadata.name = cluster.preferences.clusterName;
|
||||
}
|
||||
|
||||
entity.spec.metrics ||= { source: "local" };
|
||||
|
||||
if (entity.spec.metrics.source === "local") {
|
||||
const prometheus: KubernetesClusterPrometheusMetrics = entity.spec?.metrics?.prometheus || {};
|
||||
|
||||
prometheus.type = cluster.preferences.prometheusProvider?.type;
|
||||
prometheus.address = cluster.preferences.prometheus;
|
||||
entity.spec.metrics.prometheus = prometheus;
|
||||
}
|
||||
|
||||
if (cluster.preferences.icon) {
|
||||
entity.spec.icon ??= {};
|
||||
entity.spec.icon.src = cluster.preferences.icon;
|
||||
} else if (cluster.preferences.icon === null) {
|
||||
/**
|
||||
* NOTE: only clear the icon if set to `null` by ClusterIconSettings.
|
||||
* We can then also clear that value too
|
||||
*/
|
||||
entity.spec.icon = undefined;
|
||||
cluster.preferences.icon = undefined;
|
||||
}
|
||||
|
||||
this.dependencies.catalogEntityRegistry.items.splice(index, 1, entity);
|
||||
}
|
||||
|
||||
@action
|
||||
protected updateEntityStatus(entity: KubernetesCluster, cluster?: Cluster) {
|
||||
if (this.dependencies.clustersThatAreBeingDeleted.has(entity.getId())) {
|
||||
entity.status.phase = LensKubernetesClusterStatus.DELETING;
|
||||
entity.status.enabled = false;
|
||||
} else {
|
||||
entity.status.phase = (() => {
|
||||
if (!cluster) {
|
||||
this.dependencies.logger.silly(`${logPrefix} setting entity ${entity.getName()} to DISCONNECTED, reason="no cluster"`);
|
||||
|
||||
return LensKubernetesClusterStatus.DISCONNECTED;
|
||||
}
|
||||
|
||||
if (cluster.accessible) {
|
||||
this.dependencies.logger.silly(`${logPrefix} setting entity ${entity.getName()} to CONNECTED, reason="cluster is accessible"`);
|
||||
|
||||
return LensKubernetesClusterStatus.CONNECTED;
|
||||
}
|
||||
|
||||
if (!cluster.disconnected) {
|
||||
this.dependencies.logger.silly(`${logPrefix} setting entity ${entity.getName()} to CONNECTING, reason="cluster is not disconnected"`);
|
||||
|
||||
return LensKubernetesClusterStatus.CONNECTING;
|
||||
}
|
||||
|
||||
// Extensions are not allowed to use the Lens specific status phases
|
||||
if (!lensSpecificClusterStatuses.has(entity?.status?.phase)) {
|
||||
this.dependencies.logger.silly(`${logPrefix} not clearing entity ${entity.getName()} status, reason="custom string"`);
|
||||
|
||||
return entity.status.phase;
|
||||
}
|
||||
|
||||
this.dependencies.logger.silly(`${logPrefix} setting entity ${entity.getName()} to DISCONNECTED, reason="fallthrough"`);
|
||||
|
||||
return LensKubernetesClusterStatus.DISCONNECTED;
|
||||
})();
|
||||
|
||||
entity.status.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
protected syncClustersFromCatalog(entities: KubernetesCluster[]) {
|
||||
for (const entity of entities) {
|
||||
const cluster = this.dependencies.store.getById(entity.getId());
|
||||
|
||||
if (!cluster) {
|
||||
const model = {
|
||||
id: entity.getId(),
|
||||
kubeConfigPath: entity.spec.kubeconfigPath,
|
||||
contextName: entity.spec.kubeconfigContext,
|
||||
accessibleNamespaces: entity.spec.accessibleNamespaces ?? [],
|
||||
};
|
||||
|
||||
try {
|
||||
/**
|
||||
* Add the bare minimum of data to ClusterStore. And especially no
|
||||
* preferences, as those might be configured by the entity's source
|
||||
*/
|
||||
this.dependencies.store.addCluster(model);
|
||||
} catch (error) {
|
||||
if (isErrnoException(error) && error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) {
|
||||
this.dependencies.logger.warn(`${logPrefix} kubeconfig file disappeared`, model);
|
||||
} else {
|
||||
this.dependencies.logger.error(`${logPrefix} failed to add cluster: ${error}`, model);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cluster.kubeConfigPath = entity.spec.kubeconfigPath;
|
||||
cluster.contextName = entity.spec.kubeconfigContext;
|
||||
|
||||
if (entity.spec.accessibleNamespaces) {
|
||||
cluster.accessibleNamespaces.replace(entity.spec.accessibleNamespaces);
|
||||
}
|
||||
|
||||
if (entity.spec.metrics) {
|
||||
const { source, prometheus } = entity.spec.metrics;
|
||||
|
||||
if (source !== "local" && prometheus) {
|
||||
const { type, address } = prometheus;
|
||||
|
||||
if (type) {
|
||||
cluster.preferences.prometheusProvider = { type };
|
||||
}
|
||||
|
||||
if (address) {
|
||||
cluster.preferences.prometheus = address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.updateEntityFromCluster(cluster);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected onNetworkOffline = () => {
|
||||
this.dependencies.logger.info(`${logPrefix} network is offline`);
|
||||
this.dependencies.store.clustersList.forEach((cluster) => {
|
||||
if (!cluster.disconnected) {
|
||||
cluster.online = false;
|
||||
cluster.accessible = false;
|
||||
cluster.refreshConnectionStatus().catch((e) => e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
protected onNetworkOnline = () => {
|
||||
this.dependencies.logger.info(`${logPrefix} network is online`);
|
||||
this.dependencies.store.clustersList.forEach((cluster) => {
|
||||
if (!cluster.disconnected) {
|
||||
cluster.refreshConnectionStatus().catch((e) => e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
stop() {
|
||||
this.dependencies.store.clusters.forEach((cluster: Cluster) => {
|
||||
cluster.disconnect();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function catalogEntityFromCluster(cluster: Cluster) {
|
||||
return new KubernetesCluster({
|
||||
metadata: {
|
||||
uid: cluster.id,
|
||||
name: cluster.name,
|
||||
source: "local",
|
||||
labels: {
|
||||
...cluster.labels,
|
||||
},
|
||||
distro: cluster.distribution,
|
||||
kubeVersion: cluster.version,
|
||||
},
|
||||
spec: {
|
||||
kubeconfigPath: cluster.kubeConfigPath,
|
||||
kubeconfigContext: cluster.contextName,
|
||||
icon: {},
|
||||
},
|
||||
status: {
|
||||
phase: cluster.disconnected
|
||||
? LensKubernetesClusterStatus.DISCONNECTED
|
||||
: LensKubernetesClusterStatus.CONNECTED,
|
||||
reason: "",
|
||||
message: "",
|
||||
active: !cluster.disconnected,
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user