mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Move ownership and enabling tracking into cluster store
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
b066fb3527
commit
29dadd478a
@ -28,11 +28,7 @@ class KubectlDownloader {
|
||||
resolveWithFullResponse: true
|
||||
}).catch((error) => { console.log(error); });
|
||||
|
||||
if (response.headers["etag"]) {
|
||||
return response.headers["etag"].replace(/"/g, "");
|
||||
}
|
||||
|
||||
return "";
|
||||
return response.headers?.["etag"]?.replace(/"/g, "") ?? "";
|
||||
}
|
||||
|
||||
public async checkBinary() {
|
||||
@ -87,7 +83,7 @@ class KubectlDownloader {
|
||||
throw(error);
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
file.on("close", () => {
|
||||
console.log("kubectl binary download closed");
|
||||
fs.chmod(this.path, 0o755, (err) => {
|
||||
@ -116,4 +112,3 @@ downloads.forEach((dlOpts) => {
|
||||
console.log(`Downloading: ${JSON.stringify(dlOpts)}`);
|
||||
downloader.downloadKubectl().then(() => downloader.checkBinary().then(() => console.log("Download complete")));
|
||||
});
|
||||
|
||||
|
||||
@ -362,12 +362,12 @@
|
||||
"terser-webpack-plugin": "^3.0.3",
|
||||
"ts-jest": "^26.1.0",
|
||||
"ts-loader": "^7.0.5",
|
||||
"ts-node": "^8.10.2",
|
||||
"ts-node": "^9.1.1",
|
||||
"type-fest": "^0.18.0",
|
||||
"typedoc": "0.17.0-3",
|
||||
"typedoc-plugin-markdown": "^2.4.0",
|
||||
"typeface-roboto": "^0.0.75",
|
||||
"typescript": "4.0.2",
|
||||
"typescript": "^4.2.3",
|
||||
"url-loader": "^4.1.0",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "^3.3.11",
|
||||
|
||||
@ -88,7 +88,7 @@ describe("empty config", () => {
|
||||
expect(storedCluster.id).toBe("foo");
|
||||
expect(storedCluster.preferences.terminalCWD).toBe("/tmp");
|
||||
expect(storedCluster.preferences.icon).toBe("data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5");
|
||||
expect(storedCluster.enabled).toBe(true);
|
||||
expect(clusterStore.isClusterEnabled(storedCluster)).toBe(true);
|
||||
});
|
||||
|
||||
it("adds cluster to default workspace", () => {
|
||||
@ -265,8 +265,8 @@ describe("config with existing clusters", () => {
|
||||
it("marks owned cluster disabled by default", () => {
|
||||
const storedClusters = clusterStore.clustersList;
|
||||
|
||||
expect(storedClusters[0].enabled).toBe(true);
|
||||
expect(storedClusters[2].enabled).toBe(false);
|
||||
expect(clusterStore.isClusterEnabled(storedClusters[0])).toBe(true);
|
||||
expect(clusterStore.isClusterEnabled(storedClusters[2])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -336,9 +336,9 @@ users:
|
||||
const storedClusters = clusterStore.clustersList;
|
||||
|
||||
expect(storedClusters.length).toBe(2);
|
||||
expect(storedClusters[0].enabled).toBeFalsy;
|
||||
expect(clusterStore.isClusterEnabled(storedClusters[0])).toBeFalsy;
|
||||
expect(storedClusters[1].id).toBe("cluster2");
|
||||
expect(storedClusters[1].enabled).toBeTruthy;
|
||||
expect(clusterStore.isClusterEnabled(storedClusters[1])).toBeTruthy;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -11,11 +11,12 @@ import { appEventBus } from "./event-bus";
|
||||
import { dumpConfigYaml } from "./kube-helpers";
|
||||
import { saveToAppFiles } from "./utils/saveToAppFiles";
|
||||
import { KubeConfig } from "@kubernetes/client-node";
|
||||
import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc";
|
||||
import { broadcastMessage, handleRequest, InvalidKubeconfigChannel, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc";
|
||||
import _ from "lodash";
|
||||
import move from "array-move";
|
||||
import type { WorkspaceId } from "./workspace-store";
|
||||
import { ResourceType } from "../renderer/components/+cluster-settings/components/cluster-metrics-setting";
|
||||
import { LensExtensionId } from "../extensions/lens-extension";
|
||||
|
||||
export interface ClusterIconUpload {
|
||||
clusterId: string;
|
||||
@ -34,8 +35,9 @@ export type ClusterPrometheusMetadata = {
|
||||
};
|
||||
|
||||
export interface ClusterStoreModel {
|
||||
activeCluster?: ClusterId; // last opened cluster
|
||||
activeClusterId?: ClusterId; // last opened cluster
|
||||
clusters?: ClusterModel[];
|
||||
clusterOwners?: [ClusterId, LensExtensionId][];
|
||||
}
|
||||
|
||||
export type ClusterId = string;
|
||||
@ -59,11 +61,6 @@ export interface ClusterModel {
|
||||
/** Metadata */
|
||||
metadata?: ClusterMetadata;
|
||||
|
||||
/**
|
||||
* If extension sets ownerRef it has to explicitly mark a cluster as enabled during onActive (or when cluster is saved)
|
||||
*/
|
||||
ownerRef?: string;
|
||||
|
||||
/** List of accessible namespaces */
|
||||
accessibleNamespaces?: string[];
|
||||
|
||||
@ -71,6 +68,16 @@ export interface ClusterModel {
|
||||
kubeConfig?: string; // yaml
|
||||
}
|
||||
|
||||
export interface ClusterManagementRecord {
|
||||
ownerId: LensExtensionId;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface GetByWorkspaceIdOptions {
|
||||
includeDisabled?: boolean; // default false
|
||||
sortByIconOrder?: boolean; // default true
|
||||
}
|
||||
|
||||
export interface ClusterPreferences extends ClusterPrometheusPreferences {
|
||||
terminalCWD?: string;
|
||||
clusterName?: string;
|
||||
@ -92,6 +99,22 @@ export interface ClusterPrometheusPreferences {
|
||||
};
|
||||
}
|
||||
|
||||
function splitAddClusterArgs(args: ClusterModel[] | [...ClusterModel[], string]): [ClusterModel[]] | [ClusterModel[], string] {
|
||||
const lastArg = args.pop();
|
||||
|
||||
if (lastArg) {
|
||||
return [[]];
|
||||
}
|
||||
|
||||
if (typeof lastArg === "string") {
|
||||
return [args as ClusterModel[], lastArg];
|
||||
}
|
||||
|
||||
args.push(lastArg);
|
||||
|
||||
return [args as ClusterModel[]];
|
||||
}
|
||||
|
||||
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
static getCustomKubeConfigPath(clusterId: ClusterId): string {
|
||||
return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs", clusterId);
|
||||
@ -106,9 +129,11 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
@observable activeCluster: ClusterId;
|
||||
@observable activeClusterId: ClusterId;
|
||||
@observable removedClusters = observable.map<ClusterId, Cluster>();
|
||||
@observable clusters = observable.map<ClusterId, Cluster>();
|
||||
@observable clusterManagingInfo = observable.map<ClusterId, ClusterManagementRecord>();
|
||||
@observable erroredClusterModels = observable.array<ClusterModel>();
|
||||
|
||||
private static stateRequestChannel = "cluster:states";
|
||||
|
||||
@ -189,28 +214,50 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
});
|
||||
}
|
||||
|
||||
get activeClusterId() {
|
||||
return this.activeCluster;
|
||||
}
|
||||
|
||||
@computed get clustersList(): Cluster[] {
|
||||
return Array.from(this.clusters.values());
|
||||
}
|
||||
|
||||
@computed get enabledClustersList(): Cluster[] {
|
||||
return this.clustersList.filter((c) => c.enabled);
|
||||
return this.clustersList.filter(c => this.isClusterEnabled(c));
|
||||
}
|
||||
|
||||
@computed get active(): Cluster | null {
|
||||
return this.getById(this.activeCluster);
|
||||
return this.getById(this.activeClusterId);
|
||||
}
|
||||
|
||||
@computed get connectedClustersList(): Cluster[] {
|
||||
return this.clustersList.filter((c) => !c.disconnected);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param clusterOrId The cluster or its ID to check if it is owned
|
||||
* @returns true if an extension has claimed to be managing a cluster
|
||||
*/
|
||||
isClusterManaged(clusterOrId: Cluster | ClusterId): boolean {
|
||||
const clusterId = typeof clusterOrId === "string"
|
||||
? clusterOrId
|
||||
: clusterOrId.id;
|
||||
|
||||
return this.clusterManagingInfo.has(clusterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the enabled status of a cluster
|
||||
* @param clusterOrId The cluster or its ID to check if it is owned
|
||||
* @returns true if not managed, else true if owner has marked as enabled
|
||||
*/
|
||||
isClusterEnabled(clusterOrId: Cluster | ClusterId): boolean {
|
||||
const clusterId = typeof clusterOrId === "string"
|
||||
? clusterOrId
|
||||
: clusterOrId.id;
|
||||
|
||||
return this.clusterManagingInfo.get(clusterId)?.enabled ?? true;
|
||||
}
|
||||
|
||||
isActive(id: ClusterId) {
|
||||
return this.activeCluster === id;
|
||||
return this.activeClusterId === id;
|
||||
}
|
||||
|
||||
isMetricHidden(resource: ResourceType) {
|
||||
@ -221,7 +268,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
setActive(id: ClusterId) {
|
||||
const clusterId = this.clusters.has(id) ? id : null;
|
||||
|
||||
this.activeCluster = clusterId;
|
||||
this.activeClusterId = clusterId;
|
||||
workspaceStore.setLastActiveClusterId(clusterId);
|
||||
}
|
||||
|
||||
@ -249,37 +296,50 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
return this.clusters.get(id);
|
||||
}
|
||||
|
||||
getByWorkspaceId(workspaceId: string): Cluster[] {
|
||||
const clusters = Array.from(this.clusters.values())
|
||||
.filter(cluster => cluster.workspace === workspaceId);
|
||||
getByWorkspaceId(workspaceId: string, options?: GetByWorkspaceIdOptions): Cluster[] {
|
||||
const includeDisabled = options?.includeDisabled ?? false;
|
||||
const sortByIconOrder = options?.sortByIconOrder ?? true;
|
||||
|
||||
const clusters = Array.from(this.clusters.values())
|
||||
.filter(cluster => (
|
||||
cluster.workspace === workspaceId
|
||||
&& (
|
||||
includeDisabled
|
||||
|| this.isClusterEnabled(cluster)
|
||||
)
|
||||
));
|
||||
|
||||
if (sortByIconOrder) {
|
||||
return _.sortBy(clusters, cluster => cluster.preferences.iconOrder);
|
||||
}
|
||||
|
||||
@action
|
||||
addClusters(...models: ClusterModel[]): Cluster[] {
|
||||
const clusters: Cluster[] = [];
|
||||
|
||||
models.forEach(model => {
|
||||
clusters.push(this.addCluster(model));
|
||||
});
|
||||
|
||||
return clusters;
|
||||
}
|
||||
|
||||
@action
|
||||
addCluster(model: ClusterModel | Cluster): Cluster {
|
||||
addClusters<M extends ClusterModel, MM extends M[]>(...args: ([...MM] | [...MM, LensExtensionId])): Cluster[] {
|
||||
const [models, ownerId] = splitAddClusterArgs(args);
|
||||
|
||||
return models.map(model => this.addCluster(model, ownerId));
|
||||
}
|
||||
|
||||
@action
|
||||
addCluster(clusterOrModel: ClusterModel | Cluster, ownerId?: LensExtensionId): Cluster {
|
||||
appEventBus.emit({ name: "cluster", action: "add" });
|
||||
let cluster = model as Cluster;
|
||||
|
||||
if (!(model instanceof Cluster)) {
|
||||
cluster = new Cluster(model);
|
||||
const cluster = clusterOrModel instanceof Cluster
|
||||
? clusterOrModel
|
||||
: new Cluster(clusterOrModel);
|
||||
|
||||
if (ownerId) {
|
||||
if (this.isClusterManaged(cluster)) {
|
||||
throw new Error("Extension tried to claim an already managed cluster");
|
||||
}
|
||||
|
||||
if (!cluster.isManaged) {
|
||||
cluster.enabled = true;
|
||||
this.clusterManagingInfo.set(cluster.id, { ownerId, enabled: false });
|
||||
}
|
||||
this.clusters.set(model.id, cluster);
|
||||
|
||||
this.clusters.set(clusterOrModel.id, cluster);
|
||||
|
||||
return cluster;
|
||||
}
|
||||
@ -296,7 +356,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
if (cluster) {
|
||||
this.clusters.delete(clusterId);
|
||||
|
||||
if (this.activeCluster === clusterId) {
|
||||
if (this.activeClusterId === clusterId) {
|
||||
this.setActive(null);
|
||||
}
|
||||
|
||||
@ -309,31 +369,43 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
|
||||
@action
|
||||
removeByWorkspaceId(workspaceId: string) {
|
||||
this.getByWorkspaceId(workspaceId).forEach(cluster => {
|
||||
this.removeById(cluster.id);
|
||||
const workspaceClusters = this.getByWorkspaceId(workspaceId, {
|
||||
includeDisabled: true,
|
||||
sortByIconOrder: false,
|
||||
});
|
||||
|
||||
for (const cluster of workspaceClusters) {
|
||||
this.removeById(cluster.id);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
protected fromStore({ activeCluster, clusters = [] }: ClusterStoreModel = {}) {
|
||||
protected fromStore({ activeClusterId, clusters = [], clusterOwners = [] }: ClusterStoreModel = {}) {
|
||||
const currentClusters = this.clusters.toJS();
|
||||
const newClusters = new Map<ClusterId, Cluster>();
|
||||
const removedClusters = new Map<ClusterId, Cluster>();
|
||||
const erroredClusterModels: ClusterModel[] = [];
|
||||
const clusterOwnersMap = new Map<ClusterId, LensExtensionId>(clusterOwners);
|
||||
|
||||
// update new clusters
|
||||
for (const clusterModel of clusters) {
|
||||
let cluster = currentClusters.get(clusterModel.id);
|
||||
if (currentClusters.has(clusterModel.id)) {
|
||||
const cluster = currentClusters.get(clusterModel.id);
|
||||
|
||||
if (cluster) {
|
||||
cluster.updateModel(clusterModel);
|
||||
} else {
|
||||
cluster = new Cluster(clusterModel);
|
||||
|
||||
if (!cluster.isManaged && cluster.apiUrl) {
|
||||
cluster.enabled = true;
|
||||
}
|
||||
}
|
||||
newClusters.set(clusterModel.id, cluster);
|
||||
} else {
|
||||
try {
|
||||
newClusters.set(clusterModel.id, new Cluster(clusterModel));
|
||||
} catch (error) {
|
||||
const { preferences, contextName: context, kubeConfigPath: kubeconfig } = clusterModel;
|
||||
const clusterName = preferences?.clusterName || context;
|
||||
|
||||
logger.error(`[CLUSTER-STORE]: Failed to load kubeconfig for the cluster '${clusterName}'.`, { error, context, kubeconfig });
|
||||
broadcastMessage(InvalidKubeconfigChannel, clusterModel.id);
|
||||
erroredClusterModels.push(clusterModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update removed clusters
|
||||
@ -343,15 +415,17 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
}
|
||||
});
|
||||
|
||||
this.activeCluster = newClusters.get(activeCluster)?.enabled ? activeCluster : null;
|
||||
this.activeClusterId = clusterOwnersMap.get(activeClusterId) ? null : activeClusterId;
|
||||
this.clusters.replace(newClusters);
|
||||
this.removedClusters.replace(removedClusters);
|
||||
this.erroredClusterModels.replace(erroredClusterModels);
|
||||
this.clusterManagingInfo.replace(clusterOwnersMap);
|
||||
}
|
||||
|
||||
toJSON(): ClusterStoreModel {
|
||||
return toJS({
|
||||
activeCluster: this.activeCluster,
|
||||
clusters: this.clustersList.map(cluster => cluster.toJSON()),
|
||||
activeClusterId: this.activeClusterId,
|
||||
clusters: this.clustersList.map(cluster => cluster.toJSON()).concat(this.erroredClusterModels),
|
||||
}, {
|
||||
recurseEverything: true
|
||||
});
|
||||
|
||||
0
src/common/utils/split-args.ts
Normal file
0
src/common/utils/split-args.ts
Normal file
@ -44,7 +44,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be installed on
|
||||
*/
|
||||
abstract async install(cluster: Cluster): Promise<void>;
|
||||
abstract install(cluster: Cluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be upgraded. The implementation
|
||||
@ -52,7 +52,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be upgraded on
|
||||
*/
|
||||
abstract async upgrade(cluster: Cluster): Promise<void>;
|
||||
abstract upgrade(cluster: Cluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be uninstalled. The implementation
|
||||
@ -60,7 +60,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be uninstalled from
|
||||
*/
|
||||
abstract async uninstall(cluster: Cluster): Promise<void>;
|
||||
abstract uninstall(cluster: Cluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is called periodically by Lens to determine details about the feature's current status. The implementation
|
||||
@ -72,7 +72,7 @@ export abstract class ClusterFeature {
|
||||
*
|
||||
* @return a promise, resolved with the updated ClusterFeatureStatus
|
||||
*/
|
||||
abstract async updateStatus(cluster: Cluster): Promise<ClusterFeatureStatus>;
|
||||
abstract updateStatus(cluster: Cluster): Promise<ClusterFeatureStatus>;
|
||||
|
||||
/**
|
||||
* this is a helper method that conveniently applies kubernetes resources to the cluster.
|
||||
|
||||
@ -18,14 +18,14 @@ export class ClusterStore extends Singleton {
|
||||
* Active cluster id
|
||||
*/
|
||||
get activeClusterId(): string {
|
||||
return internalClusterStore.activeCluster;
|
||||
return internalClusterStore.activeClusterId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set active cluster id
|
||||
*/
|
||||
set activeClusterId(id : ClusterId) {
|
||||
internalClusterStore.activeCluster = id;
|
||||
internalClusterStore.activeClusterId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -4,7 +4,7 @@ import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api";
|
||||
import type { WorkspaceId } from "../common/workspace-store";
|
||||
import { action, comparer, computed, observable, reaction, toJS, when } from "mobx";
|
||||
import { apiKubePrefix } from "../common/vars";
|
||||
import { broadcastMessage, InvalidKubeconfigChannel } from "../common/ipc";
|
||||
import { broadcastMessage } from "../common/ipc";
|
||||
import { ContextHandler } from "./context-handler";
|
||||
import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node";
|
||||
import { Kubectl } from "./kubectl";
|
||||
@ -38,7 +38,6 @@ export type ClusterRefreshOptions = {
|
||||
|
||||
export interface ClusterState {
|
||||
initialized: boolean;
|
||||
enabled: boolean;
|
||||
apiUrl: string;
|
||||
online: boolean;
|
||||
disconnected: boolean;
|
||||
@ -71,12 +70,6 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
* @internal
|
||||
*/
|
||||
public contextHandler: ContextHandler;
|
||||
/**
|
||||
* Owner reference
|
||||
*
|
||||
* If extension sets this it needs to also mark cluster as enabled on activate (or when added to a store)
|
||||
*/
|
||||
public ownerRef: string;
|
||||
protected kubeconfigManager: KubeconfigManager;
|
||||
protected eventDisposers: Function[] = [];
|
||||
protected activated = false;
|
||||
@ -86,7 +79,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
whenReady = when(() => this.ready);
|
||||
|
||||
/**
|
||||
* Is cluster object initializinng on-going
|
||||
* Is cluster object initializing on-going
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@ -129,12 +122,6 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
* @internal
|
||||
*/
|
||||
@observable kubeProxyUrl: string; // lens-proxy to kube-api url
|
||||
/**
|
||||
* Is cluster instance enabled (disabled clusters are currently hidden)
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable enabled = false; // only enabled clusters are visible to users
|
||||
/**
|
||||
* Is cluster online
|
||||
*
|
||||
@ -258,23 +245,20 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
constructor(model: ClusterModel) {
|
||||
this.updateModel(model);
|
||||
|
||||
try {
|
||||
const kubeconfig = this.getKubeconfig();
|
||||
|
||||
validateKubeConfig(kubeconfig, this.contextName, { validateCluster: true, validateUser: false, validateExec: false});
|
||||
this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server;
|
||||
} catch(err) {
|
||||
logger.error(err);
|
||||
logger.error(`[CLUSTER] Failed to load kubeconfig for the cluster '${this.name || this.contextName}' (context: ${this.contextName}, kubeconfig: ${this.kubeConfigPath}).`);
|
||||
broadcastMessage(InvalidKubeconfigChannel, model.id);
|
||||
}
|
||||
}
|
||||
kubeConfig?: string;
|
||||
|
||||
/**
|
||||
* Is cluster managed by an extension
|
||||
*
|
||||
* @deprecated use `clusterStore.isClusterManaged(clusterId)`
|
||||
*/
|
||||
get isManaged(): boolean {
|
||||
return !!this.ownerRef;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -612,7 +596,6 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
workspace: this.workspace,
|
||||
preferences: this.preferences,
|
||||
metadata: this.metadata,
|
||||
ownerRef: this.ownerRef,
|
||||
accessibleNamespaces: this.accessibleNamespaces,
|
||||
};
|
||||
|
||||
@ -627,7 +610,6 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
getState(): ClusterState {
|
||||
const state: ClusterState = {
|
||||
initialized: this.initialized,
|
||||
enabled: this.enabled,
|
||||
apiUrl: this.apiUrl,
|
||||
online: this.online,
|
||||
ready: this.ready,
|
||||
|
||||
@ -273,7 +273,7 @@ export class Kubectl {
|
||||
|
||||
logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const stream = customRequest({
|
||||
url: this.url,
|
||||
gzip: true,
|
||||
|
||||
@ -183,7 +183,7 @@ export class LensBinary {
|
||||
throw(error);
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
file.on("close", () => {
|
||||
this.logger.debug(`${this.originalBinaryName} binary download closed`);
|
||||
if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => {
|
||||
|
||||
12
src/migrations/cluster-store/4.2.0.ts
Normal file
12
src/migrations/cluster-store/4.2.0.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { migration } from "../migration-wrapper";
|
||||
|
||||
export default migration({
|
||||
version: "4.2.0",
|
||||
run(store) {
|
||||
const activeCluster = store.get("activeCluster");
|
||||
|
||||
if (activeCluster) {
|
||||
store.set("activeClusterId", activeCluster);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -7,6 +7,7 @@ import version260Beta3 from "./2.6.0-beta.3";
|
||||
import version270Beta0 from "./2.7.0-beta.0";
|
||||
import version270Beta1 from "./2.7.0-beta.1";
|
||||
import version360Beta1 from "./3.6.0-beta.1";
|
||||
import version420 from "./4.2.0";
|
||||
import snap from "./snap";
|
||||
|
||||
export default {
|
||||
@ -17,5 +18,6 @@ export default {
|
||||
...version270Beta0,
|
||||
...version270Beta1,
|
||||
...version360Beta1,
|
||||
...version420,
|
||||
...snap
|
||||
};
|
||||
|
||||
@ -56,7 +56,6 @@ export class WorkspaceClusterStore extends ItemStore<ClusterItem> {
|
||||
() => (
|
||||
clusterStore
|
||||
.getByWorkspaceId(this.workspaceId)
|
||||
.filter(cluster => cluster.enabled)
|
||||
.map(cluster => new ClusterItem(cluster))
|
||||
)
|
||||
);
|
||||
|
||||
@ -108,8 +108,8 @@ export class ClustersMenu extends React.Component<Props> {
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
const workspace = workspaceStore.getById(workspaceStore.currentWorkspaceId);
|
||||
const clusters = clusterStore.getByWorkspaceId(workspace.id).filter(cluster => cluster.enabled);
|
||||
const activeClusterId = clusterStore.activeCluster;
|
||||
const clusters = clusterStore.getByWorkspaceId(workspace.id);
|
||||
const activeClusterId = clusterStore.activeClusterId;
|
||||
|
||||
return (
|
||||
<div className={cssNames("ClustersMenu flex column", className)}>
|
||||
@ -192,7 +192,7 @@ export class ClustersMenu extends React.Component<Props> {
|
||||
@observer
|
||||
export class ChooseCluster extends React.Component {
|
||||
@computed get options() {
|
||||
const clusters = clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId).filter(cluster => cluster.enabled);
|
||||
const clusters = clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId);
|
||||
const options = clusters.map((cluster) => {
|
||||
return { value: cluster.id, label: cluster.name };
|
||||
});
|
||||
|
||||
@ -17,7 +17,7 @@ export class ReadableWebToNodeStream extends Readable {
|
||||
* Default web API stream reader
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader
|
||||
*/
|
||||
private reader: ReadableStreamReader;
|
||||
private reader: ReadableStreamReader<any>;
|
||||
private pendingRead: Promise<any>;
|
||||
|
||||
/**
|
||||
|
||||
24
yarn.lock
24
yarn.lock
@ -4052,6 +4052,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
|
||||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
create-require@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cross-fetch@^3.0.4:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c"
|
||||
@ -13460,12 +13465,13 @@ ts-loader@^7.0.5:
|
||||
micromatch "^4.0.0"
|
||||
semver "^6.0.0"
|
||||
|
||||
ts-node@^8.10.2:
|
||||
version "8.10.2"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d"
|
||||
integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==
|
||||
ts-node@^9.1.1:
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
|
||||
integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
|
||||
dependencies:
|
||||
arg "^4.1.0"
|
||||
create-require "^1.1.0"
|
||||
diff "^4.0.1"
|
||||
make-error "^1.1.1"
|
||||
source-map-support "^0.5.17"
|
||||
@ -13618,16 +13624,16 @@ typeface-roboto@^0.0.75:
|
||||
resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-0.0.75.tgz#98d5ba35ec234bbc7172374c8297277099cc712b"
|
||||
integrity sha512-VrR/IiH00Z1tFP4vDGfwZ1esNqTiDMchBEXYY9kilT6wRGgFoCAlgkEUMHb1E3mB0FsfZhv756IF0+R+SFPfdg==
|
||||
|
||||
typescript@4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2"
|
||||
integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==
|
||||
|
||||
typescript@^4.0.3:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9"
|
||||
integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==
|
||||
|
||||
typescript@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
|
||||
integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
|
||||
|
||||
uglify-js@^3.1.4:
|
||||
version "3.9.4"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.4.tgz#867402377e043c1fc7b102253a22b64e5862401b"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user