From f930d9ee670a6dce8977dcdb18643e48c7af33fd Mon Sep 17 00:00:00 2001 From: Brinda Santh Date: Thu, 5 Sep 2019 16:13:28 -0400 Subject: Move GRPC management api to designer api. Change-Id: I58ee303d361cf4f1996c966c094ec66886587b52 Issue-ID: CCSDK-1682 Signed-off-by: Brinda Santh --- .../designer/api/BluePrintManagementGRPCHandler.kt | 151 +++++++++++++++++++++ .../designer/api/BlueprintModelController.kt | 27 +++- .../api/ControllerBlueprintExceptionHandler.kt | 56 -------- .../api/DesignerBlueprintExceptionHandler.kt | 56 ++++++++ .../designer/api/handler/BluePrintModelHandler.kt | 62 ++++++--- .../api/BluePrintManagementGRPCHandlerTest.kt | 136 +++++++++++++++++++ .../designer/api/BlueprintModelControllerTest.kt | 33 ++++- .../designer-api/src/test/resources/test-cba.zip | Bin 0 -> 9554 bytes 8 files changed, 442 insertions(+), 79 deletions(-) create mode 100644 ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandler.kt delete mode 100644 ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/ControllerBlueprintExceptionHandler.kt create mode 100644 ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/DesignerBlueprintExceptionHandler.kt create mode 100644 ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandlerTest.kt create mode 100644 ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/resources/test-cba.zip (limited to 'ms/blueprintsprocessor/modules/inbounds/designer-api') diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandler.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandler.kt new file mode 100644 index 000000000..b7badb53b --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandler.kt @@ -0,0 +1,151 @@ +/* + * Copyright © 2017-2018 AT&T Intellectual Property. + * Modifications Copyright © 2019 Bell Canada. + * Modifications Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.designer.api + +import io.grpc.StatusException +import io.grpc.stub.StreamObserver +import kotlinx.coroutines.runBlocking +import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader +import org.onap.ccsdk.cds.controllerblueprints.common.api.Status +import org.onap.ccsdk.cds.controllerblueprints.core.* +import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration +import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService +import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache +import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils +import org.onap.ccsdk.cds.controllerblueprints.core.utils.currentTimestamp +import org.onap.ccsdk.cds.controllerblueprints.management.api.* +import org.slf4j.LoggerFactory +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.stereotype.Service +import java.io.File +import java.util.* + +@Service +open class BluePrintManagementGRPCHandler(private val bluePrintLoadConfiguration: BluePrintLoadConfiguration, + private val blueprintsProcessorCatalogService: BluePrintCatalogService) + : BluePrintManagementServiceGrpc.BluePrintManagementServiceImplBase() { + + private val log = LoggerFactory.getLogger(BluePrintManagementGRPCHandler::class.java) + + @PreAuthorize("hasRole('USER')") + override fun uploadBlueprint(request: BluePrintUploadInput, responseObserver: + StreamObserver) { + runBlocking { + + log.info("request(${request.commonHeader.requestId})") + val uploadId = UUID.randomUUID().toString() + val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, uploadId) + val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, uploadId) + try { + val cbaFile = normalizedFile(blueprintArchive, "cba.zip") + + saveToDisk(request, cbaFile) + + val uploadAction = request.actionIdentifiers?.actionName.emptyTONull() + ?: UploadAction.DRAFT.toString() + + when (uploadAction) { + UploadAction.DRAFT.toString() -> { + val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(uploadId, cbaFile, false) + responseObserver.onNext(successStatus("Successfully uploaded CBA($blueprintId)...", + request.commonHeader)) + } + UploadAction.PUBLISH.toString() -> { + val blueprintId = blueprintsProcessorCatalogService.saveToDatabase(uploadId, cbaFile, true) + responseObserver.onNext(successStatus("Successfully uploaded CBA($blueprintId)...", + request.commonHeader)) + } + UploadAction.VALIDATE.toString() -> { + //TODO("Not Implemented") + responseObserver.onError(failStatus("Not Implemented", + BluePrintProcessorException("Not Implemented"))) + } + UploadAction.ENRICH.toString() -> { + //TODO("Not Implemented") + responseObserver.onError(failStatus("Not Implemented", + BluePrintProcessorException("Not Implemented"))) + } + } + responseObserver.onCompleted() + } catch (e: Exception) { + responseObserver.onError(failStatus("request(${request.commonHeader.requestId}): Failed to upload CBA", e)) + } finally { + // Clean blueprint script cache + val cacheKey = BluePrintFileUtils + .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, uploadId)) + BluePrintCompileCache.cleanClassLoader(cacheKey) + deleteNBDir(blueprintArchive) + deleteNBDir(blueprintWorking) + } + } + } + + @PreAuthorize("hasRole('USER')") + override fun removeBlueprint(request: BluePrintRemoveInput, responseObserver: + StreamObserver) { + + runBlocking { + val blueprintName = request.blueprintName + val blueprintVersion = request.blueprintVersion + val blueprint = "blueprint $blueprintName:$blueprintVersion" + + log.info("request(${request.commonHeader.requestId}): Received delete $blueprint") + + + try { + blueprintsProcessorCatalogService.deleteFromDatabase(blueprintName, blueprintVersion) + responseObserver.onNext(successStatus("Successfully deleted $blueprint", request.commonHeader)) + responseObserver.onCompleted() + } catch (e: Exception) { + responseObserver.onError(failStatus("request(${request.commonHeader.requestId}): Failed to delete $blueprint", e)) + } + } + } + + private fun saveToDisk(request: BluePrintUploadInput, cbaFile: File) { + log.info("request(${request.commonHeader.requestId}): Writing CBA File under :${cbaFile.absolutePath}") + + // Recreate Folder + cbaFile.parentFile.reCreateDirs() + + // Write the File + cbaFile.writeBytes(request.fileChunk.chunk.toByteArray()).apply { + log.info("request(${request.commonHeader.requestId}): CBA file(${cbaFile.absolutePath} written successfully") + } + + } + + private fun successStatus(message: String, header: CommonHeader): BluePrintManagementOutput = + BluePrintManagementOutput.newBuilder() + .setCommonHeader(header) + .setStatus(Status.newBuilder() + .setTimestamp(currentTimestamp()) + .setMessage(message) + .setCode(200) + .build()) + .build() + + private fun failStatus(message: String, e: Exception): StatusException { + log.error(message, e) + return io.grpc.Status.INTERNAL + .withDescription(message) + .withCause(e) + .asException() + } +} diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelController.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelController.kt index f67ed25c3..4d13486c3 100644 --- a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelController.kt +++ b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelController.kt @@ -17,14 +17,17 @@ package org.onap.ccsdk.cds.blueprintsprocessor.designer.api +import io.swagger.annotations.ApiOperation +import io.swagger.annotations.ApiParam import kotlinx.coroutines.runBlocking -import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModelSearch import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler.BluePrintModelHandler +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException import org.springframework.core.io.Resource import org.springframework.http.MediaType import org.springframework.http.ResponseEntity import org.springframework.http.codec.multipart.FilePart +import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.* /** @@ -40,18 +43,21 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint @PostMapping("", produces = [MediaType.APPLICATION_JSON_VALUE], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) @ResponseBody @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun saveBlueprint(@RequestPart("file") filePart: FilePart): BlueprintModelSearch = runBlocking { bluePrintModelHandler.saveBlueprintModel(filePart) } @GetMapping("", produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody + @PreAuthorize("hasRole('USER')") fun allBlueprintModel(): List { return this.bluePrintModelHandler.allBlueprintModel() } @DeleteMapping("/{id}") @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun deleteBlueprint(@PathVariable(value = "id") id: String) { this.bluePrintModelHandler.deleteBlueprintModel(id) } @@ -59,6 +65,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint @GetMapping("/by-name/{name}/version/{version}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun getBlueprintByNameAndVersion(@PathVariable(value = "name") name: String, @PathVariable(value = "version") version: String): BlueprintModelSearch { return this.bluePrintModelHandler.getBlueprintModelSearchByNameAndVersion(name, version) @@ -67,6 +74,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint @GetMapping("/download/by-name/{name}/version/{version}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun downloadBlueprintByNameAndVersion(@PathVariable(value = "name") name: String, @PathVariable(value = "version") version: String): ResponseEntity { return this.bluePrintModelHandler.downloadBlueprintModelFileByNameAndVersion(name, version) @@ -75,6 +83,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint @GetMapping("/{id}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun getBlueprintModel(@PathVariable(value = "id") id: String): BlueprintModelSearch { return this.bluePrintModelHandler.getBlueprintModelSearch(id) } @@ -82,6 +91,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint @GetMapping("/download/{id}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun downloadBluePrint(@PathVariable(value = "id") id: String): ResponseEntity { return this.bluePrintModelHandler.downloadBlueprintModelFile(id) } @@ -90,6 +100,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint .MULTIPART_FORM_DATA_VALUE]) @ResponseBody @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun enrichBlueprint(@RequestPart("file") file: FilePart): ResponseEntity = runBlocking { bluePrintModelHandler.enrichBlueprint(file) } @@ -97,13 +108,27 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint @PostMapping("/publish", produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody @Throws(BluePrintException::class) + @PreAuthorize("hasRole('USER')") fun publishBlueprint(@RequestPart("file") file: FilePart): BlueprintModelSearch = runBlocking { bluePrintModelHandler.publishBlueprint(file) } @GetMapping("/search/{tags}", produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody + @PreAuthorize("hasRole('USER')") fun searchBlueprintModels(@PathVariable(value = "tags") tags: String): List { return this.bluePrintModelHandler.searchBlueprintModels(tags) } + + @DeleteMapping("/name/{name}/version/{version}") + @ApiOperation(value = "Delete a CBA", + notes = "Delete the CBA package identified by its name and version.", + produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasRole('USER')") + fun deleteBlueprint(@ApiParam(value = "Name of the CBA.", required = true) + @PathVariable(value = "name") name: String, + @ApiParam(value = "Version of the CBA.", required = true) + @PathVariable(value = "version") version: String) = runBlocking { + bluePrintModelHandler.deleteBlueprintModel(name, version) + } } diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/ControllerBlueprintExceptionHandler.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/ControllerBlueprintExceptionHandler.kt deleted file mode 100644 index 0d2a7b7dc..000000000 --- a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/ControllerBlueprintExceptionHandler.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright © 2018-2019 Bell Canada Intellectual Property. - * - * 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. - */ - -package org.onap.ccsdk.cds.blueprintsprocessor.designer.api - -import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException -import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode -import org.slf4j.LoggerFactory -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.ExceptionHandler -import org.springframework.web.bind.annotation.RestControllerAdvice - -/** - * ControllerBlueprintExceptionHandler Purpose: Handle exceptions in controllerBlueprint API and provide the right - * HTTP code status - * - * @author Vinal Patel - * @version 1.0 - */ -@RestControllerAdvice("org.onap.ccsdk.cds.controllerblueprints") -open class ControllerBlueprintExceptionHandler { - - companion object ControllerBlueprintExceptionHandler { - val LOG = LoggerFactory.getLogger(ControllerBlueprintExceptionHandler::class.java) - } - - @ExceptionHandler - fun ControllerBlueprintExceptionHandler(e: BluePrintException): ResponseEntity { - val errorCode = ErrorCode.valueOf(e.code) - val errorMessage = ErrorMessage(errorCode?.message(e.message!!), errorCode?.value, "ControllerBluePrint_Error_Message") - LOG.error("Error: $errorCode ${e.message}") - return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode!!.httpCode)) - } - - @ExceptionHandler - fun ControllerBlueprintExceptionHandler(e: Exception): ResponseEntity { - val errorCode = ErrorCode.GENERIC_FAILURE - val errorMessage = ErrorMessage(errorCode?.message(e.message!!), errorCode?.value, "ControllerBluePrint_Error_Message") - LOG.error("Error: $errorCode ${e.message}") - return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode!!.httpCode)) - } -} diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/DesignerBlueprintExceptionHandler.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/DesignerBlueprintExceptionHandler.kt new file mode 100644 index 000000000..c140c9a07 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/DesignerBlueprintExceptionHandler.kt @@ -0,0 +1,56 @@ +/* + * Copyright © 2018-2019 Bell Canada Intellectual Property. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.designer.api + +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException +import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode +import org.slf4j.LoggerFactory +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice + +/** + * ControllerBlueprintExceptionHandler Purpose: Handle exceptions in controllerBlueprint API and provide the right + * HTTP code status + * + * @author Vinal Patel + * @version 1.0 + */ +@RestControllerAdvice("org.onap.ccsdk.cds.controllerblueprints") +open class DesignerBlueprintExceptionHandler { + + companion object ControllerBlueprintExceptionHandler { + val LOG = LoggerFactory.getLogger(DesignerBlueprintExceptionHandler::class.java) + } + + @ExceptionHandler + fun ControllerBlueprintExceptionHandler(e: BluePrintException): ResponseEntity { + val errorCode = ErrorCode.valueOf(e.code) + val errorMessage = ErrorMessage(errorCode?.message(e.message!!), errorCode?.value, "ControllerBluePrint_Error_Message") + LOG.error("Error: $errorCode ${e.message}") + return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode!!.httpCode)) + } + + @ExceptionHandler + fun ControllerBlueprintExceptionHandler(e: Exception): ResponseEntity { + val errorCode = ErrorCode.GENERIC_FAILURE + val errorMessage = ErrorMessage(errorCode?.message(e.message!!), errorCode?.value, "ControllerBluePrint_Error_Message") + LOG.error("Error: $errorCode ${e.message}") + return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode!!.httpCode)) + } +} diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/handler/BluePrintModelHandler.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/handler/BluePrintModelHandler.kt index c074573dd..af7b3fe8d 100644 --- a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/handler/BluePrintModelHandler.kt +++ b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/handler/BluePrintModelHandler.kt @@ -18,6 +18,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler +import kotlinx.coroutines.reactive.awaitSingle import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModel import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModelSearch import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.repository.BlueprintModelContentRepository @@ -29,6 +30,8 @@ import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfigur import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintCatalogService import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintEnhancerService +import org.onap.ccsdk.cds.controllerblueprints.core.scripts.BluePrintCompileCache +import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintFileUtils import org.slf4j.LoggerFactory import org.springframework.core.io.ByteArrayResource import org.springframework.core.io.Resource @@ -50,7 +53,7 @@ import java.util.* */ @Service -open class BluePrintModelHandler(private val controllerBlueprintsCatalogService: BluePrintCatalogService, +open class BluePrintModelHandler(private val blueprintsProcessorCatalogService: BluePrintCatalogService, private val bluePrintLoadConfiguration: BluePrintLoadConfiguration, private val blueprintModelSearchRepository: BlueprintModelSearchRepository, private val blueprintModelRepository: BlueprintModelRepository, @@ -77,29 +80,19 @@ open class BluePrintModelHandler(private val controllerBlueprintsCatalogService: */ @Throws(BluePrintException::class) open suspend fun saveBlueprintModel(filePart: FilePart): BlueprintModelSearch { - val saveId = UUID.randomUUID().toString() - val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId) try { - //Recreate the Dir - normalizedFile(bluePrintLoadConfiguration.blueprintArchivePath, saveId).reCreateDirs() - val deCompressedFile = normalizedFile(blueprintArchive, "cba.zip") - // Copy the File Part to Local File - BluePrintEnhancerUtils.copyFromFilePart(filePart, deCompressedFile) - // Save the Copied file to Database - val blueprintId = controllerBlueprintsCatalogService.saveToDatabase(saveId, deCompressedFile, false) + val blueprintId = upload(filePart, false) // Check and Return the Saved File val blueprintModelSearch = blueprintModelSearchRepository.findById(blueprintId) ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, String.format(BLUEPRINT_MODEL_ID_FAILURE_MSG, blueprintId)) - log.info("Save($saveId) successful for blueprint(${blueprintModelSearch.artifactName}) " + + log.info("Save successful for blueprint(${blueprintModelSearch.artifactName}) " + "version(${blueprintModelSearch.artifactVersion})") return blueprintModelSearch } catch (e: IOException) { throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value, "Error in Save CBA: ${e.message}", e) - } finally { - deleteDir(blueprintArchive) } } @@ -261,6 +254,10 @@ open class BluePrintModelHandler(private val controllerBlueprintsCatalogService: } } + open suspend fun deleteBlueprintModel(name: String, version: String) { + blueprintsProcessorCatalogService.deleteFromDatabase(name, version) + } + /** * This is a CBA enrichBlueprint method * Save the Zip File in archive location and extract the cba content. @@ -303,14 +300,8 @@ open class BluePrintModelHandler(private val controllerBlueprintsCatalogService: */ @Throws(BluePrintException::class) open suspend fun publishBlueprint(filePart: FilePart): BlueprintModelSearch { - val publishId = UUID.randomUUID().toString() - val blueprintArchive = bluePrintLoadConfiguration.blueprintArchivePath.plus(File.separator).plus(publishId) - val blueprintWorkingDir = bluePrintLoadConfiguration.blueprintWorkingPath.plus(File.separator).plus(publishId) try { - val compressedFilePart = BluePrintEnhancerUtils - .extractCompressFilePart(filePart, blueprintArchive, blueprintWorkingDir) - - val blueprintId = controllerBlueprintsCatalogService.saveToDatabase(publishId, compressedFilePart, true) + val blueprintId = upload(filePart, true) return blueprintModelSearchRepository.findById(blueprintId) ?: throw BluePrintException(ErrorCode.RESOURCE_NOT_FOUND.value, @@ -319,11 +310,40 @@ open class BluePrintModelHandler(private val controllerBlueprintsCatalogService: } catch (e: Exception) { throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value, "Error in Publishing CBA: ${e.message}", e) + } + } + + //TODO("Combine Rest and GRPC Handler") + suspend fun upload(filePart: FilePart, validate: Boolean): String { + val saveId = UUID.randomUUID().toString() + val blueprintArchive = normalizedPathName(bluePrintLoadConfiguration.blueprintArchivePath, saveId) + val blueprintWorking = normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId) + try { + val compressedFile = normalizedFile(blueprintArchive, "cba.zip") + compressedFile.parentFile.reCreateNBDirs() + // Copy the File Part to Local File + copyFromFilePart(filePart, compressedFile) + // Save the Copied file to Database + return blueprintsProcessorCatalogService.saveToDatabase(saveId, compressedFile, validate) + } catch (e: IOException) { + throw BluePrintException(ErrorCode.IO_FILE_INTERRUPT.value, + "Error in Upload CBA: ${e.message}", e) } finally { - BluePrintEnhancerUtils.cleanEnhancer(blueprintArchive, blueprintWorkingDir) + // Clean blueprint script cache + val cacheKey = BluePrintFileUtils + .compileCacheKey(normalizedPathName(bluePrintLoadConfiguration.blueprintWorkingPath, saveId)) + BluePrintCompileCache.cleanClassLoader(cacheKey) + deleteNBDir(blueprintArchive) + deleteNBDir(blueprintWorking) } } + private suspend fun copyFromFilePart(filePart: FilePart, targetFile: File): File { + return filePart.transferTo(targetFile) + .thenReturn(targetFile) + .awaitSingle() + } + companion object { private const val BLUEPRINT_MODEL_ID_FAILURE_MSG = "failed to get blueprint model id(%s) from repo" diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandlerTest.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandlerTest.kt new file mode 100644 index 000000000..f0411b0d7 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BluePrintManagementGRPCHandlerTest.kt @@ -0,0 +1,136 @@ +/* + * Copyright © 2017-2018 AT&T Intellectual Property. + * Modifications Copyright © 2019 Bell Canada. + * Modifications Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.designer.api + +import com.google.protobuf.ByteString +import io.grpc.testing.GrpcServerRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.onap.ccsdk.cds.controllerblueprints.common.api.ActionIdentifiers +import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader +import org.onap.ccsdk.cds.controllerblueprints.core.deleteDir +import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile +import org.onap.ccsdk.cds.controllerblueprints.management.api.* +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.context.annotation.ComponentScan +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit4.SpringRunner +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +@RunWith(SpringRunner::class) +@EnableAutoConfiguration +@DirtiesContext +@ComponentScan(basePackages = ["org.onap.ccsdk.cds.blueprintsprocessor", "org.onap.ccsdk.cds.controllerblueprints"]) +@TestPropertySource(locations = ["classpath:application-test.properties"]) +class BluePrintManagementGRPCHandlerTest { + + @get:Rule + val grpcServerRule = GrpcServerRule().directExecutor() + + @Autowired + lateinit var bluePrintManagementGRPCHandler: BluePrintManagementGRPCHandler + + @BeforeTest + fun init() { + // Create a server, add service, start, and register for automatic graceful shutdown. + grpcServerRule.serviceRegistry.addService(bluePrintManagementGRPCHandler) + deleteDir("target", "blueprints") + } + + @AfterTest + fun cleanDir() { + deleteDir("target", "blueprints") + } + + @Test + fun `test upload blueprint`() { + val blockingStub = BluePrintManagementServiceGrpc.newBlockingStub(grpcServerRule.channel) + val id = "123_upload" + val req = createUploadInputRequest(id, UploadAction.PUBLISH.toString()) + val output = blockingStub.uploadBlueprint(req) + + assertEquals(200, output.status.code) + assertTrue(output.status.message.contains("Successfully uploaded CBA")) + assertEquals(id, output.commonHeader.requestId) + } + + @Test + fun `test delete blueprint`() { + val blockingStub = BluePrintManagementServiceGrpc.newBlockingStub(grpcServerRule.channel) + val id = "123_delete" + val req = createUploadInputRequest(id, UploadAction.DRAFT.toString()) + + var output = blockingStub.uploadBlueprint(req) + assertEquals(200, output.status.code) + assertTrue(output.status.message.contains("Successfully uploaded CBA")) + assertEquals(id, output.commonHeader.requestId) + + val removeReq = createRemoveInputRequest(id) + output = blockingStub.removeBlueprint(removeReq) + assertEquals(200, output.status.code) + } + + private fun createUploadInputRequest(id: String, action: String): BluePrintUploadInput { + val file = normalizedFile("./src/test/resources/test-cba.zip") + assertTrue(file.exists(), "couldnt get file ${file.absolutePath}") + + val commonHeader = CommonHeader + .newBuilder() + .setTimestamp("2012-04-23T18:25:43.511Z") + .setOriginatorId("System") + .setRequestId(id) + .setSubRequestId("1234-56").build() + + val actionIdentifier = ActionIdentifiers.newBuilder() + .setActionName(action) + .setBlueprintName("sample") + .setBlueprintVersion("1.0.0") + .build() + + val fileChunk = FileChunk.newBuilder().setChunk(ByteString.copyFrom(file.inputStream().readBytes())) + .build() + + return BluePrintUploadInput.newBuilder() + .setCommonHeader(commonHeader) + .setActionIdentifiers(actionIdentifier) + .setFileChunk(fileChunk) + .build() + } + + private fun createRemoveInputRequest(id: String): BluePrintRemoveInput { + val commonHeader = CommonHeader + .newBuilder() + .setTimestamp("2012-04-23T18:25:43.511Z") + .setOriginatorId("System") + .setRequestId(id) + .setSubRequestId("1234-56").build() + + return BluePrintRemoveInput.newBuilder() + .setCommonHeader(commonHeader) + .setBlueprintName("sample") + .setBlueprintVersion("1.0.0") + .build() + } +} diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelControllerTest.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelControllerTest.kt index 877584ed6..149108087 100644 --- a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelControllerTest.kt +++ b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelControllerTest.kt @@ -176,6 +176,31 @@ class BlueprintModelControllerTest { @Test fun test07_publishBlueprintModel() { + bp = runBlocking { + val body = MultipartBodyBuilder().apply { + part("file", object : ByteArrayResource(testZipFile!!.readBytes()) { + override fun getFilename(): String { + return "test.zip" + } + }) + }.build() + + val publishBP = webTestClient + .post() + .uri("/api/v1/blueprint-model/publish") + .body(BodyInserters.fromMultipartData(body)) + .exchange() + .expectStatus().isOk + .returnResult() + .responseBody + .awaitSingle() + + assertNotNull(publishBP, "failed to get response") + assertEquals("baseconfiguration", publishBP.artifactName, "mismatch artifact name") + assertEquals("1.0.0", publishBP.artifactVersion, "mismatch artifact version") + assertEquals("Y", publishBP.published, "mismatch publish") + publishBP + } } @Test @@ -196,7 +221,13 @@ class BlueprintModelControllerTest { @Test fun test10_deleteBluePrint() { - webTestClient.delete().uri("/api/v1/blueprint-model/${bp!!.id}") +// webTestClient.delete().uri("/api/v1/blueprint-model/${bp!!.id}") +// .header("Authorization", "Basic " + Base64Utils +// .encodeToString(("ccsdkapps" + ":" + "ccsdkapps").toByteArray(UTF_8))) +// .exchange() +// .expectStatus().is2xxSuccessful + + webTestClient.delete().uri("/api/v1/blueprint-model/name/${bp!!.artifactName}/version/${bp!!.artifactVersion}") .header("Authorization", "Basic " + Base64Utils .encodeToString(("ccsdkapps" + ":" + "ccsdkapps").toByteArray(UTF_8))) .exchange() diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/resources/test-cba.zip b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/resources/test-cba.zip new file mode 100644 index 000000000..785ec6c00 Binary files /dev/null and b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/test/resources/test-cba.zip differ -- cgit 1.2.3-korg