@@ -30,7 +30,34 @@ import { Progress } from './util/progress';
3030import { FileContentChangeNotifier , WatchUtil } from './util/watch' ;
3131import { vsCommand } from './vscommand' ;
3232
33- const kubeConfigFolder : string = path . join ( Platform . getUserHomePath ( ) , '.kube' ) ;
33+ /**
34+ * Returns the list of kube config files:
35+ * - If KUBECONFIG is not set, just ~/.kube/config
36+ * - If KUBECONFIG is set, follows the semantics for specifying multiple config files described here:
37+ * https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#append-home-kube-config-to-your-kubeconfig-environment-variable
38+ * BUT: it shows an error if multiple configs are specified, since the Kubernetes client we are using doesn't support this use case.
39+ */
40+ function getKubeConfigFiles ( ) : string [ ] {
41+ if ( process . env . KUBECONFIG ) {
42+ let configuredFiles : string [ ] = [ ] ;
43+ if ( process . platform === 'win32' ) {
44+ configuredFiles = process . env . KUBECONFIG . split ( ';' ) ;
45+ } else {
46+ configuredFiles = process . env . KUBECONFIG . split ( ':' ) ;
47+ }
48+ if ( configuredFiles . length > 1 ) {
49+ void window . showWarningMessage ( 'KUBECONFIG specifies multiple files. Unfortunately, the extension doesn\'t work properly with this setup. Expect things to break.' ) ;
50+ }
51+ const filesThatExist : string [ ] = [ ] ;
52+ for ( const configFile of configuredFiles ) {
53+ if ( fs . existsSync ( configFile ) ) {
54+ filesThatExist . push ( configFile ) ;
55+ }
56+ }
57+ return filesThatExist ;
58+ }
59+ return [ path . join ( Platform . getUserHomePath ( ) , '.kube' , 'config' ) ] ;
60+ }
3461
3562type ExplorerItem = KubernetesObject | Helm . HelmRelease | Context | TreeItem ;
3663
@@ -42,7 +69,7 @@ type PackageJSON = {
4269const CREATE_OR_SET_PROJECT_ITEM = {
4370 label : 'Create new or set active Project' ,
4471 command : {
45- title : 'Create new or ser active Project' ,
72+ title : 'Create new or set active Project' ,
4673 command : 'openshift.project.set'
4774 }
4875} ;
@@ -52,7 +79,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
5279
5380 private treeView : TreeView < ExplorerItem > ;
5481
55- private fsw : FileContentChangeNotifier ;
82+ private kubeConfigWatchers : FileContentChangeNotifier [ ] ;
5683 private kubeContext : Context ;
5784 private kubeConfig : KubeConfigUtils ;
5885
@@ -70,22 +97,25 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
7097 // ignore config loading error and let odo report it on first call
7198 }
7299 try {
73- this . fsw = WatchUtil . watchFileForContextChange ( kubeConfigFolder , 'config' ) ;
100+ const kubeconfigFiles = getKubeConfigFiles ( ) ;
101+ this . kubeConfigWatchers = kubeconfigFiles . map ( kubeconfigFile => WatchUtil . watchFileForContextChange ( path . dirname ( kubeconfigFile ) , path . basename ( kubeconfigFile ) ) ) ;
74102 } catch ( err ) {
75103 void window . showWarningMessage ( 'Couldn\'t install watcher for Kubernetes configuration file. OpenShift Application Explorer view won\'t be updated automatically.' ) ;
76104 }
77- this . fsw ?. emitter ?. on ( 'file-changed' , ( ) => {
78- const ku2 = new KubeConfigUtils ( ) ;
79- const newCtx = ku2 . getContextObject ( ku2 . currentContext ) ;
80- if ( ! this . kubeContext
81- || ( this . kubeContext . cluster !== newCtx . cluster
82- || this . kubeContext . user !== newCtx . user
83- || this . kubeContext . namespace !== newCtx . namespace ) ) {
84- this . refresh ( ) ;
85- }
86- this . kubeContext = newCtx ;
87- this . kubeConfig = ku2 ;
88- } ) ;
105+ for ( const fsw of this . kubeConfigWatchers ) {
106+ fsw . emitter ?. on ( 'file-changed' , ( ) => {
107+ const ku2 = new KubeConfigUtils ( ) ;
108+ const newCtx = ku2 . getContextObject ( ku2 . currentContext ) ;
109+ if ( Boolean ( this . kubeContext ) !== Boolean ( newCtx )
110+ || ( this . kubeContext . cluster !== newCtx . cluster
111+ || this . kubeContext . user !== newCtx . user
112+ || this . kubeContext . namespace !== newCtx . namespace ) ) {
113+ this . refresh ( ) ;
114+ }
115+ this . kubeContext = newCtx ;
116+ this . kubeConfig = ku2 ;
117+ } ) ;
118+ }
89119 this . treeView = window . createTreeView < ExplorerItem > ( 'openshiftProjectExplorer' , {
90120 treeDataProvider : this ,
91121 } ) ;
@@ -110,7 +140,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
110140 contextValue : 'openshift.openConfigFile' ,
111141 label : element . label ,
112142 collapsibleState : TreeItemCollapsibleState . None ,
113- tooltip : 'Default KubeConfig' ,
143+ tooltip : element . label as string ,
114144 description : element . description ,
115145 iconPath : new ThemeIcon ( 'file' )
116146 } ;
@@ -175,11 +205,8 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
175205 await Odo . Instance . getProjects ( ) ;
176206 result = [ this . kubeContext ] ;
177207 if ( this . kubeContext ) {
178- const homeDir = this . kubeConfig . findHomeDir ( ) ;
179- if ( homeDir ) {
180- const config = path . join ( homeDir , '.kube' , 'config' ) ;
181- result . unshift ( { label : 'Default KubeConfig' , description : `${ config } ` } )
182- }
208+ const config = getKubeConfigFiles ( ) ;
209+ result . unshift ( { label : process . env . KUBECONFIG ? 'Custom KubeConfig' : 'Default KubeConfig' , description : config . join ( ':' ) } )
183210 }
184211 } catch ( err ) {
185212 // ignore because ether server is not accessible or user is logged out
@@ -246,7 +273,9 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
246273 }
247274
248275 dispose ( ) : void {
249- this . fsw ?. watcher ?. close ( ) ;
276+ for ( const fsw of this . kubeConfigWatchers ) {
277+ fsw ?. watcher ?. close ( ) ;
278+ }
250279 this . treeView . dispose ( ) ;
251280 }
252281
0 commit comments