Skip to content

Commit e760918

Browse files
authored
Support for volume claim templates for workspaces (redhat-developer#519)
* Support for volume claim templates for workspaces
1 parent b2e159b commit e760918

21 files changed

+511
-42
lines changed

Diff for: src/pipeline/wizard.ts

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { TknResourceItem } from '../tekton/webviewstartpipeline';
1212
import { startPipeline } from '../tekton/startpipeline';
1313
import { addTriggerToPipeline } from '../tekton/addtrigger';
1414
import { createPvc } from '../tekton/createpvc';
15+
import { startPipelineFromJson } from '../tekton/start-pipeline-from-json';
1516

1617
export interface PipelineWizardInput {
1718
readonly resourceColumn: vscode.ViewColumn;
@@ -66,6 +67,11 @@ export class PipelineWizard extends Disposable {
6667
const inputAddTrigger = e.body;
6768
this.dispose();
6869
return await addTriggerToPipeline(inputAddTrigger);
70+
case 'startPipeline_yaml':
71+
// eslint-disable-next-line no-case-declarations
72+
const startPipelineRun = e.body;
73+
this.dispose();
74+
return startPipelineFromJson(startPipelineRun);
6975
}
7076
}));
7177

Diff for: src/tekton.d.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export interface TknWorkspaces {
157157
}
158158

