Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pipelines in application explorer #4749

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as path from 'path';
import validator from 'validator';
import { Disposable, InputBox, QuickInputButtons, ThemeIcon, TreeItem, window } from 'vscode';
import { CommandText } from './base/command';
import { DeploymentPodObject, OpenShiftExplorer } from './explorer';
import { OtherObject, OpenShiftExplorer } from './explorer';
import { Oc } from './oc/ocWrapper';
import { validateRFC1123DNSLabel } from './openshift/nameValidator';
import { inputValue, quickBtn } from './util/inputValue';
Expand Down Expand Up @@ -103,7 +103,7 @@ export class Deployment implements Disposable {
if (!component) {
return;
}
const pods: DeploymentPodObject[] = await OpenShiftExplorer.getInstance().getPods(component);
const pods: OtherObject[] = await OpenShiftExplorer.getInstance().getPods(component);
const runnngPodsLength = pods.filter((pod) => pod.status.phase === 'Running').length;
let count = runnngPodsLength.toString();
count = await inputValue(`How many replicas would you like to scale ${component.kind}/${component.metadata.name}?`,
Expand Down
98 changes: 70 additions & 28 deletions src/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { vsCommand } from './vscommand';
import { CustomResourceDefinitionStub, K8sResourceKind } from './webview/common/createServiceTypes';
import { OpenShiftTerminalManager } from './webview/openshift-terminal/openShiftTerminal';

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

export type OpenShiftObject = {
kind: string,
Expand All @@ -50,9 +50,18 @@ export type OpenShiftObject = {
},
}

export interface DeploymentPodObject extends KubernetesObject {
export type PipelineTasks = {
name: string
context: string
}

export type task = {
[key: string]: string
}

export interface OtherObject extends KubernetesObject {
spec?: {
[key: string]: string
tasks?: task[]
},
status?: {
[key: string]: string
Expand Down Expand Up @@ -209,6 +218,16 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
};
}

if ('name' in element && 'context' in element) {
return {
contextValue: 'openshift.pipeline.tasks',
label: element.name,
tooltip: 'Task Name',
collapsibleState: TreeItemCollapsibleState.None,
iconPath: new ThemeIcon('repo')
};
}

// It's a Helm installation
if ('chart' in element) {
if (element.chart === 'noChart') {
Expand Down Expand Up @@ -255,7 +274,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
collapsibleState: TreeItemCollapsibleState.Collapsed
}
} else if (element.kind === 'Pod') {
const contextElement: DeploymentPodObject = element;
const contextElement: OtherObject = element;
return {
contextValue: 'openshift.k8sObject.pod',
label: contextElement.metadata.name,
Expand All @@ -270,7 +289,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
}
}
}
const contextElement: DeploymentPodObject = element;
const contextElement: OtherObject = element;
if (!contextElement.spec) {
const elementValue = this.makeCaps(element.metadata.name);
return {
Expand All @@ -286,15 +305,15 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
}
}

private getDeploymentIconSuffix(pods: DeploymentPodObject[]): string {
private getDeploymentIconSuffix(pods: OtherObject[]): string {
// Find all not 'Running' pods
const notRunning = pods.filter((pod) => pod.status && pod.status.phase !== 'Running');
if (notRunning.length === 0) {
return '-green'; // All running - return 'green'
}
// Find any 'Failed' or 'Unknown' pod - if any return error ('red')
const failed = notRunning.find((pod) => pod.status &&
(pod.status.phase === 'Failed' || pod.status.phase === 'Unknown'));
(pod.status.phase === 'Failed' || pod.status.phase === 'Unknown'));
if (failed) {
return '-red'; // At least one failed or unknown - return 'red'
}
Expand Down Expand Up @@ -327,7 +346,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos

inCrashLoopBackOff = inCrashLoopBackOff || reason === 'CrashLoopBackOff';

const msg = `${reason}: ${message ? message.trim(): 'No valuable message'}`;
const msg = `${reason}: ${message ? message.trim() : 'No valuable message'}`;
// Skip duplicated messages
if (messages.length < 3 && !(messages.find((m) => m.startsWith(`${reason}:`)))) {
messages.push(msg);
Expand All @@ -347,7 +366,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
const messages: string[] = [];
deployment.status.conditions?.filter((c) => c.status === 'False')
.forEach((c) => {
const message = `${c.reason}: ${c.message ? c.message.trim(): 'No valuable message'}`;
const message = `${c.reason}: ${c.message ? c.message.trim() : 'No valuable message'}`;

// Skip duplicated messages
if (messages.length < 3 && !(messages.find((m) => m.startsWith(`${c.reason}:`)))) {
Expand All @@ -366,7 +385,7 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
const availableReplicas = element.status.availableReplicas ? element.status.availableReplicas : 0;
const unavailableReplicas = element.status.unavailableReplicas ? element.status.unavailableReplicas : 0;

let pods: DeploymentPodObject[] = [];
let pods: OtherObject[] = [];
if (shouldHaveReplicas) {
try {
pods = await this.getPods(element);
Expand Down Expand Up @@ -404,24 +423,24 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
);
}
const iconSuffix = !shouldHaveReplicas ? '' :
podErrors.inCrashLoopBackOff ? '-red' : this.getDeploymentIconSuffix(pods);
podErrors.inCrashLoopBackOff ? '-red' : this.getDeploymentIconSuffix(pods);
const iconPath = element.kind === 'Deployment' || element.kind === 'DeploymentConfig' ?
imagePath(`context/component-node${iconSuffix}.png`) : undefined;

const routeURL = await Oc.Instance.getRouteURL(element.metadata.name);
return {
contextValue: `openshift.k8sObject.${element.kind}${routeURL ? '.route' : ''}`,
label: element.metadata.name,
description,
tooltip,
collapsibleState: element.kind === 'Deployment' ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None,
iconPath,
command: {
title: 'Load',
command: 'openshift.resource.load',
arguments: [element]
}
};
contextValue: `openshift.k8sObject.${element.kind}${routeURL ? '.route' : ''}`,
label: element.metadata.name,
description,
tooltip,
collapsibleState: element.kind === 'Deployment' ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None,
iconPath,
command: {
title: 'Load',
command: 'openshift.resource.load',
arguments: [element]
}
};
}

private makeCaps(kind: string): string {
Expand Down Expand Up @@ -560,6 +579,12 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
name: 'routes'
},
} as OpenShiftObject;
const pipelines = {
kind: 'pipelines',
metadata: {
name: 'pipelines'
},
} as OpenShiftObject;
const statefulSets = {
kind: 'statefulsets',
metadata: {
Expand Down Expand Up @@ -605,11 +630,11 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
result.push(pods,
statefulSets, daemonSets, jobs, cronJobs);
if (isOpenshiftCluster) {
result.push(deploymentConfigs, imageStreams, buildConfigs, routes);
result.push(deploymentConfigs, imageStreams, buildConfigs, routes, pipelines);
}
} else if ('kind' in element) {
const collectableServices: CustomResourceDefinitionStub[] = await this.getServiceKinds();
let collections: KubernetesObject[] | Helm.HelmRelease[] | ExplorerItem[];
let collections: KubernetesObject[] | Helm.HelmRelease[] | ExplorerItem[] | PipelineTasks[];
switch (element.kind) {
case 'helmReleases':
collections = await Helm.getHelmReleases();
Expand All @@ -619,6 +644,9 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
}]
}
break;
case 'pipelines':
collections = await this.getPipelineTasks(element);
break;
default:
try {
collections = await Oc.Instance.getKubernetesObjects(element.kind, undefined, undefined, this.executionContext);
Expand Down Expand Up @@ -665,6 +693,20 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
return await Oc.Instance.getKubernetesObjects('pods', undefined, element.metadata.name, this.executionContext);
}

public async getPipelineTasks(element: KubernetesObject | OpenShiftObject): Promise<PipelineTasks[]> {
const namespace: string = await Oc.Instance.getActiveProject();
const collections: OtherObject[] = await Oc.Instance.getKubernetesObjects(element.kind, namespace, undefined, this.executionContext);
const taskNames: PipelineTasks[] = [];
if (!collections || collections.length === 0 || !collections[0].spec) {
return [];
}
const tasks = collections[0].spec.tasks;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On clean (just created, not having any deployments) Sandbox account I'm receiving the following error:

Cannot read properties of undefined (reading 'spec')

That's probably happening while going through this line of code

tasks?.map((task) => {
taskNames.push({ name : task.name, context: 'pipelineTask' });
})
return taskNames;
}

refresh(target?: ExplorerItem): void {
// Create new Execution Context before refreshing
if (this.executionContext) {
Expand All @@ -686,15 +728,15 @@ export class OpenShiftExplorer implements TreeDataProvider<ExplorerItem>, Dispos
public static async loadResource(component: KubernetesObject) {
if (component) {
if ('chart' in component && 'name' in component && 'revision' in component
&& 'status' in component && component.chart !== 'noChart'
&& component.status === 'deployed') { // Deployed Helm Chart
&& 'status' in component && component.chart !== 'noChart'
&& component.status === 'deployed') { // Deployed Helm Chart
const releaseName: string = typeof component.name === 'string' ? component.name : '';
const revisionString: string | undefined = typeof component.revision === 'string' ? component.revision : undefined;
const revision = revisionString ? parseInt(revisionString, 10) : undefined;
void OpenShiftExplorer.getInstance().loadKubernetesHelmChart(releaseName, revision);
} else {
if (component.kind === 'Pod') {
const contextElement: DeploymentPodObject = component;
const contextElement: OtherObject = component;
const pods = await OpenShiftExplorer.getInstance().getPods(contextElement);
if (pods.length === 0) {
contextElement.status.phase = 'Terminated'
Expand Down
Loading