mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fix cluster.test.ts tests
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
199f142559
commit
ffb840f0ed
@ -3,7 +3,6 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ipcMain } from "electron";
|
|
||||||
import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
|
import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
|
||||||
import { broadcastMessage } from "../ipc";
|
import { broadcastMessage } from "../ipc";
|
||||||
import type { ClusterContextHandler } from "../../main/context-handler/context-handler";
|
import type { ClusterContextHandler } from "../../main/context-handler/context-handler";
|
||||||
@ -14,7 +13,6 @@ import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig
|
|||||||
import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from "../kube-helpers";
|
import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from "../kube-helpers";
|
||||||
import type { KubeApiResource, KubeResource } from "../rbac";
|
import type { KubeApiResource, KubeResource } from "../rbac";
|
||||||
import { apiResourceRecord, apiResources } from "../rbac";
|
import { apiResourceRecord, apiResources } from "../rbac";
|
||||||
import logger from "../../main/logger";
|
|
||||||
import { VersionDetector } from "../../main/cluster-detectors/version-detector";
|
import { VersionDetector } from "../../main/cluster-detectors/version-detector";
|
||||||
import { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
|
import { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
|
||||||
import plimit from "p-limit";
|
import plimit from "p-limit";
|
||||||
@ -26,11 +24,13 @@ import { clusterListNamespaceForbiddenChannel } from "../ipc/cluster";
|
|||||||
import type { CanI } from "./authorization-review.injectable";
|
import type { CanI } from "./authorization-review.injectable";
|
||||||
import type { ListNamespaces } from "./list-namespaces.injectable";
|
import type { ListNamespaces } from "./list-namespaces.injectable";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
|
import type { Logger } from "../logger";
|
||||||
|
|
||||||
export interface ClusterDependencies {
|
export interface ClusterDependencies {
|
||||||
readonly directoryForKubeConfigs: string;
|
readonly directoryForKubeConfigs: string;
|
||||||
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager;
|
readonly logger: Logger;
|
||||||
createContextHandler: (cluster: Cluster) => ClusterContextHandler;
|
createKubeconfigManager: (cluster: Cluster) => KubeconfigManager | undefined;
|
||||||
|
createContextHandler: (cluster: Cluster) => ClusterContextHandler | undefined;
|
||||||
createKubectl: (clusterVersion: string) => Kubectl;
|
createKubectl: (clusterVersion: string) => Kubectl;
|
||||||
createAuthorizationReview: (config: KubeConfig) => CanI;
|
createAuthorizationReview: (config: KubeConfig) => CanI;
|
||||||
createListNamespaces: (config: KubeConfig) => ListNamespaces;
|
createListNamespaces: (config: KubeConfig) => ListNamespaces;
|
||||||
@ -256,17 +256,14 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
|
|
||||||
this.apiUrl = cluster.server;
|
this.apiUrl = cluster.server;
|
||||||
|
|
||||||
if (ipcMain) {
|
// for the time being, until renderer gets its own cluster type
|
||||||
// for the time being, until renderer gets its own cluster type
|
this._contextHandler = this.dependencies.createContextHandler(this);
|
||||||
this._contextHandler = this.dependencies.createContextHandler(this);
|
this._proxyKubeconfigManager = this.dependencies.createKubeconfigManager(this);
|
||||||
this._proxyKubeconfigManager = this.dependencies.createKubeconfigManager(this);
|
this.dependencies.logger.debug(`[CLUSTER]: Cluster init success`, {
|
||||||
|
id: this.id,
|
||||||
logger.debug(`[CLUSTER]: Cluster init success`, {
|
context: this.contextName,
|
||||||
id: this.id,
|
apiUrl: this.apiUrl,
|
||||||
context: this.contextName,
|
});
|
||||||
apiUrl: this.apiUrl,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -309,7 +306,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
protected bindEvents() {
|
protected bindEvents() {
|
||||||
logger.info(`[CLUSTER]: bind events`, this.getMeta());
|
this.dependencies.logger.info(`[CLUSTER]: bind events`, this.getMeta());
|
||||||
const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s
|
const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s
|
||||||
const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes
|
const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes
|
||||||
|
|
||||||
@ -330,13 +327,13 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
protected async recreateProxyKubeconfig() {
|
protected async recreateProxyKubeconfig() {
|
||||||
logger.info("[CLUSTER]: Recreating proxy kubeconfig");
|
this.dependencies.logger.info("[CLUSTER]: Recreating proxy kubeconfig");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.proxyKubeconfigManager.clear();
|
await this.proxyKubeconfigManager.clear();
|
||||||
await this.getProxyKubeconfig();
|
await this.getProxyKubeconfig();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`[CLUSTER]: failed to recreate proxy kubeconfig`, error);
|
this.dependencies.logger.error(`[CLUSTER]: failed to recreate proxy kubeconfig`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +347,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
return this.pushState();
|
return this.pushState();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`[CLUSTER]: activate`, this.getMeta());
|
this.dependencies.logger.info(`[CLUSTER]: activate`, this.getMeta());
|
||||||
|
|
||||||
if (!this.eventsDisposer.length) {
|
if (!this.eventsDisposer.length) {
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
@ -368,7 +365,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
await this.refreshAccessibility();
|
await this.refreshAccessibility();
|
||||||
// download kubectl in background, so it's not blocking dashboard
|
// download kubectl in background, so it's not blocking dashboard
|
||||||
this.ensureKubectl()
|
this.ensureKubectl()
|
||||||
.catch(error => logger.warn(`[CLUSTER]: failed to download kubectl for clusterId=${this.id}`, error));
|
.catch(error => this.dependencies.logger.warn(`[CLUSTER]: failed to download kubectl for clusterId=${this.id}`, error));
|
||||||
this.broadcastConnectUpdate("Connected, waiting for view to load ...");
|
this.broadcastConnectUpdate("Connected, waiting for view to load ...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +389,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
*/
|
*/
|
||||||
@action
|
@action
|
||||||
async reconnect() {
|
async reconnect() {
|
||||||
logger.info(`[CLUSTER]: reconnect`, this.getMeta());
|
this.dependencies.logger.info(`[CLUSTER]: reconnect`, this.getMeta());
|
||||||
await this.contextHandler?.restartServer();
|
await this.contextHandler?.restartServer();
|
||||||
this.disconnected = false;
|
this.disconnected = false;
|
||||||
}
|
}
|
||||||
@ -402,10 +399,10 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
*/
|
*/
|
||||||
@action disconnect(): void {
|
@action disconnect(): void {
|
||||||
if (this.disconnected) {
|
if (this.disconnected) {
|
||||||
return void logger.debug("[CLUSTER]: already disconnected", { id: this.id });
|
return void this.dependencies.logger.debug("[CLUSTER]: already disconnected", { id: this.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`[CLUSTER]: disconnecting`, { id: this.id });
|
this.dependencies.logger.info(`[CLUSTER]: disconnecting`, { id: this.id });
|
||||||
this.eventsDisposer();
|
this.eventsDisposer();
|
||||||
this.contextHandler?.stopServer();
|
this.contextHandler?.stopServer();
|
||||||
this.disconnected = true;
|
this.disconnected = true;
|
||||||
@ -416,7 +413,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
this.allowedNamespaces = [];
|
this.allowedNamespaces = [];
|
||||||
this.resourceAccessStatuses.clear();
|
this.resourceAccessStatuses.clear();
|
||||||
this.pushState();
|
this.pushState();
|
||||||
logger.info(`[CLUSTER]: disconnected`, { id: this.id });
|
this.dependencies.logger.info(`[CLUSTER]: disconnected`, { id: this.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -425,7 +422,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
*/
|
*/
|
||||||
@action
|
@action
|
||||||
async refresh(opts: ClusterRefreshOptions = {}) {
|
async refresh(opts: ClusterRefreshOptions = {}) {
|
||||||
logger.info(`[CLUSTER]: refresh`, this.getMeta());
|
this.dependencies.logger.info(`[CLUSTER]: refresh`, this.getMeta());
|
||||||
await this.refreshConnectionStatus();
|
await this.refreshConnectionStatus();
|
||||||
|
|
||||||
if (this.accessible) {
|
if (this.accessible) {
|
||||||
@ -443,7 +440,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
*/
|
*/
|
||||||
@action
|
@action
|
||||||
async refreshMetadata() {
|
async refreshMetadata() {
|
||||||
logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
|
this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
|
||||||
const metadata = await DetectorRegistry.getInstance().detectForCluster(this);
|
const metadata = await DetectorRegistry.getInstance().detectForCluster(this);
|
||||||
const existingMetadata = this.metadata;
|
const existingMetadata = this.metadata;
|
||||||
|
|
||||||
@ -514,7 +511,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
|
|
||||||
return ClusterStatus.AccessGranted;
|
return ClusterStatus.AccessGranted;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`[CLUSTER]: Failed to connect to "${this.contextName}": ${error}`);
|
this.dependencies.logger.error(`[CLUSTER]: Failed to connect to "${this.contextName}": ${error}`);
|
||||||
|
|
||||||
if (isRequestError(error)) {
|
if (isRequestError(error)) {
|
||||||
if (error.statusCode) {
|
if (error.statusCode) {
|
||||||
@ -594,7 +591,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
* @param state cluster state
|
* @param state cluster state
|
||||||
*/
|
*/
|
||||||
pushState(state = this.getState()) {
|
pushState(state = this.getState()) {
|
||||||
logger.silly(`[CLUSTER]: push-state`, state);
|
this.dependencies.logger.silly(`[CLUSTER]: push-state`, state);
|
||||||
broadcastMessage("cluster:state", this.id, state);
|
broadcastMessage("cluster:state", this.id, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,7 +614,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
broadcastConnectUpdate(message: string, isError = false): void {
|
broadcastConnectUpdate(message: string, isError = false): void {
|
||||||
const update: KubeAuthUpdate = { message, isError };
|
const update: KubeAuthUpdate = { message, isError };
|
||||||
|
|
||||||
logger.debug(`[CLUSTER]: broadcasting connection update`, { ...update, meta: this.getMeta() });
|
this.dependencies.logger.debug(`[CLUSTER]: broadcasting connection update`, { ...update, meta: this.getMeta() });
|
||||||
broadcastMessage(`cluster:${this.id}:connection-update`, update);
|
broadcastMessage(`cluster:${this.id}:connection-update`, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,7 +634,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
if (namespaceList.length === 0 && error instanceof HttpError && error.statusCode === 403) {
|
if (namespaceList.length === 0 && error instanceof HttpError && error.statusCode === 403) {
|
||||||
const { response } = error as HttpError & { response: Response };
|
const { response } = error as HttpError & { response: Response };
|
||||||
|
|
||||||
logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.id, error: response.body });
|
this.dependencies.logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.id, error: response.body });
|
||||||
broadcastMessage(clusterListNamespaceForbiddenChannel, this.id);
|
broadcastMessage(clusterListNamespaceForbiddenChannel, this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export interface Logger {
|
|||||||
error: (message: string, ...args: any) => void;
|
error: (message: string, ...args: any) => void;
|
||||||
debug: (message: string, ...args: any) => void;
|
debug: (message: string, ...args: any) => void;
|
||||||
warn: (message: string, ...args: any) => void;
|
warn: (message: string, ...args: any) => void;
|
||||||
|
silly: (message: string, ...args: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const logLevel = process.env.LOG_LEVEL
|
const logLevel = process.env.LOG_LEVEL
|
||||||
|
|||||||
@ -3,32 +3,6 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const logger = {
|
|
||||||
silly: jest.fn(),
|
|
||||||
debug: jest.fn(),
|
|
||||||
log: jest.fn(),
|
|
||||||
info: jest.fn(),
|
|
||||||
error: jest.fn(),
|
|
||||||
crit: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
jest.mock("winston", () => ({
|
|
||||||
format: {
|
|
||||||
colorize: jest.fn(),
|
|
||||||
combine: jest.fn(),
|
|
||||||
simple: jest.fn(),
|
|
||||||
label: jest.fn(),
|
|
||||||
timestamp: jest.fn(),
|
|
||||||
printf: jest.fn(),
|
|
||||||
splat: jest.fn(),
|
|
||||||
},
|
|
||||||
createLogger: jest.fn().mockReturnValue(logger),
|
|
||||||
transports: {
|
|
||||||
Console: jest.fn(),
|
|
||||||
File: jest.fn(),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock("../../common/ipc");
|
jest.mock("../../common/ipc");
|
||||||
jest.mock("request");
|
jest.mock("request");
|
||||||
jest.mock("request-promise-native");
|
jest.mock("request-promise-native");
|
||||||
@ -109,6 +83,7 @@ describe("create clusters", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
cluster.disconnect();
|
||||||
mockFs.restore();
|
mockFs.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import createContextHandlerInjectable from "../context-handler/create-context-ha
|
|||||||
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
||||||
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
|
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
|
||||||
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
||||||
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
|
|
||||||
const createClusterInjectable = getInjectable({
|
const createClusterInjectable = getInjectable({
|
||||||
id: "create-cluster",
|
id: "create-cluster",
|
||||||
@ -24,6 +25,7 @@ const createClusterInjectable = getInjectable({
|
|||||||
createContextHandler: di.inject(createContextHandlerInjectable),
|
createContextHandler: di.inject(createContextHandlerInjectable),
|
||||||
createAuthorizationReview: di.inject(authorizationReviewInjectable),
|
createAuthorizationReview: di.inject(authorizationReviewInjectable),
|
||||||
createListNamespaces: di.inject(listNamespacesInjectable),
|
createListNamespaces: di.inject(listNamespacesInjectable),
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (model) => new Cluster(dependencies, model);
|
return (model) => new Cluster(dependencies, model);
|
||||||
|
|||||||
@ -108,6 +108,7 @@ export const getDiForUnitTesting = (
|
|||||||
debug: noop,
|
debug: noop,
|
||||||
error: (message: string, ...args: any) => console.error(message, ...args),
|
error: (message: string, ...args: any) => console.error(message, ...args),
|
||||||
info: noop,
|
info: noop,
|
||||||
|
silly: noop,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import type { ClusterDependencies } from "../../common/cluster/cluster";
|
|||||||
import { Cluster } from "../../common/cluster/cluster";
|
import { Cluster } from "../../common/cluster/cluster";
|
||||||
import directoryForKubeConfigsInjectable from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
import directoryForKubeConfigsInjectable from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||||
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
||||||
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
|
|
||||||
const createClusterInjectable = getInjectable({
|
const createClusterInjectable = getInjectable({
|
||||||
id: "create-cluster",
|
id: "create-cluster",
|
||||||
@ -14,11 +15,12 @@ const createClusterInjectable = getInjectable({
|
|||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const dependencies: ClusterDependencies = {
|
const dependencies: ClusterDependencies = {
|
||||||
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
|
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
|
||||||
createKubeconfigManager: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
createKubeconfigManager: () => undefined,
|
||||||
createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");},
|
createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");},
|
||||||
createContextHandler: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
createContextHandler: () => undefined,
|
||||||
createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||||
createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (model) => new Cluster(dependencies, model);
|
return (model) => new Cluster(dependencies, model);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user