1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

more refactorings & fixes on kubeconfig paths

Signed-off-by: Jussi Nummelin <jussi.nummelin@gmail.com>
This commit is contained in:
Jussi Nummelin 2020-06-15 22:29:31 +03:00 committed by Jari Kolehmainen
parent c46a5f6f20
commit 7178d0534a
7 changed files with 79 additions and 58 deletions

View File

@ -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
}

View File

@ -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 ""

View File

@ -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

View File

@ -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"
}
],

View File

@ -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)
}

View File

@ -10,6 +10,15 @@
<b-form-group
label="Choose config:"
>
<b-form-file
v-model="file"
:state="Boolean(file)"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
@input="reloadKubeContexts()"
></b-form-file>
<div class="mt-3">Selected file: {{ file ? file.name : '' }}</div>
<b-form-select
id="kubecontext-select"
v-model="kubecontext"
@ -114,6 +123,9 @@ import * as k8s from "@kubernetes/client-node"
import { dumpConfigYaml } from "../../../main/k8s"
import ClustersMixin from "@/_vue/mixins/ClustersMixin";
import * as path from "path"
import fs from 'fs'
import { v4 as uuidv4 } from 'uuid';
import * as clusterStore from "../../common/cluster-store"
class ClusterAccessError extends Error {}
@ -126,6 +138,8 @@ export default {
},
data(){
return {
file: null,
filepath: null,
clusterconfig: "",
httpsProxy: "",
kubecontext: "",
@ -137,7 +151,10 @@ export default {
}
},
mounted: function() {
this.$store.dispatch("reloadAvailableKubeContexts");
const kubeConfigPath = path.join(process.env.HOME, '.kube', 'config')
this.filepath = kubeConfigPath
this.file = new File(fs.readFileSync(this.filepath), this.filepath)
this.$store.dispatch("reloadAvailableKubeContexts", this.filepath);
this.seenContexts = JSON.parse(JSON.stringify(this.$store.getters.seenContexts)) // clone seenContexts from store
this.storeSeenContexts()
},
@ -164,6 +181,10 @@ export default {
},
},
methods: {
reloadKubeContexts() {
this.filepath = this.file.path
this.$store.dispatch("reloadAvailableKubeContexts", this.file.path);
},
isNewContext(context) {
return this.newContexts.indexOf(context) > -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){

View File

@ -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);
}