@@ -10,6 +10,8 @@ import { CommandOption, CommandText } from '../base/command';
1010import { CliChannel } from '../cli' ;
1111import { Platform } from '../util/platform' ;
1212import { ClusterType , KubernetesConsole } from './types' ;
13+ import { Project } from './project' ;
14+ import { KubeConfigUtils } from '../util/kubeUtils' ;
1315
1416/**
1517 * A wrapper around the `oc` CLI tool.
@@ -437,6 +439,110 @@ export class Oc {
437439 return result . stdout ;
438440 }
439441
442+ public async deleteProject ( projectName : string ) : Promise < string > {
443+ const obj = await this . isOpenShiftCluster ( ) ? 'project' : 'namespace' ;
444+ return await CliChannel . getInstance ( ) . executeTool (
445+ new CommandText ( 'oc' , `delete ${ obj } ${ projectName } ` )
446+ )
447+ . then ( ( result ) => result . stdout ) ;
448+ }
449+
450+ public async createProject ( projectName : string ) : Promise < string > {
451+ const cmd = await this . isOpenShiftCluster ( ) ? 'new-project' : 'create namespace' ;
452+
453+ return await CliChannel . getInstance ( ) . executeTool (
454+ new CommandText ( 'oc' , `${ cmd } ${ projectName } ` )
455+ )
456+ . then ( async ( result ) => {
457+ // oc doesn't handle switching to the newly created namespace/project
458+ await this . setProject ( projectName ) ;
459+ return result . stdout ;
460+ } ) ;
461+ }
462+
463+ /**
464+ * Changes which project is currently being used.
465+ *
466+ * On non-OpenShift, namespaces are used instead of projects
467+ *
468+ * @param newProject the new project to use
469+ */
470+ public async setProject ( projectName : string ) : Promise < void > {
471+ if ( await this . isOpenShiftCluster ( ) ) {
472+ await CliChannel . getInstance ( ) . executeTool (
473+ new CommandText ( 'oc' , `project ${ projectName } ` ) ,
474+ ) ;
475+ } else {
476+ await CliChannel . getInstance ( ) . executeTool (
477+ new CommandText ( 'oc' , 'config set-context' , [
478+ new CommandOption ( '--current' ) ,
479+ new CommandOption ( '--namespace' , projectName )
480+ ] )
481+ ) ;
482+ }
483+ }
484+
485+ public async getProjects ( ) : Promise < Project [ ] > {
486+ return this . _listProjects ( ) ;
487+ }
488+
489+ /**
490+ * Returns the active project or null if no project is active
491+ *
492+ * @returns the active project or null if no project is active
493+ */
494+ public async getActiveProject ( ) : Promise < string > {
495+ const projects = await this . _listProjects ( ) ;
496+ if ( ! projects . length ) {
497+ return null ;
498+ }
499+ let activeProject = projects . find ( ( project ) => project . active ) ;
500+ if ( activeProject ) return activeProject . name ;
501+
502+ // If not found - use Kube Config current context or 'default'
503+ const kcu = new KubeConfigUtils ( ) ;
504+ const currentContext = kcu . findContext ( kcu . currentContext ) ;
505+ if ( currentContext ) {
506+ const active = currentContext . namespace || 'default' ;
507+ activeProject = projects . find ( ( project ) => project . name === active ) ;
508+ }
509+ return activeProject ? activeProject . name : null ;
510+ }
511+
512+ private async _listProjects ( ) : Promise < Project [ ] > {
513+ const onlyOneProject = 'you have one project on this server:' ;
514+ const namespaces : Project [ ] = [ ] ;
515+ return await CliChannel . getInstance ( ) . executeTool (
516+ new CommandText ( 'oc' , 'projects' )
517+ )
518+ . then ( ( result ) => {
519+ const lines = result . stdout && result . stdout . split ( / \r ? \n / g) ;
520+ for ( let line of lines ) {
521+ line = line . trim ( ) ;
522+ if ( line === '' ) continue ;
523+ if ( line . toLocaleLowerCase ( ) . startsWith ( onlyOneProject ) ) {
524+ 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 . - ] * ) " ./ ) ;
525+ if ( matches ) {
526+ namespaces . push ( { name : matches [ 1 ] , active : true } ) ;
527+ break ; // No more projects are to be listed
528+ }
529+ } else {
530+ const words : string [ ] = line . split ( ' ' ) ;
531+ if ( words . length > 0 && words . length <= 2 ) {
532+ // The list of projects may have eithe 1 (project name) or 2 words
533+ // (an asterisk char, indicating that the project is active, and project name).
534+ // Otherwise, it's either a header or a footer text
535+ const active = words . length === 2 && words [ 0 ] . trim ( ) === '*' ;
536+ const projectName = words [ words . length - 1 ] // The last word of array
537+ namespaces . push ( { name : projectName , active } ) ;
538+ }
539+ }
540+ }
541+ return namespaces ;
542+ } )
543+ . catch ( ( error ) => namespaces ) ;
544+ }
545+
440546 /**
441547 * Returns the oc command to list all resources of the given type in the given (or current) namespace
442548 *
0 commit comments