CDS-UI: support gRPC integration with blueprint processor mS 48/88948/6
authorNirvan Ramjuttun <nirvan.ramjuttun@amdocs.com>
Thu, 30 May 2019 18:07:23 +0000 (14:07 -0400)
committerNirvan Ramjuttun <nirvan.ramjuttun@amdocs.com>
Wed, 26 Jun 2019 18:50:58 +0000 (14:50 -0400)
- For deploy blueprint functionality

Change-Id: I35395ae315ac063c3bb3f6893956965ecb74e74e
Issue-ID: CCSDK-1274
Signed-off-by: Nirvan Ramjuttun <nirvan.ramjuttun@amdocs.com>
cds-ui/server/config/app-config.ts [deleted file]
cds-ui/server/package.json
cds-ui/server/pom.xml
cds-ui/server/src/clients/blueprint-management-service-grpc-client.ts [new file with mode: 0644]
cds-ui/server/src/config/app-config.ts [new file with mode: 0644]
cds-ui/server/src/controllers/blueprint-rest.controller.ts
cds-ui/server/src/datasources/blueprint.datasource-template.ts
cds-ui/server/src/datasources/resource-dictionary.datasource-template.ts
pom.xml

diff --git a/cds-ui/server/config/app-config.ts b/cds-ui/server/config/app-config.ts
deleted file mode 100644 (file)
index 80f2464..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-export const controllerApiConfig = Object.freeze({
-    url: process.env.API_BLUEPRINT_CONTROLLER_BASE_URL || "http://localhost:8080/api/v1",
-    authToken: process.env.API_BLUEPRINT_CONTROLLER_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw=="
-});
-
-export const processorApiConfig = Object.freeze({
-    url: process.env.API_BLUEPRINT_PROCESSOR_BASE_URL || "http://localhost:8081/api/v1",
-    authToken: process.env.API_BLUEPRINT_PROCESSOR_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw=="
-});
\ No newline at end of file
index 5b8f7e6..2f33aba 100644 (file)
@@ -12,7 +12,7 @@
     },
     "scripts": {
         "build:apidocs": "lb-apidocs",
-        "build": "lb-tsc es2017 --outDir dist",
+        "build": "npm run copy:proto && lb-tsc es2017 --copy-resources --outDir dist",
         "build:watch": "lb-tsc --watch",
         "clean": "lb-clean dist",
         "lint": "npm run prettier:check && npm run tslint",
@@ -29,7 +29,8 @@
         "migrate": "node ./dist/src/migrate",
         "prestart": "npm run build",
         "start": "node .",
-        "prepublishOnly": "npm run test"
+        "prepublishOnly": "npm run test",
+        "copy:proto": "mkdir -p dist; cp -R target/generated/proto-definition/proto/ dist/proto"
     },
     "repository": {
         "type": "git"
@@ -45,6 +46,7 @@
         "src"
     ],
     "dependencies": {
+        "@grpc/proto-loader": "^0.5.1",
         "@loopback/boot": "^1.0.8",
         "@loopback/context": "^1.16.0",
         "@loopback/core": "^1.1.3",
@@ -55,6 +57,7 @@
         "@loopback/service-proxy": "^1.0.8",
         "@types/form-data": "^2.2.1",
         "@types/jszip": "^3.1.5",
+        "@types/uuid": "^3.4.4",
         "bluebird": "^3.5.3",
         "cors": "^2.8.5",
         "file": "^0.2.2",
         "form-data": "^2.3.3",
         "formidable": "^1.2.1",
         "fs": "0.0.1-security",
+        "grpc": "^1.21.1",
         "jszip": "^3.2.1",
         "loopback-connector-rest": "^3.4.1",
         "multer": "^1.4.1",
         "multiparty": "^4.2.1",
         "nodemon": "^1.18.10",
+        "uuid": "^3.3.2",
         "winston": "^3.2.1"
     },
     "devDependencies": {
index ae9b1b2..8d758c7 100644 (file)
@@ -42,8 +42,37 @@ limitations under the License.
         <docker.push.phase>deploy</docker.push.phase>
     </properties>
 
+
     <build>
         <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>3.1.1</version>
+                <executions>
+                    <execution>
+                        <id>unpack-blueprint-grpc-proto</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.onap.ccsdk.cds.components</groupId>
+                                    <artifactId>proto-definition</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/generated/proto-definition/proto</outputDirectory>
+                                    <includes>**/*.proto</includes>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
             <plugin>
                 <groupId>com.github.eirslett</groupId>
                 <artifactId>frontend-maven-plugin</artifactId>
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 (file)
index 0000000..b66b2a7
--- /dev/null
@@ -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<any> {
+
+        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<any>((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 (file)
index 0000000..24aeb26
--- /dev/null
@@ -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'
+        })
+    })
+});
+
+
index 877fa02..52e77ee 100644 (file)
@@ -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<Response> {
     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<Response>{
-    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<Response>{
-    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<Response>{
@@ -256,7 +256,7 @@ export class BlueprintRestController {
   }
 
   async downloadFileFromBlueprintController(uri: string, response: Response): Promise<Response> {
-    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<Response> {
@@ -277,4 +277,16 @@ export class BlueprintRestController {
         });
     })
   }
+
+  async uploadFileToBlueprintProcessorGrpc(file: multiparty.File, response: Response): Promise<Response> {
+    return new Promise<Response>((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
index f5dad3a..35edf33 100644 (file)
@@ -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": "$.*"
         },
index 1c459e0..c749eee 100644 (file)
@@ -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": "$.*"
diff --git a/pom.xml b/pom.xml
index 3ffafbe..64be23b 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -35,8 +35,8 @@ limitations under the License.
     <description>CCSDK Controller Design Studio</description>
 
     <modules>
-        <module>cds-ui</module>
         <module>components</module>
+        <module>cds-ui</module>
         <module>ms</module>
     </modules>