Skip to content

Commit

Permalink
Fix uninstalling Helm charts
Browse files Browse the repository at this point in the history
- Show Helm releases in the project explorer using results from `helm list`
- Add description text for items in the application explorer to helm
  distinguish them
- Refactor Helm commands into their own folder
- Add integration tests for Helm commands

Fixes redhat-developer#3021

Signed-off-by: David Thompson <davthomp@redhat.com>
  • Loading branch information
datho7561 committed Jul 28, 2023
1 parent 073ae7b commit 9ce6117
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"base": "$tsc-watch",
},
"presentation": {
"reveal": "silent",
"reveal": "never",
},
},
{
Expand Down
Binary file added images/context/helm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,7 @@
},
{
"command": "openshift.resource.load",
"when": "view == openshiftProjectExplorer && viewItem == openshift.k8sObject || viewItem == openshift.k8sObject.helm"
"when": "view == openshiftProjectExplorer && viewItem == openshift.k8sObject"
},
{
"command": "openshift.resource.unInstall",
Expand Down
50 changes: 28 additions & 22 deletions src/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,33 @@
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { Context, KubernetesObject } from '@kubernetes/client-node';
import * as fs from 'fs';
import * as path from 'path';
import {
Disposable,
commands, Disposable,
Event,
EventEmitter,
ThemeIcon,
EventEmitter, extensions, ThemeIcon,
TreeDataProvider,
TreeItem,
TreeItemCollapsibleState,
TreeView,
Uri,
commands,
extensions,
version,
window,
Uri, version,
window
} from 'vscode';

import * as fs from 'fs';
import * as path from 'path';
import { Platform } from './util/platform';

import { Context, KubernetesObject } from '@kubernetes/client-node';
import { CliChannel } from './cli';
import * as Helm from './helm/helm';
import { Command } from './odo/command';
import { Odo3, newInstance } from './odo3';
import { newInstance, Odo3 } from './odo3';
import { KubeConfigUtils } from './util/kubeUtils';
import { Platform } from './util/platform';
import { Progress } from './util/progress';
import { FileContentChangeNotifier, WatchUtil } from './util/watch';
import { vsCommand } from './vscommand';

const kubeConfigFolder: string = path.join(Platform.getUserHomePath(), '.kube');

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

type PackageJSON = {
version: string;
Expand Down Expand Up @@ -142,8 +137,18 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
};
}

// otherwise it is a KubernetesObject instance
// It's a Helm installation
if ('chart' in element) {
return {
contextValue: 'openshift.k8sObject.helm',
label: element.name,
collapsibleState: TreeItemCollapsibleState.None,
description: 'Helm Release',
iconPath: path.resolve(__dirname, '../../images/context/helm.png'),
};
}

// otherwise it is a KubernetesObject instance
if ('kind' in element) {
if (element.kind === 'project') {
return {
Expand All @@ -154,8 +159,9 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
}
}
return {
contextValue: element.metadata.labels['helm.sh/chart'] ? 'openshift.k8sObject.helm': 'openshift.k8sObject',
contextValue: 'openshift.k8sObject',
label: element.metadata.name,
description: `${element.kind.substring(0, 1).toLocaleUpperCase()}${element.kind.substring(1)}`,
collapsibleState: TreeItemCollapsibleState.None,
iconPath: path.resolve(__dirname, '../../images/context/component-node.png'),
command: {
Expand Down Expand Up @@ -229,7 +235,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
}
}
} else {
result = [...await this.odo3.getDeploymentConfigs(), ...await this.odo3.getDeployments()];
result = [...await this.odo3.getDeploymentConfigs(), ...await this.odo3.getDeployments(), ...await Helm.getHelmReleases()];
}
// don't show Open In Developer Dashboard if not openshift cluster
const openshiftResources = await CliChannel.getInstance().executeTool(Command.isOpenshiftCluster());
Expand Down Expand Up @@ -260,9 +266,9 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
}

