diff options
Diffstat (limited to 'cds-ui')
14 files changed, 258 insertions, 45 deletions
diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.service.spec.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.service.spec.ts new file mode 100644 index 000000000..418b7e9ca --- /dev/null +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { SearchTemplateService } from './search-template.service'; + +describe('SearchTemplateService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: SearchTemplateService = TestBed.get(SearchTemplateService); + expect(service).toBeTruthy(); + }); +}); diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.service.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.service.ts new file mode 100644 index 000000000..fdb261d52 --- /dev/null +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { ApiService } from '../../../../common/core/services/api.service'; + +@Injectable({ + providedIn: 'root' +}) +export class SearchTemplateService { + + constructor(private _http: HttpClient, private api: ApiService) { } + + searchByTags(uri: string, searchText: String): Observable<any>{ + return this.api.post(uri, searchText); + } +} diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.html b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.html index d11b37144..97c65b220 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.html +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.html @@ -22,7 +22,7 @@ limitations under the License. <mat-step [stepControl]="step1FormGroup"> <ng-template matStepLabel>Choose CBA Template file</ng-template> <div class="matStepContent"> - <app-template-options></app-template-options> + <app-template-options (option)="templateSelected($event)"></app-template-options> <br> <div> <button mat-button matStepperNext class="matStepNextBtn">Proceed</button> @@ -30,10 +30,10 @@ limitations under the License. </div> </mat-step> - <mat-step [stepControl]="step2FormGroup"> + <mat-step [stepControl]="step2FormGroup" *ngIf="templateOption==1 || templateOption == 2"> <ng-template matStepLabel>Browse CBA Template file</ng-template> <div class="matStepContent"> - <app-search-template (cbaFile)="fileChange($event)"></app-search-template> + <app-search-template [optionSelected]="templateOption" (cbaFile)="fileChange($event)"></app-search-template> <!-- <div> <button mat-button matStepperNext class="matStepNextBtn">Upload</button> </div>--> diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.ts index d9591dd80..561f15a5d 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.component.ts @@ -38,6 +38,7 @@ export class SelectTemplateComponent implements OnInit { metaData: IMetaData; blueprintState: IBlueprintState; importModel: IImportModel; + templateOption: any; constructor(private store: Store<IBlueprintState>) { // this.importModel.file = ''; @@ -45,6 +46,12 @@ export class SelectTemplateComponent implements OnInit { ngOnInit() { } + + templateSelected(option: any) { + this.templateOption = option; + console.log(this.templateOption); + } + fileChange(topologyTemp: ITopologyTemplate) { this.topologyTemplate = topologyTemp; console.log(topologyTemp); @@ -57,6 +64,7 @@ export class SelectTemplateComponent implements OnInit { upload() { } + // saveBlueprintModel(){ // this.blueprint.toplogyTemplates=this.topologyTemplate; // this.blueprint.metadata= this.metaData; diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/template-options/template-options.component.html b/cds-ui/client/src/app/feature-modules/blueprint/select-template/template-options/template-options.component.html index d66b559f3..57ff00df5 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/template-options/template-options.component.html +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/template-options/template-options.component.html @@ -19,7 +19,7 @@ limitations under the License. ============LICENSE_END============================================ --> <mat-radio-group> - <mat-radio-button value="1" (click)="selected(1)">Upload Template file</mat-radio-button><br><br> - <!-- <mat-radio-button value="2" (click)="selected(2)">Starter Template</mat-radio-button><br><br> - <mat-radio-button value="3" (click)="selected(3)">Existing Model File</mat-radio-button> --> + <mat-radio-button value="1" (click)="selected(1)">Upload Template file</mat-radio-button><br> <br> + <mat-radio-button value="2" (click)="selected(2)">Starter Template</mat-radio-button><br> <br> + <mat-radio-button value="3" (click)="selected(3)">Existing Model File</mat-radio-button> </mat-radio-group>
\ No newline at end of file diff --git a/cds-ui/server/config/app-config.ts b/cds-ui/server/config/app-config.ts deleted file mode 100644 index 80f246427..000000000 --- a/cds-ui/server/config/app-config.ts +++ /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 diff --git a/cds-ui/server/package.json b/cds-ui/server/package.json index 5b8f7e67c..2f33abae7 100644 --- a/cds-ui/server/package.json +++ b/cds-ui/server/package.json @@ -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", @@ -63,11 +66,13 @@ "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": { diff --git a/cds-ui/server/pom.xml b/cds-ui/server/pom.xml index ae9b1b293..8d758c710 100644 --- a/cds-ui/server/pom.xml +++ b/cds-ui/server/pom.xml @@ -42,9 +42,38 @@ 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> <!-- Use the latest released version: https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ --> 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<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 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<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 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": "$.*" diff --git a/cds-ui/server/src/sequence.ts b/cds-ui/server/src/sequence.ts index b282cbc62..84da5249d 100644 --- a/cds-ui/server/src/sequence.ts +++ b/cds-ui/server/src/sequence.ts @@ -31,6 +31,7 @@ import { SequenceHandler, } from '@loopback/rest'; import { logger } from './logger/logger'; +import { v4 as uuid } from 'uuid'; const SequenceActions = RestBindings.SequenceActions; @@ -44,16 +45,22 @@ export class MySequence implements SequenceHandler { ) { } async handle(context: RequestContext) { + const { request, response } = context; try { - const { request, response } = context; - logger.info("Incoming request from %s %s and with header %s query %s params %s", - request.method, request.url, JSON.stringify(request.headers), JSON.stringify(request.query), JSON.stringify(request.params)) + if (!('X-ONAP-RequestID' in request.headers || 'x-onap-requestid' in request.headers)) { + request.headers = { 'X-ONAP-RequestID': uuid(), ...request.headers} + logger.info(JSON.stringify(request.headers)) + } const route = this.findRoute(request); const args = await this.parseParams(request, route); const result = await this.invoke(route, args); this.send(response, result); } catch (err) { this.reject(context, err); + } finally { + const { authorization, ...headers} = request.headers; + logger.info("Incoming request from %s %s and with header %s query %s params %s and response code: %s", + request.method, request.url, JSON.stringify(headers), JSON.stringify(request.query), JSON.stringify(request.params), JSON.stringify(response.statusCode)) } } } |