From e58609d82be0fda6bc19b0ad53a958f84c878e63 Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Thu, 19 Jul 2018 14:30:28 -0700 Subject: [PATCH] Adding status icons for Helm release status (#318) --- images/helmDeployed.svg | 1 + images/helmFailed.svg | 1 + src/explorer.ts | 13 +++++++++++-- src/helm.exec.ts | 12 ++++++------ src/helm.ts | 3 ++- src/kubectl.ts | 6 ++++-- src/kubectlUtils.ts | 22 ---------------------- src/outputUtils.ts | 22 ++++++++++++++++++++++ 8 files changed, 47 insertions(+), 33 deletions(-) create mode 100644 images/helmDeployed.svg create mode 100644 images/helmFailed.svg create mode 100644 src/outputUtils.ts diff --git a/images/helmDeployed.svg b/images/helmDeployed.svg new file mode 100644 index 000000000..da5b2d073 --- /dev/null +++ b/images/helmDeployed.svg @@ -0,0 +1 @@ + diff --git a/images/helmFailed.svg b/images/helmFailed.svg new file mode 100644 index 000000000..e99a0b359 --- /dev/null +++ b/images/helmFailed.svg @@ -0,0 +1 @@ + diff --git a/src/explorer.ts b/src/explorer.ts index 21682d6fe..2217aae2a 100644 --- a/src/explorer.ts +++ b/src/explorer.ts @@ -23,6 +23,14 @@ export function createKubernetesResource(kind: kuberesources.ResourceKind, id: s return new KubernetesResource(kind, id, metadata); } +function getIconForHelmRelease(status: string): vscode.Uri { + if (status === "deployed") { + return vscode.Uri.file(path.join(__dirname, "../../images/helmDeployed.svg")); + } else { + return vscode.Uri.file(path.join(__dirname, "../../images/helmFailed.svg")); + } +} + function getIconForPodStatus(status: string): vscode.Uri { if (status === "running" || status === "completed") { return vscode.Uri.file(path.join(__dirname, "../../images/runningPod.svg")); @@ -417,7 +425,7 @@ export class KubernetesFileObject implements KubernetesObject { class HelmReleaseResource implements KubernetesObject { readonly id: string; - constructor(readonly name: string) { + constructor(readonly name: string, readonly status: string) { this.id = "helmrelease:" + name; } @@ -433,6 +441,7 @@ class HelmReleaseResource implements KubernetesObject { arguments: [this] }; treeItem.contextValue = "vsKubernetes.helmRelease"; + treeItem.iconPath = getIconForHelmRelease(this.status.toLowerCase()); return treeItem; } } @@ -455,6 +464,6 @@ class HelmReleasesFolder extends KubernetesFolder { return [new DummyObject("Helm list error", releases.error[0])]; } - return releases.result.map((r) => new HelmReleaseResource(r)); + return releases.result.map((r) => new HelmReleaseResource(r.name, r.status)); } } diff --git a/src/helm.exec.ts b/src/helm.exec.ts index bd8c5029d..40e9b4ce2 100644 --- a/src/helm.exec.ts +++ b/src/helm.exec.ts @@ -12,6 +12,7 @@ import { showWorkspaceFolderPick } from './hostutils'; import { shell as sh, ShellResult } from './shell'; import { K8S_RESOURCE_SCHEME, HELM_RESOURCE_AUTHORITY } from './kuberesources.virtualfs'; import { Errorable } from './errorable'; +import { parseLineOutput } from './outputUtils'; export interface PickChartUIOptions { readonly warnIfNoCharts: boolean; @@ -292,12 +293,12 @@ export async function helmExecAsync(args: string): Promise { const HELM_PAGING_PREFIX = "next:"; -export async function helmListAll(namespace?: string): Promise> { +export async function helmListAll(namespace?: string): Promise> { if (!ensureHelm(EnsureMode.Alert)) { return { succeeded: false, error: [ "Helm client is not installed" ] }; } - const releases: string[] = []; + const releases: {[key: string]: string}[] = []; let offset: string | null = null; do { @@ -321,9 +322,8 @@ export async function helmListAll(namespace?: string): Promise 0) { - lines.shift(); // remove the header line - const names = lines.map((l) => l.split('\t')[0].trim()); - releases.push(...names); + const helmReleases = parseLineOutput(lines, helm.HELM_OUTPUT_COLUMN_SEPARATOR); + releases.push(...helmReleases); } } while (offset !== null); @@ -427,4 +427,4 @@ export function searchForChart(name: string, version?: string): Requirement { export function helmHome(): string { const h = process.env.HOME; return process.env["HELM_HOME"] || filepath.join(h, '.helm'); -} \ No newline at end of file +} diff --git a/src/helm.ts b/src/helm.ts index a346c32b2..852e25e10 100644 --- a/src/helm.ts +++ b/src/helm.ts @@ -1,6 +1,7 @@ export const PREVIEW_SCHEME = 'helm-template-preview'; export const PREVIEW_URI = PREVIEW_SCHEME + '://preview'; export const INSPECT_SCHEME = 'helm-inspect-values'; +export const HELM_OUTPUT_COLUMN_SEPARATOR = /\t+/g; let previewShown = false; @@ -10,4 +11,4 @@ export function hasPreviewBeenShown(): boolean { export function recordPreviewHasBeenShown(): void { previewShown = true; -} \ No newline at end of file +} diff --git a/src/kubectl.ts b/src/kubectl.ts index 936f06c4f..374c4c4e8 100644 --- a/src/kubectl.ts +++ b/src/kubectl.ts @@ -5,7 +5,9 @@ import { FS } from './fs'; import { Shell, ShellHandler, ShellResult } from './shell'; import * as binutil from './binutil'; import { Errorable } from './errorable'; -import { parseLineOutput } from './kubectlUtils'; +import { parseLineOutput } from './outputUtils'; + +const KUBECTL_OUTPUT_COLUMN_SEPARATOR = /\s+/g; export interface Kubectl { checkPresent(errorMessageMode: CheckPresentMessageMode): Promise; @@ -237,7 +239,7 @@ async function fromLines(context: Context, command: string): Promise l.length > 0); - const parsedOutput = parseLineOutput(lines); + const parsedOutput = parseLineOutput(lines, KUBECTL_OUTPUT_COLUMN_SEPARATOR); return { succeeded: true, result: parsedOutput }; } return { succeeded: false, error: [ shellResult.stderr ] }; diff --git a/src/kubectlUtils.ts b/src/kubectlUtils.ts index c7cb083ee..9d67d69df 100644 --- a/src/kubectlUtils.ts +++ b/src/kubectlUtils.ts @@ -334,25 +334,3 @@ export async function getResourceAsJson { - const lineInfoObject = {}; - const bits = line.replace(/\s+/g, '|').split('|'); - bits.forEach((columnValue, index) => { - lineInfoObject[parsedHeaders[index]] = columnValue; - }); - return lineInfoObject; - }); -} diff --git a/src/outputUtils.ts b/src/outputUtils.ts new file mode 100644 index 000000000..e98327e5a --- /dev/null +++ b/src/outputUtils.ts @@ -0,0 +1,22 @@ +/** + * Parse column based output which is seperated by whitespace(s) from kubectl or similar sources + * for example, kubectl get po + * @param lineOutput raw output with headers from kubectl or similar sources + * @param columnSeparator a regex for the column separators + * @return array of objects with key as column header and value + */ +export function parseLineOutput(lineOutput: string[], columnSeparator: RegExp): { [key: string]: string }[] { + const headers = lineOutput.shift(); + if (!headers) { + return []; + } + const parsedHeaders = headers.toLowerCase().replace(columnSeparator, '|').split('|'); + return lineOutput.map((line) => { + const lineInfoObject = {}; + const bits = line.replace(columnSeparator, '|').split('|'); + bits.forEach((columnValue, index) => { + lineInfoObject[parsedHeaders[index].trim()] = columnValue.trim(); + }); + return lineInfoObject; + }); +}