From 2ac64f2e1ab92dcb2f36cfdd95331964009820cf Mon Sep 17 00:00:00 2001 From: Nirvan Ramjuttun Date: Thu, 30 May 2019 14:07:23 -0400 Subject: CDS-UI: support gRPC integration with blueprint processor mS - For deploy blueprint functionality Change-Id: I35395ae315ac063c3bb3f6893956965ecb74e74e Issue-ID: CCSDK-1274 Signed-off-by: Nirvan Ramjuttun --- .../blueprint-management-service-grpc-client.ts | 86 ++++++++++++++++++++++ cds-ui/server/src/config/app-config.ts | 47 ++++++++++++ .../src/controllers/blueprint-rest.controller.ts | 30 +++++--- .../datasources/blueprint.datasource-template.ts | 8 +- .../resource-dictionary.datasource-template.ts | 24 +++--- 5 files changed, 170 insertions(+), 25 deletions(-) create mode 100644 cds-ui/server/src/clients/blueprint-management-service-grpc-client.ts create mode 100644 cds-ui/server/src/config/app-config.ts (limited to 'cds-ui/server/src') diff --git a/cds-ui/server/src/clients/blueprint-management-service-grpc-client.ts b/cds-ui/server/src/clients/blueprint-management-service-grpc-client.ts new file mode 100644 index 000000000..b66b2a771 --- /dev/null +++ b/cds-ui/server/src/clients/blueprint-management-service-grpc-client.ts @@ -0,0 +1,86 @@ +/** + ~ Copyright © 2019 Bell Canada. + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. +*/ +import * as fs from 'fs'; +import * as uuidv1 from 'uuid/v1'; +const grpc = require('grpc'); +import * as protoLoader from '@grpc/proto-loader'; +import {processorApiConfig} from '../config/app-config'; + +const PROTO_PATH = processorApiConfig.grpc.bluePrintManagement.protoPath; + +// Suggested options for similarity to existing grpc.load behavior +const packageDefinition: protoLoader.PackageDefinition = protoLoader.loadSync( + PROTO_PATH, + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true + }); + +const protoDescriptor = grpc.loadPackageDefinition(packageDefinition); +// The protoDescriptor object has the full package hierarchy + +const stub = new protoDescriptor.org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementService( + "" + processorApiConfig.grpc.host + ":" + processorApiConfig.grpc.port + "", + grpc.credentials.createInsecure()); + +const metadata = new grpc.Metadata(); +metadata.add('Authorization', processorApiConfig.grpc.authToken); + +class BluePrintManagementServiceGrpcClient { + + async uploadBlueprint(filePath: string): Promise { + + let input = { + commonHeader: { + timestamp: new Date(), + originatorId: "cds-ui", + requestId: uuidv1(), + subRequestId: "1234-56", + }, + fileChunk: { + chunk: fs.readFileSync(filePath) + } + } + + let removeTempFile = () => { + fs.unlink(filePath, (err: any) => { + if (err) { + console.error(err); + } + }); + } + + return new Promise((resolve, reject) => { + stub.uploadBlueprint(input, metadata, (err: any, output: any) => { + if (err) { + removeTempFile(); + reject(err); + return; + } + + removeTempFile(); + resolve(output); + }); + }); + + } +} + +export const bluePrintManagementServiceGrpcClient = new BluePrintManagementServiceGrpcClient(); + diff --git a/cds-ui/server/src/config/app-config.ts b/cds-ui/server/src/config/app-config.ts new file mode 100644 index 000000000..24aeb26b5 --- /dev/null +++ b/cds-ui/server/src/config/app-config.ts @@ -0,0 +1,47 @@ +/** + ~ Copyright © 2019 Bell Canada. + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. +*/ +export const appConfig = Object.freeze({ + action: Object.freeze({ + deployBlueprint: Object.freeze({ + grpcEnabled: process.env.APP_ACTION_DEPLOY_BLUEPRINT_GRPC_ENABLED || true + }) + }) +}); + +export const controllerApiConfig = Object.freeze({ + http: Object.freeze({ + url: process.env.API_BLUEPRINT_CONTROLLER_HTTP_BASE_URL || "http://localhost:8080/api/v1", + authToken: process.env.API_BLUEPRINT_CONTROLLER_HTTP_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==" + }) +}); + +export const processorApiConfig = Object.freeze({ + http: Object.freeze({ + url: process.env.API_BLUEPRINT_PROCESSOR_HTTP_BASE_URL || "http://localhost:8081/api/v1", + authToken: process.env.API_BLUEPRINT_PROCESSOR_HTTP_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==" + }), + grpc: Object.freeze({ + host: process.env.API_BLUEPRINT_PROCESSOR_GRPC_HOST || "localhost", + port: process.env.API_BLUEPRINT_PROCESSOR_GRPC_PORT || 9111, + authToken: process.env.API_BLUEPRINT_PROCESSOR_GRPC_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==", + bluePrintManagement: Object.freeze({ + //this path is relative to 'dist' folder + protoPath: __dirname + '../../../proto/BluePrintManagement.proto' + }) + }) +}); + + diff --git a/cds-ui/server/src/controllers/blueprint-rest.controller.ts b/cds-ui/server/src/controllers/blueprint-rest.controller.ts index 877fa02bb..52e77ee7b 100644 --- a/cds-ui/server/src/controllers/blueprint-rest.controller.ts +++ b/cds-ui/server/src/controllers/blueprint-rest.controller.ts @@ -48,7 +48,8 @@ import { BlueprintService } from '../services'; import * as fs from 'fs'; import * as multiparty from 'multiparty'; import * as request_lib from 'request'; -import {controllerApiConfig, processorApiConfig} from '../../config/app-config'; +import {controllerApiConfig, processorApiConfig, appConfig} from '../config/app-config'; +import {bluePrintManagementServiceGrpcClient} from '../clients/blueprint-management-service-grpc-client'; export class BlueprintRestController { constructor( @@ -197,11 +198,10 @@ export class BlueprintRestController { ): Promise { return new Promise((resolve, reject) => { this.getFileFromMultiPartForm(request).then(file=>{ - this.uploadFileToBlueprintProcessor(file, "/execution-service/upload/", response).then(resp=>{ - resolve(resp); - }, err=>{ - reject(err); - }); + if(appConfig.action.deployBlueprint.grpcEnabled) + return this.uploadFileToBlueprintProcessorGrpc(file, response); + else + return this.uploadFileToBlueprintProcessor(file, "/execution-service/upload/", response); }, err=>{ reject(err); }); @@ -209,11 +209,11 @@ export class BlueprintRestController { } async uploadFileToBlueprintController(file: multiparty.File, uri: string, response: Response): Promise{ - return this.uploadFileToBlueprintService(file, controllerApiConfig.url + uri, controllerApiConfig.authToken, response); + return this.uploadFileToBlueprintService(file, controllerApiConfig.http.url + uri, controllerApiConfig.http.authToken, response); } async uploadFileToBlueprintProcessor(file: multiparty.File, uri: string, response: Response): Promise{ - return this.uploadFileToBlueprintService(file, processorApiConfig.url + uri, processorApiConfig.authToken, response); + return this.uploadFileToBlueprintService(file, processorApiConfig.http.url + uri, processorApiConfig.http.authToken, response); } async uploadFileToBlueprintService(file: multiparty.File, url: string, authToken: string, response: Response): Promise{ @@ -256,7 +256,7 @@ export class BlueprintRestController { } async downloadFileFromBlueprintController(uri: string, response: Response): Promise { - return this.downloadFileFromBlueprintService(controllerApiConfig.url + uri, controllerApiConfig.authToken, response); + return this.downloadFileFromBlueprintService(controllerApiConfig.http.url + uri, controllerApiConfig.http.authToken, response); } async downloadFileFromBlueprintService(url: string, authToken: string, response: Response): Promise { @@ -277,4 +277,16 @@ export class BlueprintRestController { }); }) } + + async uploadFileToBlueprintProcessorGrpc(file: multiparty.File, response: Response): Promise { + return new Promise((resolve, reject) => { + bluePrintManagementServiceGrpcClient.uploadBlueprint(file.path).then(output=>{ + response.send(output.status.message); + resolve(response); + }, err=>{ + response.status(500).send(err); + resolve(response); + }); + }); + } } \ No newline at end of file diff --git a/cds-ui/server/src/datasources/blueprint.datasource-template.ts b/cds-ui/server/src/datasources/blueprint.datasource-template.ts index f5dad3a1e..35edf33e3 100644 --- a/cds-ui/server/src/datasources/blueprint.datasource-template.ts +++ b/cds-ui/server/src/datasources/blueprint.datasource-template.ts @@ -1,19 +1,19 @@ -import {controllerApiConfig} from '../../config/app-config'; +import {controllerApiConfig} from '../config/app-config'; export default { "name": "blueprint", "connector": "rest", - "baseURL": controllerApiConfig.url, + "baseURL": controllerApiConfig.http.url, "crud": false, "debug": true, "operations": [{ "template": { "method": "GET", - "url": controllerApiConfig.url + "/blueprint-model/", + "url": controllerApiConfig.http.url + "/blueprint-model/", "headers": { "accepts": "application/json", "content-type": "application/json", - "authorization": controllerApiConfig.authToken + "authorization": controllerApiConfig.http.authToken }, "responsePath": "$.*" }, diff --git a/cds-ui/server/src/datasources/resource-dictionary.datasource-template.ts b/cds-ui/server/src/datasources/resource-dictionary.datasource-template.ts index 1c459e0e7..c749eee62 100644 --- a/cds-ui/server/src/datasources/resource-dictionary.datasource-template.ts +++ b/cds-ui/server/src/datasources/resource-dictionary.datasource-template.ts @@ -1,19 +1,19 @@ -import {controllerApiConfig} from '../../config/app-config'; +import {controllerApiConfig} from '../config/app-config'; export default { "name": "resourceDictionary", "connector": "rest", - "baseURL": controllerApiConfig.url + "/dictionary", + "baseURL": controllerApiConfig.http.url + "/dictionary", "crud": false, "debug": true, "operations": [{ "template": { "method": "GET", - "url": controllerApiConfig.url + "/dictionary/{name}", + "url": controllerApiConfig.http.url + "/dictionary/{name}", "headers": { "accepts": "application/json", "content-type": "application/json", - "authorization": controllerApiConfig.authToken + "authorization": controllerApiConfig.http.authToken }, "responsePath": "$.*" }, @@ -25,11 +25,11 @@ export default { { "template": { "method": "GET", - "url": controllerApiConfig.url + "/dictionary/source-mapping", + "url": controllerApiConfig.http.url + "/dictionary/source-mapping", "headers": { "accepts": "application/json", "content-type": "application/json", - "authorization": controllerApiConfig.authToken + "authorization": controllerApiConfig.http.authToken }, "responsePath": "$.*" }, @@ -41,11 +41,11 @@ export default { { "template": { "method": "GET", - "url": controllerApiConfig.url + "/dictionary/search/{tags}", + "url": controllerApiConfig.http.url + "/dictionary/search/{tags}", "headers": { "accepts": "application/json", "content-type": "application/json", - "authorization": controllerApiConfig.authToken + "authorization": controllerApiConfig.http.authToken }, "responsePath": "$.*" }, @@ -57,11 +57,11 @@ export default { { "template": { "method": "POST", - "url": controllerApiConfig.url + "/dictionary", + "url": controllerApiConfig.http.url + "/dictionary", "headers": { "accepts": "application/json", "content-type": "application/json", - "authorization": controllerApiConfig.authToken + "authorization": controllerApiConfig.http.authToken }, "body": "{resourceDictionary}", "responsePath": "$.*" @@ -74,11 +74,11 @@ export default { { "template": { "method": "POST", - "url": controllerApiConfig.url + "/dictionary/by-names", + "url": controllerApiConfig.http.url + "/dictionary/by-names", "headers": { "accepts": "application/json", "content-type": "application/json", - "authorization": controllerApiConfig.authToken + "authorization": controllerApiConfig.http.authToken }, "body": "{resourceDictionaryList}", "responsePath": "$.*" -- cgit 1.2.3-korg