diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index ffbcff47f8..7b97c9e31c 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -1,4 +1,7 @@ +import { app, remote } from "electron" import ElectronStore from "electron-store" +import { ensureDirSync, writeFileSync } from "fs-extra" +import * as path from "path" import { Cluster, ClusterBaseInfo } from "../main/cluster"; import * as version200Beta2 from "../migrations/cluster-store/2.0.0-beta.2" import * as version241 from "../migrations/cluster-store/2.4.1" @@ -117,4 +120,17 @@ export class ClusterStore { } } -export const clusterStore = ClusterStore.getInstance(); +export const clusterStore: ClusterStore = ClusterStore.getInstance(); + +// Writes kubeconfigs to "embedded" store, i.e. .../Lens/kubeconfigs/ +export function writeEmbeddedKubeConfig(clusterId: string, kubeConfig: string): string { + // This can be called from main & renderer + const a = (app || remote.app) + const kubeConfigBase = path.join(a.getPath("userData"), "kubeconfigs") + ensureDirSync(kubeConfigBase) + + const kubeConfigFile = path.join(kubeConfigBase, clusterId) + writeFileSync(kubeConfigFile, kubeConfig) + + return kubeConfigFile +} diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 621ce9c46c..ffcdb1816b 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -86,7 +86,6 @@ export class Cluster implements ClusterInfo { constructor(clusterInfo: ClusterBaseInfo) { if (clusterInfo) Object.assign(this, clusterInfo) if (!this.preferences) this.preferences = {} - this.kubeconfigManager = new KubeconfigManager(this) } public proxyKubeconfigPath() { @@ -95,7 +94,9 @@ export class Cluster implements ClusterInfo { public async init(kc: KubeConfig) { this.contextHandler = new ContextHandler(kc, this) - //this.contextName = kc.currentContext + await this.contextHandler.init() // So we get the proxy port reserved + this.kubeconfigManager = new KubeconfigManager(this) + this.url = this.contextHandler.url this.apiUrl = kc.getCurrentCluster().server } @@ -139,14 +140,6 @@ export class Cluster implements ClusterInfo { this.eventCount = await this.getEventCount(); } - // public updateKubeconfig(kubeconfig: string) { - // const storedCluster = clusterStore.getCluster(this.id) - // if (!storedCluster) { return } - - // this.kubeConfig = kubeconfig - // this.save() - // } - public getPrometheusApiPrefix() { if (!this.preferences.prometheus?.prefix) { return "" diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index 4bee1e3214..f8d104ae53 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -22,14 +22,14 @@ export class ContextHandler { protected apiTarget: ServerOptions protected proxyTarget: ServerOptions - protected clusterUrl: url.UrlWithStringQuery - protected proxyServer: KubeAuthProxy + public clusterUrl: url.UrlWithStringQuery + public proxyServer: KubeAuthProxy protected clientCert: string protected clientKey: string protected secureApiConnection = true protected defaultNamespace: string - protected proxyPort: number + public proxyPort: number protected kubernetesApi: string protected prometheusProvider: string protected prometheusPath: string @@ -38,21 +38,6 @@ export class ContextHandler { constructor(kc: KubeConfig, cluster: Cluster) { this.id = cluster.id this.kc = kc - logger.info(`**** ctxHandler.kc: ${JSON.stringify(kc, null, 2)}`) - // this.kc.users = [ - // { - // name: kc.getCurrentUser().name, - // token: this.id - // } - // ] - // this.kc.contexts = [ - // { - // name: kc.currentContext, - // cluster: kc.getCurrentCluster().name, - // user: kc.getCurrentUser().name, - // namespace: kc.getContextObject(kc.currentContext).namespace - // } - // ] this.kc.setCurrentContext(cluster.contextName) this.cluster = cluster @@ -61,16 +46,14 @@ export class ContextHandler { this.defaultNamespace = kc.getContextObject(kc.currentContext).namespace this.url = `http://${this.id}.localhost:${cluster.port}/` this.kubernetesApi = `http://127.0.0.1:${cluster.port}/${this.id}` - // this.kc.clusters = [ - // { - // name: kc.getCurrentCluster().name, - // server: this.kubernetesApi, - // skipTLSVerify: true - // } - // ] + this.setClusterPreferences(cluster.preferences) } + public async init() { + await this.resolveProxyPort() + } + public setClusterPreferences(clusterPreferences?: ClusterPreferences) { this.prometheusProvider = clusterPreferences.prometheusProvider?.type diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index 52d67abd0d..320ebce56a 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -20,19 +20,18 @@ export class KubeconfigManager { return this.tempFile } + /** + * Creates new "temporary" kubeconfig that point to the kubectl-proxy. + * This way any user of the config does not need to know anything about the auth etc. details. + */ protected createTemporaryKubeconfig(): string { ensureDir(this.configDir) const path = `${this.configDir}/${randomFileName("kubeconfig")}` - logger.debug('Creating temporary kubeconfig: ' + path) - logger.debug(`cluster url: ${this.cluster.url}`) - logger.debug(`cluster api url: ${this.cluster.apiUrl}`) - - // TODO Make the names come from actual cluster.name etc. let kc = { clusters: [ { name: this.cluster.contextName, - server: `http://127.0.0.1:${this.cluster.port}/${this.cluster.id}` + server: `http://127.0.0.1:${this.cluster.contextHandler.proxyPort}` } ], users: [ @@ -44,6 +43,7 @@ export class KubeconfigManager { { name: this.cluster.contextName, cluster: this.cluster.contextName, + namespace: this.cluster.contextHandler.kc.getContextObject(this.cluster.contextName).namespace, user: "proxy" } ], diff --git a/src/migrations/cluster-store/3.5.0-beta.1.ts b/src/migrations/cluster-store/3.5.0-beta.1.ts index e0c48b7fb4..984449e8b5 100644 --- a/src/migrations/cluster-store/3.5.0-beta.1.ts +++ b/src/migrations/cluster-store/3.5.0-beta.1.ts @@ -2,6 +2,8 @@ import { app } from "electron" import { ensureDirSync, writeFileSync } from "fs-extra" import * as path from "path" +import { KubeConfig } from "@kubernetes/client-node"; +import * as clusterStore from "../../cluster-store" export function migration(store: any) { console.log("CLUSTER STORE, MIGRATION: 3.5.0-beta.1"); @@ -11,21 +13,23 @@ export function migration(store: any) { ensureDirSync(kubeConfigBase) let storedClusters = store.get("clusters") as any[] if (!storedClusters) return - + console.log("num clusters to migrate: ", storedClusters.length) for (let cluster of storedClusters ) { + // TODO Should probably guard this, not to make the whole migration fail if one cluster fails!? // take the embedded kubeconfig and dump it into a file - const kubeConfigFile = path.join(kubeConfigBase, cluster.id) - writeFileSync(kubeConfigFile, cluster.kubeConfig) - delete cluster.kubeConfig + const kubeConfigFile = clusterStore.writeEmbeddedKubeConfig(cluster.id, cluster.kubeConfig) cluster.kubeConfigPath = kubeConfigFile - // TODO Need to parse the context name from the config - - - // "overwrite" the cluster configs + + const kc = new KubeConfig() + kc.loadFromFile(cluster.kubeConfigPath) + cluster.contextName = kc.getCurrentContext() + + delete cluster.kubeConfig clusters.push(cluster) } + // "overwrite" the cluster configs if (clusters.length > 0) { store.set("clusters", clusters) } diff --git a/src/renderer/_vue/components/AddClusterPage.vue b/src/renderer/_vue/components/AddClusterPage.vue index 39a1c56030..85c826d40a 100644 --- a/src/renderer/_vue/components/AddClusterPage.vue +++ b/src/renderer/_vue/components/AddClusterPage.vue @@ -10,6 +10,15 @@ + +
Selected file: {{ file ? file.name : '' }}
+ -1 }, @@ -197,12 +218,15 @@ export default { try { const kc = new k8s.KubeConfig(); kc.loadFromString(this.clusterconfig); // throws TypeError if we cannot parse kubeconfig - - // TODO Remove hardcoded path - const configPath = path.join(process.env.HOME, '.kube', 'config'); - + const clusterId = uuidv4(); + // We need to store the kubeconfig to "app-home"/ + if (this.kubecontext === "custom") { + // TODO Call "writeEmbeddedKubeConfig" + this.filepath = clusterStore.writeEmbeddedKubeConfig(clusterId, this.clusterconfig) + } const clusterInfo = { - kubeConfigPath: configPath, + id: clusterId, + kubeConfigPath: this.filepath, contextName: kc.currentContext, preferences: { clusterName: kc.currentContext @@ -212,6 +236,7 @@ export default { if (this.httpsProxy) { clusterInfo.preferences.httpsProxy = this.httpsProxy } + console.log("sending clusterInfo:", clusterInfo) let res = await this.$store.dispatch('addCluster', clusterInfo) console.log("addCluster result:", res) if(!res){ diff --git a/src/renderer/_vue/store/modules/kube-contexts.js b/src/renderer/_vue/store/modules/kube-contexts.js index 7e708b6b01..9a75e7a33c 100644 --- a/src/renderer/_vue/store/modules/kube-contexts.js +++ b/src/renderer/_vue/store/modules/kube-contexts.js @@ -6,10 +6,10 @@ const state = { } const actions = { - reloadAvailableKubeContexts: ({commit}) => { + reloadAvailableKubeContexts({commit}, file) { let kc = new k8s.KubeConfig(); try { - kc.loadFromDefault(); + kc.loadFromFile(file); } catch (error) { console.error("Failed to read default kubeconfig: " + error.message); }