Skip to content

Commit

Permalink
Swtich from 'odo' to 'oc' for create/set/get active/delete project an…
Browse files Browse the repository at this point in the history
…d list ptojects

Issue: #3662

Signed-off-by: Victor Rubezhny <vrubezhny@redhat.com>
  • Loading branch information
vrubezhny authored and datho7561 committed Jan 26, 2024
1 parent 831d478 commit 976e968
Show file tree
Hide file tree
Showing 21 changed files with 238 additions and 196 deletions.
17 changes: 9 additions & 8 deletions src/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { CommandText } from './base/command';
import * as Helm from './helm/helm';
import { HelmRepo } from './helm/helmChartType';
import { Oc } from './oc/ocWrapper';
import { Odo } from './odo/odoWrapper';
import { Component } from './openshift/component';
import { getServiceKindStubs } from './openshift/serviceHelpers';
import { KubeConfigUtils, getKubeConfigFiles } from './util/kubeUtils';
Expand All @@ -35,6 +34,7 @@ import { FileContentChangeNotifier, WatchUtil } from './util/watch';
import { vsCommand } from './vscommand';
import { CustomResourceDefinitionStub } from './webview/common/createServiceTypes';
import { OpenShiftTerminalManager } from './webview/openshift-terminal/openShiftTerminal';
import { LoginUtil } from './util/loginUtil';

type ExplorerItem = KubernetesObject | Helm.HelmRelease | Context | TreeItem | OpenShiftObject | HelmRepo;