159159
export interface TknPipelineTrigger {
160+
apiVersion?: string;
160161
metadata: TknMetadata;
161162
spec: TknSpec;
162163
}
@@ -175,7 +176,7 @@ export interface TknTask {
175176
// JSON types
176177

177178
export interface Param {
178-
name: string;
179+
name?: string;
179180
}
180181

181182
export type VolumeTypeSecret = {
@@ -210,8 +211,20 @@ type PipelineRunResourceCommonProperties = {
210211
name: string;
211212
};
212213

214+
export interface VolumeTypeClaim {
215+
metadata: ObjectMetadata;
216+
spec: {
217+
accessModes: string[];
218+
resources: {
219+
requests: {
220+
storage: string;
221+
};
222+
};
223+
};
224+
}
225+
213226
export interface PipelineRunWorkspace extends Param {
214-
[volumeType: string]: VolumeTypeSecret | VolumeTypeConfigMaps | VolumeTypePVC | {};
227+
[volumeType: string]: VolumeTypeSecret | VolumeTypeConfigMaps | VolumeTypePVC | VolumeTypeClaim | {};
215228
}
216229

217230
export type PipelineRunReferenceResource = PipelineRunResourceCommonProperties & {

Diff for: src/tekton/addtrigger.ts

+22-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { PipelineRunData, TriggerTemplateKindParam, TriggerTemplateKind, EventLi
1414
import { TektonItem } from './tektonitem';
1515
import { Command } from '../tkn';
1616
import { AddTriggerFormValues, Pipeline, TriggerBindingKind, Resources, Param, Workspaces } from './triggertype';
17-
import { K8sKind, RouteKind } from './k8s-type';
17+
import { K8sKind, PipelineRunKind, RouteKind } from './k8s-type';
1818
import * as yaml from 'js-yaml';
1919
import { Platform } from '../util/platform';
2020
import { exposeRoute, RouteModel } from './expose';
@@ -25,6 +25,7 @@ import { NewPvc } from './createpvc';
2525
import { getExposeURl } from '../util/exposeurl';
2626
import { telemetryLogCommand, telemetryLogError } from '../telemetry';
2727
import { getStderrString } from '../util/stderrstring';
28+
import { VCT } from './pipelinecontent';
2829

2930
export const TriggerTemplateModel = {
3031
apiGroup: 'triggers.tekton.dev',
@@ -89,14 +90,14 @@ export async function addTrigger(inputAddTrigger: AddTriggerFormValues): Promise
8990
await exposeRoute(eventListener.metadata.name, inputAddTrigger.commandId);
9091
}
9192

92-
export async function k8sCreate(trigger: TriggerTemplateKind | EventListenerKind | RouteKind | NewPvc, commandId?: string): Promise<boolean> {
93+
export async function k8sCreate(trigger: TriggerTemplateKind | EventListenerKind | RouteKind | NewPvc | PipelineRunKind, commandId?: string, kind?: string): Promise<boolean> {
9394
const quote = Platform.OS === 'win32' ? '"' : '\'';
9495
const triggerYaml = yaml.safeDump(trigger, {skipInvalid: true});
9596
const tempPath = os.tmpdir();
9697
if (!tempPath) {
9798
return false;
9899
}
99-
const fsPath = path.join(tempPath, `${trigger.metadata.name}.yaml`);
100+
const fsPath = path.join(tempPath, `${trigger.metadata.name || trigger.metadata.generateName}.yaml`);
100101
await fs.writeFile(fsPath, triggerYaml, 'utf8');
101102
const result = await cli.execute(Command.create(`${quote}${fsPath}${quote}`));
102103
if (result.error) {
@@ -109,6 +110,11 @@ export async function k8sCreate(trigger: TriggerTemplateKind | EventListenerKind
109110
telemetryLogCommand(commandId, 'Trigger successfully created');
110111
vscode.window.showInformationMessage(`Trigger successfully created. Expose URL: ${url}`);
111112
}
113+
if (kind === PipelineRunModel.kind && !result.error) {
114+
const message = 'Pipeline successfully started';
115+
telemetryLogCommand(commandId, message);
116+
vscode.window.showInformationMessage(message);
117+
}
112118
await fs.unlink(fsPath);
113119
return true;
114120
}
@@ -140,14 +146,14 @@ export async function getPipelineRunFrom(inputAddTrigger: AddTriggerFormValues,
140146
},
141147
params: inputAddTrigger.params,
142148
resources: inputAddTrigger.resources,
143-
workspaces: getPipelineRunWorkspaces(inputAddTrigger.workspaces),
149+
workspaces: getPipelineRunWorkspaces(inputAddTrigger.workspaces, inputAddTrigger.volumeClaimTemplate),
144150
serviceAccountName: inputAddTrigger.serviceAccount,
145151
},
146152
};
147153
return await getPipelineRunData(pipelineRunData, options);
148154
}
149155

150-
export function getPipelineRunWorkspaces(workspaces: Workspaces[]): PipelineRunWorkspace[] {
156+
export function getPipelineRunWorkspaces(workspaces: Workspaces[], volumeClaimTemplate?: VCT[]): PipelineRunWorkspace[] {
151157
const newWorkspace = [];
152158
if (workspaces && workspaces.length === 0) return newWorkspace;
153159
workspaces.map((workspaceData: Workspaces) => {
@@ -168,7 +174,17 @@ export function getPipelineRunWorkspaces(workspaces: Workspaces[]): PipelineRunW
168174
}
169175
newWorkspaceObject[WorkspaceResource[workspaceData.workspaceType]] = workspaceResourceObject;
170176
newWorkspace.push(newWorkspaceObject);
171-
})
177+
});
178+
if (volumeClaimTemplate && volumeClaimTemplate.length !== 0) {
179+
volumeClaimTemplate.map(value => {
180+
const workspaceObject = {};
181+
workspaceObject['name'] = value.metadata.name,
182+
workspaceObject[value.kind] = {
183+
spec: value.spec
184+
}
185+
newWorkspace.push(workspaceObject);
186+
})
187+
}
172188
return newWorkspace;
173189
}
174190

Diff for: src/tekton/createpvc.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface NewPvc {
1111
kind: string;
1212
metadata: {
1313
name: string;
14+
generateName?: string;
1415
};
1516
spec: {
1617
accessMode: string[];

Diff for: src/tekton/k8s-type.ts

+21-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See LICENSE file in the project root for license information.
44
*-----------------------------------------------------------------------------------------------*/
55

6+
import { PipelineRunResource, PipelineRunWorkspace, TknParams, TknResource, TknWorkspaces } from '../tekton';
67
import { ObjectMetadata } from './triggertype';
78

89
export type K8sKind = {
@@ -70,7 +71,7 @@ export type K8sResourceCommon = {
7071
metadata?: ObjectMetadata;
7172
};
7273

73-
export type RouteKind = {
74+
export interface RouteKind extends K8sResourceCommon {
7475
spec: {
7576
alternateBackends?: RouteTarget[];
7677
host?: string;
@@ -86,4 +87,22 @@ export type RouteKind = {
8687
status?: {
8788
ingress: RouteIngress[];
8889
};
89-
} & K8sResourceCommon;
90+
}
91+
92+
export interface PipelineSpec {
93+
params?: TknParams[];
94+
resources?: TknResource[];
95+
serviceAccountName?: string;
96+
workspaces?: TknWorkspaces[];
97+
}
98+
99+
export interface PipelineRunKind extends K8sResourceCommon {
100+
spec: {
101+
pipelineRef?: { name: string };
102+
pipelineSpec?: PipelineSpec;
103+
params?: TknParams[];
104+
workspaces?: PipelineRunWorkspace[];
105+
resources?: PipelineRunResource[];
106+
serviceAccountName?: string;
107+
};
108+
}

Diff for: src/tekton/pipelinecontent.ts

+17
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ export interface Params {
4747
description?: string;
4848
name: string;
4949
}
50+
51+
export interface VCT {
52+
kind: string;
53+
metadata: {
54+
name: string;
55+
};
56+
spec: {
57+
accessModes: string[];
58+
resources: {
59+
requests: {
60+
storage: string;
61+
};
62+
};
63+
volumeMode?: string;
64+
};
65+
}
5066

5167
export interface StartObject {
5268
name: string;
@@ -64,6 +80,7 @@ export interface StartObject {
6480
workspaces: Workspaces[];
6581
};
6682
commandId?: string;
83+
volumeClaimTemplate?: VCT[];
6784
}
6885

6986
export interface Trigger {

Diff for: src/tekton/start-pipeline-from-json.ts

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*-----------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat, Inc. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE file in the project root for license information.
4+
*-----------------------------------------------------------------------------------------------*/
5+
6+
import { window } from 'vscode';
7+
import { cli } from '../cli';
8+
import { PipelineRunWorkspace, TknPipelineTrigger } from '../tekton';
9+
import { telemetryLogError } from '../telemetry';
10+
import { Command } from '../tkn';
11+
import { k8sCreate, PipelineRunModel } from './addtrigger';
12+
import { PipelineRunKind } from './k8s-type';
13+
import { Params, Resources, StartObject, VCT, Workspaces } from './pipelinecontent';
14+
15+
export async function startPipelineFromJson(formValue: StartObject): Promise<void> {
16+
const pipelineRunJson = await getPipelineRun(formValue, formValue.commandId);
17+
await k8sCreate(pipelineRunJson, formValue.commandId, PipelineRunModel.kind);
18+
}
19+
20+
export async function getPipelineRun(formValue: StartObject, commandId?: string): Promise<PipelineRunKind> {
21+
const pipelineRunData: PipelineRunKind = {
22+
metadata: {
23+
},
24+
spec: {
25+
pipelineRef: {
26+
name: formValue.name,
27+
},
28+
params: getPipelineRunParams(formValue.params),
29+
resources: getPipelineRunResources(formValue.resources),
30+
workspaces: getPipelineRunWorkspaces(formValue.workspaces, formValue.volumeClaimTemplate),
31+
serviceAccountName: formValue.serviceAccount
32+
},
33+
};
34+
const result = await cli.execute(Command.getPipeline(formValue.name));
35+
let pipeline: TknPipelineTrigger;
36+
if (result.error) {
37+
telemetryLogError(commandId, result.error.toString())
38+
window.showErrorMessage(`fail to fetch pipeline: ${result.error}`);
39+
return;
40+
}
41+
try {
42+
pipeline = JSON.parse(result.stdout);
43+
} catch (ignore) {
44+
//show no pipelines if output is not correct json
45+
}
46+
return getPipelineRunData(pipeline, pipelineRunData);
47+
}
48+
49+
function getPipelineRunData(pipeline: TknPipelineTrigger, pipelineRunData: PipelineRunKind): PipelineRunKind {
50+
const pipelineName = pipeline.metadata.name;
51+
const resources = pipelineRunData?.spec.resources;
52+
const workspaces = pipelineRunData?.spec.workspaces;
53+
const params = pipelineRunData?.spec.params;
54+
const serviceAccountName = pipelineRunData?.spec.serviceAccountName;
55+
56+
const newPipelineRun = {
57+
apiVersion: pipeline.apiVersion,
58+
kind: PipelineRunModel.kind,
59+
metadata: {
60+
generateName: `${pipelineName}-`,
61+
namespace: pipeline.metadata.namespace,
62+
},
63+
spec: {
64+
pipelineRef: {
65+
name: pipelineName,
66+
},
67+
resources,
68+
params,
69+
workspaces,
70+
status: null,
71+
serviceAccountName
72+
},
73+
};
74+
return newPipelineRun;
75+
}
76+
77+
function getPipelineRunResources(resources: Resources[]): Resources[] {
78+
const newResource = [];
79+
if (resources && resources.length !== 0) {
80+
resources.map(val => {
81+
newResource.push({name: val.name, resourceRef: { name: val.resourceRef}})
82+
})
83+
}
84+
return newResource;
85+
}
86+
87+
function getPipelineRunParams(params: Params[]): Params[] {
88+
if (params && params.length !== 0) {
89+
params.map(val => {
90+
val['value'] = val.default;
91+
delete val.default
92+
});
93+
return params;
94+
} else {
95+
return [];
96+
}
97+
}
98+
99+
function getPipelineRunWorkspaces(workspace: Workspaces[], volumeClaimTemplate: VCT[]): PipelineRunWorkspace[] {
100+
const newWorkSpace = [];
101+
if (workspace && workspace.length !== 0) {
102+
workspace.map(value => {
103+
const workspaceObject = {};
104+
workspaceObject['name'] = value.name;
105+
if (value.workspaceType === 'Secret') {
106+
workspaceObject['secret'] = {
107+
items: value.item,
108+
secretName: value.workspaceName
109+
}
110+
} else if (value.workspaceType === 'ConfigMap') {
111+
workspaceObject['configMap'] = {
112+
items: value.item,
113+
name: value.workspaceName
114+
}
115+
} else if (value.workspaceType === 'PersistentVolumeClaim') {
116+
workspaceObject['persistentVolumeClaim'] = {
117+
claimName: value.workspaceName
118+
}
119+
} else if (value.workspaceType === 'EmptyDirectory') {
120+
workspaceObject['emptyDir'] = {}
121+
}
122+
newWorkSpace.push(workspaceObject);
123+
})
124+
}
125+
if (volumeClaimTemplate && volumeClaimTemplate.length !== 0) {
126+
volumeClaimTemplate.map(value => {
127+
const workspaceObject = {};
128+
workspaceObject['name'] = value.metadata.name,
129+
workspaceObject[value.kind] = {
130+
spec: value.spec
131+
}
132+
newWorkSpace.push(workspaceObject);
133+
})
134+
}
135+
return newWorkSpace;
136+
}

0 commit comments

Comments
 (0)