Modify CDS-UI server to allow communicating with external blueprint mS
[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} from '../../config/app-config';
52
53 export class BlueprintRestController {
54   constructor(
55     @inject('services.BlueprintService') 
56     public bpservice: BlueprintService,
57   ) {}
58
59   @get('/blueprints', {
60     responses: {
61       '200': {
62         description: 'Blueprint model instance',
63         content: { 'application/json': { schema: { 'x-ts-type': Blueprint } } },
64       },
65     },
66   })
67   async getall() {
68     return await this.bpservice.getAllblueprints();
69   }
70
71   @post('/create-blueprint')
72   async upload(
73     @requestBody({
74       description: 'multipart/form-data value.',
75       required: true,
76       content: {
77         'multipart/form-data': {
78           // Skip body parsing
79           'x-parser': 'stream',
80           schema: {type: 'object'},
81         },
82       },
83     })
84     request: Request,
85     @inject(RestBindings.Http.RESPONSE) response: Response,
86   ): Promise<Response> {
87     return new Promise((resolve, reject) => { 
88        this.getFileFromMultiPartForm(request).then(file=>{
89          this.uploadFileToBlueprintController(file, "/blueprint-model/", response).then(resp=>{
90           resolve(resp);
91          }, err=>{
92            reject(err);
93          });
94       }, err=>{
95         reject(err);
96       });
97     });
98   }
99
100   @post('/publish')
101   async publish(
102     @requestBody({
103       description: 'multipart/form-data value.',
104       required: true,
105       content: {
106         'multipart/form-data': {
107           // Skip body parsing
108           'x-parser': 'stream',
109           schema: {type: 'object'},
110         },
111       },
112     })
113     request: Request,
114     @inject(RestBindings.Http.RESPONSE) response: Response,
115   ): Promise<Response> {
116     return new Promise((resolve, reject) => { 
117        this.getFileFromMultiPartForm(request).then(file=>{
118          this.uploadFileToBlueprintController(file, "/blueprint-model/publish/", response).then(resp=>{
119           resolve(resp);
120          }, err=>{
121            reject(err);
122          });
123       }, err=>{
124         reject(err);
125       });
126     });
127   }
128
129   @post('/enrich-blueprint')
130   async enrich(
131     @requestBody({
132       description: 'multipart/form-data value.',
133       required: true,
134       content: {
135         'multipart/form-data': {
136           // Skip body parsing
137           'x-parser': 'stream',
138           schema: {type: 'object'},
139         },
140       },
141     })
142     request: Request,
143     @inject(RestBindings.Http.RESPONSE) response: Response,
144   ): Promise<Response> {
145     return new Promise((resolve, reject) => { 
146        this.getFileFromMultiPartForm(request).then(file=>{
147          this.uploadFileToBlueprintController(file, "/blueprint-model/enrich/", response).then(resp=>{
148            resolve(resp);
149          }, err=>{
150            reject(err);
151          });
152       }, err=>{
153         reject(err);
154       });
155     });
156   }
157
158   @get('/download-blueprint/{name}/{version}')
159   async download(
160     @param.path.string('name') name: string,
161     @param.path.string('version') version:string,
162     @inject(RestBindings.Http.RESPONSE) response: Response,
163   ): Promise<Response> {
164     return this.downloadFileFromBlueprintController("/blueprint-model/download/by-name/"+name+"/version/"+version, response);
165   }
166
167   async getFileFromMultiPartForm(request: Request): Promise<multiparty.File>{
168     return new Promise((resolve, reject) => {
169       let form = new multiparty.Form();
170       form.parse(request, (err: any, fields: any, files: { [x: string]: any[]; }) => {
171         if (err) reject(err);
172         let file = files['file'][0]; // get the file from the returned files object
173         if(!file){
174           reject('File was not found in form data.');
175         }else{
176           resolve(file);
177         }
178       });
179     })
180   }
181
182   @post('/deploy-blueprint')
183   async deploy(
184     @requestBody({
185       description: 'multipart/form-data value.',
186       required: true,
187       content: {
188         'multipart/form-data': {
189           // Skip body parsing
190           'x-parser': 'stream',
191           schema: {type: 'object'},
192         },
193       },
194     })
195     request: Request,
196     @inject(RestBindings.Http.RESPONSE) response: Response,
197   ): Promise<Response> {
198     return new Promise((resolve, reject) => { 
199        this.getFileFromMultiPartForm(request).then(file=>{
200          this.uploadFileToBlueprintProcessor(file, "/execution-service/upload/", response).then(resp=>{
201           resolve(resp);
202          }, err=>{
203            reject(err);
204          });
205       }, err=>{
206         reject(err);
207       });
208     });
209   }
210
211   async uploadFileToBlueprintController(file: multiparty.File, uri: string, response: Response): Promise<Response>{
212     return this.uploadFileToBlueprintService(file, controllerApiConfig.url + uri, controllerApiConfig.authToken, response);
213   }
214
215   async uploadFileToBlueprintProcessor(file: multiparty.File, uri: string, response: Response): Promise<Response>{
216     return this.uploadFileToBlueprintService(file, processorApiConfig.url + uri, processorApiConfig.authToken, response);
217   }
218
219   async uploadFileToBlueprintService(file: multiparty.File, url: string, authToken: string, response: Response): Promise<Response>{
220     let options = {
221       url: url,
222       headers: {
223         Authorization: authToken,
224         'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
225       },
226       formData: {
227         file: {
228           value: fs.createReadStream(file.path),
229           options: {
230             filename: 'cba.zip',
231             contentType: 'application/zip'
232           }
233         }
234       }
235     };
236
237     var removeTempFile = () => {
238       fs.unlink(file.path, (err: any) => {
239         if (err) {
240           console.error(err);
241         } 
242       });
243     }
244
245     return new Promise((resolve, reject) => {
246       request_lib.post(options)
247         .on("error", err => {
248           reject(err);
249         })
250         .pipe(response)
251         .once("finish", () => {
252           removeTempFile();
253           resolve(response);
254         });
255     })
256   }
257
258   async downloadFileFromBlueprintController(uri: string, response: Response): Promise<Response> {
259     return this.downloadFileFromBlueprintService(controllerApiConfig.url + uri, controllerApiConfig.authToken, response);
260   }
261
262   async downloadFileFromBlueprintService(url: string, authToken: string, response: Response): Promise<Response> {
263     let options = {
264       url: url,
265       headers: {
266         Authorization: authToken,
267       }
268     };
269     return new Promise((resolve, reject) => {
270       request_lib.get(options)
271         .on("error", err => {
272           reject(err);
273         })
274         .pipe(response)
275         .once("finish", () => {
276           resolve(response);
277         });
278     })
279   }
280 }