diff options
author | Alexis de Talhouët <adetalhouet89@gmail.com> | 2019-01-15 14:44:58 -0500 |
---|---|---|
committer | Alexis de Talhouët <adetalhouet89@gmail.com> | 2019-01-18 13:56:01 -0500 |
commit | bdf3467390d8f5884c9ea0b5691630e15e1a9760 (patch) | |
tree | b55794392e9ea3680ba5907fb1b213519948f6a3 | |
parent | 44cb2fcd7f6686e6531a5a5222d45bdf31739efb (diff) |
Implement CBA upload through REST
Change-Id: I417254c5107f8b0031932e6a7cf0599561ee9a3c
Issue-ID: CCSDK-910
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
9 files changed, 175 insertions, 27 deletions
diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt index 05f6a2db6..a2c7344bc 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt @@ -17,6 +17,7 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.node.JsonNodeFactory import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ActionIdentifiers @@ -46,6 +47,8 @@ class ComponentNetconfExecutorTest { fun testComponentNetconfExecutor() { val executionServiceInput = ExecutionServiceInput() + executionServiceInput.payload = JsonNodeFactory.instance.objectNode() + val commonHeader = CommonHeader() commonHeader.requestId = "1234" executionServiceInput.commonHeader = commonHeader diff --git a/ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/python/executor/ComponentJythonExecutorTest.kt b/ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/python/executor/ComponentJythonExecutorTest.kt index 07591a502..7684b2b03 100644 --- a/ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/python/executor/ComponentJythonExecutorTest.kt +++ b/ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/python/executor/ComponentJythonExecutorTest.kt @@ -17,6 +17,7 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.python.executor import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.node.JsonNodeFactory import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ActionIdentifiers @@ -43,8 +44,9 @@ class ComponentJythonExecutorTest { @Test fun testPythonComponentInjection() { - val executionServiceInput = ExecutionServiceInput() + executionServiceInput.payload = JsonNodeFactory.instance.objectNode() + val commonHeader = CommonHeader() commonHeader.requestId = "1234" executionServiceInput.commonHeader = commonHeader @@ -68,6 +70,7 @@ class ComponentJythonExecutorTest { componentJythonExecutor.bluePrintRuntimeService = bluePrintRuntimeService componentJythonExecutor.stepName = "activate-jython" + componentJythonExecutor.apply(executionServiceInput) } diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandler.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandler.kt index 0668d3c93..9af04db4b 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandler.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandler.kt @@ -16,7 +16,6 @@ package org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api -import com.google.protobuf.util.JsonFormat import io.grpc.stub.StreamObserver import org.onap.ccsdk.apps.blueprintsprocessor.core.BluePrintCoreConfiguration import org.onap.ccsdk.apps.controllerblueprints.processing.api.BluePrintProcessingServiceGrpc diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt index 0a67e878d..35d4e67c5 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt @@ -21,7 +21,14 @@ import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInp import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceOutput import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType -import org.springframework.web.bind.annotation.* +import org.springframework.http.codec.multipart.FilePart +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.ResponseBody +import org.springframework.web.bind.annotation.RestController import reactor.core.publisher.Mono @RestController @@ -32,13 +39,23 @@ class ExecutionServiceController { lateinit var executionServiceHandler: ExecutionServiceHandler - @RequestMapping(path = arrayOf("/ping"), method = arrayOf(RequestMethod.GET), produces = arrayOf(MediaType.APPLICATION_JSON_VALUE)) + @RequestMapping(path = ["/ping"], method = [RequestMethod.GET], produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody fun ping(): Mono<String> { return Mono.just("Success") } - @RequestMapping(path = arrayOf("/process"), method = arrayOf(RequestMethod.POST), produces = arrayOf(MediaType.APPLICATION_JSON_VALUE)) + @PostMapping(path = ["/upload"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) + @ApiOperation(value = "Upload CBA", notes = "Takes a File and load it in the runtime database") + @ResponseBody + fun upload(@RequestPart("file") parts: Mono<FilePart>): Mono<String> { + return parts + .filter { it is FilePart } + .ofType(FilePart::class.java) + .flatMap(executionServiceHandler::upload) + } + + @RequestMapping(path = ["/process"], method = [RequestMethod.POST], produces = [MediaType.APPLICATION_JSON_VALUE]) @ApiOperation(value = "Resolve Resource Mappings", notes = "Takes the blueprint information and process as per the payload") @ResponseBody fun process(@RequestBody executionServiceInput: ExecutionServiceInput): Mono<ExecutionServiceOutput> { diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt index 56a6393af..56903745d 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandler.kt @@ -16,20 +16,39 @@ package org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api +import org.onap.ccsdk.apps.blueprintsprocessor.core.BluePrintCoreConfiguration import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceOutput -import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintCatalogService +import org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api.utils.saveCBAFile import org.onap.ccsdk.apps.blueprintsprocessor.services.workflow.BlueprintDGExecutionService +import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException +import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintCatalogService +import org.onap.ccsdk.apps.controllerblueprints.core.utils.BluePrintFileUtils import org.onap.ccsdk.apps.controllerblueprints.core.utils.BluePrintMetadataUtils import org.slf4j.LoggerFactory +import org.springframework.http.codec.multipart.FilePart import org.springframework.stereotype.Service +import reactor.core.publisher.Mono @Service -class ExecutionServiceHandler(private val bluePrintCatalogService: BluePrintCatalogService, +class ExecutionServiceHandler(private val bluePrintCoreConfiguration: BluePrintCoreConfiguration, + private val bluePrintCatalogService: BluePrintCatalogService, private val blueprintDGExecutionService: BlueprintDGExecutionService) { private val log = LoggerFactory.getLogger(ExecutionServiceHandler::class.toString()) + fun upload(filePart: FilePart): Mono<String> { + try { + val archivedPath = BluePrintFileUtils.getCbaStorageDirectory(bluePrintCoreConfiguration.archivePath) + val cbaPath = saveCBAFile(filePart, archivedPath) + bluePrintCatalogService.saveToDatabase(cbaPath.toFile()).let { + return Mono.just("{\"status\": \"Successfully uploaded blueprint with id($it)\"}") + } + } catch (e: Exception) { + return Mono.error<String>(BluePrintException("Error uploading the CBA file.", e)) + } + } + fun process(executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput { val requestId = executionServiceInput.commonHeader.requestId @@ -47,6 +66,4 @@ class ExecutionServiceHandler(private val bluePrintCatalogService: BluePrintCata return blueprintDGExecutionService.executeDirectedGraph(blueprintRuntimeService, executionServiceInput) } - - }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/utils/TimeUtils.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/utils/Utils.kt index 78fd022fe..6d22fdab5 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/utils/TimeUtils.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/utils/Utils.kt @@ -15,9 +15,16 @@ */ package org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api.utils +import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintException +import org.springframework.http.codec.multipart.FilePart +import org.springframework.util.StringUtils +import java.io.File +import java.io.IOException +import java.nio.file.Path import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter +import java.util.* fun currentTimestamp(): String { @@ -25,3 +32,28 @@ fun currentTimestamp(): String { val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") return formatter.format(now) } + + +@Throws(BluePrintException::class, IOException::class) +fun saveCBAFile(filePart: FilePart, targetDirectory: Path): Path { + + val fileName = StringUtils.cleanPath(filePart.filename()) + + if (StringUtils.getFilenameExtension(fileName) != "zip") { + throw BluePrintException("Invalid file extension required ZIP") + } + + val changedFileName = UUID.randomUUID().toString() + ".zip" + + val targetLocation = targetDirectory.resolve(changedFileName) + + val file = File(targetLocation.toString()) + if (file.exists()) { + file.delete() + } + file.createNewFile() + + filePart.transferTo(file) + + return targetLocation +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt index 15e6ca946..de1201488 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/ExecutionServiceHandlerTest.kt @@ -17,45 +17,72 @@ package org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith +import org.onap.ccsdk.apps.blueprintsprocessor.core.BluePrintCoreConfiguration import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BluePrintCatalogService import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest import org.springframework.context.annotation.ComponentScan -import org.springframework.test.annotation.DirtiesContext +import org.springframework.core.io.ByteArrayResource +import org.springframework.http.client.MultipartBodyBuilder +import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner +import org.springframework.test.web.reactive.server.WebTestClient +import org.springframework.web.reactive.function.BodyInserters +import java.nio.file.Files import java.nio.file.Paths import kotlin.test.assertTrue -@Ignore @RunWith(SpringRunner::class) -@DirtiesContext -@EnableAutoConfiguration +@WebFluxTest +@ContextConfiguration(classes = [ExecutionServiceHandler::class, BluePrintCoreConfiguration::class, BluePrintCatalogService::class]) @ComponentScan(basePackages = ["org.onap.ccsdk.apps.blueprintsprocessor", "org.onap.ccsdk.apps.controllerblueprints"]) @TestPropertySource(locations = ["classpath:application-test.properties"]) class ExecutionServiceHandlerTest { @Autowired - lateinit var executionServiceHandler: ExecutionServiceHandler - - @Autowired lateinit var blueprintCatalog: BluePrintCatalogService + @Autowired + lateinit var webTestClient: WebTestClient + @Test - fun testProcess() { + fun `test rest upload blueprint`() { val file = Paths.get("./src/test/resources/test-cba.zip").toFile() assertTrue(file.exists(), "couldnt get file ${file.absolutePath}") + val body = MultipartBodyBuilder().apply { + part("file", object : ByteArrayResource(Files.readAllBytes(Paths.get("./src/test/resources/test-cba.zip"))) { + override fun getFilename(): String { + return "test-cba.zip" + } + }) + }.build() + + webTestClient + .post() + .uri("/api/v1/execution-service/upload") + .body(BodyInserters.fromMultipartData(body)) + .exchange() + .expectStatus().isOk + } + + @Test + fun `test rest process`() { + val file = Paths.get("./src/test/resources/test-cba.zip").toFile() + assertTrue(file.exists(), "couldnt get file ${file.absolutePath}") blueprintCatalog.saveToDatabase(file) val executionServiceInput = JacksonUtils.readValueFromClassPathFile("execution-input/default-input.json", ExecutionServiceInput::class.java)!! - - executionServiceHandler.process(executionServiceInput) + webTestClient + .post() + .uri("/api/v1/execution-service/process") + .body(BodyInserters.fromObject(executionServiceInput)) + .exchange() + .expectStatus().isOk } - }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/mock/Mock.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/mock/Mock.kt new file mode 100644 index 000000000..c54e61769 --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/selfservice/api/mock/Mock.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 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. + */ +package org.onap.ccsdk.apps.blueprintsprocessor.selfservice.api.mock + +import org.onap.ccsdk.apps.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.apps.blueprintsprocessor.services.execution.AbstractComponentFunction +import org.onap.ccsdk.apps.controllerblueprints.core.asJsonPrimitive +import org.slf4j.LoggerFactory +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +open class MockComponentConfiguration { + + @Bean(name = ["component-resource-assignment", "component-netconf-executor", "component-jython-executor"]) + open fun createComponentFunction(): AbstractComponentFunction { + return MockComponentFunction() + } +} + +class MockComponentFunction : AbstractComponentFunction() { + + private val log = LoggerFactory.getLogger(MockComponentFunction::class.java) + + override fun process(executionRequest: ExecutionServiceInput) { + log.info("Processing component : $operationInputs") + + bluePrintRuntimeService.setNodeTemplateAttributeValue(nodeTemplateName, + "assignment-params", "params".asJsonPrimitive()) + } + + override fun recover(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) { + log.info("Recovering component..") + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/services/execution/AbstractComponentFunction.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/services/execution/AbstractComponentFunction.kt index c9e147ba5..f7c901dfd 100644 --- a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/services/execution/AbstractComponentFunction.kt +++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/services/execution/AbstractComponentFunction.kt @@ -53,17 +53,17 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic return stepName
}
- override fun prepareRequest(executionServiceInput: ExecutionServiceInput): ExecutionServiceInput {
+ override fun prepareRequest(executionRequest: ExecutionServiceInput): ExecutionServiceInput { checkNotNull(bluePrintRuntimeService) { "failed to prepare blueprint runtime" }
check(stepName.isNotEmpty()) { "failed to assign step name" }
- this.executionServiceInput = executionServiceInput
+ this.executionServiceInput = executionRequest - processId = executionServiceInput.commonHeader.requestId
+ processId = executionRequest.commonHeader.requestId check(processId.isNotEmpty()) { "couldn't get process id for step($stepName)" }
- workflowName = executionServiceInput.actionIdentifiers.actionName
+ workflowName = executionRequest.actionIdentifiers.actionName check(workflowName.isNotEmpty()) { "couldn't get action name for step($stepName)" }
log.info("preparing request id($processId) for workflow($workflowName) step($stepName)")
@@ -88,12 +88,14 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic this.operationInputs.putAll(operationResolvedProperties)
- return executionServiceInput
+ return executionRequest }
override fun prepareResponse(): ExecutionServiceOutput {
log.info("Preparing Response...")
executionServiceOutput.commonHeader = executionServiceInput.commonHeader
+ executionServiceOutput.actionIdentifiers = executionServiceInput.actionIdentifiers + executionServiceOutput.payload = executionServiceInput.payload // Resolve the Output Expression
val stepOutputs = bluePrintRuntimeService
|