@vsCommand('openshift.resource.unInstall')
public static async unInstallHelmChart(component: KubernetesObject) {
return Progress.execFunctionWithProgress(`Uninstalling ${component.metadata.name}`, async () => {
await CliChannel.getInstance().executeTool(Command.unInstallHelmChart(component.metadata.name));
public static async unInstallHelmChart(release: Helm.HelmRelease) {
return Progress.execFunctionWithProgress(`Uninstalling ${release.name}`, async () => {
await Helm.unInstallHelmChart(release.name);
OpenShiftExplorer.getInstance().refresh();
});
}
Expand Down
72 changes: 72 additions & 0 deletions src/helm/helm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/
import { CliChannel, CliExitData } from '../cli';
import * as HelmCommands from './helmCommands';

export type HelmRelease = {
name: string;
namespace: string;
revision: string;
updated: string;
status: string;
chart: string;
app_version: string;
};

/**
* Returns a list of all Helm releases in the current namespace on the current cluster.
*
* @returns a list of all Helm releases in the current namespace on the current cluster
*/
export async function getHelmReleases(): Promise<HelmRelease[]> {
const res = await CliChannel.getInstance().executeTool(HelmCommands.listHelmReleases());
return JSON.parse(res.stdout) as HelmRelease[];
}

/**
* Adds the OpenShift Helm repo to the cluster.
*
* @returns the CLI output data from running the necessary command
*/
export async function addHelmRepo(): Promise<CliExitData> {
return await CliChannel.getInstance().executeTool(HelmCommands.addHelmRepo());
}

/**
* Updates the content of all the Helm repos.
*
* @returns the CLI output data from running the necessary command
*/
export async function updateHelmRepo(): Promise<CliExitData> {
return await CliChannel.getInstance().executeTool(HelmCommands.updateHelmRepo());
}

/**
* Install a chart from the OpenShift Helm Repo
*
* @param name the name of the release
* @param chartName the name of the chart to install
* @param version the version of the chart to use for the release
* @returns the CLI output data from running the necessary command
*/
export async function installHelmChart(
name: string,
chartName: string,
version: string,
): Promise<CliExitData> {
return await CliChannel.getInstance().executeTool(
HelmCommands.installHelmChart(name, chartName, version),
);
}

/**
* Uninstalls the given Helm release from the cluster.
*
* @param name the name of the Helm release to uninstall
* @returns the CLI output data from running the necessary command
*/
export async function unInstallHelmChart(name: string): Promise<CliExitData> {
return await CliChannel.getInstance().executeTool(HelmCommands.unInstallHelmChart(name));
}
26 changes: 26 additions & 0 deletions src/helm/helmCommands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import { CommandOption, CommandText } from '../base/command';

export function addHelmRepo(): CommandText {
return new CommandText('helm repo add openshift https://charts.openshift.io/');
}

export function updateHelmRepo(): CommandText {
return new CommandText('helm repo update');
}

export function installHelmChart(name: string, chartName: string, version: string): CommandText {
return new CommandText('helm', `install ${name} openshift/${chartName}`, [new CommandOption('--version', version)]);
}

export function unInstallHelmChart(name: string): CommandText {
return new CommandText(`helm uninstall ${name}`);
}

export function listHelmReleases(): CommandText {
return new CommandText('helm', 'list', [new CommandOption('-o', 'json')]);
}
16 changes: 0 additions & 16 deletions src/odo/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,22 +127,6 @@ export class Command {
return new CommandText('oc version');
}

static addHelmRepo(): CommandText {
return new CommandText('helm repo add openshift https://charts.openshift.io/');
}

static updateHelmRepo(): CommandText {
return new CommandText('helm repo update');
}

static installHelmChart(name: string, chartName: string, version: string): CommandText {
return new CommandText(`helm install ${name} openshift/${chartName} --version ${version}`);
}

static unInstallHelmChart(name: string): CommandText {
return new CommandText(`helm uninstall ${name}`);
}

static printOcVersionJson(): CommandText {
return new CommandText('oc version -ojson');
}
Expand Down
44 changes: 9 additions & 35 deletions src/registriesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,26 @@
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/
import { Subject } from 'rxjs';
import validator from 'validator';
import * as vscode from 'vscode';
import {
TreeDataProvider,
TreeItem,
Event,
EventEmitter,
TreeView,
window,
Uri,
TreeItemCollapsibleState,
commands,
commands, Event,
EventEmitter, TreeDataProvider,
TreeItem, TreeItemCollapsibleState, TreeView, Uri, window
} from 'vscode';
import { CliExitData } from './cli';
import { getInstance, Odo, OdoImpl } from './odo';
import { Command } from './odo/command';
import {
ComponentTypeDescription,
DevfileComponentType,
Registry,
Registry
} from './odo/componentType';
import { StarterProject } from './odo/componentTypeDescription';
import { Progress } from './util/progress';
import { vsCommand, VsCommandError } from './vscommand';
import validator from 'validator';
import { Command } from './odo/command';
import { CliExitData } from './cli';
import { Subject } from 'rxjs';
import fetch = require('make-fetch-happen');
import { Progress } from './util/progress';

type ComponentType = Registry;

Expand Down Expand Up @@ -116,26 +110,6 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
return this.registries;
}

public async addHelmRepo(): Promise<CliExitData> {
const response = await getInstance().execute(Command.addHelmRepo());
return response;
}

public async updateHelmRepo(): Promise<CliExitData> {
const response = await getInstance().execute(Command.updateHelmRepo());
return response;
}

public async installHelmChart(name: string, chartName: string, version: string): Promise<CliExitData> {
const data = await getInstance().execute(Command.installHelmChart(name, chartName, version));
return data;
}

public async unInstallHelmChart(name: string): Promise<CliExitData> {
const data = await getInstance().execute(Command.unInstallHelmChart(name));
return data;
}

public async getAllComponents(): Promise<void> {
return new Promise<void>((resolve) => {
let isError = false;
Expand Down
8 changes: 4 additions & 4 deletions src/webview/helm-chart/helmChartLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as path from 'path';
import * as vscode from 'vscode';
import * as YAML from 'yaml';
import { OpenShiftExplorer } from '../../explorer';
import { ComponentTypesView } from '../../registriesView';
import * as Helm from '../../helm/helm';
import { ExtCommandTelemetryEvent } from '../../telemetry';
import { ExtensionID } from '../../util/constants';
import { vsCommand } from '../../vscommand';
Expand Down Expand Up @@ -36,7 +36,7 @@ export class HelmCommand {
chartName: event.chartName,
show: true
});
await ComponentTypesView.instance.installHelmChart(event.name, event.chartName, event.version);
await Helm.installHelmChart(event.name, event.chartName, event.version);
vscode.window.showInformationMessage(`Helm Chart: ${event.name} is successfully installed and will be reflected in the tree view.`);
OpenShiftExplorer.getInstance().refresh();
panel.webview.postMessage({
Expand Down Expand Up @@ -120,8 +120,8 @@ export default class HelmChartLoader {

async function getHelmCharts(eventName: string): Promise<void> {
if (helmRes.length === 0) {
await ComponentTypesView.instance.addHelmRepo();
await ComponentTypesView.instance.updateHelmRepo();
await Helm.addHelmRepo();
await Helm.updateHelmRepo();
const signupResponse = await fetch('https://charts.openshift.io/index.yaml', {
method: 'GET'
});
Expand Down
Loading

0 comments on commit 9ce6117

Please sign in to comment.