mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Clean up electron-store based stores
- Add some type script types for better editor experience - Remove redundent global of a singleton Signed-off-by: Sebastian Malton <smalton@mirantis.com> remove references to double statics Signed-off-by: Sebastian Malton <smalton@mirantis.com> fix mocking of user-store Signed-off-by: Sebastian Malton <smalton@mirantis.com>
This commit is contained in:
parent
55687b7d35
commit
a6f7bc3c10
25
spec/src/main/kubectl_spec.ts
Normal file
25
spec/src/main/kubectl_spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
jest.mock("electron")
|
||||||
|
jest.mock("../../../src/common/user-store", () => ({
|
||||||
|
UserStore: {
|
||||||
|
getInstance: () => ({
|
||||||
|
getPreferences: () => ({
|
||||||
|
downloadMirror: "default",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
import { Kubectl } from "../../../src/main/kubectl"
|
||||||
|
|
||||||
|
describe("kubectlVersion", () => {
|
||||||
|
|
||||||
|
it("returns bundled version if exactly same version used", async () => {
|
||||||
|
const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion)
|
||||||
|
expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns bundled version if same major.minor version is used", async () => {
|
||||||
|
const kubectl = new Kubectl("1.17.0")
|
||||||
|
expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion)
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -11,7 +11,7 @@ import { getAppVersion } from "./utils/app-version";
|
|||||||
|
|
||||||
export class ClusterStore {
|
export class ClusterStore {
|
||||||
private static instance: ClusterStore;
|
private static instance: ClusterStore;
|
||||||
public store: ElectronStore;
|
private store: ElectronStore;
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
this.store = new ElectronStore({
|
this.store = new ElectronStore({
|
||||||
@ -116,5 +116,3 @@ export class ClusterStore {
|
|||||||
ClusterStore.instance = null
|
ClusterStore.instance = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const clusterStore: ClusterStore = ClusterStore.getInstance();
|
|
||||||
|
|||||||
@ -235,7 +235,7 @@ describe("for a pre 2.4.1 config with an existing cluster", () => {
|
|||||||
|
|
||||||
it("migrates to modern format throwing out the state related data", async () => {
|
it("migrates to modern format throwing out the state related data", async () => {
|
||||||
const clusterStore = ClusterStore.getInstance()
|
const clusterStore = ClusterStore.getInstance()
|
||||||
const storedClusterData = clusterStore.store.get('clusters')[0]
|
const storedClusterData = clusterStore.getAllClusters()[0]
|
||||||
expect(storedClusterData.hasOwnProperty('online')).toBe(false)
|
expect(storedClusterData.hasOwnProperty('online')).toBe(false)
|
||||||
expect(storedClusterData.hasOwnProperty('accessible')).toBe(false)
|
expect(storedClusterData.hasOwnProperty('accessible')).toBe(false)
|
||||||
expect(storedClusterData.hasOwnProperty('failureReason')).toBe(false)
|
expect(storedClusterData.hasOwnProperty('failureReason')).toBe(false)
|
||||||
@ -306,7 +306,7 @@ describe("for a pre 2.6.0 config with a cluster icon", () => {
|
|||||||
|
|
||||||
it("moves the icon into preferences", async () => {
|
it("moves the icon into preferences", async () => {
|
||||||
const clusterStore = ClusterStore.getInstance()
|
const clusterStore = ClusterStore.getInstance()
|
||||||
const storedClusterData = clusterStore.store.get('clusters')[0]
|
const storedClusterData = clusterStore.getAllClusters()[0]
|
||||||
expect(storedClusterData.hasOwnProperty('icon')).toBe(false)
|
expect(storedClusterData.hasOwnProperty('icon')).toBe(false)
|
||||||
expect(storedClusterData.preferences.hasOwnProperty('icon')).toBe(true)
|
expect(storedClusterData.preferences.hasOwnProperty('icon')).toBe(true)
|
||||||
expect(storedClusterData.preferences.icon).toBe("icon path")
|
expect(storedClusterData.preferences.icon).toBe("icon path")
|
||||||
@ -343,7 +343,7 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => {
|
|||||||
|
|
||||||
it("adds cluster to default workspace", async () => {
|
it("adds cluster to default workspace", async () => {
|
||||||
const clusterStore = ClusterStore.getInstance()
|
const clusterStore = ClusterStore.getInstance()
|
||||||
const storedClusterData = clusterStore.store.get("clusters")[0]
|
const storedClusterData = clusterStore.getAllClusters()[0]
|
||||||
expect(storedClusterData.workspace).toBe('default')
|
expect(storedClusterData.workspace).toBe('default')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import request from "request"
|
import { Options } from "request"
|
||||||
import { userStore } from "./user-store"
|
import { UserStore } from "../common/user-store"
|
||||||
|
|
||||||
export function globalRequestOpts(requestOpts: request.Options ) {
|
export function globalRequestOpts(requestOpts: Options): Options {
|
||||||
const userPrefs = userStore.getPreferences()
|
const userPrefs = UserStore.getInstance().getPreferences()
|
||||||
if (userPrefs.httpsProxy) {
|
if (userPrefs.httpsProxy) {
|
||||||
requestOpts.proxy = userPrefs.httpsProxy
|
requestOpts.proxy = userPrefs.httpsProxy
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import ua from "universal-analytics"
|
import ua from "universal-analytics"
|
||||||
import { machineIdSync } from "node-machine-id"
|
import { machineIdSync } from 'node-machine-id'
|
||||||
import { userStore } from "./user-store"
|
import { UserStore } from "../common/user-store"
|
||||||
|
|
||||||
const GA_ID = "UA-159377374-1"
|
const GA_ID = "UA-159377374-1"
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export class Tracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected telemetryAllowed() {
|
protected telemetryAllowed() {
|
||||||
const userPrefs = userStore.getPreferences()
|
const userPrefs = UserStore.getInstance().getPreferences()
|
||||||
return !!userPrefs.allowTelemetry
|
return !!userPrefs.allowTelemetry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export interface UserPreferences {
|
|||||||
|
|
||||||
export class UserStore {
|
export class UserStore {
|
||||||
private static instance: UserStore;
|
private static instance: UserStore;
|
||||||
public store: ElectronStore;
|
private store: ElectronStore;
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
this.store = new ElectronStore({
|
this.store = new ElectronStore({
|
||||||
@ -56,17 +56,11 @@ export class UserStore {
|
|||||||
|
|
||||||
public getPreferences(): UserPreferences {
|
public getPreferences(): UserPreferences {
|
||||||
const prefs = this.store.get("preferences", {})
|
const prefs = this.store.get("preferences", {})
|
||||||
if (!prefs.colorTheme) {
|
prefs.colorTheme = prefs.colorTheme || "dark";
|
||||||
prefs.colorTheme = "dark"
|
prefs.downloadMirror = prefs.downloadMirror || "default";
|
||||||
}
|
prefs.allowTelemetry = prefs.allowTelemetry ?? true;
|
||||||
if (!prefs.downloadMirror) {
|
|
||||||
prefs.downloadMirror = "default"
|
|
||||||
}
|
|
||||||
if (prefs.allowTelemetry === undefined) {
|
|
||||||
prefs.allowTelemetry = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefs
|
return prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInstance(): UserStore {
|
static getInstance(): UserStore {
|
||||||
@ -80,7 +74,3 @@ export class UserStore {
|
|||||||
UserStore.instance = null
|
UserStore.instance = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const userStore: UserStore = UserStore.getInstance();
|
|
||||||
|
|
||||||
export { userStore };
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import mockFs from "mock-fs"
|
import mockFs from "mock-fs"
|
||||||
import { userStore, UserStore } from "./user-store"
|
import { UserStore } from "./user-store"
|
||||||
|
|
||||||
// Console.log needs to be called before fs-mocks, see https://github.com/tschaub/mock-fs/issues/234
|
// Console.log needs to be called before fs-mocks, see https://github.com/tschaub/mock-fs/issues/234
|
||||||
console.log("");
|
console.log("");
|
||||||
@ -13,7 +13,6 @@ describe("for an empty config", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mockFs(mockOpts)
|
mockFs(mockOpts)
|
||||||
const userStore = UserStore.getInstance()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -21,31 +20,31 @@ describe("for an empty config", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("allows setting and retrieving lastSeenAppVersion", async () => {
|
it("allows setting and retrieving lastSeenAppVersion", async () => {
|
||||||
userStore.setLastSeenAppVersion("1.2.3");
|
UserStore.getInstance().setLastSeenAppVersion("1.2.3");
|
||||||
expect(userStore.lastSeenAppVersion()).toBe("1.2.3");
|
expect(UserStore.getInstance().lastSeenAppVersion()).toBe("1.2.3");
|
||||||
})
|
})
|
||||||
|
|
||||||
it("allows adding and listing seen contexts", async () => {
|
it("allows adding and listing seen contexts", async () => {
|
||||||
userStore.storeSeenContext(['foo'])
|
UserStore.getInstance().storeSeenContext(['foo'])
|
||||||
expect(userStore.getSeenContexts().length).toBe(1)
|
expect(UserStore.getInstance().getSeenContexts().length).toBe(1)
|
||||||
userStore.storeSeenContext(['foo', 'bar'])
|
UserStore.getInstance().storeSeenContext(['foo', 'bar'])
|
||||||
const seenContexts = userStore.getSeenContexts()
|
const seenContexts = UserStore.getInstance().getSeenContexts()
|
||||||
expect(seenContexts.length).toBe(2) // check 'foo' isn't added twice
|
expect(seenContexts.length).toBe(2) // check 'foo' isn't added twice
|
||||||
expect(seenContexts[0]).toBe('foo')
|
expect(seenContexts[0]).toBe('foo')
|
||||||
expect(seenContexts[1]).toBe('bar')
|
expect(seenContexts[1]).toBe('bar')
|
||||||
})
|
})
|
||||||
|
|
||||||
it("allows setting and getting preferences", async () => {
|
it("allows setting and getting preferences", async () => {
|
||||||
userStore.setPreferences({
|
UserStore.getInstance().setPreferences({
|
||||||
httpsProxy: 'abcd://defg',
|
httpsProxy: 'abcd://defg',
|
||||||
})
|
})
|
||||||
const storedPreferences = userStore.getPreferences()
|
const storedPreferences = UserStore.getInstance().getPreferences()
|
||||||
expect(storedPreferences.httpsProxy).toBe('abcd://defg')
|
expect(storedPreferences.httpsProxy).toBe('abcd://defg')
|
||||||
expect(storedPreferences.colorTheme).toBe('dark') // defaults to dark
|
expect(storedPreferences.colorTheme).toBe('dark') // defaults to dark
|
||||||
userStore.setPreferences({
|
UserStore.getInstance().setPreferences({
|
||||||
colorTheme: 'light'
|
colorTheme: 'light'
|
||||||
})
|
})
|
||||||
expect(userStore.getPreferences().colorTheme).toBe('light')
|
expect(UserStore.getInstance().getPreferences().colorTheme).toBe('light')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -62,7 +61,6 @@ describe("migrations", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mockFs(mockOpts)
|
mockFs(mockOpts)
|
||||||
const userStore = UserStore.getInstance()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -70,6 +68,6 @@ describe("migrations", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("sets last seen app version to 0.0.0", async () => {
|
it("sets last seen app version to 0.0.0", async () => {
|
||||||
expect(userStore.lastSeenAppVersion()).toBe('0.0.0')
|
expect(UserStore.getInstance().lastSeenAppVersion()).toBe('0.0.0')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ElectronStore from "electron-store"
|
import ElectronStore from "electron-store"
|
||||||
import { clusterStore } from "./cluster-store"
|
import { ClusterStore } from "./cluster-store"
|
||||||
|
|
||||||
export interface WorkspaceData {
|
export interface WorkspaceData {
|
||||||
id: string;
|
id: string;
|
||||||
@ -7,6 +7,10 @@ export interface WorkspaceData {
|
|||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WorkspaceStoreData {
|
||||||
|
workspaces: WorkspaceData[];
|
||||||
|
}
|
||||||
|
|
||||||
export class Workspace implements WorkspaceData {
|
export class Workspace implements WorkspaceData {
|
||||||
public id: string
|
public id: string
|
||||||
public name: string
|
public name: string
|
||||||
@ -20,12 +24,19 @@ export class Workspace implements WorkspaceData {
|
|||||||
export class WorkspaceStore {
|
export class WorkspaceStore {
|
||||||
public static defaultId = "default"
|
public static defaultId = "default"
|
||||||
private static instance: WorkspaceStore;
|
private static instance: WorkspaceStore;
|
||||||
public store: ElectronStore;
|
private store: ElectronStore<WorkspaceStoreData>;
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
this.store = new ElectronStore({
|
this.store = new ElectronStore({
|
||||||
name: "lens-workspace-store"
|
name: "lens-workspace-store",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (this.store.get("workspaces", []).length === 0) {
|
||||||
|
this.store.set("workspaces", [{
|
||||||
|
id: "default",
|
||||||
|
name: "default"
|
||||||
|
}]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public storeWorkspace(workspace: WorkspaceData) {
|
public storeWorkspace(workspace: WorkspaceData) {
|
||||||
@ -46,12 +57,16 @@ export class WorkspaceStore {
|
|||||||
const workspaces = this.getAllWorkspaces()
|
const workspaces = this.getAllWorkspaces()
|
||||||
const index = workspaces.findIndex((w) => w.id === workspace.id)
|
const index = workspaces.findIndex((w) => w.id === workspace.id)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
clusterStore.removeClustersByWorkspace(workspace.id)
|
ClusterStore.getInstance().removeClustersByWorkspace(workspace.id)
|
||||||
workspaces.splice(index, 1)
|
workspaces.splice(index, 1)
|
||||||
this.store.set("workspaces", workspaces)
|
this.store.set("workspaces", workspaces)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getWorkspace(id: string): Workspace | null {
|
||||||
|
return this.store.get("workspaces", []).find(wsd => wsd.id == id) || null;
|
||||||
|
}
|
||||||
|
|
||||||
public getAllWorkspaces(): Array<Workspace> {
|
public getAllWorkspaces(): Array<Workspace> {
|
||||||
const workspacesData: WorkspaceData[] = this.store.get("workspaces", [])
|
const workspacesData: WorkspaceData[] = this.store.get("workspaces", [])
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { KubeConfig } from "@kubernetes/client-node"
|
import { KubeConfig } from "@kubernetes/client-node"
|
||||||
import { PromiseIpc } from "electron-promise-ipc"
|
import PromiseIpc from "electron-promise-ipc"
|
||||||
import http from "http"
|
import http from "http"
|
||||||
import { Cluster, ClusterBaseInfo } from "./cluster"
|
import { Cluster, ClusterBaseInfo } from "./cluster"
|
||||||
import { clusterStore } from "../common/cluster-store"
|
import { ClusterStore } from "../common/cluster-store"
|
||||||
import * as k8s from "./k8s"
|
import * as k8s from "./k8s"
|
||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
import { LensProxy } from "./proxy"
|
import { LensProxy } from "./proxy"
|
||||||
@ -39,7 +39,7 @@ export class ClusterManager {
|
|||||||
protected clusters: Map<string, Cluster>;
|
protected clusters: Map<string, Cluster>;
|
||||||
|
|
||||||
constructor(clusters: Cluster[], port: number) {
|
constructor(clusters: Cluster[], port: number) {
|
||||||
this.promiseIpc = new PromiseIpc({ timeout: 2000 })
|
this.promiseIpc = new PromiseIpc.PromiseIpc({ maxTimeoutMs: 2000 })
|
||||||
this.port = port
|
this.port = port
|
||||||
this.clusters = new Map()
|
this.clusters = new Map()
|
||||||
clusters.forEach((clusterInfo) => {
|
clusters.forEach((clusterInfo) => {
|
||||||
@ -174,10 +174,10 @@ export class ClusterManager {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const clusterIcon = await this.uploadClusterIcon(cluster, fileUpload.name, fileUpload.path)
|
const clusterIcon = await this.uploadClusterIcon(cluster, fileUpload.name, fileUpload.path)
|
||||||
clusterStore.reloadCluster(cluster);
|
ClusterStore.getInstance().reloadCluster(cluster);
|
||||||
if(!cluster.preferences) cluster.preferences = {};
|
if(!cluster.preferences) cluster.preferences = {};
|
||||||
cluster.preferences.icon = clusterIcon
|
cluster.preferences.icon = clusterIcon
|
||||||
clusterStore.storeCluster(cluster);
|
ClusterStore.getInstance().storeCluster(cluster);
|
||||||
return {success: true, cluster: cluster.toClusterInfo(), message: ""}
|
return {success: true, cluster: cluster.toClusterInfo(), message: ""}
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
return {success: false, message: error}
|
return {success: false, message: error}
|
||||||
@ -189,7 +189,7 @@ export class ClusterManager {
|
|||||||
const cluster = this.getCluster(id)
|
const cluster = this.getCluster(id)
|
||||||
if (cluster && cluster.preferences) {
|
if (cluster && cluster.preferences) {
|
||||||
cluster.preferences.icon = null;
|
cluster.preferences.icon = null;
|
||||||
clusterStore.storeCluster(cluster)
|
ClusterStore.getInstance().storeCluster(cluster)
|
||||||
return {success: true, cluster: cluster.toClusterInfo(), message: ""}
|
return {success: true, cluster: cluster.toClusterInfo(), message: ""}
|
||||||
} else {
|
} else {
|
||||||
return {success: false, message: "Cluster not found"}
|
return {success: false, message: "Cluster not found"}
|
||||||
@ -221,7 +221,7 @@ export class ClusterManager {
|
|||||||
logger.debug(`IPC: clusterStored: ${clusterId}`)
|
logger.debug(`IPC: clusterStored: ${clusterId}`)
|
||||||
const cluster = this.clusters.get(clusterId)
|
const cluster = this.clusters.get(clusterId)
|
||||||
if (cluster) {
|
if (cluster) {
|
||||||
clusterStore.reloadCluster(cluster);
|
ClusterStore.getInstance().reloadCluster(cluster);
|
||||||
cluster.stopServer()
|
cluster.stopServer()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -244,7 +244,7 @@ export class ClusterManager {
|
|||||||
const cluster = this.clusters.get(id)
|
const cluster = this.clusters.get(id)
|
||||||
if (cluster) {
|
if (cluster) {
|
||||||
cluster.stopServer()
|
cluster.stopServer()
|
||||||
clusterStore.removeCluster(cluster.id);
|
ClusterStore.getInstance().removeCluster(cluster.id);
|
||||||
this.clusters.delete(cluster.id)
|
this.clusters.delete(cluster.id)
|
||||||
}
|
}
|
||||||
return Array.from(this.clusters.values())
|
return Array.from(this.clusters.values())
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { ContextHandler } from "./context-handler"
|
import { ContextHandler } from "./context-handler"
|
||||||
import { FeatureStatusMap } from "./feature"
|
import { FeatureStatusMap } from "./feature"
|
||||||
import * as k8s from "./k8s"
|
import * as k8s from "./k8s"
|
||||||
import { clusterStore } from "../common/cluster-store"
|
import { ClusterStore } from "../common/cluster-store"
|
||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"
|
import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"
|
||||||
import * as fm from "./feature-manager";
|
import * as fm from "./feature-manager";
|
||||||
import { Kubectl } from "./kubectl";
|
import { Kubectl } from "./kubectl";
|
||||||
import { KubeconfigManager } from "./kubeconfig-manager"
|
import { KubeconfigManager } from "./kubeconfig-manager"
|
||||||
import { PromiseIpc } from "electron-promise-ipc"
|
import PromiseIpc from "electron-promise-ipc"
|
||||||
import request from "request-promise-native"
|
import request from "request-promise-native"
|
||||||
import { apiPrefix } from "../common/vars";
|
import { apiPrefix } from "../common/vars";
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ export class Cluster implements ClusterInfo {
|
|||||||
public preferences: ClusterPreferences;
|
public preferences: ClusterPreferences;
|
||||||
|
|
||||||
protected eventPoller: NodeJS.Timeout;
|
protected eventPoller: NodeJS.Timeout;
|
||||||
protected promiseIpc = new PromiseIpc({ timeout: 2000 })
|
protected promiseIpc = new PromiseIpc.PromiseIpc({ maxTimeoutMs: 2000 })
|
||||||
|
|
||||||
protected kubeconfigManager: KubeconfigManager;
|
protected kubeconfigManager: KubeconfigManager;
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ export class Cluster implements ClusterInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async refreshCluster() {
|
public async refreshCluster() {
|
||||||
clusterStore.reloadCluster(this)
|
ClusterStore.getInstance().reloadCluster(this)
|
||||||
this.contextHandler.setClusterPreferences(this.preferences)
|
this.contextHandler.setClusterPreferences(this.preferences)
|
||||||
|
|
||||||
const connectionStatus = await this.getConnectionStatus()
|
const connectionStatus = await this.getConnectionStatus()
|
||||||
@ -147,14 +147,11 @@ export class Cluster implements ClusterInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getPrometheusApiPrefix() {
|
public getPrometheusApiPrefix() {
|
||||||
if (!this.preferences.prometheus?.prefix) {
|
return this.preferences.prometheus?.prefix || "";
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return this.preferences.prometheus.prefix
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public save() {
|
public save() {
|
||||||
clusterStore.storeCluster(this)
|
ClusterStore.getInstance().storeCluster(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
public toClusterInfo(): ClusterInfo {
|
public toClusterInfo(): ClusterInfo {
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import logger from "./logger"
|
|||||||
import initMenu from "./menu"
|
import initMenu from "./menu"
|
||||||
import * as proxy from "./proxy"
|
import * as proxy from "./proxy"
|
||||||
import { WindowManager } from "./window-manager";
|
import { WindowManager } from "./window-manager";
|
||||||
import { clusterStore } from "../common/cluster-store"
|
import { ClusterStore } from "../common/cluster-store"
|
||||||
import { tracker } from "./tracker"
|
import { tracker } from "./tracker"
|
||||||
import { ClusterManager } from "./cluster-manager";
|
import { ClusterManager } from "./cluster-manager";
|
||||||
import AppUpdater from "./app-updater"
|
import AppUpdater from "./app-updater"
|
||||||
@ -70,7 +70,7 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create cluster manager
|
// create cluster manager
|
||||||
clusterManager = new ClusterManager(clusterStore.getAllClusterObjects(), port)
|
clusterManager = new ClusterManager(ClusterStore.getInstance().getAllClusterObjects(), port)
|
||||||
// run proxy
|
// run proxy
|
||||||
try {
|
try {
|
||||||
proxyServer = proxy.listen(port, clusterManager)
|
proxyServer = proxy.listen(port, clusterManager)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { spawn, ChildProcess } from "child_process"
|
import { spawn, ChildProcess } from "child_process"
|
||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
import * as tcpPortUsed from "tcp-port-used"
|
import * as tcpPortUsed from "tcp-port-used"
|
||||||
import { Kubectl, bundledKubectl } from "./kubectl"
|
import { Kubectl } from "./kubectl"
|
||||||
import { Cluster } from "./cluster"
|
import { Cluster } from "./cluster"
|
||||||
import { PromiseIpc } from "electron-promise-ipc"
|
import PromiseIpc from "electron-promise-ipc"
|
||||||
import { findMainWebContents } from "./webcontents"
|
import { findMainWebContents } from "./webcontents"
|
||||||
|
|
||||||
export class KubeAuthProxy {
|
export class KubeAuthProxy {
|
||||||
@ -13,22 +13,20 @@ export class KubeAuthProxy {
|
|||||||
protected env: NodeJS.ProcessEnv = null
|
protected env: NodeJS.ProcessEnv = null
|
||||||
protected proxyProcess: ChildProcess
|
protected proxyProcess: ChildProcess
|
||||||
protected port: number
|
protected port: number
|
||||||
protected kubectl: Kubectl
|
|
||||||
protected promiseIpc: any
|
protected promiseIpc: any
|
||||||
|
|
||||||
constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) {
|
constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) {
|
||||||
this.env = env
|
this.env = env
|
||||||
this.port = port
|
this.port = port
|
||||||
this.cluster = cluster
|
this.cluster = cluster
|
||||||
this.kubectl = bundledKubectl
|
this.promiseIpc = new PromiseIpc.PromiseIpc({ maxTimeoutMs: 2000 })
|
||||||
this.promiseIpc = new PromiseIpc({ timeout: 2000 })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async run(): Promise<void> {
|
public async run(): Promise<void> {
|
||||||
if (this.proxyProcess) {
|
if (this.proxyProcess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const proxyBin = await this.kubectl.kubectlPath()
|
const proxyBin = await Kubectl.bundled().kubectlPath()
|
||||||
let args = [
|
let args = [
|
||||||
"proxy",
|
"proxy",
|
||||||
"-p", this.port.toString(),
|
"-p", this.port.toString(),
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import { ensureDir, pathExists } from "fs-extra"
|
|||||||
import { globalRequestOpts } from "../common/request"
|
import { globalRequestOpts } from "../common/request"
|
||||||
import * as lockFile from "proper-lockfile"
|
import * as lockFile from "proper-lockfile"
|
||||||
import { helmCli } from "./helm-cli"
|
import { helmCli } from "./helm-cli"
|
||||||
import { userStore } from "../common/user-store"
|
|
||||||
import { getBundledKubectlVersion} from "../common/utils/app-version"
|
import { getBundledKubectlVersion} from "../common/utils/app-version"
|
||||||
|
import { UserStore } from "../common/user-store"
|
||||||
|
|
||||||
const bundledVersion = getBundledKubectlVersion()
|
const bundledVersion = getBundledKubectlVersion()
|
||||||
const kubectlMap: Map<string, string> = new Map([
|
const kubectlMap: Map<string, string> = new Map([
|
||||||
@ -32,18 +32,19 @@ const packageMirrors: Map<string, string> = new Map([
|
|||||||
["china", "https://mirror.azure.cn/kubernetes/kubectl"]
|
["china", "https://mirror.azure.cn/kubernetes/kubectl"]
|
||||||
])
|
])
|
||||||
|
|
||||||
const initScriptVersionString = "# lens-initscript v3\n"
|
const initScriptVersionString = "# lens-initscript v3";
|
||||||
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
||||||
const isDevelopment = process.env.NODE_ENV !== "production"
|
const bundledPath = (
|
||||||
let bundledPath: string = null
|
isDevelopment
|
||||||
|
? path.join(process.cwd(), "binaries", "client", process.platform, process.arch, "kubectl")
|
||||||
if(isDevelopment) {
|
: path.join(process.resourcesPath, process.arch, "kubectl")
|
||||||
bundledPath = path.join(process.cwd(), "binaries", "client", process.platform, process.arch, "kubectl")
|
)
|
||||||
} else {
|
+ (process.platform === "win32" ? ".exe" : "");
|
||||||
bundledPath = path.join(process.resourcesPath, process.arch, "kubectl")
|
const archMap: Record<string, string> = {
|
||||||
}
|
"x64": "amd64",
|
||||||
|
"x86": "386",
|
||||||
if(process.platform === "win32") bundledPath = `${bundledPath}.exe`
|
"ia32": "386",
|
||||||
|
};
|
||||||
|
|
||||||
export class Kubectl {
|
export class Kubectl {
|
||||||
|
|
||||||
@ -77,21 +78,11 @@ export class Kubectl {
|
|||||||
logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback")
|
logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback")
|
||||||
}
|
}
|
||||||
|
|
||||||
let arch = null
|
const arch = archMap[process.arch] || process.arch;
|
||||||
|
|
||||||
if(process.arch == "x64") {
|
|
||||||
arch = "amd64"
|
|
||||||
} else if(process.arch == "x86" || process.arch == "ia32") {
|
|
||||||
arch = "386"
|
|
||||||
} else {
|
|
||||||
arch = process.arch
|
|
||||||
}
|
|
||||||
|
|
||||||
const platformName = process.platform === "win32" ? "windows" : process.platform
|
const platformName = process.platform === "win32" ? "windows" : process.platform
|
||||||
const binaryName = process.platform === "win32" ? "kubectl.exe" : "kubectl"
|
const binaryName = process.platform === "win32" ? "kubectl.exe" : "kubectl"
|
||||||
|
|
||||||
this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}`
|
this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}`
|
||||||
|
|
||||||
this.dirname = path.normalize(path.join(Kubectl.kubectlDir, this.kubectlVersion))
|
this.dirname = path.normalize(path.join(Kubectl.kubectlDir, this.kubectlVersion))
|
||||||
this.path = path.join(this.dirname, binaryName)
|
this.path = path.join(this.dirname, binaryName)
|
||||||
}
|
}
|
||||||
@ -107,7 +98,7 @@ export class Kubectl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async binDir() {
|
public async binDir(): Promise<string> {
|
||||||
try {
|
try {
|
||||||
await this.ensureKubectl()
|
await this.ensureKubectl()
|
||||||
return this.dirname
|
return this.dirname
|
||||||
@ -117,70 +108,90 @@ export class Kubectl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async checkBinary(checkVersion = true) {
|
public async checkBinary(checkVersion = true): Promise<boolean> {
|
||||||
const exists = await pathExists(this.path)
|
const exists = await pathExists(this.path)
|
||||||
if (exists) {
|
if (!exists) {
|
||||||
if (!checkVersion) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkVersion) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { stdout } = await promiseExec(`"${this.path}" version --client=true -o json`)
|
||||||
|
const output = JSON.parse(stdout)
|
||||||
|
let version: string = output.clientVersion.gitVersion
|
||||||
|
if (version[0] === 'v') {
|
||||||
|
version = version.slice(1)
|
||||||
|
}
|
||||||
|
if (version === this.kubectlVersion) {
|
||||||
|
logger.debug(`Local kubectl is version ${this.kubectlVersion}`)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`)
|
||||||
try {
|
|
||||||
const { stdout, stderr } = await promiseExec(`"${this.path}" version --client=true -o json`)
|
|
||||||
const output = JSON.parse(stdout)
|
|
||||||
let version: string = output.clientVersion.gitVersion
|
|
||||||
if (version[0] === 'v') {
|
|
||||||
version = version.slice(1)
|
|
||||||
}
|
|
||||||
if (version === this.kubectlVersion) {
|
|
||||||
logger.debug(`Local kubectl is version ${this.kubectlVersion}`)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`)
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`)
|
|
||||||
}
|
|
||||||
await fs.promises.unlink(this.path)
|
|
||||||
}
|
}
|
||||||
return false
|
catch(err) {
|
||||||
|
logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`)
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.promises.unlink(this.path)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async checkBundled(): Promise<boolean> {
|
protected async checkBundled(): Promise<boolean> {
|
||||||
if(this.kubectlVersion === Kubectl.bundledKubectlVersion) {
|
if (this.kubectlVersion !== Kubectl.bundledKubectlVersion) {
|
||||||
try {
|
return false;
|
||||||
const exist = await pathExists(this.path)
|
}
|
||||||
if (!exist) {
|
|
||||||
await fs.promises.copyFile(Kubectl.bundledKubectlPath, this.path)
|
try {
|
||||||
await fs.promises.chmod(this.path, 0o755)
|
const exist = await pathExists(this.path)
|
||||||
}
|
if (!exist) {
|
||||||
return true
|
await fs.promises.copyFile(Kubectl.bundledKubectlPath, this.path)
|
||||||
} catch(err) {
|
await fs.promises.chmod(this.path, 0o755)
|
||||||
logger.error("Could not copy the bundled kubectl to app-data: " + err)
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
} else {
|
return true
|
||||||
|
} catch(err) {
|
||||||
|
logger.error("Could not copy the bundled kubectl to app-data: " + err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ensureKubectl(): Promise<boolean> {
|
public async ensureKubectl(): Promise<boolean> {
|
||||||
await ensureDir(this.dirname, 0o755)
|
await ensureDir(this.dirname, 0o755);
|
||||||
return lockFile.lock(this.dirname).then(async (release) => {
|
let release: () => Promise<void>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
release = await lockFile.lock(this.dirname);
|
||||||
logger.debug(`Acquired a lock for ${this.kubectlVersion}`)
|
logger.debug(`Acquired a lock for ${this.kubectlVersion}`)
|
||||||
const bundled = await this.checkBundled()
|
|
||||||
const isValid = await this.checkBinary(!bundled)
|
try {
|
||||||
if(!isValid) {
|
if (!await this.checkBinary(!await this.checkBundled())) {
|
||||||
await this.downloadKubectl().catch((error) => { logger.error(error) });
|
await this.downloadKubectl()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(e)
|
||||||
}
|
}
|
||||||
await this.writeInitScripts().catch((error) => { logger.error("Failed to write init scripts"); logger.error(error) })
|
|
||||||
logger.debug(`Releasing lock for ${this.kubectlVersion}`)
|
try {
|
||||||
release()
|
await this.writeInitScripts();
|
||||||
|
} catch (e) {
|
||||||
|
logger.error("Failed to write init scripts");
|
||||||
|
logger.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}).catch((e) => {
|
} catch (e) {
|
||||||
logger.error(`Failed to get a lock for ${this.kubectlVersion}`)
|
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
return false
|
return false
|
||||||
})
|
} finally {
|
||||||
|
if (release) {
|
||||||
|
logger.debug(`Releasing lock for ${this.kubectlVersion}`)
|
||||||
|
release();
|
||||||
|
} else {
|
||||||
|
logger.error(`Failed to get a lock for ${this.kubectlVersion}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async downloadKubectl() {
|
public async downloadKubectl() {
|
||||||
@ -229,52 +240,55 @@ export class Kubectl {
|
|||||||
|
|
||||||
protected async writeInitScripts() {
|
protected async writeInitScripts() {
|
||||||
const helmPath = helmCli.getBinaryDir()
|
const helmPath = helmCli.getBinaryDir()
|
||||||
const fsPromises = fs.promises;
|
|
||||||
const bashScriptPath = path.join(this.dirname, '.bash_set_path')
|
const bashScriptPath = path.join(this.dirname, '.bash_set_path')
|
||||||
const bashScriptIsLatest = await this.scriptIsLatest(bashScriptPath)
|
|
||||||
if(!bashScriptIsLatest) {
|
if (!await this.scriptIsLatest(bashScriptPath)) {
|
||||||
let bashScript = "" + initScriptVersionString
|
const bashScript = `
|
||||||
bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n"
|
${initScriptVersionString}
|
||||||
bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n"
|
tempkubeconfig="$KUBECONFIG"
|
||||||
bashScript += "if test -f \"$HOME/.bash_profile\"; then\n"
|
test -f "/etc/profile" && . "/etc/profile"
|
||||||
bashScript += " . \"$HOME/.bash_profile\"\n"
|
if test -f "$HOME/.bash_profile"; then
|
||||||
bashScript += "elif test -f \"$HOME/.bash_login\"; then\n"
|
. "$HOME/.bash_profile"
|
||||||
bashScript += " . \"$HOME/.bash_login\"\n"
|
elif test -f "$HOME/.bash_login"; then
|
||||||
bashScript += "elif test -f \"$HOME/.profile\"; then\n"
|
. "$HOME/.bash_login"
|
||||||
bashScript += " . \"$HOME/.profile\"\n"
|
elif test -f "$HOME/.profile"; then
|
||||||
bashScript += "fi\n"
|
. "$HOME/.profile"
|
||||||
bashScript += `export PATH="${this.dirname}:${helmPath}:$PATH"\n`
|
fi
|
||||||
bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"
|
export PATH="${this.dirname}:${helmPath}:$PATH"
|
||||||
bashScript += "unset tempkubeconfig\n"
|
export KUBECONFIG="$tempkubeconfig"
|
||||||
await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 })
|
unset tempkubeconfig
|
||||||
|
`.trimLeft();
|
||||||
|
|
||||||
|
await fs.promises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const zshScriptPath = path.join(this.dirname, '.zlogin')
|
const zshScriptPath = path.join(this.dirname, '.zlogin')
|
||||||
const zshScriptIsLatest = await this.scriptIsLatest(zshScriptPath)
|
if (!await this.scriptIsLatest(zshScriptPath)) {
|
||||||
if(!zshScriptIsLatest) {
|
const zshScript = `
|
||||||
let zshScript = "" + initScriptVersionString
|
${initScriptVersionString}
|
||||||
|
tempkubeconfig="$KUBECONFIG"
|
||||||
|
|
||||||
zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n"
|
${/* restore previous ZDOTDIR */""}
|
||||||
// restore previous ZDOTDIR
|
export ZDOTDIR="$OLD_ZDOTDIR"
|
||||||
zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n"
|
|
||||||
// source all the files
|
|
||||||
zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n"
|
|
||||||
zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n"
|
|
||||||
zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n"
|
|
||||||
zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n"
|
|
||||||
|
|
||||||
// voodoo to replace any previous occurences of kubectl path in the PATH
|
${/* source all the files */""}
|
||||||
zshScript += `kubectlpath=\"${this.dirname}"\n`
|
test -f "$OLD_ZDOTDIR/.zshenv" && . "$OLD_ZDOTDIR/.zshenv"
|
||||||
zshScript += `helmpath=\"${helmPath}"\n`
|
test -f "$OLD_ZDOTDIR/.zprofile" && . "$OLD_ZDOTDIR/.zprofile"
|
||||||
zshScript += "p=\":$kubectlpath:\"\n"
|
test -f "$OLD_ZDOTDIR/.zlogin" && . "$OLD_ZDOTDIR/.zlogin"
|
||||||
zshScript += "d=\":$PATH:\"\n"
|
test -f "$OLD_ZDOTDIR/.zshrc" && . "$OLD_ZDOTDIR/.zshrc"
|
||||||
zshScript += "d=${d//$p/:}\n"
|
|
||||||
zshScript += "d=${d/#:/}\n"
|
${/* voodoo to replace any previous occurences of kubectl path in the PATH */""}
|
||||||
zshScript += "export PATH=\"$kubectlpath:$helmpath:${d/%:/}\"\n"
|
kubectlpath="${this.dirname}"
|
||||||
zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"
|
p=":$kubectlpath:"
|
||||||
zshScript += "unset tempkubeconfig\n"
|
d=":$PATH:"
|
||||||
zshScript += "unset OLD_ZDOTDIR\n"
|
d=\${d//$p/:}
|
||||||
await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 })
|
export PATH="$kubectlpath:$helmpath:\${d/%:/}"
|
||||||
|
export KUBECONFIG="$tempkubeconfig"
|
||||||
|
unset tempkubeconfig
|
||||||
|
unset OLD_ZDOTDIR
|
||||||
|
`.trimLeft();
|
||||||
|
|
||||||
|
await fs.promises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,13 +299,7 @@ export class Kubectl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getDownloadMirror() {
|
protected getDownloadMirror() {
|
||||||
const mirror = packageMirrors.get(userStore.getPreferences().downloadMirror)
|
return packageMirrors.get(UserStore.getInstance().getPreferences().downloadMirror)
|
||||||
if (mirror) {
|
|| packageMirrors.get("default"); // MacOS packages are only available from default
|
||||||
return mirror
|
|
||||||
}
|
|
||||||
return packageMirrors.get("default") // MacOS packages are only available from default
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bundledKubectl = Kubectl.bundled()
|
|
||||||
export { bundledKubectl }
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { app } from "electron"
|
import { app } from "electron"
|
||||||
import { CoreV1Api } from "@kubernetes/client-node"
|
import { CoreV1Api, AuthorizationV1Api } from "@kubernetes/client-node"
|
||||||
import { LensApiRequest } from "../router"
|
import { LensApiRequest } from "../router"
|
||||||
import { LensApi } from "../lens-api"
|
import { LensApi } from "../lens-api"
|
||||||
import { userStore } from "../../common/user-store"
|
import { UserStore } from "../../common/user-store"
|
||||||
import { Cluster } from "../cluster"
|
import { Cluster } from "../cluster"
|
||||||
|
|
||||||
export interface IConfigRoutePayload {
|
export interface IConfigRoutePayload {
|
||||||
@ -94,7 +94,7 @@ class ConfigRoute extends LensApi {
|
|||||||
const data: IConfigRoutePayload = {
|
const data: IConfigRoutePayload = {
|
||||||
clusterName: cluster.contextName,
|
clusterName: cluster.contextName,
|
||||||
lensVersion: app.getVersion(),
|
lensVersion: app.getVersion(),
|
||||||
lensTheme: `kontena-${userStore.getPreferences().colorTheme}`,
|
lensTheme: `kontena-${UserStore.getInstance().getPreferences().colorTheme}`,
|
||||||
kubeVersion: cluster.version,
|
kubeVersion: cluster.version,
|
||||||
chartsEnabled: true,
|
chartsEnabled: true,
|
||||||
isClusterAdmin: cluster.isAdmin,
|
isClusterAdmin: cluster.isAdmin,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { LensApiRequest } from "../router"
|
import { LensApiRequest } from "../router"
|
||||||
import { LensApi } from "../lens-api"
|
import { LensApi } from "../lens-api"
|
||||||
import { spawn, ChildProcessWithoutNullStreams } from "child_process"
|
import { spawn, ChildProcessWithoutNullStreams } from "child_process"
|
||||||
import { bundledKubectl } from "../kubectl"
|
import { Kubectl } from "../kubectl"
|
||||||
import { getFreePort } from "../port"
|
import { getFreePort } from "../port"
|
||||||
import { shell } from "electron"
|
import { shell } from "electron"
|
||||||
import * as tcpPortUsed from "tcp-port-used"
|
import * as tcpPortUsed from "tcp-port-used"
|
||||||
@ -37,7 +37,7 @@ class PortForward {
|
|||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
this.localPort = await getFreePort()
|
this.localPort = await getFreePort()
|
||||||
const kubectlBin = await bundledKubectl.kubectlPath()
|
const kubectlBin = await Kubectl.bundled().kubectlPath()
|
||||||
const args = [
|
const args = [
|
||||||
"--kubeconfig", this.kubeConfig,
|
"--kubeconfig", this.kubeConfig,
|
||||||
"port-forward",
|
"port-forward",
|
||||||
|
|||||||
@ -22,8 +22,9 @@
|
|||||||
import ClusterMenuItem from "@/_vue/components/MainMenu/ClusterMenuItem";
|
import ClusterMenuItem from "@/_vue/components/MainMenu/ClusterMenuItem";
|
||||||
import AddClusterMenuItem from "@/_vue/components/MainMenu/AddClusterMenuItem";
|
import AddClusterMenuItem from "@/_vue/components/MainMenu/AddClusterMenuItem";
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
import { clusterStore } from "../../../../common/cluster-store"
|
|
||||||
import { isMac } from "../../../../common/vars"
|
import { isMac } from "../../../../common/vars"
|
||||||
|
import { ClusterStore } from "@/../common/cluster-store";
|
||||||
|
import * as os from "os";
|
||||||
|
|
||||||
const {remote} = require('electron')
|
const {remote} = require('electron')
|
||||||
const {Menu, MenuItem} = remote
|
const {Menu, MenuItem} = remote
|
||||||
@ -47,7 +48,7 @@ export default {
|
|||||||
},
|
},
|
||||||
set: function (clusters) {
|
set: function (clusters) {
|
||||||
this.$store.commit("updateClusters", clusters);
|
this.$store.commit("updateClusters", clusters);
|
||||||
clusterStore.storeClusters(clusters);
|
ClusterStore.getInstance().storeClusters(clusters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import semver from "semver"
|
import semver from "semver"
|
||||||
import { userStore } from "../../../common/user-store"
|
|
||||||
import { getAppVersion } from "../../../common/utils/app-version"
|
import { getAppVersion } from "../../../common/utils/app-version"
|
||||||
|
import { UserStore } from "../../common/user-store"
|
||||||
import KubeContexts from './modules/kube-contexts'
|
import KubeContexts from './modules/kube-contexts'
|
||||||
import Clusters from './modules/clusters'
|
import Clusters from './modules/clusters'
|
||||||
import HelmRepos from './modules/helm-repos'
|
import HelmRepos from './modules/helm-repos'
|
||||||
@ -31,29 +31,24 @@ export default new Vuex.Store({
|
|||||||
hud: {
|
hud: {
|
||||||
isMenuVisible: true,
|
isMenuVisible: true,
|
||||||
},
|
},
|
||||||
seenContexts: userStore.getSeenContexts(),
|
seenContexts: UserStore.getInstance().getSeenContexts(),
|
||||||
lastSeenAppVersion: userStore.lastSeenAppVersion(),
|
lastSeenAppVersion: UserStore.getInstance().lastSeenAppVersion(),
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
storeSeenContexts(state, context) {
|
storeSeenContexts(state, context) {
|
||||||
const seenContexts = userStore.storeSeenContext(context);
|
state.seenContexts = UserStore.getInstance().storeSeenContext(context)
|
||||||
state.seenContexts = seenContexts
|
|
||||||
},
|
},
|
||||||
updateLastSeenAppVersion(state, appVersion) {
|
updateLastSeenAppVersion(state, appVersion) {
|
||||||
state.lastSeenAppVersion = appVersion;
|
state.lastSeenAppVersion = appVersion;
|
||||||
userStore.setLastSeenAppVersion(appVersion)
|
UserStore.getInstance().setLastSeenAppVersion(appVersion)
|
||||||
},
|
},
|
||||||
loadPreferences(state) {
|
loadPreferences(state) {
|
||||||
this.commit("savePreferences", userStore.getPreferences());
|
this.commit("savePreferences", UserStore.getInstance().getPreferences());
|
||||||
},
|
},
|
||||||
savePreferences(state, prefs) {
|
savePreferences(state, prefs) {
|
||||||
if (prefs.allowTelemetry) {
|
tracker.event("telemetry", prefs.allowTelemetry ? "enabled" : "disabled")
|
||||||
tracker.event("telemetry", "enabled")
|
|
||||||
} else {
|
|
||||||
tracker.event("telemetry", "disabled")
|
|
||||||
}
|
|
||||||
state.preferences = prefs;
|
state.preferences = prefs;
|
||||||
userStore.setPreferences(prefs);
|
UserStore.getInstance().setPreferences(prefs);
|
||||||
this.dispatch("destroyWebviews")
|
this.dispatch("destroyWebviews")
|
||||||
promiseIpc.send("preferencesSaved")
|
promiseIpc.send("preferencesSaved")
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import Vue from "vue"
|
import Vue from "vue"
|
||||||
import { ClusterInfo } from "../../../../main/cluster"
|
import { ClusterInfo } from "../../../../main/cluster"
|
||||||
import { MutationTree, ActionTree, GetterTree } from "vuex"
|
import { MutationTree, ActionTree, GetterTree } from "vuex"
|
||||||
import { PromiseIpc } from 'electron-promise-ipc'
|
import PromiseIpc from 'electron-promise-ipc'
|
||||||
import { Tracker } from "../../../../common/tracker"
|
import { Tracker } from "../../../../common/tracker"
|
||||||
import { remote } from "electron"
|
import { remote } from "electron"
|
||||||
import { clusterStore } from "../../../../common/cluster-store"
|
import { ClusterStore } from "../../../../common/cluster-store"
|
||||||
import { Workspace } from "../../../../common/workspace-store"
|
import { Workspace } from "../../../../common/workspace-store"
|
||||||
|
|
||||||
const promiseIpc = new PromiseIpc( { maxTimeoutMs: 120000 } );
|
const promiseIpc = new PromiseIpc.PromiseIpc( { maxTimeoutMs: 120000 } );
|
||||||
const tracker = new Tracker(remote.app);
|
const tracker = new Tracker(remote.app);
|
||||||
|
|
||||||
export interface LensWebview {
|
export interface LensWebview {
|
||||||
@ -130,7 +130,7 @@ const actions: ActionTree<ClusterState, any> = {
|
|||||||
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
||||||
async installClusterFeature({commit}, data) {
|
async installClusterFeature({commit}, data) {
|
||||||
// Custom no timeout IPC as install can take very variable time
|
// Custom no timeout IPC as install can take very variable time
|
||||||
const ipc = new PromiseIpc();
|
const ipc = new PromiseIpc.PromiseIpc();
|
||||||
const response = await ipc.send('installFeature', data)
|
const response = await ipc.send('installFeature', data)
|
||||||
console.log("installer result:", response);
|
console.log("installer result:", response);
|
||||||
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
||||||
@ -142,7 +142,7 @@ const actions: ActionTree<ClusterState, any> = {
|
|||||||
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
||||||
async upgradeClusterFeature({commit}, data) {
|
async upgradeClusterFeature({commit}, data) {
|
||||||
// Custom no timeout IPC as install can take very variable time
|
// Custom no timeout IPC as install can take very variable time
|
||||||
const ipc = new PromiseIpc();
|
const ipc = new PromiseIpc.PromiseIpc();
|
||||||
const response = await ipc.send('upgradeFeature', data)
|
const response = await ipc.send('upgradeFeature', data)
|
||||||
console.log("upgrade result:", response);
|
console.log("upgrade result:", response);
|
||||||
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
||||||
@ -155,7 +155,7 @@ const actions: ActionTree<ClusterState, any> = {
|
|||||||
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
// For data structure see: cluster-manager.ts / FeatureInstallRequest
|
||||||
async uninstallClusterFeature({commit}, data) {
|
async uninstallClusterFeature({commit}, data) {
|
||||||
// Custom no timeout IPC as uninstall can take very variable time
|
// Custom no timeout IPC as uninstall can take very variable time
|
||||||
const ipc = new PromiseIpc();
|
const ipc = new PromiseIpc.PromiseIpc();
|
||||||
const response = await ipc.send('uninstallFeature', data)
|
const response = await ipc.send('uninstallFeature', data)
|
||||||
console.log("uninstaller result:", response);
|
console.log("uninstaller result:", response);
|
||||||
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
const cluster = await ipc.send('refreshCluster', data.clusterId)
|
||||||
@ -217,7 +217,7 @@ const actions: ActionTree<ClusterState, any> = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
storeCluster({commit}, cluster: ClusterInfo) {
|
storeCluster({commit}, cluster: ClusterInfo) {
|
||||||
clusterStore.storeCluster(cluster);
|
ClusterStore.getInstance().storeCluster(cluster);
|
||||||
commit("updateCluster", cluster)
|
commit("updateCluster", cluster)
|
||||||
promiseIpc.send("clusterStored", cluster.id)
|
promiseIpc.send("clusterStored", cluster.id)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MutationTree, ActionTree, GetterTree } from "vuex"
|
import { MutationTree, ActionTree, GetterTree } from "vuex"
|
||||||
import { workspaceStore, Workspace, WorkspaceData } from "../../../../common/workspace-store"
|
import { WorkspaceStore, Workspace, WorkspaceData } from "../../../../common/workspace-store"
|
||||||
|
|
||||||
export interface WorkspaceState {
|
export interface WorkspaceState {
|
||||||
workspaces: Array<Workspace>;
|
workspaces: Array<Workspace>;
|
||||||
@ -7,8 +7,8 @@ export interface WorkspaceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const state: WorkspaceState = {
|
const state: WorkspaceState = {
|
||||||
workspaces: workspaceStore.getAllWorkspaces(),
|
workspaces: WorkspaceStore.getInstance().getAllWorkspaces(),
|
||||||
currentWorkspace: workspaceStore.getAllWorkspaces().find((w) => w.id === "default")
|
currentWorkspace: WorkspaceStore.getInstance().getAllWorkspaces().find((w) => w.id === "default"),
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions: ActionTree<WorkspaceState, any> = {
|
const actions: ActionTree<WorkspaceState, any> = {
|
||||||
@ -27,16 +27,16 @@ const mutations: MutationTree<WorkspaceState> = {
|
|||||||
state.currentWorkspace = workspace
|
state.currentWorkspace = workspace
|
||||||
},
|
},
|
||||||
addWorkspace(state, workspace: WorkspaceData) {
|
addWorkspace(state, workspace: WorkspaceData) {
|
||||||
workspaceStore.storeWorkspace(workspace)
|
WorkspaceStore.getInstance().storeWorkspace(workspace)
|
||||||
state.workspaces = workspaceStore.getAllWorkspaces()
|
state.workspaces = WorkspaceStore.getInstance().getAllWorkspaces()
|
||||||
},
|
},
|
||||||
updateWorkspace(state, workspace: WorkspaceData) {
|
updateWorkspace(state, workspace: WorkspaceData) {
|
||||||
workspaceStore.storeWorkspace(workspace)
|
WorkspaceStore.getInstance().storeWorkspace(workspace)
|
||||||
state.workspaces = workspaceStore.getAllWorkspaces()
|
state.workspaces = WorkspaceStore.getInstance().getAllWorkspaces()
|
||||||
},
|
},
|
||||||
removeWorkspace(state, workspace: Workspace) {
|
removeWorkspace(state, workspace: Workspace) {
|
||||||
workspaceStore.removeWorkspace(workspace)
|
WorkspaceStore.getInstance().removeWorkspace(workspace)
|
||||||
state.workspaces = workspaceStore.getAllWorkspaces()
|
state.workspaces = WorkspaceStore.getInstance().getAllWorkspaces()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user