Expand Down Expand Up @@ -223,12 +223,13 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
let result: ExplorerItem[] = [];
if (!element) {
try {
await Odo.Instance.getProjects();
result = [this.kubeContext];
if (this.kubeContext) {
const config = getKubeConfigFiles();
void commands.executeCommand('setContext', 'canCreateNamespace', await Oc.Instance.canCreateNamespace());
result.unshift({ label: process.env.KUBECONFIG ? 'Custom KubeConfig' : 'Default KubeConfig', description: config.join(':') })
if (!await LoginUtil.Instance.requireLogin()) {
result = [this.kubeContext];
if (this.kubeContext) {
const config = getKubeConfigFiles();
void commands.executeCommand('setContext', 'canCreateNamespace', await Oc.Instance.canCreateNamespace());
result.unshift({ label: process.env.KUBECONFIG ? 'Custom KubeConfig' : 'Default KubeConfig', description: config.join(':') })
}
}
} catch (err) {
// ignore because ether server is not accessible or user is logged out
Expand All @@ -244,7 +245,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
// * example is sandbox context created when login to sandbox first time
// (3) there is namespace set in context and namespace exists in the cluster
// (4) there is namespace set in context and namespace does not exist in the cluster
const namespaces = await Odo.Instance.getProjects();
const namespaces = await Oc.Instance.getProjects();
const helmContext = {
kind: 'helm',
metadata: {
Expand Down
106 changes: 106 additions & 0 deletions src/oc/ocWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { CommandOption, CommandText } from '../base/command';
import { CliChannel } from '../cli';
import { Platform } from '../util/platform';
import { ClusterType, KubernetesConsole } from './types';
import { Project } from './project';
import { KubeConfigUtils } from '../util/kubeUtils';

/**
* A wrapper around the `oc` CLI tool.
Expand Down Expand Up @@ -437,6 +439,110 @@ export class Oc {
return result.stdout;
}

public async deleteProject(projectName: string): Promise<string> {
const obj = await this.isOpenShiftCluster() ? 'project' : 'namespace';
return await CliChannel.getInstance().executeTool(
new CommandText('oc', `delete ${obj} ${projectName}`)
)
.then((result) => result.stdout);
}

public async createProject(projectName: string): Promise<string> {
const cmd = await this.isOpenShiftCluster() ? 'new-project' : 'create namespace';

return await CliChannel.getInstance().executeTool(
new CommandText('oc', `${cmd} ${projectName}`)
)
.then(async (result) => {
// oc doesn't handle switching to the newly created namespace/project
await this.setProject(projectName);
return result.stdout;
});
}

/**
* Changes which project is currently being used.
*
* On non-OpenShift, namespaces are used instead of projects
*
* @param newProject the new project to use
*/
public async setProject(projectName: string): Promise<void> {
if(await this.isOpenShiftCluster()) {
await CliChannel.getInstance().executeTool(
new CommandText('oc', `project ${projectName}`),
);
} else {
await CliChannel.getInstance().executeTool(
new CommandText('oc', 'config set-context', [
new CommandOption('--current'),
new CommandOption('--namespace', projectName)
])
);
}
}

public async getProjects(): Promise<Project[]> {
return this._listProjects();
}

/**
* Returns the active project or null if no project is active
*
* @returns the active project or null if no project is active
*/
public async getActiveProject(): Promise<string> {
const projects = await this._listProjects();
if (!projects.length) {
return null;
}
let activeProject = projects.find((project) => project.active);
if (activeProject) return activeProject.name;

// If not found - use Kube Config current context or 'default'
const kcu = new KubeConfigUtils();
const currentContext = kcu.findContext(kcu.currentContext);
if (currentContext) {
const active = currentContext.namespace || 'default';
activeProject = projects.find((project) => project.name ===active);
}
return activeProject ? activeProject.name : null;
}

private async _listProjects(): Promise<Project[]> {
const onlyOneProject = 'you have one project on this server:';
const namespaces: Project[] = [];
return await CliChannel.getInstance().executeTool(
new CommandText('oc', 'projects')
)
.then( (result) => {
const lines = result.stdout && result.stdout.split(/\r?\n/g);
for (let line of lines) {
line = line.trim();
if (line === '') continue;
if (line.toLocaleLowerCase().startsWith(onlyOneProject)) {
const matches = line.match(/You\shave\sone\sproject\son\sthis\sserver:\s"([a-zA-Z0-9]+[a-zA-Z0-9.-]*)"./);
if (matches) {
namespaces.push({name: matches[1], active: true});
break; // No more projects are to be listed
}
} else {
const words: string[] = line.split(' ');
if (words.length > 0 && words.length <= 2) {
// The list of projects may have eithe 1 (project name) or 2 words
// (an asterisk char, indicating that the project is active, and project name).
// Otherwise, it's either a header or a footer text
const active = words.length === 2 && words[0].trim() === '*';
const projectName = words[words.length - 1] // The last word of array
namespaces.push( {name: projectName, active });
}
}
}
return namespaces;
})
.catch((error) => namespaces);
}

/**
* Returns the oc command to list all resources of the given type in the given (or current) namespace
*
Expand Down
File renamed without changes.
57 changes: 0 additions & 57 deletions src/odo/odoWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { Command } from './command';
import { AnalyzeResponse, ComponentTypeAdapter, ComponentTypeDescription, DevfileComponentType, Registry } from './componentType';
import { ComponentDescription, StarterProject } from './componentTypeDescription';
import { BindableService } from './odoTypes';
import { Project } from './project';

/**
* Wraps the `odo` cli tool.
Expand Down Expand Up @@ -78,21 +77,6 @@ export class Odo {
void commands.executeCommand('setContext', 'isLoggedIn', false);
}

public async getProjects(): Promise<Project[]> {
return this._listProjects();
}

/**
* Changes which project is currently being used.
*
* On non-OpenShift, namespaces are used instead of projects
*
* @param newProject the new project to use
*/
public async setProject(newProject: string): Promise<void> {
await this.execute(new CommandText('odo', `set namespace ${newProject}`), undefined, true);
}

public getKubeconfigEnv(): { KUBECONFIG?: string } {
const addEnv: { KUBECONFIG?: string } = {};
let kc: KubeConfig;
Expand Down Expand Up @@ -183,22 +167,6 @@ export class Odo {
return result;
}

public async deleteProject(projectName: string): Promise<void> {
await this.execute(
new CommandText('odo', `delete namespace ${projectName}`, [
new CommandOption('-f'),
new CommandOption('-w'),
]),
);
}

public async createProject(projectName: string): Promise<void> {
await Odo.instance.execute(
new CommandText('odo', `create namespace ${projectName}`, [new CommandOption('-w')]),
);
// odo handles switching to the newly created namespace/project
}

public async createComponentFromFolder(
type: string,
registryName: string,
Expand Down Expand Up @@ -376,31 +344,6 @@ export class Odo {
);
}

/**
* Returns the active project or null if no project is active
*
* @returns the active project or null if no project is active
*/
public async getActiveProject(): Promise<string> {
const projects = await this._listProjects();
if (!projects.length) {
return null;
}
const activeProject = projects.find((project) => project.active);
return activeProject ? activeProject.name : null;
}

private async _listProjects(): Promise<Project[]> {
const response = await this.execute(
new CommandText('odo', 'list project', [new CommandOption('-o', 'json', false)]),
);
const responseObj = JSON.parse(response.stdout);
if (!responseObj?.namespaces) {
return [];
}
return responseObj.namespaces as Project[];
}

/**
* Deletes all the odo configuration files associated with the component (`.odo`, `devfile.yaml`) located at the given path.
*
Expand Down
3 changes: 1 addition & 2 deletions src/openshift/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { CliChannel } from '../cli';
import { OpenShiftExplorer } from '../explorer';
import { Oc } from '../oc/ocWrapper';
import { Command } from '../odo/command';
import { Odo } from '../odo/odoWrapper';
import * as NameValidator from '../openshift/nameValidator';
import { TokenStore } from '../util/credentialManager';
import { Filters } from '../util/filters';
Expand Down Expand Up @@ -108,7 +107,7 @@ export class Cluster extends OpenShiftItem {
async (progress) => {
const [consoleInfo, namespace] = await Promise.all([
Oc.Instance.getConsoleInfo(),
Odo.Instance.getActiveProject(),
Oc.Instance.getActiveProject(),
]);
progress.report({ increment: 100, message: 'Starting default browser' });
// eg. https://console-openshift-console.apps-crc.testing/catalog/ns/default?catalogType=OperatorBackedService
Expand Down
14 changes: 7 additions & 7 deletions src/openshift/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export class Component extends OpenShiftItem {
}

private static async checkForPodman(): Promise<boolean> {
if (await Component.odo.isPodmanPresent()) {
if (await Odo.Instance.isPodmanPresent()) {
return true;
}
void window.showErrorMessage('Podman is not present in the system, please install podman on your machine and try again.', 'Install podman')
Expand Down Expand Up @@ -378,7 +378,7 @@ export class Component extends OpenShiftItem {
@vsCommand('openshift.component.openInBrowser')
@clusterRequired()
static async openInBrowser(component: ComponentWorkspaceFolder): Promise<string | null | undefined> {
const componentDescription = await Component.odo.describeComponent(component.contextPath, !!Component.getComponentDevState(component).runOn);
const componentDescription = await Odo.Instance.describeComponent(component.contextPath, !!Component.getComponentDevState(component).runOn);
if (componentDescription.devForwardedPorts?.length === 1) {
const fp = componentDescription.devForwardedPorts[0];
await commands.executeCommand('vscode.open', Uri.parse(`http://${fp.localAddress}:${fp.localPort}`));
Expand Down Expand Up @@ -502,7 +502,7 @@ export class Component extends OpenShiftItem {
let componentType: ComponentTypeAdapter;
let componentTypeCandidates: ComponentTypeAdapter[];
if (!useExistingDevfile && (!opts || !opts.devFilePath || opts.devFilePath.length === 0)) {
const componentTypes = await Component.odo.getComponentTypes();
const componentTypes = await Odo.Instance.getComponentTypes();
progressIndicator.busy = true;
progressIndicator.placeholder = opts?.componentTypeName ? `Checking if '${opts.componentTypeName}' Component type is available` : 'Loading available Component types';
progressIndicator.show();
Expand Down Expand Up @@ -534,7 +534,7 @@ export class Component extends OpenShiftItem {
progressIndicator.placeholder = 'Loading Starter Projects for selected Component Type'
progressIndicator.show();

const starterProjects: StarterProject[] = await this.odo.getStarterProjects(componentType);
const starterProjects: StarterProject[] = await Odo.Instance.getStarterProjects(componentType);
progressIndicator.hide();
if (starterProjects?.length && starterProjects.length > 0) {
const create = await window.showQuickPick(['Yes', 'No'], { placeHolder: `Initialize Component using ${starterProjects.length === 1 ? '\''.concat(starterProjects[0].name.concat('\' ')) : ''}Starter Project?` });
Expand Down Expand Up @@ -574,7 +574,7 @@ export class Component extends OpenShiftItem {
try {
await Progress.execFunctionWithProgress(
`Creating new Component '${componentName}'`,
() => Component.odo.createComponentFromFolder(
() => Odo.Instance.createComponentFromFolder(
componentType?.name, // in case of using existing devfile
componentType?.registryName,
componentName,
Expand Down Expand Up @@ -706,7 +706,7 @@ export class Component extends OpenShiftItem {
}

static async startOdoAndConnectDebugger(component: ComponentWorkspaceFolder, config: DebugConfiguration): Promise<string> {
const componentDescription = await Component.odo.describeComponent(component.contextPath, !!Component.getComponentDevState(component).runOn);
const componentDescription = await Odo.Instance.describeComponent(component.contextPath, !!Component.getComponentDevState(component).runOn);
if (componentDescription.devForwardedPorts?.length > 0) {
// try to find debug port
const debugPortsCandidates:number[] = [];
Expand Down Expand Up @@ -792,7 +792,7 @@ export class Component extends OpenShiftItem {
const CANCEL = 'Cancel';
const response = await window.showWarningMessage(`Are you sure you want to delete the configuration for the component ${context.contextPath}?\nOpenShift Toolkit will no longer recognize the project as a component.`, DELETE_CONFIGURATION, CANCEL);
if (response === DELETE_CONFIGURATION) {
await Component.odo.deleteComponentConfiguration(context.contextPath);
await Odo.Instance.deleteComponentConfiguration(context.contextPath);
void commands.executeCommand('openshift.componentsView.refresh');
}
}
Expand Down
5 changes: 1 addition & 4 deletions src/openshift/openshiftItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import { commands, QuickPickItem, window } from 'vscode';
import { inputValue } from '../util/inputValue';
import { Oc } from '../oc/ocWrapper';
import { Odo } from '../odo/odoWrapper';
import { Project } from '../odo/project';
import { Project } from '../oc/project';
import { ServerlessFunctionView } from '../serverlessFunction/view';
import * as NameValidator from './nameValidator';

Expand All @@ -24,8 +23,6 @@ export class QuickPickCommand implements QuickPickItem {
}

export default class OpenShiftItem {
protected static readonly odo = Odo.Instance;

protected static readonly serverlessView: ServerlessFunctionView = ServerlessFunctionView.getInstance();

static async getName(message: string, offset?: string, defaultValue = ''): Promise<string> {
Expand Down
Loading

0 comments on commit 976e968

Please sign in to comment.