@@ -200,6 +200,25 @@ export class Oc {
200200 return false ;
201201 }
202202
203+ /**
204+ * Returns true if the current user is authorized to list namespaces on the cluster, and false otherwise.
205+ *
206+ * @returns true if the current user is authorized to list namespaces on the cluster, and false otherwise
207+ */
208+ public async canListNamespaces ( ) : Promise < boolean > {
209+ try {
210+ const result = await CliChannel . getInstance ( ) . executeTool (
211+ new CommandText ( 'oc' , 'auth can-i list projects' ) ,
212+ ) ;
213+ if ( result . stdout === 'yes' ) {
214+ return true ;
215+ }
216+ } catch {
217+ //ignore
218+ }
219+ return false ;
220+ }
221+
203222 /**
204223 * Returns true if the current user is authorized to delete a namespace on the cluster, and false otherwise.
205224 *
@@ -505,7 +524,8 @@ export class Oc {
505524 }
506525
507526 public async getProjects ( ) : Promise < Project [ ] > {
508- return this . _listProjects ( ) ;
527+ return this . _listProjects ( )
528+ . then ( ( projects ) => this . fixActiveProject ( projects ) ) ;
509529 }
510530
511531 /**
@@ -514,51 +534,109 @@ export class Oc {
514534 * @returns the active project or null if no project is active
515535 */
516536 public async getActiveProject ( ) : Promise < string > {
517- const projects = await this . _listProjects ( ) ;
518- if ( ! projects . length ) {
519- return null ;
537+ return this . _listProjects ( )
538+ . then ( ( projects ) => {
539+ const fixedProjects = this . fixActiveProject ( projects ) ;
540+ const activeProject = fixedProjects . find ( ( project ) => project . active ) ;
541+ return activeProject ? activeProject . name : null ;
542+ } ) ;
543+ }
544+
545+ /**
546+ * Fixes the projects array by marking up an active project (if not set)
547+ * by the following rules:
548+ * - If there is only one single project - mark it as active
549+ * - If there is already at least one project marked as active - return the projects "as is"
550+ * - If Kube Config's current context has a namespace set - find an according project
551+ * and mark it as active
552+ * - [fixup for Sandbox cluster] Get Kube Configs's curernt username and try finding a project,
553+ * which name is partially created from that username - if found, treat it as an active project
554+ * - Try a 'default' as a project name, if found - use it as an active project name
555+ * - Use first project as active
556+ *
557+ * @returns The array of Projects with at least one project marked as an active
558+ */
559+ public fixActiveProject ( projects : Project [ ] ) : Project [ ] {
560+ if ( ! projects . length ) return [ ] ;
561+
562+ // If there is only one single project - mark it as active
563+ if ( projects . length === 1 ) {
564+ projects [ 0 ] . active = true ;
565+ return projects ;
520566 }
567+
568+ // If there is already at least one project marked as active - return the projects "as is"
521569 let activeProject = projects . find ( ( project ) => project . active ) ;
522- if ( activeProject ) return activeProject . name ;
570+ if ( activeProject ) return projects ;
523571
524- // If not found - use Kube Config current context or 'default'
572+ // Try Kube Config current context to find existing active project
525573 const kcu = new KubeConfigUtils ( ) ;
526574 const currentContext = kcu . findContext ( kcu . currentContext ) ;
527575 if ( currentContext ) {
528- const active = currentContext . namespace || 'default' ;
529- activeProject = projects . find ( ( project ) => project . name === active ) ;
576+ if ( currentContext . namespace ) {
577+ activeProject = projects . find ( ( project ) => project . name === currentContext . namespace ) ;
578+ if ( activeProject ) {
579+ activeProject . active = true ;
580+ return projects ;
581+ }
582+ }
583+ }
584+
585+ // [fixup for Sandbox cluster] Get Kube Configs's curernt username and try finding a project,
586+ // which name is partially created from that username
587+ const currentUser = kcu . getCurrentUser ( ) ;
588+ if ( currentUser ) {
589+ const projectPrefix = currentUser . name . substring ( 0 , currentUser . name . indexOf ( '/' ) ) ;
590+ if ( projectPrefix . length > 0 ) {
591+ activeProject = projects . find ( ( project ) => project . name . includes ( projectPrefix ) ) ;
592+ if ( activeProject ) {
593+ activeProject . active = true ;
594+ void Oc . Instance . setProject ( activeProject . name ) ;
595+ return projects ;
596+ }
597+ }
598+ }
599+
600+ // Add Kube Config current context to the proect list for cases where
601+ // projects/namespaces cannot be listed due to the cluster config restrictions
602+ // (such a project/namespace can be set active manually)
603+ if ( currentContext ) {
604+ if ( currentContext . namespace ) {
605+ const fixedProjects = [
606+ {
607+ name : currentContext . namespace ,
608+ active : true
609+ } ,
610+ ...projects
611+ ]
612+ void Oc . Instance . setProject ( currentContext . namespace ) ;
613+ return fixedProjects ;
614+ }
615+ }
616+
617+ // Try a 'default' as a project name, if found - use it as an active project name
618+ activeProject = projects . find ( ( project ) => project . name === 'default' ) ;
619+ if ( activeProject ) {
620+ activeProject . active = true ;
621+ return projects ;
530622 }
531- return activeProject ? activeProject . name : null ;
623+
624+ projects [ 0 ] . active = true ;
625+ void Oc . Instance . setProject ( projects [ 0 ] . name ) ;
626+ return projects ;
532627 }
533628
534629 private async _listProjects ( ) : Promise < Project [ ] > {
535- const onlyOneProject = 'you have one project on this server:' ;
536630 const namespaces : Project [ ] = [ ] ;
537631 return await CliChannel . getInstance ( ) . executeTool (
538- new CommandText ( 'oc' , 'projects' )
632+ new CommandText ( 'oc' , 'projects -q ' )
539633 )
540634 . then ( ( result ) => {
541635 const lines = result . stdout && result . stdout . split ( / \r ? \n / g) ;
542636 for ( let line of lines ) {
543637 line = line . trim ( ) ;
544638 if ( line === '' ) continue ;
545- if ( line . toLocaleLowerCase ( ) . startsWith ( onlyOneProject ) ) {
546- const matches = line . match ( / Y o u \s h a v e \s o n e \s p r o j e c t \s o n \s t h i s \s s e r v e r : \s " ( [ a - z A - Z 0 - 9 ] + [ a - z A - Z 0 - 9 . - ] * ) " ./ ) ;
547- if ( matches ) {
548- namespaces . push ( { name : matches [ 1 ] , active : true } ) ;
549- break ; // No more projects are to be listed
550- }
551- } else {
552- const words : string [ ] = line . split ( ' ' ) ;
553- if ( words . length > 0 && words . length <= 2 ) {
554- // The list of projects may have eithe 1 (project name) or 2 words
555- // (an asterisk char, indicating that the project is active, and project name).
556- // Otherwise, it's either a header or a footer text
557- const active = words . length === 2 && words [ 0 ] . trim ( ) === '*' ;
558- const projectName = words [ words . length - 1 ] // The last word of array
559- namespaces . push ( { name : projectName , active } ) ;
560- }
561- }
639+ namespaces . push ( { name : line , active : false } ) ;
562640 }
563641 return namespaces ;
564642 } )
0 commit comments