Skip to content

Commit 0e2f5fe

Browse files
committed
Support KUBECONFIG environment variable
- Watch for changes in file(s) indicated by `KUBECONFIG` when it's set - Warn when multiple config files are specified in `KUBECONFIG`, since the Kubernetes client library we are using doesn't support this use case Closes #3382 Signed-off-by: David Thompson <davthomp@redhat.com>
1 parent 6821c8c commit 0e2f5fe

File tree

2 files changed

+59
-23
lines changed

2 files changed

+59
-23
lines changed

src/explorer.ts

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,58 @@ import { Context, KubernetesObject } from '@kubernetes/client-node';
77
import * as fs from 'fs';
88
import * as path from 'path';
99
import {
10-
commands, Disposable,
10+
Disposable,
1111
Event,
12-
EventEmitter, extensions, ThemeIcon,
12+
EventEmitter,
13+
ThemeIcon,
1314
TreeDataProvider,
1415
TreeItem,
1516
TreeItemCollapsibleState,
1617
TreeView,
17-
Uri, version,
18+
Uri,
19+
commands,
20+
extensions,
21+
version,
1822
window
1923
} from 'vscode';
2024
import { CliChannel } from './cli';
2125
import * as Helm from './helm/helm';
2226
import { Command } from './odo/command';
23-
import { newInstance, Odo3 } from './odo3';
27+
import { Odo3, newInstance } from './odo3';
2428
import { KubeConfigUtils } from './util/kubeUtils';
2529
import { Platform } from './util/platform';
2630
import { Progress } from './util/progress';
2731
import { FileContentChangeNotifier, WatchUtil } from './util/watch';
2832
import { vsCommand } from './vscommand';
2933

30-
const kubeConfigFolder: string = path.join(Platform.getUserHomePath(), '.kube');
34+
/**
35+
* Returns the list of kube config files:
36+
* - If KUBECONFIG is not set, just ~/.kube/config
37+
* - If KUBECONFIG is set, follows the semantics for specifying multiple config files described here:
38+
* https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#append-home-kube-config-to-your-kubeconfig-environment-variable
39+
* BUT: it shows an error if multiple configs are specified, since the Kubernetes client we are using doesn't support this use case.
40+
*/
41+
function getKubeConfigFiles(): string[] {
42+
if (process.env.KUBECONFIG) {
43+
let configuredFiles: string[] = [];
44+
if (process.platform === 'win32') {
45+
configuredFiles = process.env.KUBECONFIG.split(';');
46+
} else {
47+
configuredFiles = process.env.KUBECONFIG.split(':');
48+
}
49+
if (configuredFiles.length > 1) {
50+
void window.showWarningMessage('KUBECONFIG specifies multiple files. Unfortunately, the extension doesn\'t work properly with this setup. Expect things to break.');
51+
}
52+
const filesThatExist: string[] = [];
53+
for (const configFile of configuredFiles) {
54+
if (fs.existsSync(configFile)) {
55+
filesThatExist.push(configFile);
56+
}
57+
}
58+
return filesThatExist;
59+
}
60+
return [path.join(Platform.getUserHomePath(), '.kube', 'config')];
61+
}
3162

3263
type ExplorerItem = KubernetesObject | Helm.HelmRelease | Context | TreeItem;
3364

@@ -39,7 +70,7 @@ type PackageJSON = {
3970
const CREATE_OR_SET_PROJECT_ITEM = {
4071
label: 'Create new or set active Project',
4172
command: {
42-
title: 'Create new or ser active Project',
73+
title: 'Create new or set active Project',
4374
command: 'openshift.project.set'
4475
}
4576
};
@@ -49,7 +80,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
4980

5081
private treeView: TreeView<ExplorerItem>;
5182

52-
private fsw: FileContentChangeNotifier;
83+
private kubeConfigWatchers: FileContentChangeNotifier[];
5384
private kubeContext: Context;
5485
private kubeConfig: KubeConfigUtils;
5586

@@ -69,22 +100,25 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
69100
// ignore config loading error and let odo report it on first call
70101
}
71102
try {
72-
this.fsw = WatchUtil.watchFileForContextChange(kubeConfigFolder, 'config');
103+
const kubeconfigFiles = getKubeConfigFiles();
104+
this.kubeConfigWatchers = kubeconfigFiles.map(kubeconfigFile => WatchUtil.watchFileForContextChange(path.dirname(kubeconfigFile), path.basename(kubeconfigFile)));
73105
} catch (err) {
74106
void window.showWarningMessage('Couldn\'t install watcher for Kubernetes configuration file. OpenShift Application Explorer view won\'t be updated automatically.');
75107
}
76-
this.fsw?.emitter?.on('file-changed', () => {
77-
const ku2 = new KubeConfigUtils();
78-
const newCtx = ku2.getContextObject(ku2.currentContext);
79-
if (!this.kubeContext
80-
|| (this.kubeContext.cluster !== newCtx.cluster
81-
|| this.kubeContext.user !== newCtx.user
82-
|| this.kubeContext.namespace !== newCtx.namespace)) {
83-
this.refresh();
84-
}
85-
this.kubeContext = newCtx;
86-
this.kubeConfig = ku2;
87-
});
108+
for (const fsw of this.kubeConfigWatchers) {
109+
fsw.emitter?.on('file-changed', () => {
110+
const ku2 = new KubeConfigUtils();
111+
const newCtx = ku2.getContextObject(ku2.currentContext);
112+
if (Boolean(this.kubeContext) !== Boolean(newCtx)
113+
|| (this.kubeContext.cluster !== newCtx.cluster
114+
|| this.kubeContext.user !== newCtx.user
115+
|| this.kubeContext.namespace !== newCtx.namespace)) {
116+
this.refresh();
117+
}
118+
this.kubeContext = newCtx;
119+
this.kubeConfig = ku2;
120+
});
121+
}
88122
this.treeView = window.createTreeView<ExplorerItem>('openshiftProjectExplorer', {
89123
treeDataProvider: this,
90124
});
@@ -256,7 +290,9 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
256290
}
257291

258292
dispose(): void {
259-
this.fsw?.watcher?.close();
293+
for (const fsw of this.kubeConfigWatchers) {
294+
fsw?.watcher?.close();
295+
}
260296
this.treeView.dispose();
261297
}
262298

src/util/kubeUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
* Licensed under the MIT License. See LICENSE file in the project root for license information.
44
*-----------------------------------------------------------------------------------------------*/
55

6+
import { KubeConfig, findHomeDir, loadYaml } from '@kubernetes/client-node';
7+
import { Cluster, User } from '@kubernetes/client-node/dist/config_types';
68
import * as fs from 'fs';
79
import * as path from 'path';
810
import { QuickPickItem } from 'vscode';
9-
import { KubeConfig, findHomeDir, loadYaml } from '@kubernetes/client-node';
10-
import { User, Cluster } from '@kubernetes/client-node/dist/config_types';
1111

1212
function fileExists(file: string): boolean {
1313
try {

0 commit comments

Comments
 (0)