@@ -45,11 +45,6 @@ export class KubeConfig {
4545 */
4646 public 'currentContext' : string ;
4747
48- /**
49- * Root directory for a config file driven config. Used for loading relative cert paths.
50- */
51- public 'rootDirectory' : string ;
52-
5348 public getContexts ( ) {
5449 return this . contexts ;
5550 }
@@ -102,8 +97,9 @@ export class KubeConfig {
10297 }
10398
10499 public loadFromFile ( file : string ) {
105- this . rootDirectory = path . dirname ( file ) ;
100+ const rootDirectory = path . dirname ( file ) ;
106101 this . loadFromString ( fs . readFileSync ( file , 'utf8' ) ) ;
102+ this . makePathsAbsolute ( rootDirectory ) ;
107103 }
108104
109105 public applytoHTTPSOptions ( opts : https . RequestOptions ) {
@@ -201,9 +197,55 @@ export class KubeConfig {
201197 this . currentContext = contextName ;
202198 }
203199
200+ public mergeConfig ( config : KubeConfig ) {
201+ this . currentContext = config . currentContext ;
202+ config . clusters . forEach ( ( cluster : Cluster ) => {
203+ this . addCluster ( cluster ) ;
204+ } ) ;
205+ config . users . forEach ( ( user : User ) => {
206+ this . addUser ( user ) ;
207+ } ) ;
208+ config . contexts . forEach ( ( ctx : Context ) => {
209+ this . addContext ( ctx ) ;
210+ } ) ;
211+ }
212+
213+ public addCluster ( cluster : Cluster ) {
214+ this . clusters . forEach ( ( c : Cluster , ix : number ) => {
215+ if ( c . name === cluster . name ) {
216+ throw new Error ( `Duplicate cluster: ${ c . name } ` ) ;
217+ }
218+ } ) ;
219+ this . clusters . push ( cluster ) ;
220+ }
221+
222+ public addUser ( user : User ) {
223+ this . users . forEach ( ( c : User , ix : number ) => {
224+ if ( c . name === user . name ) {
225+ throw new Error ( `Duplicate user: ${ c . name } ` ) ;
226+ }
227+ } ) ;
228+ this . users . push ( user ) ;
229+ }
230+
231+ public addContext ( ctx : Context ) {
232+ this . contexts . forEach ( ( c : Context , ix : number ) => {
233+ if ( c . name === ctx . name ) {
234+ throw new Error ( `Duplicate context: ${ c . name } ` ) ;
235+ }
236+ } ) ;
237+ this . contexts . push ( ctx ) ;
238+ }
239+
204240 public loadFromDefault ( ) {
205241 if ( process . env . KUBECONFIG && process . env . KUBECONFIG . length > 0 ) {
206- this . loadFromFile ( process . env . KUBECONFIG ) ;
242+ const files = process . env . KUBECONFIG . split ( path . delimiter ) ;
243+ this . loadFromFile ( files [ 0 ] ) ;
244+ for ( let i = 1 ; i < files . length ; i ++ ) {
245+ const kc = new KubeConfig ( ) ;
246+ kc . loadFromFile ( files [ i ] ) ;
247+ this . mergeConfig ( kc ) ;
248+ }
207249 return ;
208250 }
209251 const home = findHomeDir ( ) ;
@@ -247,6 +289,22 @@ export class KubeConfig {
247289 return apiClient ;
248290 }
249291
292+ public makePathsAbsolute ( rootDirectory : string ) {
293+ this . clusters . forEach ( ( cluster : Cluster ) => {
294+ if ( cluster . caFile ) {
295+ cluster . caFile = makeAbsolutePath ( rootDirectory , cluster . caFile ) ;
296+ }
297+ } ) ;
298+ this . users . forEach ( ( user : User ) => {
299+ if ( user . certFile ) {
300+ user . certFile = makeAbsolutePath ( rootDirectory , user . certFile ) ;
301+ }
302+ if ( user . keyFile ) {
303+ user . keyFile = makeAbsolutePath ( rootDirectory , user . keyFile ) ;
304+ }
305+ } ) ;
306+ }
307+
250308 private getCurrentContextObject ( ) {
251309 return this . getContextObject ( this . currentContext ) ;
252310 }
@@ -261,18 +319,15 @@ export class KubeConfig {
261319 if ( cluster != null && cluster . skipTLSVerify ) {
262320 opts . rejectUnauthorized = false ;
263321 }
264- const ca =
265- cluster != null
266- ? bufferFromFileOrString ( this . rootDirectory , cluster . caFile , cluster . caData )
267- : null ;
322+ const ca = cluster != null ? bufferFromFileOrString ( cluster . caFile , cluster . caData ) : null ;
268323 if ( ca ) {
269324 opts . ca = ca ;
270325 }
271- const cert = bufferFromFileOrString ( this . rootDirectory , user . certFile , user . certData ) ;
326+ const cert = bufferFromFileOrString ( user . certFile , user . certData ) ;
272327 if ( cert ) {
273328 opts . cert = cert ;
274329 }
275- const key = bufferFromFileOrString ( this . rootDirectory , user . keyFile , user . keyData ) ;
330+ const key = bufferFromFileOrString ( user . keyFile , user . keyData ) ;
276331 if ( key ) {
277332 opts . key = key ;
278333 }
@@ -363,12 +418,16 @@ export class Config {
363418 }
364419}
365420
421+ export function makeAbsolutePath ( root : string , file : string ) : string {
422+ if ( ! root || path . isAbsolute ( file ) ) {
423+ return file ;
424+ }
425+ return path . join ( root , file ) ;
426+ }
427+
366428// This is public really only for testing.
367- export function bufferFromFileOrString ( root ?: string , file ?: string , data ?: string ) : Buffer | null {
429+ export function bufferFromFileOrString ( file ?: string , data ?: string ) : Buffer | null {
368430 if ( file ) {
369- if ( ! path . isAbsolute ( file ) && root ) {
370- file = path . join ( root , file ) ;
371- }
372431 return fs . readFileSync ( file ) ;
373432 }
374433 if ( data ) {
0 commit comments