mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix: Recreate proxy kubeconfig if it is deleted (#2372)
This commit is contained in:
parent
e70ac87c52
commit
4afec72ceb
@ -85,8 +85,8 @@ describe("kubeconfig manager tests", () => {
|
||||
const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port);
|
||||
|
||||
expect(logger.error).not.toBeCalled();
|
||||
expect(kubeConfManager.getPath()).toBe(`tmp${path.sep}kubeconfig-foo`);
|
||||
const file = await fse.readFile(kubeConfManager.getPath());
|
||||
expect(await kubeConfManager.getPath()).toBe(`tmp${path.sep}kubeconfig-foo`);
|
||||
const file = await fse.readFile(await kubeConfManager.getPath());
|
||||
const yml = loadYaml<any>(file.toString());
|
||||
|
||||
expect(yml["current-context"]).toBe("minikube");
|
||||
@ -104,12 +104,12 @@ describe("kubeconfig manager tests", () => {
|
||||
const contextHandler = new ContextHandler(cluster);
|
||||
const port = await getFreePort();
|
||||
const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port);
|
||||
const configPath = kubeConfManager.getPath();
|
||||
const configPath = await kubeConfManager.getPath();
|
||||
|
||||
expect(await fse.pathExists(configPath)).toBe(true);
|
||||
await kubeConfManager.unlink();
|
||||
expect(await fse.pathExists(configPath)).toBe(false);
|
||||
await kubeConfManager.unlink(); // doesn't throw
|
||||
expect(kubeConfManager.getPath()).toBeUndefined();
|
||||
expect(await kubeConfManager.getPath()).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@ -482,14 +482,16 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getProxyKubeconfig(): KubeConfig {
|
||||
return loadConfig(this.getProxyKubeconfigPath());
|
||||
async getProxyKubeconfig(): Promise<KubeConfig> {
|
||||
const kubeconfigPath = await this.getProxyKubeconfigPath();
|
||||
|
||||
return loadConfig(kubeconfigPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getProxyKubeconfigPath(): string {
|
||||
async getProxyKubeconfigPath(): Promise<string> {
|
||||
return this.kubeconfigManager.getPath();
|
||||
}
|
||||
|
||||
@ -565,7 +567,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
* @param resourceAttributes resource attributes
|
||||
*/
|
||||
async canI(resourceAttributes: V1ResourceAttributes): Promise<boolean> {
|
||||
const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api);
|
||||
const authApi = (await this.getProxyKubeconfig()).makeApiClient(AuthorizationV1Api);
|
||||
|
||||
try {
|
||||
const accessReview = await authApi.createSelfSubjectAccessReview({
|
||||
@ -680,14 +682,14 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
return this.accessibleNamespaces;
|
||||
}
|
||||
|
||||
const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api);
|
||||
const api = (await this.getProxyKubeconfig()).makeApiClient(CoreV1Api);
|
||||
|
||||
try {
|
||||
const namespaceList = await api.listNamespace();
|
||||
|
||||
return namespaceList.body.items.map(ns => ns.metadata.name);
|
||||
} catch (error) {
|
||||
const ctx = this.getProxyKubeconfig().getContextObject(this.contextName);
|
||||
const ctx = (await this.getProxyKubeconfig()).getContextObject(this.contextName);
|
||||
|
||||
if (ctx.namespace) return [ctx.namespace];
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ export class ContextHandler {
|
||||
async getPrometheusService(): Promise<PrometheusService> {
|
||||
const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders;
|
||||
const prometheusPromises: Promise<PrometheusService>[] = providers.map(async (provider: PrometheusProvider): Promise<PrometheusService> => {
|
||||
const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api);
|
||||
const apiClient = (await this.cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api);
|
||||
|
||||
return await provider.getPrometheusService(apiClient);
|
||||
});
|
||||
|
||||
@ -56,11 +56,12 @@ export class HelmReleaseManager {
|
||||
public async upgradeRelease(name: string, chart: string, values: any, namespace: string, version: string, cluster: Cluster){
|
||||
const helm = await helmCli.binaryPath();
|
||||
const fileName = tempy.file({name: "values.yaml"});
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
await fs.promises.writeFile(fileName, yaml.safeDump(values));
|
||||
|
||||
try {
|
||||
const { stdout } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);});
|
||||
const { stdout } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${proxyKubeconfig}`).catch((error) => { throw(error.stderr);});
|
||||
|
||||
return {
|
||||
log: stdout,
|
||||
@ -73,7 +74,9 @@ export class HelmReleaseManager {
|
||||
|
||||
public async getRelease(name: string, namespace: string, cluster: Cluster) {
|
||||
const helm = await helmCli.binaryPath();
|
||||
const { stdout } = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);});
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
const { stdout } = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${proxyKubeconfig}`).catch((error) => { throw(error.stderr);});
|
||||
const release = JSON.parse(stdout);
|
||||
|
||||
release.resources = await this.getResources(name, namespace, cluster);
|
||||
@ -112,7 +115,7 @@ export class HelmReleaseManager {
|
||||
protected async getResources(name: string, namespace: string, cluster: Cluster) {
|
||||
const helm = await helmCli.binaryPath();
|
||||
const kubectl = await cluster.kubeCtl.getPath();
|
||||
const pathToKubeconfig = cluster.getProxyKubeconfigPath();
|
||||
const pathToKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch(() => {
|
||||
return { stdout: JSON.stringify({items: []})};
|
||||
});
|
||||
|
||||
@ -8,7 +8,9 @@ import { HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/h
|
||||
|
||||
class HelmService {
|
||||
public async installChart(cluster: Cluster, data: { chart: string; values: {}; name: string; namespace: string; version: string }) {
|
||||
return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath());
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, proxyKubeconfig);
|
||||
}
|
||||
|
||||
public async listCharts() {
|
||||
@ -53,8 +55,9 @@ class HelmService {
|
||||
|
||||
public async listReleases(cluster: Cluster, namespace: string = null) {
|
||||
await repoManager.init();
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace);
|
||||
return await releaseManager.listReleases(proxyKubeconfig, namespace);
|
||||
}
|
||||
|
||||
public async getRelease(cluster: Cluster, releaseName: string, namespace: string) {
|
||||
@ -64,21 +67,27 @@ class HelmService {
|
||||
}
|
||||
|
||||
public async getReleaseValues(cluster: Cluster, releaseName: string, namespace: string) {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Fetch release values");
|
||||
|
||||
return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath());
|
||||
return await releaseManager.getValues(releaseName, namespace, proxyKubeconfig);
|
||||
}
|
||||
|
||||
public async getReleaseHistory(cluster: Cluster, releaseName: string, namespace: string) {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Fetch release history");
|
||||
|
||||
return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath());
|
||||
return await releaseManager.getHistory(releaseName, namespace, proxyKubeconfig);
|
||||
}
|
||||
|
||||
public async deleteRelease(cluster: Cluster, releaseName: string, namespace: string) {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Delete release");
|
||||
|
||||
return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath());
|
||||
return await releaseManager.deleteRelease(releaseName, namespace, proxyKubeconfig);
|
||||
}
|
||||
|
||||
public async updateRelease(cluster: Cluster, releaseName: string, namespace: string, data: { chart: string; values: {}; version: string }) {
|
||||
@ -88,8 +97,10 @@ class HelmService {
|
||||
}
|
||||
|
||||
public async rollback(cluster: Cluster, releaseName: string, namespace: string, revision: number) {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Rollback release");
|
||||
const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath());
|
||||
const output = await releaseManager.rollback(releaseName, namespace, revision, proxyKubeconfig);
|
||||
|
||||
return { message: output };
|
||||
}
|
||||
|
||||
@ -24,14 +24,24 @@ export class KubeconfigManager {
|
||||
protected async init() {
|
||||
try {
|
||||
await this.contextHandler.ensurePort();
|
||||
await this.createProxyKubeconfig();
|
||||
this.tempFile = await this.createProxyKubeconfig();
|
||||
} catch (err) {
|
||||
logger.error(`Failed to created temp config for auth-proxy`, { err });
|
||||
}
|
||||
}
|
||||
|
||||
async getPath() {
|
||||
// create proxy kubeconfig if it is removed
|
||||
if (this.tempFile !== undefined && !(await fs.pathExists(this.tempFile))) {
|
||||
try {
|
||||
this.tempFile = await this.createProxyKubeconfig();
|
||||
} catch (err) {
|
||||
logger.error(`Failed to created temp config for auth-proxy`, { err });
|
||||
}
|
||||
}
|
||||
|
||||
getPath() {
|
||||
return this.tempFile;
|
||||
|
||||
}
|
||||
|
||||
protected resolveProxyUrl() {
|
||||
@ -71,9 +81,8 @@ export class KubeconfigManager {
|
||||
// write
|
||||
const configYaml = dumpConfigYaml(proxyConfig);
|
||||
|
||||
fs.ensureDir(path.dirname(tempFile));
|
||||
fs.writeFileSync(tempFile, configYaml, { mode: 0o600 });
|
||||
this.tempFile = tempFile;
|
||||
await fs.ensureDir(path.dirname(tempFile));
|
||||
await fs.writeFile(tempFile, configYaml, { mode: 0o600 });
|
||||
logger.debug(`Created temp kubeconfig "${contextName}" at "${tempFile}": \n${configYaml}`);
|
||||
|
||||
return tempFile;
|
||||
|
||||
@ -17,10 +17,10 @@ export class NodeShellSession extends ShellSession {
|
||||
super(socket, cluster);
|
||||
this.nodeName = nodeName;
|
||||
this.podId = `node-shell-${uuid()}`;
|
||||
this.kc = cluster.getProxyKubeconfig();
|
||||
}
|
||||
|
||||
public async open() {
|
||||
this.kc = await this.cluster.getProxyKubeconfig();
|
||||
const shell = await this.kubectl.getPath();
|
||||
let args = [];
|
||||
|
||||
|
||||
@ -23,12 +23,13 @@ export class ResourceApplier {
|
||||
protected async kubectlApply(content: string): Promise<string> {
|
||||
const { kubeCtl } = this.cluster;
|
||||
const kubectlPath = await kubeCtl.getPath();
|
||||
const proxyKubeconfigPath = await this.cluster.getProxyKubeconfigPath();
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const fileName = tempy.file({ name: "resource.yaml" });
|
||||
|
||||
fs.writeFileSync(fileName, content);
|
||||
const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"`;
|
||||
const cmd = `"${kubectlPath}" apply --kubeconfig "${proxyKubeconfigPath}" -o json -f "${fileName}"`;
|
||||
|
||||
logger.debug(`shooting manifests with: ${cmd}`);
|
||||
const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env);
|
||||
@ -54,6 +55,7 @@ export class ResourceApplier {
|
||||
public async kubectlApplyAll(resources: string[]): Promise<string> {
|
||||
const { kubeCtl } = this.cluster;
|
||||
const kubectlPath = await kubeCtl.getPath();
|
||||
const proxyKubeconfigPath = await this.cluster.getProxyKubeconfigPath();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const tmpDir = tempy.directory();
|
||||
@ -62,7 +64,7 @@ export class ResourceApplier {
|
||||
resources.forEach((resource, index) => {
|
||||
fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource);
|
||||
});
|
||||
const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"`;
|
||||
const cmd = `"${kubectlPath}" apply --kubeconfig "${proxyKubeconfigPath}" -o json -f "${tmpDir}"`;
|
||||
|
||||
console.log("shooting manifests with:", cmd);
|
||||
exec(cmd, (error, stdout, stderr) => {
|
||||
|
||||
@ -44,7 +44,7 @@ class KubeconfigRoute extends LensApi {
|
||||
|
||||
public async routeServiceAccountRoute(request: LensApiRequest) {
|
||||
const { params, response, cluster} = request;
|
||||
const client = cluster.getProxyKubeconfig().makeApiClient(CoreV1Api);
|
||||
const client = (await cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api);
|
||||
const secretList = await client.listNamespacedSecret(params.namespace);
|
||||
const secret = secretList.body.items.find(secret => {
|
||||
const { annotations } = secret.metadata;
|
||||
|
||||
@ -92,7 +92,7 @@ class PortForwardRoute extends LensApi {
|
||||
namespace,
|
||||
name: resourceName,
|
||||
port,
|
||||
kubeConfig: cluster.getProxyKubeconfigPath()
|
||||
kubeConfig: await cluster.getProxyKubeconfigPath()
|
||||
});
|
||||
const started = await portForward.start();
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@ import shellEnv from "shell-env";
|
||||
import { app } from "electron";
|
||||
import { Kubectl } from "./kubectl";
|
||||
import { Cluster } from "./cluster";
|
||||
import { ClusterPreferences } from "../common/cluster-store";
|
||||
import { helmCli } from "./helm/helm-cli";
|
||||
import { isWindows } from "../common/vars";
|
||||
import { appEventBus } from "../common/event-bus";
|
||||
@ -24,20 +23,18 @@ export class ShellSession extends EventEmitter {
|
||||
protected kubectlBinDir: string;
|
||||
protected kubectlPathDir: string;
|
||||
protected helmBinDir: string;
|
||||
protected preferences: ClusterPreferences;
|
||||
protected running = false;
|
||||
protected clusterId: string;
|
||||
protected cluster: Cluster;
|
||||
|
||||
constructor(socket: WebSocket, cluster: Cluster) {
|
||||
super();
|
||||
this.websocket = socket;
|
||||
this.kubeconfigPath = cluster.getProxyKubeconfigPath();
|
||||
this.kubectl = new Kubectl(cluster.version);
|
||||
this.preferences = cluster.preferences || {};
|
||||
this.clusterId = cluster.id;
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
public async open() {
|
||||
this.kubeconfigPath = await this.cluster.getProxyKubeconfigPath();
|
||||
this.kubectlBinDir = await this.kubectl.binDir();
|
||||
const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath();
|
||||
|
||||
@ -65,11 +62,13 @@ export class ShellSession extends EventEmitter {
|
||||
}
|
||||
|
||||
protected cwd(): string {
|
||||
if(!this.preferences || !this.preferences.terminalCWD || this.preferences.terminalCWD === "") {
|
||||
const { preferences } = this.cluster;
|
||||
|
||||
if(!preferences || !preferences.terminalCWD || preferences.terminalCWD === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.preferences.terminalCWD;
|
||||
return preferences.terminalCWD;
|
||||
}
|
||||
|
||||
protected async getShellArgs(shell: string): Promise<Array<string>> {
|
||||
@ -88,15 +87,17 @@ export class ShellSession extends EventEmitter {
|
||||
}
|
||||
|
||||
protected async getCachedShellEnv() {
|
||||
let env = ShellSession.shellEnvs.get(this.clusterId);
|
||||
const { id: clusterId } = this.cluster;
|
||||
|
||||
let env = ShellSession.shellEnvs.get(clusterId);
|
||||
|
||||
if (!env) {
|
||||
env = await this.getShellEnv();
|
||||
ShellSession.shellEnvs.set(this.clusterId, env);
|
||||
ShellSession.shellEnvs.set(clusterId, env);
|
||||
} else {
|
||||
// refresh env in the background
|
||||
this.getShellEnv().then((shellEnv: any) => {
|
||||
ShellSession.shellEnvs.set(this.clusterId, shellEnv);
|
||||
ShellSession.shellEnvs.set(clusterId, shellEnv);
|
||||
});
|
||||
}
|
||||
|
||||
@ -107,6 +108,7 @@ export class ShellSession extends EventEmitter {
|
||||
const env = clearKubeconfigEnvVars(JSON.parse(JSON.stringify(await shellEnv())));
|
||||
const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter);
|
||||
const shell = userStore.preferences.shell || process.env.SHELL || process.env.PTYSHELL;
|
||||
const { preferences } = this.cluster;
|
||||
|
||||
if(isWindows) {
|
||||
env["SystemRoot"] = process.env.SystemRoot;
|
||||
@ -138,8 +140,8 @@ export class ShellSession extends EventEmitter {
|
||||
env["TERM_PROGRAM"] = app.getName();
|
||||
env["TERM_PROGRAM_VERSION"] = app.getVersion();
|
||||
|
||||
if (this.preferences.httpsProxy) {
|
||||
env["HTTPS_PROXY"] = this.preferences.httpsProxy;
|
||||
if (preferences.httpsProxy) {
|
||||
env["HTTPS_PROXY"] = preferences.httpsProxy;
|
||||
}
|
||||
const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]];
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user