Merge "Formmatted content for CB processor"
[ccsdk/cds.git] / cds-ui / server / src / controllers / blueprint-rest.controller.ts
1 /*
2 ============LICENSE_START==========================================
3 ===================================================================
4 Copyright (C) 2018-19 IBM Intellectual Property. All rights reserved.
5 ===================================================================
6
7 Unless otherwise specified, all software contained herein is licensed
8 under the Apache License, Version 2.0 (the License);
9 you may not use this software except in compliance with the License.
10 You may obtain a copy of the License at
11
12     http://www.apache.org/licenses/LICENSE-2.0
13
14 Unless required by applicable law or agreed to in writing, software
15 distributed under the License is distributed on an "AS IS" BASIS,
16 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 See the License for the specific language governing permissions and
18 limitations under the License.
19 ============LICENSE_END============================================
20 */
21
22
23
24 import {
25   Count,
26   CountSchema,
27   Filter,
28   repository,
29   Where,
30 } from '@loopback/repository';
31 import {
32   post,
33   param,
34   get,
35   getFilterSchemaFor,
36   getWhereSchemaFor,
37   patch,
38   put,
39   del,
40   requestBody,
41   Request,
42   Response,
43   RestBindings,
44 } from '@loopback/rest';
45 import { Blueprint } from '../models';
46 import { inject } from '@loopback/core';
47 import { BlueprintService } from '../services';
48 import * as fs from 'fs';
49 import * as multiparty from 'multiparty';
50 import * as request_lib from 'request';
51 import { controllerApiConfig, processorApiConfig, appConfig } from '../config/app-config';
52 import { bluePrintManagementServiceGrpcClient } from '../clients/blueprint-management-service-grpc-client';
53
54 export class BlueprintRestController {
55   constructor(
56     @inject('services.BlueprintService')
57     public bpservice: BlueprintService,
58   ) { }
59
60   @get('/blueprints', {
61     responses: {
62       '200': {
63         description: 'Blueprint model instance',
64         content: { 'application/json': { schema: { 'x-ts-type': Blueprint } } },
65       },
66     },
67   })
68   async getall() {
69     return await this.bpservice.getAllblueprints();
70   }
71
72   @get('/searchByTags/{tags}', {
73     responses: {
74       '200': {
75         content: { 'application/json': {} },
76       },
77     },
78   })
79   async getByTags(@param.path.string('tags') tags: string) {
80     return await this.bpservice.getByTags(tags);
81   }
82
83   @post('/create-blueprint')
84   async upload(
85     @requestBody({
86       description: 'multipart/form-data value.',
87       required: true,
88       content: {
89         'multipart/form-data': {
90           // Skip body parsing
91           'x-parser': 'stream',
92           schema: { type: 'object' },
93         },
94       },
95     })
96     request: Request,
97     @inject(RestBindings.Http.RESPONSE) response: Response,
98   ): Promise<Response> {
99     return new Promise((resolve, reject) => {
100       this.getFileFromMultiPartForm(request).then(file => {
101         this.uploadFileToBlueprintController(file, "/blueprint-model/", response).then(resp => {
102           resolve(resp);
103         }, err => {
104           reject(err);
105         });
106       }, err => {
107         reject(err);
108       });
109     });
110   }
111
112   @post('/publish')
113   async publish(
114     @requestBody({
115       description: 'multipart/form-data value.',
116       required: true,
117       content: {
118         'multipart/form-data': {
119           // Skip body parsing
120           'x-parser': 'stream',
121           schema: { type: 'object' },
122         },
123       },
124     })
125     request: Request,
126     @inject(RestBindings.Http.RESPONSE) response: Response,
127   ): Promise<Response> {
128     return new Promise((resolve, reject) => {
129       this.getFileFromMultiPartForm(request).then(file => {
130         this.uploadFileToBlueprintController(file, "/blueprint-model/publish/", response).then(resp => {
131           resolve(resp);
132         }, err => {
133           reject(err);
134         });
135       }, err => {
136         reject(err);
137       });
138     });
139   }
140
141   @post('/enrich-blueprint')
142   async enrich(
143     @requestBody({
144       description: 'multipart/form-data value.',
145       required: true,
146       content: {
147         'multipart/form-data': {
148           // Skip body parsing
149           'x-parser': 'stream',
150           schema: { type: 'object' },
151         },
152       },
153     })
154     request: Request,
155     @inject(RestBindings.Http.RESPONSE) response: Response,
156   ): Promise<Response> {
157     return new Promise((resolve, reject) => {
158       this.getFileFromMultiPartForm(request).then(file => {
159         this.uploadFileToBlueprintController(file, "/blueprint-model/enrich/", response).then(resp => {
160           resolve(resp);
161         }, err => {
162           reject(err);
163         });
164       }, err => {
165         reject(err);
166       });
167     });
168   }
169
170   @get('/download-blueprint/{name}/{version}')
171   async download(
172     @param.path.string('name') name: string,
173     @param.path.string('version') version: string,
174     @inject(RestBindings.Http.RESPONSE) response: Response,
175   ): Promise<Response> {
176     return this.downloadFileFromBlueprintController("/blueprint-model/download/by-name/" + name + "/version/" + version, response);
177   }
178
179   async getFileFromMultiPartForm(request: Request): Promise<multiparty.File> {
180     return new Promise((resolve, reject) => {
181       let form = new multiparty.Form();
182       form.parse(request, (err: any, fields: any, files: { [x: string]: any[]; }) => {
183         if (err) reject(err);
184         let file = files['file'][0]; // get the file from the returned files object
185         if (!file) {
186           reject('File was not found in form data.');
187         } else {
188           resolve(file);
189         }
190       });
191     })
192   }
193
194   @post('/deploy-blueprint')
195   async deploy(
196     @requestBody({
197       description: 'multipart/form-data value.',
198       required: true,
199       content: {
200         'multipart/form-data': {
201           // Skip body parsing
202           'x-parser': 'stream',
203           schema: { type: 'object' },
204         },
205       },
206     })
207     request: Request,
208     @inject(RestBindings.Http.RESPONSE) response: Response,
209   ): Promise<Response> {
210     return new Promise((resolve, reject) => {
211       this.getFileFromMultiPartForm(request).then(file => {
212         if (appConfig.action.deployBlueprint.grpcEnabled)
213           return this.uploadFileToBlueprintProcessorGrpc(file, response);
214         else
215           return this.uploadFileToBlueprintProcessor(file, "/execution-service/upload/", response);
216       }, err => {
217         reject(err);
218       });
219     });
220   }
221
222   async uploadFileToBlueprintController(file: multiparty.File, uri: string, response: Response): Promise<Response> {
223     return this.uploadFileToBlueprintService(file, controllerApiConfig.http.url + uri, controllerApiConfig.http.authToken, response);
224   }
225
226   async uploadFileToBlueprintProcessor(file: multiparty.File, uri: string, response: Response): Promise<Response> {
227     return this.uploadFileToBlueprintService(file, processorApiConfig.http.url + uri, processorApiConfig.http.authToken, response);
228   }
229
230   async uploadFileToBlueprintService(file: multiparty.File, url: string, authToken: string, response: Response): Promise<Response> {
231     let options = {
232       url: url,
233       headers: {
234         Authorization: authToken,
235         'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
236       },
237       formData: {
238         file: {
239           value: fs.createReadStream(file.path),
240           options: {
241             filename: 'cba.zip',
242             contentType: 'application/zip'
243           }
244         }
245       }
246     };
247
248     var removeTempFile = () => {
249       fs.unlink(file.path, (err: any) => {
250         if (err) {
251           console.error(err);
252         }
253       });
254     }
255
256     return new Promise((resolve, reject) => {
257       request_lib.post(options)
258         .on("error", err => {
259           reject(err);
260         })
261         .pipe(response)
262         .once("finish", () => {
263           removeTempFile();
264           resolve(response);
265         });
266     })
267   }
268
269   async downloadFileFromBlueprintController(uri: string, response: Response): Promise<Response> {
270     return this.downloadFileFromBlueprintService(controllerApiConfig.http.url + uri, controllerApiConfig.http.authToken, response);
271   }
272
273   async downloadFileFromBlueprintService(url: string, authToken: string, response: Response): Promise<Response> {
274     let options = {
275       url: url,
276       headers: {
277         Authorization: authToken,
278       }
279     };
280     return new Promise((resolve, reject) => {
281       request_lib.get(options)
282         .on("error", err => {
283           reject(err);
284         })
285         .pipe(response)
286         .once("finish", () => {
287           resolve(response);
288         });
289     })
290   }
291
292   async uploadFileToBlueprintProcessorGrpc(file: multiparty.File, response: Response): Promise<Response> {
293     return new Promise<Response>((resolve, reject) => {
294       bluePrintManagementServiceGrpcClient.uploadBlueprint(file.path).then(output => {
295         response.send(output.status.message);
296         resolve(response);
297       }, err => {
298         response.status(500).send(err);
299         resolve(response);
300       });
301     });
302   }
303 }