diff options
27 files changed, 787 insertions, 181 deletions
diff --git a/cds-ui/server/package.json b/cds-ui/server/package.json index 4d0f946d3..738a7dfe7 100644 --- a/cds-ui/server/package.json +++ b/cds-ui/server/package.json @@ -1,64 +1,83 @@ { - "name": "cds-ui-server", - "version": "1.0.0", - "description": "Intermediate layer between UI and backend. Implemented in loopback 4", - "keywords": [ - "loopback-application", - "loopback" - ], - "main": "index.js", - "engines": { - "node": ">=8.9" - }, - "scripts": { - "build:apidocs": "lb-apidocs", - "build": "lb-tsc es2017 --outDir dist", - "build:watch": "lb-tsc --watch", - "clean": "lb-clean dist", - "lint": "npm run prettier:check && npm run tslint", - "lint:fix": "npm run tslint:fix && npm run prettier:fix", - "prettier:cli": "lb-prettier \"**/*.ts\" \"**/*.js\"", - "prettier:check": "npm run prettier:cli -- -l", - "prettier:fix": "npm run prettier:cli -- --write", - "tslint": "lb-tslint", - "tslint:fix": "npm run tslint -- --fix", - "pretest": "npm run clean && npm run build", - "test": "lb-mocha --allow-console-logs \"dist/test\"", - "posttest": "npm run lint", - "test:dev": "lb-mocha --allow-console-logs dist/test/**/*.js && npm run posttest", - "migrate": "node ./dist/src/migrate", - "prestart": "npm run build", - "start": "node .", - "prepublishOnly": "npm run test" - }, - "repository": { - "type": "git" - }, - "author": "", - "license": "", - "files": [ - "README.md", - "index.js", - "index.d.ts", - "dist/src", - "dist/index*", - "src" - ], - "dependencies": { - "@loopback/boot": "^1.0.8", - "@loopback/context": "^1.4.0", - "@loopback/core": "^1.1.3", - "@loopback/openapi-v3": "^1.1.5", - "@loopback/repository": "^1.1.1", - "@loopback/rest": "^1.5.1", - "@loopback/rest-explorer": "^1.1.4", - "@loopback/service-proxy": "^1.0.8", - "loopback-connector-rest": "^3.4.1" - }, - "devDependencies": { - "@loopback/build": "^1.1.0", - "@loopback/testlab": "^1.0.3", - "@loopback/tslint-config": "^1.0.0", - "@types/node": "^10.11.2" - } + "name": "cds-ui-server", + "version": "1.0.0", + "description": "Intermediate layer between UI and backend. Implemented in loopback 4", + "keywords": [ + "loopback-application", + "loopback" + ], + "main": "index.js", + "engines": { + "node": ">=8.9" + }, + "scripts": { + "build:apidocs": "lb-apidocs", + "build": "lb-tsc es2017 --outDir dist", + "build:watch": "lb-tsc --watch", + "clean": "lb-clean dist", + "lint": "npm run prettier:check && npm run tslint", + "lint:fix": "npm run tslint:fix && npm run prettier:fix", + "prettier:cli": "lb-prettier \"**/*.ts\" \"**/*.js\"", + "prettier:check": "npm run prettier:cli -- -l", + "prettier:fix": "npm run prettier:cli -- --write", + "tslint": "lb-tslint", + "tslint:fix": "npm run tslint -- --fix", + "pretest": "npm run clean && npm run build", + "test": "lb-mocha --allow-console-logs \"dist/test\"", + "posttest": "npm run lint", + "test:dev": "lb-mocha --allow-console-logs dist/test/**/*.js && npm run posttest", + "migrate": "node ./dist/src/migrate", + "prestart": "npm run build", + "start": "node .", + "prepublishOnly": "npm run test" + }, + "repository": { + "type": "git" + }, + "author": "", + "license": "", + "files": [ + "README.md", + "index.js", + "index.d.ts", + "dist/src", + "dist/index*", + "src" + ], + "dependencies": { + "@loopback/boot": "^1.0.8", + "@loopback/context": "^1.4.0", + "@loopback/core": "^1.1.3", + "@loopback/openapi-v3": "^1.1.5", + "@loopback/repository": "^1.1.1", + "@loopback/rest": "^1.5.1", + "@loopback/rest-explorer": "^1.1.4", + "@loopback/service-proxy": "^1.0.8", + "@types/form-data": "^2.2.1", + "@types/jszip": "^3.1.5", + "bluebird": "^3.5.3", + "cors": "^2.8.5", + "file": "^0.2.2", + "file-system": "^2.2.2", + "filereader": "^0.10.3", + "form-data": "^2.3.3", + "formidable": "^1.2.1", + "fs": "0.0.1-security", + "jszip": "^3.2.1", + "loopback-connector-rest": "^3.4.1", + "multer": "^1.4.1", + "multiparty": "^4.2.1", + "nodemon": "^1.18.10" + }, + "devDependencies": { + "@loopback/build": "^1.1.0", + "@loopback/testlab": "^1.0.3", + "@loopback/tslint-config": "^2.0.3", + "@types/bluebird": "^3.5.26", + "@types/formidable": "^1.0.31", + "@types/multer": "^1.3.7", + "@types/multiparty": "0.0.32", + "@types/node": "^10.11.2", + "@types/request": "^2.48.1" + } } diff --git a/cds-ui/server/src/controllers/blueprint-rest.controller.ts b/cds-ui/server/src/controllers/blueprint-rest.controller.ts index 960f09fbe..ae028afc3 100644 --- a/cds-ui/server/src/controllers/blueprint-rest.controller.ts +++ b/cds-ui/server/src/controllers/blueprint-rest.controller.ts @@ -38,123 +38,189 @@ import { put, del, requestBody, + Request, + Response, + RestBindings, } from '@loopback/rest'; import {Blueprint} from '../models'; -import {BlueprintRepository} from '../repositories'; +import { inject } from '@loopback/core'; +import { BlueprintService } from '../services'; +import * as fs from 'fs'; +import * as multiparty from 'multiparty'; +import * as request_lib from 'request'; + +const REST_BLUEPRINT_CONTROLLER_BASE_URL = process.env.REST_BLUEPRINT_CONTROLLER_BASE_URL || "http://localhost:8080/api/v1"; +const REST_BLUEPRINT_CONTROLLER_BASIC_AUTH_HEADER = process.env.REST_BLUEPRINT_CONTROLLER_BASIC_AUTH_HEADER || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw=="; export class BlueprintRestController { constructor( - @repository(BlueprintRepository) - public blueprintRepository : BlueprintRepository, + // @repository(BlueprintRepository) + // public blueprintRepository : BlueprintRepository, + @inject('services.BlueprintService') + public bpservice: BlueprintService, ) {} - @post('/blueprints', { + @get('/blueprints', { responses: { '200': { description: 'Blueprint model instance', - content: {'application/json': {schema: {'x-ts-type': Blueprint}}}, + content: { 'application/json': { schema: { 'x-ts-type': Blueprint } } }, }, }, }) - async create(@requestBody() blueprint: Blueprint): Promise<Blueprint> { - return await this.blueprintRepository.create(blueprint); - } + async getall() { + return await this.bpservice.getAllblueprints(REST_BLUEPRINT_CONTROLLER_BASIC_AUTH_HEADER); - @get('/blueprints/count', { - responses: { - '200': { - description: 'Blueprint model count', - content: {'application/json': {schema: CountSchema}}, - }, - }, - }) - async count( - @param.query.object('where', getWhereSchemaFor(Blueprint)) where?: Where, - ): Promise<Count> { - return await this.blueprintRepository.count(where); } - @get('/blueprints', { - responses: { - '200': { - description: 'Array of Blueprint model instances', - content: { - 'application/json': { - schema: {type: 'array', items: {'x-ts-type': Blueprint}}, - }, + @post('/create-blueprint') + async upload( + @requestBody({ + description: 'multipart/form-data value.', + required: true, + content: { + 'multipart/form-data': { + // Skip body parsing + 'x-parser': 'stream', + schema: {type: 'object'}, }, }, - }, - }) - async find( - @param.query.object('filter', getFilterSchemaFor(Blueprint)) filter?: Filter, - ): Promise<Blueprint[]> { - return await this.blueprintRepository.find(filter); + }) + request: Request, + @inject(RestBindings.Http.RESPONSE) response: Response, + ): Promise<object> { + return new Promise((resolve, reject) => { + this.getFileFromMultiPartForm(request).then(file=>{ + this.uploadFileToBlueprintController(file, "/blueprint-model/").then(resp=>{ + response.setHeader("X-ONAP-RequestID", resp.headers['x-onap-requestid']); + resolve(JSON.parse(resp.body)); + }, err=>{ + reject(err); + }); + }, err=>{ + reject(err); + }); + }); } - @patch('/blueprints', { - responses: { - '200': { - description: 'Blueprint PATCH success count', - content: {'application/json': {schema: CountSchema}}, + @post('/enrich-blueprint') + async enrich( + @requestBody({ + description: 'multipart/form-data value.', + required: true, + content: { + 'multipart/form-data': { + // Skip body parsing + 'x-parser': 'stream', + schema: {type: 'object'}, + }, }, - }, - }) - async updateAll( - @requestBody() blueprint: Blueprint, - @param.query.object('where', getWhereSchemaFor(Blueprint)) where?: Where, - ): Promise<Count> { - return await this.blueprintRepository.updateAll(blueprint, where); + }) + request: Request, + @inject(RestBindings.Http.RESPONSE) response: Response, + ): Promise<any> { + return new Promise((resolve, reject) => { + this.getFileFromMultiPartForm(request).then(file=>{ + this.uploadFileToBlueprintController(file, "/blueprint-model/enrich/").then(resp=>{ + response.setHeader("X-ONAP-RequestID", resp.headers['x-onap-requestid']); + response.setHeader("Content-Disposition", resp.headers['content-disposition']); + resolve(resp.body); + }, err=>{ + reject(err); + }); + }, err=>{ + reject(err); + }); + }); } - @get('/blueprints/{id}', { - responses: { - '200': { - description: 'Blueprint model instance', - content: {'application/json': {schema: {'x-ts-type': Blueprint}}}, - }, - }, - }) - async findById(@param.path.number('id') id: number): Promise<Blueprint> { - return await this.blueprintRepository.findById(id); + @get('/download-blueprint/{id}') + async download( + @param.path.string('id') id: string, + @inject(RestBindings.Http.REQUEST) request: Request, + @inject(RestBindings.Http.RESPONSE) response: Response, + ): Promise<any> { + return new Promise((resolve, reject) => { + this.downloadFileFromBlueprintController("/blueprint-model/download/" + id).then(resp=>{ + response.setHeader("X-ONAP-RequestID", resp.headers['x-onap-requestid']); + response.setHeader("Content-Disposition", resp.headers['content-disposition']); + resolve(resp.body); + }, err=>{ + reject(err); + }); + }); } - @patch('/blueprints/{id}', { - responses: { - '204': { - description: 'Blueprint PATCH success', - }, - }, - }) - async updateById( - @param.path.number('id') id: number, - @requestBody() blueprint: Blueprint, - ): Promise<void> { - await this.blueprintRepository.updateById(id, blueprint); + async getFileFromMultiPartForm(request: Request): Promise<any>{ + return new Promise((resolve, reject) => { + // let options = { + // uploadDir: MULTIPART_FORM_UPLOAD_DIR + // } + let form = new multiparty.Form(); + form.parse(request, (err: any, fields: any, files: { [x: string]: any[]; }) => { + if (err) reject(err); + let file = files['file'][0]; // get the file from the returned files object + if(!file){ + reject('File was not found in form data.'); + }else{ + resolve(file); + } + }); + }) } - @put('/blueprints/{id}', { - responses: { - '204': { - description: 'Blueprint PUT success', + async uploadFileToBlueprintController(file: any, uri: string): Promise<any>{ + let options = { + url: REST_BLUEPRINT_CONTROLLER_BASE_URL + uri, + headers: { + Authorization: REST_BLUEPRINT_CONTROLLER_BASIC_AUTH_HEADER, + 'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' }, - }, - }) - async replaceById( - @param.path.number('id') id: number, - @requestBody() blueprint: Blueprint, - ): Promise<void> { - await this.blueprintRepository.replaceById(id, blueprint); - } + formData: { + file: { + value: fs.createReadStream(file.path), + options: { + filename: 'cba.zip', + contentType: 'application/zip' + } + } + } + }; - @del('/blueprints/{id}', { - responses: { - '204': { - description: 'Blueprint DELETE success', - }, - }, - }) - async deleteById(@param.path.number('id') id: number): Promise<void> { - await this.blueprintRepository.deleteById(id); + return new Promise((resolve, reject) => { + request_lib.post(options, (err: any, resp: any, body: any) => { + if (err) { + //delete tmp file + fs.unlink(file.path, (err: any) => { + if (err) { + console.error(err); + return + } + }) + reject(err); + }else{ + resolve(resp); + } + }) + }) } + + async downloadFileFromBlueprintController(uri: string): Promise<any> { + let options = { + url: REST_BLUEPRINT_CONTROLLER_BASE_URL + uri, + headers: { + Authorization: REST_BLUEPRINT_CONTROLLER_BASIC_AUTH_HEADER, + } + }; + + return new Promise((resolve, reject) => { + request_lib.get(options, (err: any, resp: any, body: any) => { + if (err) { + reject(err); + }else{ + resolve(resp); + } + }) + }) } +}
\ No newline at end of file diff --git a/cds-ui/server/src/datasources/blueprint.datasource.json b/cds-ui/server/src/datasources/blueprint.datasource.json new file mode 100644 index 000000000..86b1c2c15 --- /dev/null +++ b/cds-ui/server/src/datasources/blueprint.datasource.json @@ -0,0 +1,22 @@ +{ + "name": "blueprint", + "connector": "rest", + "baseURL": "http://localhost:8080/api/v1/", + "crud": false, + "operations": [{ + "template": { + "method": "GET", + "url": "http://localhost:8080/api/v1/blueprint-model/", + "headers": { + "accepts": "application/json", + "content-type": "application/json", + "authorization": "{authtoken}" + }, + "responsePath": "$.*" + }, + "functions": { + "getAllblueprints": ["authtoken"] + + } + }] +}
\ No newline at end of file diff --git a/cds-ui/server/src/datasources/blueprint.datasource.ts b/cds-ui/server/src/datasources/blueprint.datasource.ts new file mode 100644 index 000000000..008612693 --- /dev/null +++ b/cds-ui/server/src/datasources/blueprint.datasource.ts @@ -0,0 +1,14 @@ +import {inject} from '@loopback/core'; +import {juggler} from '@loopback/repository'; +import * as config from './blueprint.datasource.json'; + +export class BlueprintDataSource extends juggler.DataSource { + static dataSourceName = 'blueprint'; + + constructor( + @inject('datasources.config.blueprint', {optional: true}) + dsConfig: object = config, + ) { + super(dsConfig); + } +} diff --git a/cds-ui/server/src/datasources/index.ts b/cds-ui/server/src/datasources/index.ts index 1726b4515..f7a934cd8 100644 --- a/cds-ui/server/src/datasources/index.ts +++ b/cds-ui/server/src/datasources/index.ts @@ -21,3 +21,4 @@ limitations under the License. export * from './db.datasource'; +export * from './blueprint.datasource'; diff --git a/cds-ui/server/src/datasources/rest.config.json b/cds-ui/server/src/datasources/rest.datasource.json index 86f33fbd4..86f33fbd4 100644 --- a/cds-ui/server/src/datasources/rest.config.json +++ b/cds-ui/server/src/datasources/rest.datasource.json diff --git a/cds-ui/server/src/datasources/rest.datasource.ts b/cds-ui/server/src/datasources/rest.datasource.ts index 42cdb8018..1b5a44d79 100644 --- a/cds-ui/server/src/datasources/rest.datasource.ts +++ b/cds-ui/server/src/datasources/rest.datasource.ts @@ -21,7 +21,7 @@ limitations under the License. import { juggler } from '@loopback/service-proxy'; -import * as config from './rest.config.json'; +import * as config from './rest.datasource.json'; export class RestDataSource extends juggler.DataSource { diff --git a/cds-ui/server/src/services/blueprint.service.ts b/cds-ui/server/src/services/blueprint.service.ts new file mode 100644 index 000000000..f48253652 --- /dev/null +++ b/cds-ui/server/src/services/blueprint.service.ts @@ -0,0 +1,19 @@ +import {getService} from '@loopback/service-proxy'; +import {inject, Provider} from '@loopback/core'; +import {BlueprintDataSource} from '../datasources'; + +export interface BlueprintService { + getAllblueprints(authtoken: string): Promise<any>; +} + +export class BlueprintServiceProvider implements Provider<BlueprintService> { + constructor( + // blueprint must match the name property in the datasource json file + @inject('datasources.blueprint') + protected dataSource: BlueprintDataSource = new BlueprintDataSource(), + ) {} + + value(): Promise<BlueprintService> { + return getService(this.dataSource); + } +}
\ No newline at end of file diff --git a/cds-ui/server/src/services/index.ts b/cds-ui/server/src/services/index.ts new file mode 100644 index 000000000..26b01ed0b --- /dev/null +++ b/cds-ui/server/src/services/index.ts @@ -0,0 +1 @@ +export * from './blueprint.service'; diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintManagementGRPCHandler.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintManagementGRPCHandler.kt index 251ae2c3a..549d6cd9f 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintManagementGRPCHandler.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintManagementGRPCHandler.kt @@ -62,7 +62,7 @@ open class BluePrintManagementGRPCHandler(private val bluePrintPathConfiguration responseObserver.onNext(successStatus("Successfully uploaded CBA($blueprintId)...", request.commonHeader)) responseObserver.onCompleted() } catch (e: Exception) { - failStatus("request(${request.commonHeader.requestId}): Failed to upload CBA", e) + responseObserver.onError(failStatus("request(${request.commonHeader.requestId}): Failed to upload CBA", e)) } finally { deleteDir(bluePrintPathConfiguration.blueprintArchivePath, uploadId) deleteDir(bluePrintPathConfiguration.blueprintWorkingPath, uploadId) @@ -87,7 +87,7 @@ open class BluePrintManagementGRPCHandler(private val bluePrintPathConfiguration responseObserver.onNext(successStatus("Successfully deleted $blueprint", request.commonHeader)) responseObserver.onCompleted() } catch (e: Exception) { - failStatus("request(${request.commonHeader.requestId}): Failed to delete $blueprint", e) + responseObserver.onError(failStatus("request(${request.commonHeader.requestId}): Failed to delete $blueprint", e)) } } } diff --git a/ms/cds-sdc-listener/application/pom.xml b/ms/cds-sdc-listener/application/pom.xml index 899d173ef..c2ec8b98c 100644 --- a/ms/cds-sdc-listener/application/pom.xml +++ b/ms/cds-sdc-listener/application/pom.xml @@ -20,6 +20,11 @@ <artifactId>cds-sdc-listener-application</artifactId> <name>CDS-SDC Listener Application </name> + <properties> + <grpc.version>1.17.1</grpc.version> + <protobuf.version>3.6.1</protobuf.version> + </properties> + <dependencies> <!-- Spring boot --> <dependency> @@ -51,6 +56,46 @@ <scope>test</scope> </dependency> + <!-- GRPC Dependencies --> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>grpc-netty</artifactId> + <version>${grpc.version}</version> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>grpc-protobuf</artifactId> + <version>${grpc.version}</version> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>grpc-stub</artifactId> + <version>${grpc.version}</version> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + <version>${protobuf.version}</version> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>grpc-testing</artifactId> + <version>${grpc.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.components</groupId> + <artifactId>proto-definition</artifactId> + <version>0.4.2-SNAPSHOT</version> + </dependency> + + <!-- SDC Distribution client dependency --> + <dependency> + <groupId>org.onap.sdc.sdc-distribution-client</groupId> + <artifactId>sdc-distribution-client</artifactId> + <version>1.3.0</version> + </dependency> + </dependencies> <build> diff --git a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerNotificationCallback.java b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerNotificationCallback.java index aaab8d81f..e2aae9654 100644 --- a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerNotificationCallback.java +++ b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerNotificationCallback.java @@ -9,7 +9,13 @@ package org.onap.ccsdk.cds.cdssdclistener; import static org.onap.sdc.utils.DistributionActionResultEnum.SUCCESS; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; import java.util.Objects; +import java.util.Optional; +import org.onap.ccsdk.cds.cdssdclistener.dto.CdsSdcListenerDto; import org.onap.ccsdk.cds.cdssdclistener.service.ListenerServiceImpl; import org.onap.sdc.api.IDistributionClient; import org.onap.sdc.api.consumer.INotificationCallback; @@ -19,9 +25,14 @@ import org.onap.sdc.api.results.IDistributionClientDownloadResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; import org.springframework.stereotype.Component; +@ConfigurationProperties("listenerservice") @Component +@ComponentScan("org.onap.ccsdk.cds.cdssdclistener.dto") public class CdsSdcListenerNotificationCallback implements INotificationCallback { @Autowired @@ -30,6 +41,9 @@ public class CdsSdcListenerNotificationCallback implements INotificationCallback @Autowired private ListenerServiceImpl listenerService; + @Value("${listenerservice.config.archivePath}") + private String pathToStoreArchives; + private static final Logger LOGGER = LoggerFactory.getLogger(CdsSdcListenerNotificationCallback.class); @Override @@ -45,7 +59,7 @@ public class CdsSdcListenerNotificationCallback implements INotificationCallback } /** - * Download the TOSCA CSAR artifact. + * Download the TOSCA CSAR artifact and process it. * * @param info - Artifact information * @param distributionClient - SDC distribution client @@ -53,6 +67,7 @@ public class CdsSdcListenerNotificationCallback implements INotificationCallback private void downloadCsarArtifacts(IArtifactInfo info, IDistributionClient distributionClient) { final String url = info.getArtifactURL(); final String id = info.getArtifactUUID(); + if (Objects.equals(info.getArtifactType(), CdsSdcListenerConfiguration.TOSCA_CSAR)) { LOGGER.info("Trying to download the artifact from : {} and UUID is {} ", url, id); @@ -63,8 +78,30 @@ public class CdsSdcListenerNotificationCallback implements INotificationCallback LOGGER.error("Failed to download the artifact from : {} due to {} ", url, result.getDistributionActionResult()); } else { - // TODO Store the CSAR into CSARArchive path and extract the Blueprint using ListenerServiceImpl.extractBluePrint + LOGGER.info("Trying to write CSAR artifact to file with URL {} and UUID {}", url, id); + processCsarArtifact(result); } } } + + public void processCsarArtifact(IDistributionClientDownloadResult result) { + Path cbaArchivePath = Paths.get(pathToStoreArchives, "cba-archive"); + Path csarArchivePath = Paths.get(pathToStoreArchives, "csar-archive"); + + // extract and store the CSAR archive into local disk. + listenerService.extractCsarAndStore(result, csarArchivePath.toString()); + + Optional<List<File>> csarFiles = listenerService.getFilesFromDisk(csarArchivePath); + + if (csarFiles.isPresent()) { + + //Extract CBA archive from CSAR package and and store it into CDS Database. + csarFiles.get() + .forEach(file -> listenerService.extractBluePrint(file.getAbsolutePath(), cbaArchivePath.toString())); + + listenerService.saveBluePrintToCdsDatabase(cbaArchivePath); + } else { + LOGGER.error("The CSAR file is not present at this location {}", csarArchivePath); + } + } } diff --git a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/client/CdsSdcListenerAuthClientInterceptor.java b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/client/CdsSdcListenerAuthClientInterceptor.java new file mode 100644 index 000000000..528fbe2f3 --- /dev/null +++ b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/client/CdsSdcListenerAuthClientInterceptor.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 Bell Canada. All rights reserved. + * + * NOTICE: All the intellectual and technical concepts contained herein are + * proprietary to Bell Canada and are protected by trade secret or copyright law. + * Unauthorized copying of this file, via any medium is strictly prohibited. + */ + +package org.onap.ccsdk.cds.cdssdclistener.client; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ForwardingClientCall; +import io.grpc.Metadata; +import io.grpc.Metadata.Key; +import io.grpc.MethodDescriptor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * To provide authentication with GRPC server. + */ +@ConfigurationProperties("listenerservice") +@Component +public class CdsSdcListenerAuthClientInterceptor implements ClientInterceptor { + + @Value("${listenerservice.config.authHeader}") + private String basicAuth; + + @Override + public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor, + CallOptions callOptions, Channel channel) { + Key<String> authHeader = Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER); + return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>( + channel.newCall(methodDescriptor, callOptions)) { + @Override + public void start(Listener<RespT> responseListener, Metadata headers) { + headers.put(authHeader, basicAuth); + super.start(responseListener, headers); + } + }; + } +} diff --git a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerClient.java b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/client/CdsSdcListenerClient.java index 76295bacb..6f888dd0b 100644 --- a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerClient.java +++ b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/client/CdsSdcListenerClient.java @@ -5,9 +5,12 @@ * proprietary to Bell Canada and are protected by trade secret or copyright law. * Unauthorized copying of this file, via any medium is strictly prohibited. */ -package org.onap.ccsdk.cds.cdssdclistener; +package org.onap.ccsdk.cds.cdssdclistener.client; import java.util.Optional; +import org.onap.ccsdk.cds.cdssdclistener.CdsSdcListenerConfiguration; +import org.onap.ccsdk.cds.cdssdclistener.dto.CdsSdcListenerDto; +import org.onap.ccsdk.cds.cdssdclistener.CdsSdcListenerNotificationCallback; import org.onap.ccsdk.cds.cdssdclistener.exceptions.CdsSdcListenerException; import org.onap.sdc.api.IDistributionClient; import org.onap.sdc.api.results.IDistributionClientResult; @@ -17,10 +20,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component +@ComponentScan("org.onap.ccsdk.cds.cdssdclistener.dto") public class CdsSdcListenerClient { private static Logger LOG = LoggerFactory.getLogger(CdsSdcListenerClient.class); diff --git a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerDto.java b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/dto/CdsSdcListenerDto.java index 7d154da42..41039eb28 100644 --- a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerDto.java +++ b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/dto/CdsSdcListenerDto.java @@ -5,10 +5,12 @@ * proprietary to Bell Canada and are protected by trade secret or copyright law. * Unauthorized copying of this file, via any medium is strictly prohibited. */ -package org.onap.ccsdk.cds.cdssdclistener; +package org.onap.ccsdk.cds.cdssdclistener.dto; import org.onap.sdc.api.IDistributionClient; +import org.springframework.stereotype.Component; +@Component public class CdsSdcListenerDto { private IDistributionClient distributionClient; diff --git a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/handler/BluePrintProcesssorHandler.java b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/handler/BluePrintProcesssorHandler.java new file mode 100644 index 000000000..6b03b6da2 --- /dev/null +++ b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/handler/BluePrintProcesssorHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 Bell Canada. All rights reserved. + * + * NOTICE: All the intellectual and technical concepts contained herein are + * proprietary to Bell Canada and are protected by trade secret or copyright law. + * Unauthorized copying of this file, via any medium is strictly prohibited. + */ + +package org.onap.ccsdk.cds.cdssdclistener.handler; + +import io.grpc.ManagedChannel; +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementOutput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc.BluePrintManagementServiceBlockingStub; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@ConfigurationProperties("listenerservice") +@Component +public class BluePrintProcesssorHandler implements AutoCloseable { + + private static final Logger LOGGER = LoggerFactory.getLogger(BluePrintProcesssorHandler.class); + + private ManagedChannel channel; + + /** + * Sending CBA archive to CDS backend to store into its Database. + * + * @param request BluePrintManagementInput object holds CBA archive, its version and blueprints. + * @param managedChannel - ManagedChannel object helps to access the server or application end point. + * @return A response object + */ + public Status sendRequest(BluePrintUploadInput request, ManagedChannel managedChannel) { + LOGGER.info("Sending request to blueprint processor"); + + this.channel = managedChannel; + + final BluePrintManagementServiceBlockingStub syncStub = BluePrintManagementServiceGrpc.newBlockingStub(channel); + + // Send the request to CDS backend. + final BluePrintManagementOutput response = syncStub.uploadBlueprint(request); + + return response.getStatus(); + } + + @Override + public void close() { + if (channel != null) { + channel.shutdown(); + } + LOGGER.info("Stopping GRPC connection to CDS backend"); + } +} diff --git a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerService.java b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerService.java index 5dc0c2194..1efbe8f33 100644 --- a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerService.java +++ b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerService.java @@ -8,7 +8,8 @@ package org.onap.ccsdk.cds.cdssdclistener.service; -import java.util.zip.ZipFile; +import java.nio.file.Path; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; public interface ListenerService { @@ -23,7 +24,15 @@ public interface ListenerService { /** * Store the Zip file into CDS database. * - * @param file The file to be stored. + * @param path path where zip file exists. */ - void saveBluePrintToCdsDatabase(ZipFile file); + void saveBluePrintToCdsDatabase(Path path); + + /** + * Extract and store CSAR to file. + * + * @param result - IDistributionClientDownloadResult contains payload. + * @param csarArchivePath The destination path where CSAR will be stored. + */ + void extractCsarAndStore(IDistributionClientDownloadResult result, String csarArchivePath); } diff --git a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImpl.java b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImpl.java index 4ff2a6ea8..37052082a 100644 --- a/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImpl.java +++ b/ms/cds-sdc-listener/application/src/main/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImpl.java @@ -8,6 +8,10 @@ package org.onap.ccsdk.cds.cdssdclistener.service; +import static java.nio.file.Files.walk; +import com.google.protobuf.ByteString; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -17,12 +21,24 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Enumeration; +import java.util.List; +import java.util.Optional; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import org.apache.commons.io.FileUtils; import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.onap.ccsdk.cds.cdssdclistener.client.CdsSdcListenerAuthClientInterceptor; +import org.onap.ccsdk.cds.cdssdclistener.handler.BluePrintProcesssorHandler; +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.FileChunk; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @@ -31,13 +47,21 @@ import org.springframework.stereotype.Component; @ConfigurationProperties("listenerservice") public class ListenerServiceImpl implements ListenerService { - @Value("${listenerservice.config.csarArchive}") - private String csarArchivePath; + @Autowired + private BluePrintProcesssorHandler bluePrintProcesssorHandler; - @Value("${listenerservice.config.cbaArchive}") - private String cbaArchivePath; + @Autowired + private CdsSdcListenerAuthClientInterceptor cdsSdcListenerAuthClientInterceptor; + + @Value("${listenerservice.config.grpcAddress}") + private String grpcAddress; + + @Value("${listenerservice.config.grpcPort}") + private int grpcPort; private static final String CBA_ZIP_PATH = "Artifacts/Resources/[a-zA-Z0-9-_]+/Deployment/CONTROLLER_BLUEPRINT_ARCHIVE/[a-zA-Z0-9-_]+[.]zip"; + private static final int SUCCESS_CODE = 200; + private static final String CSAR_FILE_EXTENSION = ".csar"; private static final Logger LOGGER = LoggerFactory.getLogger(ListenerServiceImpl.class); @Override @@ -50,6 +74,7 @@ public class ListenerServiceImpl implements ListenerService { String fileName = entry.getName(); if (Pattern.matches(CBA_ZIP_PATH, fileName)) { final String cbaArchiveName = Paths.get(fileName).getFileName().toString(); + LOGGER.info("Storing the CBA archive {}", cbaArchiveName); storeBluePrint(zipFile, cbaArchiveName, cbaStorageDir, entry); } } @@ -59,13 +84,12 @@ public class ListenerServiceImpl implements ListenerService { } private void storeBluePrint(ZipFile zipFile, String fileName, Path cbaArchivePath, ZipEntry entry) { - final String changedFileName = fileName + ".zip"; - Path targetLocation = cbaArchivePath.resolve(changedFileName); + Path targetLocation = cbaArchivePath.resolve(fileName); + LOGGER.info("The target location for zip file is {}", targetLocation); File targetZipFile = new File(targetLocation.toString()); try { targetZipFile.createNewFile(); - } catch (IOException e) { LOGGER.error("Could not able to create file {}", targetZipFile, e); } @@ -73,15 +97,43 @@ public class ListenerServiceImpl implements ListenerService { try (InputStream inputStream = zipFile.getInputStream(entry); OutputStream out = new FileOutputStream( targetZipFile)) { IOUtils.copy(inputStream, out); + LOGGER.info("Succesfully store the CBA archive {} at this location", targetZipFile); + } catch (Exception e) { + LOGGER.error("Failed to put zip file into target location {}, {}", targetLocation, e); + } + } + + @Override + public void saveBluePrintToCdsDatabase(Path cbaArchivePath) { + Optional<List<File>> zipFiles = getFilesFromDisk(cbaArchivePath); + zipFiles.ifPresent(this::prepareRequestForCdsBackend); + } + + @Override + public void extractCsarAndStore(IDistributionClientDownloadResult result, String csarArchivePath) { + + // Create CSAR storage directory + Path csarStorageDir = getStorageDirectory(csarArchivePath); + + byte[] payload = result.getArtifactPayload(); + String csarFileName = result.getArtifactFilename() + CSAR_FILE_EXTENSION; + Path targetLocation = csarStorageDir.resolve(csarFileName); + + LOGGER.info("The target location for the CSAR file is {}", targetLocation); + + File targetCsarFile = new File(targetLocation.toString()); + + try (FileOutputStream outFile = new FileOutputStream(targetCsarFile)) { + outFile.write(payload, 0, payload.length); } catch (Exception e) { - LOGGER.error("Failed to put zip file into target location {}", targetLocation, e); + LOGGER.error("Failed to put CSAR file into target location {}, {}", targetLocation, e); } } private Path getStorageDirectory(String path) { Path fileStorageLocation = Paths.get(path).toAbsolutePath().normalize(); - if (!Files.exists(fileStorageLocation)) { + if (!fileStorageLocation.toFile().exists()) { try { return Files.createDirectories(fileStorageLocation); } catch (IOException e) { @@ -91,8 +143,68 @@ public class ListenerServiceImpl implements ListenerService { return fileStorageLocation; } - @Override - public void saveBluePrintToCdsDatabase(ZipFile file) { - //TODO + private void prepareRequestForCdsBackend(List<File> files) { + final ManagedChannel channel = getManagedChannel(); + + files.forEach(zipFile -> { + try { + final BluePrintUploadInput request = generateBluePrintUploadInputBuilder(zipFile); + + // Send request to CDS Backend. + final Status responseStatus = bluePrintProcesssorHandler.sendRequest(request, channel); + + if (responseStatus.getCode() != SUCCESS_CODE) { + LOGGER.error("Failed to store the CBA archive into CDS DB due to {}", + responseStatus.getErrorMessage()); + } else { + LOGGER.info(responseStatus.getMessage()); + } + + } catch (Exception e) { + LOGGER.error("Failure due to", e); + } finally { + //Delete the file from the local disk. + boolean fileDeleted = zipFile.delete(); + + if (!fileDeleted) { + LOGGER.error("Could not able to delete the zip file {}", zipFile.toString()); + } + } + }); + } + + private ManagedChannel getManagedChannel() { + return ManagedChannelBuilder.forAddress(grpcAddress, grpcPort) + .usePlaintext() + .intercept(cdsSdcListenerAuthClientInterceptor) + .build(); + } + + private BluePrintUploadInput generateBluePrintUploadInputBuilder(File file) throws IOException { + byte[] bytes = FileUtils.readFileToByteArray(file); + FileChunk fileChunk = FileChunk.newBuilder().setChunk(ByteString.copyFrom(bytes)).build(); + + return BluePrintUploadInput.newBuilder() + .setFileChunk(fileChunk) + .build(); + } + + /** + * Extract files from the given path + * + * @param path where files reside. + * @return list of files. + */ + public Optional<List<File>> getFilesFromDisk(Path path) { + try (Stream<Path> fileTree = walk(path)) { + // Get the list of files from the path + return Optional.of(fileTree.filter(Files::isRegularFile) + .map(Path::toFile) + .collect(Collectors.toList())); + } catch (IOException e) { + LOGGER.error("Failed to find the file", e); + } + + return Optional.empty(); } } diff --git a/ms/cds-sdc-listener/application/src/main/resources/application.yml b/ms/cds-sdc-listener/application/src/main/resources/application.yml index 88de3b182..657ea9e80 100644 --- a/ms/cds-sdc-listener/application/src/main/resources/application.yml +++ b/ms/cds-sdc-listener/application/src/main/resources/application.yml @@ -14,6 +14,8 @@ listenerservice: keyStorePath: activateServerTLSAuth : false isUseHttpsWithDmaap: false - csarArchive: /opt/app/onap/cds-sdc-listener/csar-archive - cbaArchive: /opt/app/onap/cds/sdc-listener/cba-archive + archivePath: opt/app/onap/cds-sdc-listener/ + grpcAddress: localhost + grpcPort: 9111 + authHeader: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw== diff --git a/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerClientTest.java b/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerClientTest.java index 4d0631f96..948631462 100644 --- a/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerClientTest.java +++ b/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/CdsSdcListenerClientTest.java @@ -17,6 +17,8 @@ import mockit.VerificationsInOrder; import mockit.integration.junit4.JMockit; import org.junit.Test; import org.junit.runner.RunWith; +import org.onap.ccsdk.cds.cdssdclistener.client.CdsSdcListenerClient; +import org.onap.ccsdk.cds.cdssdclistener.dto.CdsSdcListenerDto; import org.onap.ccsdk.cds.cdssdclistener.exceptions.CdsSdcListenerException; import org.onap.sdc.api.IDistributionClient; import org.onap.sdc.api.results.IDistributionClientResult; diff --git a/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/handler/BluePrintProcessorHandlerTest.java b/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/handler/BluePrintProcessorHandlerTest.java new file mode 100644 index 000000000..0d38decdf --- /dev/null +++ b/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/handler/BluePrintProcessorHandlerTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 Bell Canada. All rights reserved. + * + * NOTICE: All the intellectual and technical concepts contained herein are + * proprietary to Bell Canada and are protected by trade secret or copyright law. + * Unauthorized copying of this file, via any medium is strictly prohibited. + */ + +package org.onap.ccsdk.cds.cdssdclistener.handler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import com.google.protobuf.ByteString; +import io.grpc.ManagedChannel; +import io.grpc.inprocess.InProcessChannelBuilder; +import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcCleanupRule; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.ccsdk.cds.cdssdclistener.client.CdsSdcListenerAuthClientInterceptor; +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementOutput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc.BluePrintManagementServiceImplBase; +import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput; +import org.onap.ccsdk.cds.controllerblueprints.management.api.FileChunk; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + + +@RunWith(SpringRunner.class) +@EnableConfigurationProperties({BluePrintProcesssorHandler.class, CdsSdcListenerAuthClientInterceptor.class}) +@SpringBootTest(classes = {BluePrintProcessorHandlerTest.class}) +public class BluePrintProcessorHandlerTest { + + @Autowired + private BluePrintProcesssorHandler bluePrintProcesssorHandler; + + @Autowired + private CdsSdcListenerAuthClientInterceptor cdsSdcListenerAuthClientInterceptor; + + @Rule + public GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); + + private static final String CBA_ARCHIVE = "src/test/resources/testcba.zip"; + private static final String SUCCESS_MSG = "Successfully uploaded CBA"; + private static final int SUCCESS_CODE = 200; + private ManagedChannel channel; + + @Before + public void setUp() throws IOException { + final BluePrintManagementServiceImplBase serviceImplBase = new BluePrintManagementServiceImplBase() { + @Override + public void uploadBlueprint(BluePrintUploadInput request, + StreamObserver<BluePrintManagementOutput> responseObserver) { + responseObserver.onNext(getBluePrintManagementOutput()); + responseObserver.onCompleted(); + } + }; + + // Generate server name. + String serverName = InProcessServerBuilder.generateName(); + + // Create a server, add service, start, and register. + grpcCleanup.register( + InProcessServerBuilder.forName(serverName).addService(serviceImplBase).directExecutor().build().start()); + + // Create a client channel. + channel = grpcCleanup.register(InProcessChannelBuilder.forName(serverName).directExecutor().build()); + } + + @Test + public void testApplicationEndPointSucess() throws IOException { + // Arrange + BluePrintUploadInput request = generateRequest(); + + // Act + Status output = bluePrintProcesssorHandler.sendRequest(request, channel); + + // Verify + assertEquals(SUCCESS_CODE, output.getCode()); + assertTrue(output.getMessage().contains(SUCCESS_MSG)); + } + + private BluePrintUploadInput generateRequest() throws IOException { + File file = Paths.get(CBA_ARCHIVE).toFile(); + byte[] bytes = FileUtils.readFileToByteArray(file); + FileChunk fileChunk = FileChunk.newBuilder().setChunk(ByteString.copyFrom(bytes)).build(); + + return BluePrintUploadInput.newBuilder().setFileChunk(fileChunk).build(); + } + + private BluePrintManagementOutput getBluePrintManagementOutput() { + return BluePrintManagementOutput.newBuilder() + .setStatus(Status.newBuilder().setMessage(SUCCESS_MSG).setCode(200).build()) + .build(); + } +} diff --git a/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImplTest.java b/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImplTest.java index 05e1ffdec..e33fbcdcc 100644 --- a/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImplTest.java +++ b/ms/cds-sdc-listener/application/src/test/java/org/onap/ccsdk/cds/cdssdclistener/service/ListenerServiceImplTest.java @@ -8,23 +8,34 @@ package org.onap.ccsdk.cds.cdssdclistener.service; +import static junit.framework.TestCase.assertTrue; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import org.onap.ccsdk.cds.cdssdclistener.client.CdsSdcListenerAuthClientInterceptor; +import org.onap.ccsdk.cds.cdssdclistener.handler.BluePrintProcesssorHandler; +import org.onap.sdc.impl.mock.DistributionClientDownloadResultStubImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@EnableConfigurationProperties(ListenerServiceImpl.class) +@EnableConfigurationProperties({ListenerServiceImpl.class, CdsSdcListenerAuthClientInterceptor.class, + BluePrintProcesssorHandler.class}) @SpringBootTest(classes = {ListenerServiceImplTest.class}) public class ListenerServiceImplTest { private static final String CSAR_SAMPLE = "src/test/resources/service-Testsvc140.csar"; + private static final String ZIP_FILE = ".zip"; + private static final String CSAR_FILE = ".csar"; + private String csarArchivePath; private Path tempDirectoryPath; @Rule @@ -33,12 +44,40 @@ public class ListenerServiceImplTest { @Autowired private ListenerServiceImpl listenerService; + @Before + public void setup() { + csarArchivePath = folder.getRoot().toString(); + tempDirectoryPath = Paths.get(csarArchivePath, "cds-sdc-listener-test"); + } @Test - public void extractBluePrintSuccessfully() { + public void extractBluePrintSuccessfully() throws IOException { + // Act + listenerService.extractBluePrint(CSAR_SAMPLE, tempDirectoryPath.toString()); + + // Verify + String result = checkFileExists(tempDirectoryPath); + assertTrue(result.contains(ZIP_FILE)); + } + + @Test + public void storeCsarArtifactToFileSuccessfully() throws IOException { // Arrange - tempDirectoryPath = Paths.get(folder.getRoot().toString(), "cds-sdc-listener-test"); + DistributionClientDownloadResultStubImpl resultStub = new DistributionClientDownloadResultStubImpl(); // Act - listenerService.extractBluePrint(CSAR_SAMPLE, tempDirectoryPath.toString()); + listenerService.extractCsarAndStore(resultStub, tempDirectoryPath.toString()); + + // Verify + String result = checkFileExists(tempDirectoryPath); + assertTrue(result.contains(CSAR_FILE)); + } + + private String checkFileExists(Path path) throws IOException { + return Files.walk(path) + .filter(Files::isRegularFile) + .map(Path::toFile) + .findAny() + .get() + .getName(); } } diff --git a/ms/cds-sdc-listener/application/src/test/resources/testcba.zip b/ms/cds-sdc-listener/application/src/test/resources/testcba.zip Binary files differnew file mode 100644 index 000000000..c886fe6bc --- /dev/null +++ b/ms/cds-sdc-listener/application/src/test/resources/testcba.zip diff --git a/ms/controllerblueprints/application/src/main/resources/application-dev.properties b/ms/controllerblueprints/application/src/main/resources/application-dev.properties index 46218d6d2..68d76333a 100755 --- a/ms/controllerblueprints/application/src/main/resources/application-dev.properties +++ b/ms/controllerblueprints/application/src/main/resources/application-dev.properties @@ -49,7 +49,7 @@ spring.jpa.hibernate.ddl-auto=none spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect # Load Resource Source Mappings -resourceSourceMappings=processor-db=source-processor-db,input=source-input,default=source-default,primary-config-data=source-rest,capability=source-capability +resourceSourceMappings=processor-db=source-processor-db,input=source-input,default=source-default,primary-config-data=source-rest,primary-aai-data=source-rest,capability=source-capability # Controller Blueprints Core Configuration controllerblueprints.blueprintDeployPath=/etc/blueprints/deploy controllerblueprints.blueprintArchivePath=/etc/blueprints/archive diff --git a/ms/controllerblueprints/application/src/test/resources/application.properties b/ms/controllerblueprints/application/src/test/resources/application.properties index 5d970a0a6..9c5d35cab 100755 --- a/ms/controllerblueprints/application/src/test/resources/application.properties +++ b/ms/controllerblueprints/application/src/test/resources/application.properties @@ -33,7 +33,7 @@ swagger.contact.url=www.onap.com swagger.contact.email=brindasanth@onap.com
# Load Resource Source Mappings
-resourceSourceMappings=processor-db=source-processor-db,input=source-input,default=source-default,primary-config-data=source-rest,capability=source-capability
+resourceSourceMappings=processor-db=source-processor-db,input=source-input,default=source-default,primary-config-data=source-rest,primary-aai-data=source-rest,capability=source-capability
# Controller Blueprints Core Configuration
controllerblueprints.blueprintDeployPath=./target/blueprints/deploy
diff --git a/ms/controllerblueprints/modules/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDictionaryConstants.kt b/ms/controllerblueprints/modules/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDictionaryConstants.kt index 2921c2c3e..f83bdaece 100644 --- a/ms/controllerblueprints/modules/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDictionaryConstants.kt +++ b/ms/controllerblueprints/modules/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDictionaryConstants.kt @@ -28,6 +28,7 @@ object ResourceDictionaryConstants { const val SOURCE_PROCESSOR_DB = "processor-db" const val SOURCE_PRIMARY_CONFIG_DATA = "primary-config-data" const val SOURCE_PRIMARY_DB = "primary-db" + const val SOURCE_PRIMARY_AAI_DATA = "primary-aai-data" const val MODEL_DIR_RESOURCE_DEFINITION: String = "resource_dictionary" diff --git a/ms/controllerblueprints/modules/resource-dict/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/utils/ResourceDictionaryTestUtils.kt b/ms/controllerblueprints/modules/resource-dict/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/utils/ResourceDictionaryTestUtils.kt index 721a36a7f..a2d525ac3 100644 --- a/ms/controllerblueprints/modules/resource-dict/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/utils/ResourceDictionaryTestUtils.kt +++ b/ms/controllerblueprints/modules/resource-dict/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/utils/ResourceDictionaryTestUtils.kt @@ -26,5 +26,6 @@ object ResourceDictionaryTestUtils { ResourceSourceMappingFactory.registerSourceMapping("input", "source-input") ResourceSourceMappingFactory.registerSourceMapping("default", "source-default") ResourceSourceMappingFactory.registerSourceMapping("primary-config-data", "source-rest") + ResourceSourceMappingFactory.registerSourceMapping("primary-aai-data", "source-rest") } }
\ No newline at end of file |