diff options
52 files changed, 2494 insertions, 65 deletions
diff --git a/ms/blueprintsprocessor/application/pom.xml b/ms/blueprintsprocessor/application/pom.xml index b75e16134..a6dd73ba6 100755 --- a/ms/blueprintsprocessor/application/pom.xml +++ b/ms/blueprintsprocessor/application/pom.xml @@ -46,9 +46,9 @@ <dependencies> <dependency> - <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> - <artifactId>blueprint-core</artifactId> - <exclusions> + <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> + <artifactId>blueprint-core</artifactId> + <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> @@ -66,6 +66,12 @@ </exclusions> </dependency> + <!-- Error Catalog Services --> + <dependency> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog-services</artifactId> + </dependency> + <!-- North Bound --> <dependency> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> @@ -306,6 +312,10 @@ <target>1.8</target> </configuration> </plugin> + <plugin> + <groupId>pl.project13.maven</groupId> + <artifactId>git-commit-id-plugin</artifactId> + </plugin> </plugins> </build> diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintDatabaseConfiguration.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintDatabaseConfiguration.kt index 58464cb10..2e268c356 100644 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintDatabaseConfiguration.kt +++ b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintDatabaseConfiguration.kt @@ -31,7 +31,8 @@ import javax.sql.DataSource @Configuration @Import(BluePrintDBLibConfiguration::class) @EnableJpaRepositories( - basePackages = ["org.onap.ccsdk.cds.controllerblueprints", "org.onap.ccsdk.cds.blueprintsprocessor"], + basePackages = ["org.onap.ccsdk.cds.controllerblueprints", "org.onap.ccsdk.cds.blueprintsprocessor", + "org.onap.ccsdk.error.catalog"], entityManagerFactoryRef = "primaryEntityManager", transactionManagerRef = "primaryTransactionManager" ) @@ -43,7 +44,8 @@ open class BlueprintDatabaseConfiguration(primaryDataSourceProperties: PrimaryDa open fun primaryEntityManager(): LocalContainerEntityManagerFactoryBean { return primaryEntityManager( "org.onap.ccsdk.cds.controllerblueprints", - "org.onap.ccsdk.cds.blueprintsprocessor" + "org.onap.ccsdk.cds.blueprintsprocessor", + "org.onap.ccsdk.error.catalog" ) } diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.kt index 1d1baeeef..7a888f95c 100644 --- a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.kt +++ b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorApplication.kt @@ -30,7 +30,10 @@ import org.springframework.context.annotation.ComponentScan */ @SpringBootApplication @EnableAutoConfiguration(exclude = [DataSourceAutoConfiguration::class, HazelcastAutoConfiguration::class]) -@ComponentScan(basePackages = ["org.onap.ccsdk.cds.blueprintsprocessor", "org.onap.ccsdk.cds.controllerblueprints"]) +@ComponentScan( + basePackages = ["org.onap.ccsdk.error.catalog", + "org.onap.ccsdk.cds.blueprintsprocessor", "org.onap.ccsdk.cds.controllerblueprints"] +) open class BlueprintProcessorApplication fun main(args: Array<String>) { diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorExceptionHandler.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorExceptionHandler.kt new file mode 100644 index 000000000..6fcbdfdb7 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintProcessorExceptionHandler.kt @@ -0,0 +1,25 @@ +/* + * Copyright © 2018-2019 AT&T 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 + +import org.onap.ccsdk.error.catalog.services.ErrorCatalogExceptionHandler +import org.onap.ccsdk.error.catalog.services.ErrorCatalogService +import org.springframework.web.bind.annotation.RestControllerAdvice + +@RestControllerAdvice("org.onap.ccsdk.cds") +open class BlueprintProcessorExceptionHandler(private val errorCatalogService: ErrorCatalogService) : + ErrorCatalogExceptionHandler(errorCatalogService) diff --git a/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties b/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties index fffc2f4c6..671000992 100755 --- a/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties +++ b/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties @@ -27,6 +27,11 @@ server.port=8081 security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu security.user.name: ccsdkapps +# Error Managements +error.catalog.applicationId=cds +error.catalog.type=properties +error.catalog.defaultDirectory=/opt/app/onap/config + ### START -Controller Blueprints Properties # Load Resource Source Mappings resourceSourceMappings=processor-db=source-db,input=source-input,default=source-default,sdnc=source-rest,aai-data=source-rest,capability=source-capability,vault-data=source-rest,rest=source-rest,script=source-capability @@ -137,4 +142,4 @@ blueprintsprocessor.messageproducer.self-service-api.topic=producer.t #blueprintsprocessor.messageconsumer.prioritize-input.type=kafka-streams-basic-auth #blueprintsprocessor.messageconsumer.prioritize-input.bootstrapServers=127.0.0.1:9092 #blueprintsprocessor.messageconsumer.prioritize-input.applicationId=cds-controller -#blueprintsprocessor.messageconsumer.prioritize-input.topic=prioritize-input-topic
\ No newline at end of file +#blueprintsprocessor.messageconsumer.prioritize-input.topic=prioritize-input-topic diff --git a/ms/blueprintsprocessor/application/src/main/resources/application.properties b/ms/blueprintsprocessor/application/src/main/resources/application.properties index d6082bfa9..412fa3a33 100755 --- a/ms/blueprintsprocessor/application/src/main/resources/application.properties +++ b/ms/blueprintsprocessor/application/src/main/resources/application.properties @@ -60,6 +60,11 @@ blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu security.user.name: ccsdkapps +# Error Managements +error.catalog.applicationId=cds +error.catalog.type=properties +error.catalog.defaultDirectory=/opt/app/onap/config + # Used in Health Check #endpoints.user.name=ccsdkapps #endpoints.user.password=ccsdkapps @@ -130,5 +135,4 @@ cdslistener.healthcheck.mapping-service-name-with-service-link=[SDC Listener ser #Actuator properties management.endpoints.web.exposure.include=* management.endpoint.health.show-details=always - - +management.info.git.mode=full diff --git a/ms/blueprintsprocessor/application/src/main/resources/error-messages_en.properties b/ms/blueprintsprocessor/application/src/main/resources/error-messages_en.properties new file mode 100644 index 000000000..246a1d511 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/main/resources/error-messages_en.properties @@ -0,0 +1,32 @@ +# +# Copyright © 2018-2019 AT&T 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. +# +org.onap.ccsdk.cds.blueprintsprocessor.generic_failure=cause=Internal error in Blueprint Processor run time.,action=Contact CDS administrator team. +org.onap.ccsdk.cds.sdclistener.generic_failure=cause=Internal error in SDC Listener.,action=Contact CDS administrator team. +org.onap.ccsdk.cds.blueprintsprocessor.functions.python.executor.generic_failure=cause=Internal error in Blueprint Processor run time.,action=Contact CDS administrator team. +org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.generic_process_failure=cause=Internal error while processing REST call to the Self Service API.,action=Verify the request and try again. +org.onap.ccsdk.cds.blueprintsprocessor.resource.resolution.resolution_failure=cause=Fail to process Resource Resolution.,action=Verify the resource definitions. +org.onap.ccsdk.cds.blueprintsprocessor.resource.resolution.internal_error=cause=Internal error while processing Resource Resolution.,action=Verify the payload. +org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.invalid_file_extension=cause=Failed trying to upload a non ZIP file format.,action=Please reload your file and make sure it is in ZIP format. +org.onap.ccsdk.cds.blueprintsprocessor.resource_path_missing=cause=Resource path missing or wrong.,action=Please reload your artifact in run time. +org.onap.ccsdk.cds.blueprintsprocessor.resource_writing_fail=cause=Fail to write resources files.,action=Please reload your files and make sure it is in the right format. +org.onap.ccsdk.cds.blueprintsprocessor.io_file_interrupt=cause=IO file system interruption.,action=Please reload your file and make sure it is in the right format. +org.onap.ccsdk.cds.blueprintsprocessor.invalid_request_format=cause=bad request provided.,action=Verify the request payload. +org.onap.ccsdk.cds.blueprintsprocessor.unauthorized_request=cause=The request requires user authentication.,action=Please provide the right credentials. +org.onap.ccsdk.cds.blueprintsprocessor.request_not_found=cause=Request mapping doesn't exist.,action=Please verify your request. +org.onap.ccsdk.cds.blueprintsprocessor.conflict_adding_resource=cause=Duplicated entry while saving resource.,action=Please make the saving model doesn't exist. +org.onap.ccsdk.cds.blueprintsprocessor.duplicate_data=cause=Duplicated data - was expecting one result, got more than one.,action=Please provide single resource at a time. +org.onap.ccsdk.cds.blueprintsprocessor.resource_not_found=cause=No response was found for this request in the server.,action=Provide the ID to find the resource. +org.onap.ccsdk.cds.blueprintsprocessor.unsupported_media_type=cause=An invalid media was provided.,action=Please make sure your media or artifact is in the proper structure or format. diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/ErrorCatalogTestConfiguration.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/ErrorCatalogTestConfiguration.kt new file mode 100644 index 000000000..74a17fa1d --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/ErrorCatalogTestConfiguration.kt @@ -0,0 +1,28 @@ +/* + * Copyright © 2020 IBM, 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.cds.blueprintsprocessor.uat + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration + +@Configuration +@ComponentScan( + basePackages = ["org.onap.ccsdk.error.catalog"] +) +@EnableAutoConfiguration +open class ErrorCatalogTestConfiguration diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/error/ErrorCatalogServiceTest.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/error/ErrorCatalogServiceTest.kt new file mode 100644 index 000000000..8e399fd1a --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/uat/error/ErrorCatalogServiceTest.kt @@ -0,0 +1,97 @@ +/* + * Copyright © 2020 IBM, 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.cds.blueprintsprocessor.uat.error + +import org.junit.runner.RunWith +import org.onap.ccsdk.cds.blueprintsprocessor.uat.ErrorCatalogTestConfiguration +import org.onap.ccsdk.cds.controllerblueprints.core.grpcProcessorException +import org.onap.ccsdk.cds.controllerblueprints.core.httpProcessorException +import org.onap.ccsdk.error.catalog.core.ErrorCatalog +import org.onap.ccsdk.error.catalog.core.ErrorCatalogCodes +import org.onap.ccsdk.error.catalog.core.ErrorMessage +import org.onap.ccsdk.error.catalog.core.ErrorPayload +import org.onap.ccsdk.error.catalog.services.ErrorCatalogService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit4.SpringRunner +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertTrue + +@RunWith(SpringRunner::class) +@ContextConfiguration( + classes = [ErrorCatalogTestConfiguration::class] +) +@TestPropertySource(locations = ["classpath:application-test.properties"]) +class ErrorCatalogServiceTest { + @Autowired + lateinit var errorCatalogService: ErrorCatalogService + + private val domain = "org.onap.ccsdk.cds.blueprintsprocessor" + private lateinit var errorType: String + private lateinit var errorCatalogHttp: ErrorCatalog + private lateinit var errorCatalogGrpc: ErrorCatalog + private lateinit var errorPayloadHttp: ErrorPayload + private lateinit var errorPayloadGrpc: ErrorPayload + + @BeforeTest + fun setup() { + errorType = ErrorCatalogCodes.GENERIC_FAILURE + errorCatalogHttp = ErrorCatalog(errorType, domain, 500, + "Contact CDS administrator team.", "Internal error in Blueprint Processor run time.") + errorCatalogGrpc = ErrorCatalog(errorType, domain, 2, + "Contact CDS administrator team.", "Internal error in Blueprint Processor run time.") + + errorPayloadHttp = ErrorPayload(500, ErrorCatalogCodes.GENERIC_FAILURE, + "Cause: Internal error in Blueprint Processor run time. \n Action : Contact CDS administrator team.", + errorMessage = ErrorMessage("org.onap.ccsdk.cds.blueprintsprocessor", + "Internal error in Blueprint Processor run time.", "")) + errorPayloadGrpc = ErrorPayload(2, ErrorCatalogCodes.GENERIC_FAILURE, + "Cause: Internal error in Blueprint Processor run time. \n Action : Contact CDS administrator team.", + errorMessage = ErrorMessage("org.onap.ccsdk.cds.blueprintsprocessor", + "Internal error in Blueprint Processor run time.", "")) + } + + @Test + fun errorPayloadHttp() { + val errorPayload = errorCatalogService.errorPayload(httpProcessorException(errorType, domain, + "Internal error in Blueprint Processor run time.")) + assertTrue { errorPayload.isEqualTo(errorPayloadHttp) } + } + + @Test + fun errorPayloadGrpc() { + val errorPayload = errorCatalogService.errorPayload(grpcProcessorException(errorType, domain, + "Internal error in Blueprint Processor run time.")) + assertTrue { errorPayload.isEqualTo(errorPayloadGrpc) } + } + + @Test + fun getErrorCatalogHttp() { + val errorCatalog = errorCatalogService.getErrorCatalog(httpProcessorException(errorType, domain, + "Internal error in Blueprint Processor run time.")) + assertTrue { errorCatalog == errorCatalogHttp } + } + + @Test + fun getErrorCatalogGrpc() { + val errorCatalog = errorCatalogService.getErrorCatalog(grpcProcessorException(errorType, domain, + "Internal error in Blueprint Processor run time.")) + assertTrue { errorCatalog == errorCatalogGrpc } + } +} diff --git a/ms/blueprintsprocessor/application/src/test/resources/application-test.properties b/ms/blueprintsprocessor/application/src/test/resources/application-test.properties index 1d2565be3..83589403d 100644 --- a/ms/blueprintsprocessor/application/src/test/resources/application-test.properties +++ b/ms/blueprintsprocessor/application/src/test/resources/application-test.properties @@ -16,6 +16,11 @@ spring.http.log-request-details=true +# Error Managements +error.catalog.applicationId=cds +error.catalog.type=properties +error.catalog.defaultDirectory=./src/test/resources/ + blueprintsprocessor.httpPort=0 blueprintsprocessor.grpcEnable=true blueprintsprocessor.grpcPort=0 @@ -61,4 +66,3 @@ blueprintprocessor.healthcheck.mapping-service-name-with-service-link=[Execution #BaseUrls for health check Cds Listener services cdslistener.healthcheck.baseUrl=http://cds-sdc-listener:8080/ cdslistener.healthcheck.mapping-service-name-with-service-link=[SDC Listener service,/api/v1/sdclistener/healthcheck] - diff --git a/ms/blueprintsprocessor/application/src/test/resources/application.properties b/ms/blueprintsprocessor/application/src/test/resources/application.properties index ea14c493a..eabc141f9 100644 --- a/ms/blueprintsprocessor/application/src/test/resources/application.properties +++ b/ms/blueprintsprocessor/application/src/test/resources/application.properties @@ -61,6 +61,11 @@ blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts security.user.password:{bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu security.user.name:ccsdkapps +# Error Managements +error.catalog.applicationId=cds +error.catalog.type=properties +error.catalog.defaultDirectory=/opt/app/onap/config + # Executor Options blueprintsprocessor.resourceResolution.enabled=true blueprintsprocessor.netconfExecutor.enabled=true diff --git a/ms/blueprintsprocessor/application/src/test/resources/error-messages_en.properties b/ms/blueprintsprocessor/application/src/test/resources/error-messages_en.properties new file mode 100644 index 000000000..246a1d511 --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/resources/error-messages_en.properties @@ -0,0 +1,32 @@ +# +# Copyright © 2018-2019 AT&T 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. +# +org.onap.ccsdk.cds.blueprintsprocessor.generic_failure=cause=Internal error in Blueprint Processor run time.,action=Contact CDS administrator team. +org.onap.ccsdk.cds.sdclistener.generic_failure=cause=Internal error in SDC Listener.,action=Contact CDS administrator team. +org.onap.ccsdk.cds.blueprintsprocessor.functions.python.executor.generic_failure=cause=Internal error in Blueprint Processor run time.,action=Contact CDS administrator team. +org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.generic_process_failure=cause=Internal error while processing REST call to the Self Service API.,action=Verify the request and try again. +org.onap.ccsdk.cds.blueprintsprocessor.resource.resolution.resolution_failure=cause=Fail to process Resource Resolution.,action=Verify the resource definitions. +org.onap.ccsdk.cds.blueprintsprocessor.resource.resolution.internal_error=cause=Internal error while processing Resource Resolution.,action=Verify the payload. +org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.invalid_file_extension=cause=Failed trying to upload a non ZIP file format.,action=Please reload your file and make sure it is in ZIP format. +org.onap.ccsdk.cds.blueprintsprocessor.resource_path_missing=cause=Resource path missing or wrong.,action=Please reload your artifact in run time. +org.onap.ccsdk.cds.blueprintsprocessor.resource_writing_fail=cause=Fail to write resources files.,action=Please reload your files and make sure it is in the right format. +org.onap.ccsdk.cds.blueprintsprocessor.io_file_interrupt=cause=IO file system interruption.,action=Please reload your file and make sure it is in the right format. +org.onap.ccsdk.cds.blueprintsprocessor.invalid_request_format=cause=bad request provided.,action=Verify the request payload. +org.onap.ccsdk.cds.blueprintsprocessor.unauthorized_request=cause=The request requires user authentication.,action=Please provide the right credentials. +org.onap.ccsdk.cds.blueprintsprocessor.request_not_found=cause=Request mapping doesn't exist.,action=Please verify your request. +org.onap.ccsdk.cds.blueprintsprocessor.conflict_adding_resource=cause=Duplicated entry while saving resource.,action=Please make the saving model doesn't exist. +org.onap.ccsdk.cds.blueprintsprocessor.duplicate_data=cause=Duplicated data - was expecting one result, got more than one.,action=Please provide single resource at a time. +org.onap.ccsdk.cds.blueprintsprocessor.resource_not_found=cause=No response was found for this request in the server.,action=Provide the ID to find the resource. +org.onap.ccsdk.cds.blueprintsprocessor.unsupported_media_type=cause=An invalid media was provided.,action=Please make sure your media or artifact is in the proper structure or format. diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintException.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintException.kt index a2435da13..74e6bb6bd 100644 --- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintException.kt +++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintException.kt @@ -1,5 +1,6 @@ /* * Copyright © 2017-2018 AT&T Intellectual Property. + * Modifications Copyright © 2018 - 2020 IBM, Bell Canada. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,29 +22,13 @@ package org.onap.ccsdk.cds.controllerblueprints.core * * @author Brinda Santh */ -class BluePrintException : Exception { - - var code: Int = 100 +class BluePrintException : BluePrintProcessorException { constructor(cause: Throwable) : super(cause) constructor(message: String) : super(message) constructor(message: String, cause: Throwable) : super(message, cause) - constructor(cause: Throwable, message: String, vararg args: Any?) : super(String.format(message, *args), cause) - - constructor(code: Int, cause: Throwable) : super(cause) { - this.code = code - } - - constructor(code: Int, message: String) : super(message) { - this.code = code - } - - constructor(code: Int, message: String, cause: Throwable) : super(message, cause) { - this.code = code - } - - constructor(code: Int, cause: Throwable, message: String, vararg args: Any?) : - super(String.format(message, *args), cause) { - this.code = code - } + constructor(cause: Throwable, message: String, vararg args: Any?) : super(cause, message, args) + constructor(code: Int, cause: Throwable) : super(code, cause) + constructor(code: Int, message: String) : super(code, message) + constructor(code: Int, message: String, cause: Throwable) : super(code, message, cause) } diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintProcessorException.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintProcessorException.kt index b0b217051..50b6614ad 100644 --- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintProcessorException.kt +++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintProcessorException.kt @@ -1,6 +1,6 @@ /* * Copyright © 2017-2018 AT&T Intellectual Property. - * Modifications Copyright © 2018 IBM. + * Modifications Copyright © 2018 - 2020 IBM, Bell Canada. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,35 +17,55 @@ package org.onap.ccsdk.cds.controllerblueprints.core +import org.onap.ccsdk.error.catalog.core.ErrorCatalogException +import org.onap.ccsdk.error.catalog.core.ErrorCatalogExceptionFluent +import org.onap.ccsdk.error.catalog.core.ErrorMessage + /** * * * @author Brinda Santh */ -class BluePrintProcessorException : RuntimeException { - - var code: Int = 100 +open class BluePrintProcessorException : ErrorCatalogException, ErrorCatalogExceptionFluent<BluePrintProcessorException> { constructor(message: String, cause: Throwable) : super(message, cause) constructor(message: String) : super(message) constructor(cause: Throwable) : super(cause) - constructor(cause: Throwable, message: String, vararg args: Any?) : super(format(message, *args), cause) + constructor(cause: Throwable, message: String, vararg args: Any?) : super(cause, message, args) + constructor(code: Int, cause: Throwable) : super(code, cause) + constructor(code: Int, message: String) : super(code, message) + constructor(code: Int, message: String, cause: Throwable) : super(code, message, cause) + + override fun code(code: Int): BluePrintProcessorException { + return this.updateCode(code) + } + + override fun domain(domain: String): BluePrintProcessorException { + return this.updateDomain(domain) + } + + override fun action(action: String): BluePrintProcessorException { + return this.updateAction(action) + } - constructor(code: Int, cause: Throwable) : super(cause) { - this.code = code + override fun http(type: String): BluePrintProcessorException { + return this.updateHttp(type) } - constructor(code: Int, message: String) : super(message) { - this.code = code + override fun grpc(type: String): BluePrintProcessorException { + return this.updateGrpc(type) } - constructor(code: Int, message: String, cause: Throwable) : super(message, cause) { - this.code = code + override fun payloadMessage(message: String): BluePrintProcessorException { + return this.updatePayloadMessage(message) } - constructor(code: Int, cause: Throwable, message: String, vararg args: Any?) : - super(String.format(message, *args), cause) { - this.code = code + override fun addErrorPayloadMessage(message: String): BluePrintProcessorException { + return this.updateErrorPayloadMessage(message) + } + + override fun addSubError(errorMessage: ErrorMessage): BluePrintProcessorException { + return this.updateSubError(errorMessage) } } @@ -55,3 +75,64 @@ class BluePrintRetryException : RuntimeException { constructor(cause: Throwable) : super(cause) constructor(cause: Throwable, message: String, vararg args: Any?) : super(format(message, *args), cause) } + +/** Extension Functions */ + +fun processorException(message: String): BluePrintProcessorException { + return BluePrintProcessorException(message) +} + +fun processorException(code: Int, message: String): BluePrintProcessorException { + return processorException(message).code(code) +} + +fun httpProcessorException(type: String, message: String): BluePrintProcessorException { + return processorException(message).http(type) +} + +fun grpcProcessorException(type: String, message: String): BluePrintProcessorException { + return processorException(message).grpc(type) +} + +fun httpProcessorException(type: String, domain: String, message: String): BluePrintProcessorException { + val bluePrintProcessorException = processorException(message).http(type) + return bluePrintProcessorException.addDomainAndErrorMessage(domain, message) +} + +fun grpcProcessorException(type: String, domain: String, message: String): BluePrintProcessorException { + val bluePrintProcessorException = processorException(message).grpc(type) + return bluePrintProcessorException.addDomainAndErrorMessage(domain, message) +} + +fun httpProcessorException(type: String, domain: String, message: String, cause: Throwable): + BluePrintProcessorException { + val bluePrintProcessorException = processorException(message).http(type) + return bluePrintProcessorException.addDomainAndErrorMessage(domain, message, cause) +} + +fun grpcProcessorException(type: String, domain: String, message: String, cause: Throwable): + BluePrintProcessorException { + val bluePrintProcessorException = processorException(message).grpc(type) + return bluePrintProcessorException.addDomainAndErrorMessage(domain, message, cause) +} + +fun BluePrintProcessorException.updateErrorMessage(domain: String, message: String, cause: Throwable): + BluePrintProcessorException { + return this.addDomainAndErrorMessage(domain, message, cause).domain(domain) + .addErrorPayloadMessage(message) + .payloadMessage(message) +} + +fun BluePrintProcessorException.updateErrorMessage(domain: String, message: String): BluePrintProcessorException { + return this.addDomainAndErrorMessage(domain, message).domain(domain) + .addErrorPayloadMessage(message) + .payloadMessage(message) +} + +private fun BluePrintProcessorException.addDomainAndErrorMessage( + domain: String, + message: String, + cause: Throwable = Throwable() +): BluePrintProcessorException { + return this.addSubError(ErrorMessage(domain, message, cause.message ?: "")).domain(domain) +} 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 ff9aed664..1f01d1ce3 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 @@ -211,24 +211,28 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint } @PostMapping( - path = arrayOf("/workflow-spec"), produces = arrayOf(MediaType - .APPLICATION_JSON_VALUE), - consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE) + path = arrayOf("/workflow-spec"), produces = arrayOf( + MediaType + .APPLICATION_JSON_VALUE + ), + consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE) ) @ResponseBody @Throws(BluePrintException::class) @PreAuthorize("hasRole('USER')") suspend fun workflowSpec(@RequestBody workFlowSpecReq: WorkFlowSpecRequest): - ResponseEntity<String> = mdcWebCoroutineScope { + ResponseEntity<String> = mdcWebCoroutineScope { var json = bluePrintModelHandler.prepareWorkFlowSpec(workFlowSpecReq) - .asJsonString() + .asJsonString() ResponseEntity(json, HttpStatus.OK) } @GetMapping( - path = arrayOf("/workflows/blueprint-name/{name}/version/{version" + - "}"), - produces = arrayOf(MediaType.APPLICATION_JSON_VALUE) + path = arrayOf( + "/workflows/blueprint-name/{name}/version/{version" + + "}" + ), + produces = arrayOf(MediaType.APPLICATION_JSON_VALUE) ) @ResponseBody @Throws(BluePrintException::class) @@ -240,7 +244,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint @PathVariable(value = "version") version: String ): ResponseEntity<String> = mdcWebCoroutineScope { var json = bluePrintModelHandler.getWorkflowNames(name, version) - .asJsonString() + .asJsonString() ResponseEntity(json, HttpStatus.OK) } } diff --git a/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/ErrorHandling.kt b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/ErrorHandling.kt new file mode 100644 index 000000000..ae91246fe --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/ErrorHandling.kt @@ -0,0 +1,40 @@ +/* + * Copyright © 2018-2019 AT&T 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 + +object DesignerApiDomains { + // Designer Api Domains Constants + const val DESIGNER_API = "org.onap.ccsdk.cds.blueprintsprocessor.designer.api" + const val DESIGNER_API_ENHANCER = "org.onap.ccsdk.cds.blueprintsprocessor.designer.api.enhancer" + const val DESIGNER_API_HANDLER = "org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler" + const val DESIGNER_API_LOAD = "org.onap.ccsdk.cds.blueprintsprocessor.designer.api.load" + const val DESIGNER_API_SERVICE = "org.onap.ccsdk.cds.blueprintsprocessor.designer.api.service" +} + +object DesignerApiHttpErrorCodes { + init { + // Register HttpErrorCodes + // HttpErrorCodes.register("", 200) + } +} + +object DesignerGrpcErrorCodes { + init { + // Register GrpcErrorCodes + // GrpcErrorCodes.register("", 3) + } +} diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/ErrorHandling.kt b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/ErrorHandling.kt new file mode 100644 index 000000000..b37cd0eda --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/ErrorHandling.kt @@ -0,0 +1,36 @@ +/* + * Copyright © 2018-2019 AT&T 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.resource.api + +object ResourceApiDomains { + // Resource Api Domains Constants + const val RESOURCE_API = "org.onap.ccsdk.cds.blueprintsprocessor.resource.api" +} + +object ResourceApiHttpErrorCodes { + init { + // Register HttpErrorCodes + // HttpErrorCodes.register("", 200) + } +} + +object ResourceGrpcErrorCodes { + init { + // Register GrpcErrorCodes + // GrpcErrorCodes.register("", 3) + } +} diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ErrorHandling.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ErrorHandling.kt new file mode 100644 index 000000000..b76bc263a --- /dev/null +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ErrorHandling.kt @@ -0,0 +1,44 @@ +/* + * Copyright © 2018-2019 AT&T 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.selfservice.api + +object SelfServiceApiDomains { + // SelfServiceApi Domains Constants + const val BLUEPRINT_PROCESSOR = "org.onap.ccsdk.cds.blueprintsprocessor" + const val SELF_SERVICE_API = "org.onap.ccsdk.cds.blueprintsprocessor.resource.api" + const val SELF_SERVICE_API_VALIDATOR = "org.onap.ccsdk.cds.blueprintsprocessor.resource.api.validator" + const val NETCONF_EXECUTOR = "org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor" + const val RESOURCE_RESOLUTION = "org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution" + const val RESTCONF_EXECUTOR = "org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor" + const val CLI_EXECUTOR = "org.onap.ccsdk.cds.blueprintsprocessor.functions.cli.executor" + const val PYTHON_EXECUTOR = "org.onap.ccsdk.cds.blueprintsprocessor.functions.python.executor" + const val SDC_LISTENER = "org.onap.ccsdk.cds.sdclistener" +} + +object SelfServiceApiHttpErrorCodes { + init { + // Register HttpErrorCodes + // HttpErrorCodes.register("", 200) + } +} + +object SelfServiceGrpcErrorCodes { + init { + // Register GrpcErrorCodes + // GrpcErrorCodes.register("", 3) + } +} diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt index 8b268d6f8..908c04607 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt @@ -27,7 +27,9 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutp import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.mdcWebCoroutineScope import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.determineHttpStatusCode import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive +import org.onap.ccsdk.cds.controllerblueprints.core.httpProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.logger +import org.onap.ccsdk.error.catalog.core.ErrorCatalogCodes import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.http.ResponseEntity @@ -81,7 +83,9 @@ open class ExecutionServiceController { ): ResponseEntity<ExecutionServiceOutput> = mdcWebCoroutineScope { if (executionServiceInput.actionIdentifiers.mode == ACTION_MODE_ASYNC) { - throw IllegalStateException("Can't process async request through the REST endpoint. Use gRPC for async processing.") + throw httpProcessorException(ErrorCatalogCodes.GENERIC_FAILURE, + SelfServiceApiDomains.BLUEPRINT_PROCESSOR, + "Can't process async request through the REST endpoint. Use gRPC for async processing.") } ph.register() val processResult = executionServiceHandler.doProcess(executionServiceInput) diff --git a/ms/blueprintsprocessor/parent/pom.xml b/ms/blueprintsprocessor/parent/pom.xml index d1de10845..8349fa79a 100755 --- a/ms/blueprintsprocessor/parent/pom.xml +++ b/ms/blueprintsprocessor/parent/pom.xml @@ -35,6 +35,7 @@ <sli.version>${ccsdk.sli.core.version}</sli.version> <!-- Override CDS version from parent to be project.version --> <ccsdk.cds.version>${project.version}</ccsdk.cds.version> + <error.catalog.version>${project.version}</error.catalog.version> <dmaap.client.version>1.1.5</dmaap.client.version> <!-- Should be using released artifact as soon as available: --> <!-- https://github.com/springfox/springfox/milestone/44 --> @@ -291,6 +292,30 @@ <version>${kafka.version}</version> </dependency> + <!-- Error Catalog --> + <dependency> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog-core</artifactId> + <version>${error.catalog.version}</version> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog-services</artifactId> + <version>${error.catalog.version}</version> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <!-- SLI Version --> <dependency> <groupId>org.onap.ccsdk.sli.core</groupId> @@ -689,6 +714,11 @@ <groupId>io.netty</groupId> <artifactId>netty-tcnative-boringssl-static</artifactId> </dependency> + + <dependency> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog-core</artifactId> + </dependency> </dependencies> <repositories> diff --git a/ms/error-catalog/README.md b/ms/error-catalog/README.md new file mode 100755 index 000000000..d6ae56d02 --- /dev/null +++ b/ms/error-catalog/README.md @@ -0,0 +1,36 @@ +## How to use library + +##### 1. Set Error Catalog service type (Database or properties file service) in application.properties file + +``` +##### Error Managements ##### +## For database service type ## +# error.catalog.type=DB +## For database service type ## +# error.catalog.type=properties +error.catalog.applicationId=cds +error.catalog.type=properties +``` + +##### 2. Generate exception + +- HTTP Error Exception +``` +errorCatalogException: ErrorCatalogException = httpProcessorException(ErrorCatalogCodes.ERROR_TYPE, +"Error message here...") +``` + +- GRPC Error Exception +``` +errorCatalogException: ErrorCatalogException = grpcProcessorException(ErrorCatalogCodes.ERROR_TYPE, +"Error message here...") +``` + +##### 3. Update an existing exception +``` +e = errorCatalogException.code(500) +e = errorCatalogException.action("message") +... +``` + +##### 4. Add a HTTP REST Exception handler
\ No newline at end of file diff --git a/ms/error-catalog/application/pom.xml b/ms/error-catalog/application/pom.xml new file mode 100644 index 000000000..dc9d3120b --- /dev/null +++ b/ms/error-catalog/application/pom.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2018-2019 AT&T 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog</artifactId> + <version>0.7.0-SNAPSHOT</version> + </parent> + + <artifactId>error-catalog-application</artifactId> + + <name>Error Catalog Application</name> + <description>Error Catalog Application</description> +</project> diff --git a/ms/error-catalog/core/pom.xml b/ms/error-catalog/core/pom.xml new file mode 100644 index 000000000..7a46dbc7c --- /dev/null +++ b/ms/error-catalog/core/pom.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2018-2019 AT&T 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog</artifactId> + <version>0.7.0-SNAPSHOT</version> + </parent> + + <artifactId>error-catalog-core</artifactId> + + <name>Error Catalog Core</name> + <description>Error Catalog Core</description> +</project> diff --git a/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCatalogException.kt b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCatalogException.kt new file mode 100644 index 000000000..76f9cc0f1 --- /dev/null +++ b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCatalogException.kt @@ -0,0 +1,112 @@ +/* + * Copyright © 2020 IBM, Bell Canada. + * Modifications Copyright © 2019-2020 AT&T 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.error.catalog.core + +interface ErrorCatalogExceptionFluent<T> { + fun code(code: Int): T + fun domain(domain: String): T + fun action(action: String): T + fun http(type: String): T + fun grpc(type: String): T + fun payloadMessage(message: String): T + fun addErrorPayloadMessage(message: String): T + fun addSubError(errorMessage: ErrorMessage): T +} + +open class ErrorCatalogException : RuntimeException { + var code: Int = -1 + var domain: String = "" + var name: String = ErrorCatalogCodes.GENERIC_FAILURE + var action: String = "" + var errorPayload: ErrorPayload? = null + var protocol: String = "" + var errorPayloadMessages: MutableList<String>? = null + + val messageSeparator = "${System.lineSeparator()} -> " + + constructor(message: String, cause: Throwable) : super(message, cause) + constructor(message: String) : super(message) + constructor(cause: Throwable) : super(cause) + constructor(cause: Throwable, message: String, vararg args: Any?) : super(format(message, *args), cause) + + constructor(code: Int, cause: Throwable) : super(cause) { + this.code = code + } + + constructor(code: Int, message: String) : super(message) { + this.code = code + } + + constructor(code: Int, message: String, cause: Throwable) : super(message, cause) { + this.code = code + } + + constructor(code: Int, cause: Throwable, message: String, vararg args: Any?) : + super(String.format(message, *args), cause) { + this.code = code + } + + open fun <T : ErrorCatalogException> updateCode(code: Int): T { + this.code = code + return this as T + } + + open fun <T : ErrorCatalogException> updateDomain(domain: String): T { + this.domain = domain + return this as T + } + + open fun <T : ErrorCatalogException> updateAction(action: String): T { + this.action = action + return this as T + } + + fun <T : ErrorCatalogException> updateHttp(type: String): T { + this.protocol = ErrorMessageLibConstants.ERROR_CATALOG_PROTOCOL_HTTP + this.code = HttpErrorCodes.code(type) + return this as T + } + + fun <T : ErrorCatalogException> updateGrpc(type: String): T { + this.protocol = ErrorMessageLibConstants.ERROR_CATALOG_PROTOCOL_GRPC + this.code = GrpcErrorCodes.code(type) + return this as T + } + + fun <T : ErrorCatalogException> updatePayloadMessage(message: String): T { + if (this.errorPayloadMessages == null) this.errorPayloadMessages = arrayListOf() + this.errorPayloadMessages!!.add(message) + return this as T + } + + fun <T : ErrorCatalogException> updateErrorPayloadMessage(message: String): T { + if (errorPayload == null) { + errorPayload = ErrorPayload() + } + errorPayload!!.message = "${errorPayload!!.message} $messageSeparator $message" + return this as T + } + + fun <T : ErrorCatalogException> updateSubError(errorMessage: ErrorMessage): T { + if (errorPayload == null) { + errorPayload = ErrorPayload() + } + errorPayload!!.subErrors.add(errorMessage) + return this as T + } +} diff --git a/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCatalogExtensions.kt b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCatalogExtensions.kt new file mode 100644 index 000000000..76011b27d --- /dev/null +++ b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCatalogExtensions.kt @@ -0,0 +1,32 @@ +/* + * Copyright © 2018-2019 AT&T 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.error.catalog.core + +import org.slf4j.LoggerFactory +import org.slf4j.helpers.MessageFormatter +import kotlin.reflect.KClass + +fun <T : Any> logger(clazz: T) = LoggerFactory.getLogger(clazz.javaClass)!! + +fun <T : KClass<*>> logger(clazz: T) = LoggerFactory.getLogger(clazz.java)!! + +fun format(message: String, vararg args: Any?): String { + if (args != null && args.isNotEmpty()) { + return MessageFormatter.arrayFormat(message, args).message + } + return message +} diff --git a/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCodes.kt b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCodes.kt new file mode 100644 index 000000000..241e9d238 --- /dev/null +++ b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorCodes.kt @@ -0,0 +1,88 @@ +/* + * Copyright © 2018-2019 AT&T 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.error.catalog.core + +object ErrorCatalogCodes { + const val GENERIC_FAILURE = "GENERIC_FAILURE" + const val GENERIC_PROCESS_FAILURE = "GENERIC_PROCESS_FAILURE" + const val INVALID_FILE_EXTENSION = "INVALID_FILE_EXTENSION" + const val RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND" + const val RESOURCE_PATH_MISSING = "RESOURCE_PATH_MISSING" + const val RESOURCE_WRITING_FAIL = "RESOURCE_WRITING_FAIL" + const val IO_FILE_INTERRUPT = "IO_FILE_INTERRUPT" + const val INVALID_REQUEST_FORMAT = "INVALID_REQUEST_FORMAT" + const val UNAUTHORIZED_REQUEST = "UNAUTHORIZED_REQUEST" + const val REQUEST_NOT_FOUND = "REQUEST_NOT_FOUND" + const val CONFLICT_ADDING_RESOURCE = "CONFLICT_ADDING_RESOURCE" + const val DUPLICATE_DATA = "DUPLICATE_DATA" +} + +object HttpErrorCodes { + private val store: MutableMap<String, Int> = mutableMapOf() + + init { + store[ErrorCatalogCodes.GENERIC_FAILURE] = 500 + store[ErrorCatalogCodes.GENERIC_PROCESS_FAILURE] = 500 + store[ErrorCatalogCodes.INVALID_FILE_EXTENSION] = 415 + store[ErrorCatalogCodes.RESOURCE_NOT_FOUND] = 404 + store[ErrorCatalogCodes.RESOURCE_PATH_MISSING] = 503 + store[ErrorCatalogCodes.RESOURCE_WRITING_FAIL] = 503 + store[ErrorCatalogCodes.IO_FILE_INTERRUPT] = 503 + store[ErrorCatalogCodes.INVALID_REQUEST_FORMAT] = 400 + store[ErrorCatalogCodes.UNAUTHORIZED_REQUEST] = 401 + store[ErrorCatalogCodes.REQUEST_NOT_FOUND] = 404 + store[ErrorCatalogCodes.CONFLICT_ADDING_RESOURCE] = 409 + store[ErrorCatalogCodes.DUPLICATE_DATA] = 409 + } + + fun register(type: String, code: Int) { + store[type] = code + } + + fun code(type: String): Int { + // FIXME("Return Default Error Code , If missing") + return store[type]!! + } +} + +object GrpcErrorCodes { + private val store: MutableMap<String, Int> = mutableMapOf() + + init { + store[ErrorCatalogCodes.GENERIC_FAILURE] = 2 + store[ErrorCatalogCodes.GENERIC_PROCESS_FAILURE] = 2 + store[ErrorCatalogCodes.INVALID_FILE_EXTENSION] = 3 + store[ErrorCatalogCodes.RESOURCE_NOT_FOUND] = 5 + store[ErrorCatalogCodes.RESOURCE_PATH_MISSING] = 3 + store[ErrorCatalogCodes.RESOURCE_WRITING_FAIL] = 9 + store[ErrorCatalogCodes.IO_FILE_INTERRUPT] = 3 + store[ErrorCatalogCodes.INVALID_REQUEST_FORMAT] = 3 + store[ErrorCatalogCodes.UNAUTHORIZED_REQUEST] = 16 + store[ErrorCatalogCodes.REQUEST_NOT_FOUND] = 8 + store[ErrorCatalogCodes.CONFLICT_ADDING_RESOURCE] = 10 + store[ErrorCatalogCodes.DUPLICATE_DATA] = 11 + } + + fun register(type: String, code: Int) { + store[type] = code + } + + fun code(type: String): Int { + // FIXME("Return Default Error Code , If missing") + return store[type]!! + } +} diff --git a/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorLibData.kt b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorLibData.kt new file mode 100644 index 000000000..b33c118de --- /dev/null +++ b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorLibData.kt @@ -0,0 +1,94 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.core + +import com.fasterxml.jackson.annotation.JsonFormat +import org.slf4j.event.Level +import org.onap.ccsdk.error.catalog.core.ErrorMessageLibConstants.ERROR_CATALOG_DEFAULT_ERROR_CODE +import java.time.LocalDateTime + +open class ErrorPayload { + var code: Int = ERROR_CATALOG_DEFAULT_ERROR_CODE + var status: String = "" + @get:JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") + var timestamp: LocalDateTime = LocalDateTime.now() + var message: String = "" + var debugMessage: String = "" + var logLevel: String = Level.ERROR.name + val subErrors: ArrayList<ErrorMessage> = ArrayList() + + constructor() + + constructor( + code: Int = ERROR_CATALOG_DEFAULT_ERROR_CODE, + status: String, + message: String, + logLevel: String = Level.ERROR.name, + debugMessage: String = "" + ) { + this.code = code + this.status = status + this.message = message + this.logLevel = logLevel + this.debugMessage = debugMessage + } + + constructor( + code: Int = ERROR_CATALOG_DEFAULT_ERROR_CODE, + status: String, + message: String, + logLevel: String = Level.ERROR.name, + debugMessage: String = "", + errorMessage: ErrorMessage + ) { + this.code = code + this.status = status + this.message = message + this.logLevel = logLevel + this.debugMessage = debugMessage + this.subErrors.add(errorMessage) + } + + fun isEqualTo(errorPayload: ErrorPayload): Boolean { + return (this.code == errorPayload.code && this.status == errorPayload.status && this.message == errorPayload.message && + this.logLevel == errorPayload.logLevel && this.debugMessage == errorPayload.debugMessage && + this.subErrors == errorPayload.subErrors) + } +} + +/** + * + * + * @author Steve Siani + */ +data class ErrorMessage( + val domainId: String, + val message: String, + val cause: String +) + +data class ErrorCatalog( + val errorId: String, + val domainId: String, + val code: Int, + val action: String, + val cause: String +) { + fun getMessage(): String { + return "Cause: $cause ${System.lineSeparator()} Action : $action" + } +} diff --git a/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorMessageLibConstants.kt b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorMessageLibConstants.kt new file mode 100644 index 000000000..ef56e7b79 --- /dev/null +++ b/ms/error-catalog/core/src/main/kotlin/org/onap/ccsdk/error/catalog/core/ErrorMessageLibConstants.kt @@ -0,0 +1,30 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.core + +object ErrorMessageLibConstants { + const val ERROR_CATALOG_DOMAIN = "org.onap.ccsdk.error.catalog" + const val ERROR_CATALOG_TYPE = "error.catalog.type" + const val ERROR_CATALOG_TYPE_PROPERTIES = "properties" + const val ERROR_CATALOG_TYPE_DB = "DB" + const val ERROR_CATALOG_PROPERTIES_FILENAME = "error-messages_en.properties" + const val ERROR_CATALOG_MODELS = "org.onap.ccsdk.error.catalog.domain" + const val ERROR_CATALOG_REPOSITORY = "org.onap.ccsdk.error.catalog.repository" + const val ERROR_CATALOG_DEFAULT_ERROR_CODE = 500 + const val ERROR_CATALOG_PROTOCOL_HTTP = "http" + const val ERROR_CATALOG_PROTOCOL_GRPC = "grpc" +} diff --git a/ms/error-catalog/pom.xml b/ms/error-catalog/pom.xml new file mode 100644 index 000000000..91e13c218 --- /dev/null +++ b/ms/error-catalog/pom.xml @@ -0,0 +1,158 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2018-2019 AT&T 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.cds</groupId> + <artifactId>ms</artifactId> + <version>0.7.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog</artifactId> + <packaging>pom</packaging> + + <name>Error Catalog Lib</name> + <description>Error Catalog Lib for ONAP Components</description> + + <modules> + <module>application</module> + <module>core</module> + <module>services</module> + </modules> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog-services</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> + <!-- Kotlin Dependencies --> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib-common</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-script-util</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib-jdk8</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlinx</groupId> + <artifactId>kotlinx-coroutines-core</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlinx</groupId> + <artifactId>kotlinx-coroutines-reactor</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.module</groupId> + <artifactId>jackson-module-kotlin</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-compiler-embeddable</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-scripting-jvm-host</artifactId> + <!--Use kotlin-compiler-embeddable as koltin-compiler wrap--> + <!--guava dependency creating classpath issues at runtime--> + <exclusions> + <exclusion> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-compiler</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> + </dependency> + <dependency> + <groupId>javax.persistence</groupId> + <artifactId>javax.persistence-api</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.projectreactor</groupId> + <artifactId>reactor-test</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-maven-plugin</artifactId> + <version>${kotlin.maven.version}</version> + <executions> + <execution> + <id>compile</id> + <goals> + <goal>compile</goal> + </goals> + <configuration> + <sourceDirs> + <sourceDir>src/main/kotlin</sourceDir> + </sourceDirs> + </configuration> + </execution> + <execution> + <id>test-compile</id> + <goals> + <goal>test-compile</goal> + </goals> + <configuration> + <sourceDirs> + <sourceDir>${project.basedir}/src/test/kotlin</sourceDir> + </sourceDirs> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/ms/error-catalog/services/pom.xml b/ms/error-catalog/services/pom.xml new file mode 100644 index 000000000..1adbc4086 --- /dev/null +++ b/ms/error-catalog/services/pom.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2018-2019 AT&T 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog</artifactId> + <version>0.7.0-SNAPSHOT</version> + </parent> + + <artifactId>error-catalog-services</artifactId> + + <name>Error Catalog Service</name> + <description>Error Catalog Service</description> + + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.error.catalog</groupId> + <artifactId>error-catalog-core</artifactId> + </dependency> + </dependencies> +</project> diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogConfiguration.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogConfiguration.kt new file mode 100644 index 000000000..8f2440e34 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogConfiguration.kt @@ -0,0 +1,34 @@ +/* + * Copyright © 2020 IBM, Bell Canada. + * Modifications Copyright © 2019-2020 AT&T 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.error.catalog.services + +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.Configuration +import org.springframework.stereotype.Component + +@Configuration +@EnableConfigurationProperties(ErrorCatalogProperties::class) +open class ErrorCatalogConfiguration + +@Component +@ConfigurationProperties(prefix = "error.catalog") +open class ErrorCatalogProperties { + lateinit var type: String + lateinit var applicationId: String + var defaultDirectory: String = "" +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogDBService.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogDBService.kt new file mode 100644 index 000000000..841bcf539 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogDBService.kt @@ -0,0 +1,98 @@ +/* + * Copyright © 2020 IBM, Bell Canada. + * Modifications Copyright © 2019-2020 AT&T 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.error.catalog.services + +import org.onap.ccsdk.error.catalog.core.ErrorMessageLibConstants +import org.onap.ccsdk.error.catalog.services.domain.Domain +import org.onap.ccsdk.error.catalog.services.domain.ErrorMessageModel +import org.onap.ccsdk.error.catalog.services.repository.DomainRepository +import org.onap.ccsdk.error.catalog.services.repository.ErrorMessageModelRepository +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service + +@Service +@ConditionalOnProperty( + name = [ErrorMessageLibConstants.ERROR_CATALOG_TYPE], + havingValue = ErrorMessageLibConstants.ERROR_CATALOG_TYPE_DB +) +open class ErrorCatalogDBService( + private val domainRepository: DomainRepository, + private val errorMessageModelRepository: ErrorMessageModelRepository +) { + + /** + * This is a getAllDomains method to retrieve all the Domain in Error Catalog Database by pages + * + * @return Page<Domain> list of the domains by page + </Domain> */ + open fun getAllDomains(pageRequest: Pageable): Page<Domain> { + return domainRepository.findAll(pageRequest) + } + + /** + * This is a getAllDomains method to retrieve all the Domain in Error Catalog Database + * + * @return List<Domain> list of the domains + </Domain> */ + open fun getAllDomains(): List<Domain> { + return domainRepository.findAll() + } + + /** + * This is a getAllDomainsByApplication method to retrieve all the Domain that belong to an application in Error Catalog Database + * + * @return List<Domain> list of the domains + </Domain> */ + open fun getAllDomainsByApplication(applicationId: String): List<Domain> { + return domainRepository.findAllByApplicationId(applicationId) + } + + /** + * This is a getAllErrorMessagesByApplication method to retrieve all the Messages that belong to an application in Error Catalog Database + * + * @return MutableMap<String, ErrorCode> list of the abstractErrorModel + </Domain> */ + open fun getAllErrorMessagesByApplication(applicationId: String): MutableMap<String, ErrorMessageModel> { + val domains = domainRepository.findAllByApplicationId(applicationId) + val errorMessages = mutableMapOf<String, ErrorMessageModel>() + for (domain in domains) { + val errorMessagesFound = errorMessageModelRepository.findByDomainsId(domain.id) + for (errorMessageFound in errorMessagesFound) { + errorMessages["${domain.name}$MESSAGE_KEY_SEPARATOR${errorMessageFound.messageID}"] = errorMessageFound + } + } + return errorMessages + } + + open fun saveDomain( + domain: String, + applicationId: String, + description: String = "", + errorMessageList: List<ErrorMessageModel> + ) { + val domainModel = Domain(domain, applicationId, description) + domainModel.errorMessages.addAll(errorMessageList) + domainRepository.saveAndFlush(domainModel) + } + + companion object { + private const val MESSAGE_KEY_SEPARATOR = "." + } +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogExceptionHandler.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogExceptionHandler.kt new file mode 100644 index 000000000..91fa97b77 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogExceptionHandler.kt @@ -0,0 +1,31 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.services + +import org.onap.ccsdk.error.catalog.core.ErrorCatalogException +import org.onap.ccsdk.error.catalog.core.ErrorPayload +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ExceptionHandler + +abstract class ErrorCatalogExceptionHandler(private val errorCatalogService: ErrorCatalogService) { + + @ExceptionHandler(ErrorCatalogException::class) + fun errorCatalogException(e: ErrorCatalogException): ResponseEntity<ErrorPayload> { + val errorPayload = errorCatalogService.errorPayload(e) + return errorPayload.toResponseEntity() + } +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogLoadService.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogLoadService.kt new file mode 100644 index 000000000..d1af5fe55 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogLoadService.kt @@ -0,0 +1,145 @@ +/* + * Copyright © 2020 IBM, Bell Canada. + * Modifications Copyright © 2019-2020 AT&T 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.error.catalog.services + +import org.onap.ccsdk.error.catalog.core.ErrorMessageLibConstants +import org.onap.ccsdk.error.catalog.core.logger +import org.onap.ccsdk.error.catalog.services.domain.ErrorMessageModel +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.stereotype.Service +import java.io.FileNotFoundException +import java.io.IOException +import java.io.InputStream +import java.nio.file.Paths +import java.util.Properties + +interface ErrorCatalogLoadService { + + suspend fun loadErrorCatalog() + + fun getErrorMessage(domain: String, key: String): String? + + fun getErrorMessage(attribute: String): String? +} + +/** + * Representation of Blueprint Error Message lib from database service to load the properties + */ +@Service +@ConditionalOnBean(ErrorCatalogDBService::class) +open class ErrorCatalogLoadDBService( + private var errorCatalogProperties: ErrorCatalogProperties, + private var errorCatalogDBService: ErrorCatalogDBService +) : ErrorCatalogLoadService { + + private var log = logger(ErrorCatalogLoadDBService::class) + + lateinit var errorMessageInDB: Map<String, ErrorMessageModel> + + override suspend fun loadErrorCatalog() { + log.info("Application ID: ${errorCatalogProperties.applicationId} > Initializing error catalog message from database...") + errorMessageInDB = getErrorMessagesFromDB() + } + + override fun getErrorMessage(domain: String, key: String): String? { + return getErrorMessage("$domain.${key.toLowerCase()}") + } + + override fun getErrorMessage(attribute: String): String? { + val errorMessage = findErrorMessage(attribute) + return prepareErrorMessage(errorMessage) + } + + /** + * Parses the error-messages.properties file which contains error messages + */ + private suspend fun getErrorMessagesFromDB(): Map<String, ErrorMessageModel> { + return errorCatalogDBService.getAllErrorMessagesByApplication(errorCatalogProperties.applicationId) + } + + private fun findErrorMessage(attribute: String): ErrorMessageModel? { + return if (errorMessageInDB.containsKey(attribute)) { + errorMessageInDB[attribute] + } else { + null + } + } + + private fun prepareErrorMessage(errorMessage: ErrorMessageModel?): String? { + return if (errorMessage != null) { + "cause=${errorMessage.cause}, action=${errorMessage.action}" + } else { + null + } + } +} + +/** + * Representation of Blueprint Error Message lib property service to load the properties + */ +@Service +@ConditionalOnProperty( + name = [ErrorMessageLibConstants.ERROR_CATALOG_TYPE], + havingValue = ErrorMessageLibConstants.ERROR_CATALOG_TYPE_PROPERTIES +) +open class ErrorCatalogLoadPropertyService(private var errorCatalogProperties: ErrorCatalogProperties) : + ErrorCatalogLoadService { + + private val propertyFileName = ErrorMessageLibConstants.ERROR_CATALOG_PROPERTIES_FILENAME + private var propertyFileBaseDirectory = Paths.get(errorCatalogProperties.defaultDirectory) + private var propertyFilePath = propertyFileBaseDirectory.resolve(propertyFileName) + + private var log = logger(ErrorCatalogLoadPropertyService::class) + + lateinit var properties: Properties + + override suspend fun loadErrorCatalog() { + log.info("Application ID: ${errorCatalogProperties.applicationId} > Initializing error catalog message from properties...") + properties = parseErrorMessagesProps() + } + + override fun getErrorMessage(domain: String, key: String): String? { + return getErrorMessage("$domain.${key.toLowerCase()}") + } + + override fun getErrorMessage(attribute: String): String? { + return properties.getProperty(attribute) + } + + /** + * Parses the error-messages.properties file which contains error messages + */ + private fun parseErrorMessagesProps(): Properties { + var inputStream: InputStream? = null + val props = Properties() + try { + inputStream = propertyFilePath.toFile().inputStream() + props.load(inputStream) + } catch (e: FileNotFoundException) { + log.error("Application ID: ${errorCatalogProperties.applicationId} > Property File '$propertyFileName}' " + + "not found in the application directory.") + } catch (e: IOException) { + log.error("Application ID: ${errorCatalogProperties.applicationId} > Fail to load property file " + + "'$propertyFileName}' for message errors.") + } finally { + inputStream!!.close() + } + return props + } +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogService.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogService.kt new file mode 100644 index 000000000..e55e552d9 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogService.kt @@ -0,0 +1,91 @@ +/* + * Copyright © 2020 IBM, Bell Canada. + * Modifications Copyright © 2019-2020 AT&T 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.error.catalog.services + +import kotlinx.coroutines.runBlocking +import org.onap.ccsdk.error.catalog.core.ErrorCatalog +import org.onap.ccsdk.error.catalog.core.ErrorCatalogException +import org.onap.ccsdk.error.catalog.core.ErrorMessageLibConstants +import org.onap.ccsdk.error.catalog.core.ErrorPayload +import org.onap.ccsdk.error.catalog.core.GrpcErrorCodes +import org.onap.ccsdk.error.catalog.core.HttpErrorCodes +import org.onap.ccsdk.error.catalog.services.utils.ErrorCatalogUtils +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean +import org.springframework.stereotype.Service +import javax.annotation.PostConstruct + +@Service +@ConditionalOnBean(ErrorCatalogLoadService::class) +open class ErrorCatalogService(private var errorCatalogLoadService: ErrorCatalogLoadService) { + + @PostConstruct + open fun init() = runBlocking { + errorCatalogLoadService.loadErrorCatalog() + } + + fun errorPayload(errorCatalogException: ErrorCatalogException): ErrorPayload { + val errorCatalog = getErrorCatalog(errorCatalogException) + val errorPayload = ErrorPayload(errorCatalog.code, errorCatalog.errorId, errorCatalog.getMessage()) + errorPayload.subErrors.addAll(errorCatalogException.errorPayload!!.subErrors) + if (errorCatalogException.cause != null) { + errorPayload.debugMessage = errorCatalogException.cause!!.printStackTrace().toString() + } + return errorPayload + } + + fun getErrorCatalog(errorCatalogException: ErrorCatalogException): ErrorCatalog { + val errorMessage = getMessage(errorCatalogException.domain, errorCatalogException.name) + val errorCode = + if (errorCatalogException.code == -1) { + getProtocolErrorCode( + errorCatalogException.protocol, + errorCatalogException.name + ) + } else { + errorCatalogException.code + } + val action: String + val errorCause: String + if (errorMessage.isNullOrEmpty()) { + action = errorCatalogException.action + errorCause = errorCatalogException.message ?: "" + } else { + action = ErrorCatalogUtils.readErrorActionFromMessage(errorMessage) + errorCause = errorCatalogException.message ?: ErrorCatalogUtils.readErrorCauseFromMessage(errorMessage) + } + + return ErrorCatalog( + errorCatalogException.name, + errorCatalogException.domain, + errorCode, + action, + errorCause + ) + } + + private fun getProtocolErrorCode(protocol: String, type: String): Int { + return when (protocol) { + ErrorMessageLibConstants.ERROR_CATALOG_PROTOCOL_GRPC -> GrpcErrorCodes.code(type) + else -> HttpErrorCodes.code(type) + } + } + + private fun getMessage(domain: String, key: String): String? { + return errorCatalogLoadService.getErrorMessage(domain, key) + } +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogServiceExtensions.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogServiceExtensions.kt new file mode 100644 index 000000000..41481623a --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/ErrorCatalogServiceExtensions.kt @@ -0,0 +1,25 @@ +/* + * Copyright © 2018-2019 AT&T 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.error.catalog.services + +import org.onap.ccsdk.error.catalog.core.ErrorPayload +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity + +fun ErrorPayload.toResponseEntity(): ResponseEntity<ErrorPayload> { + return ResponseEntity(this, HttpStatus.resolve(this.code)!!) +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/domain/Domain.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/domain/Domain.kt new file mode 100755 index 000000000..50a05b231 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/domain/Domain.kt @@ -0,0 +1,76 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.services.domain + +import java.io.Serializable +import javax.persistence.CascadeType +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.Id +import javax.persistence.Lob +import javax.persistence.ManyToMany +import javax.persistence.Table +import javax.persistence.UniqueConstraint +import java.util.UUID +import javax.persistence.JoinTable +import javax.persistence.JoinColumn + +/** + * Provide ErrorCode Entity + * + * @author Steve Siani + * @version 1.0 + */ + +@Entity +@Table(name = "ERROR_DOMAINS", uniqueConstraints = [UniqueConstraint(columnNames = ["name", "application_id"])]) +class Domain : Serializable { + @Id + var id: String = UUID.randomUUID().toString() + + @Column(name = "name") + lateinit var name: String + + @Column(name = "application_id") + lateinit var applicationId: String + + @Lob + @Column(name = "description") + var description: String = "" + + @ManyToMany(fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) + @JoinTable( + name = "ERROR_DOMAINS_ERROR_MESSAGES", + joinColumns = [JoinColumn(name = "domain_id", referencedColumnName = "id")], + inverseJoinColumns = [JoinColumn(name = "message_id", referencedColumnName = "id")] + ) + @Column(name = "error_msg") + val errorMessages: MutableSet<ErrorMessageModel> = mutableSetOf() + + constructor() + + constructor(name: String, applicationId: String, description: String) { + this.name = name + this.description = description + this.applicationId = applicationId + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/domain/ErrorMessageModel.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/domain/ErrorMessageModel.kt new file mode 100644 index 000000000..73e143095 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/domain/ErrorMessageModel.kt @@ -0,0 +1,69 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.services.domain + +import java.io.Serializable +import java.util.UUID +import javax.persistence.CascadeType +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.Id +import javax.persistence.Lob +import javax.persistence.ManyToMany +import javax.persistence.Table +import javax.persistence.UniqueConstraint + +/** + * Provide Error Message Model Entity + * + * @author Steve Siani + * @version 1.0 + */ +@Entity +@Table(name = "ERROR_MESSAGES", uniqueConstraints = [UniqueConstraint(columnNames = ["message_id"])]) +class ErrorMessageModel : Serializable { + + @Id + var id: String = UUID.randomUUID().toString() + + @Column(name = "message_id", nullable = false) + lateinit var messageID: String + + @Lob + @Column(name = "cause") + var cause: String = "" + + @Lob + @Column(name = "action") + lateinit var action: String + + @ManyToMany(mappedBy = "errorMessages", fetch = FetchType.EAGER, cascade = [CascadeType.PERSIST]) + val domains: MutableSet<Domain> = mutableSetOf() + + companion object { + private const val serialVersionUID = 1L + } + + constructor() + + constructor(messageId: String, cause: String, action: String) { + this.messageID = messageId + this.cause = cause + this.action = action + } +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/repository/DomainRepository.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/repository/DomainRepository.kt new file mode 100644 index 000000000..700340b10 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/repository/DomainRepository.kt @@ -0,0 +1,45 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.services.repository + +import org.onap.ccsdk.error.catalog.services.domain.Domain +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +/** + * @param <T> Model + */ +@Repository +interface DomainRepository : JpaRepository<Domain, String> { + + /** + * This is a findByNameAndApplicationId method + * + * @param name name + * @param applicationId applicationId + * @return Optional<T> + */ + fun findByNameAndApplicationId(name: String, applicationId: String): Domain? + + /** + * This is a findAllByApplicationId method + * + * @param applicationId applicationId + * @return List<T> + */ + fun findAllByApplicationId(applicationId: String): List<Domain> +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/repository/ErrorMessageModelRepository.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/repository/ErrorMessageModelRepository.kt new file mode 100644 index 000000000..084474970 --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/repository/ErrorMessageModelRepository.kt @@ -0,0 +1,36 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.services.repository + +import org.onap.ccsdk.error.catalog.services.domain.ErrorMessageModel +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +/** + * @param <T> Model + */ +@Repository +interface ErrorMessageModelRepository : JpaRepository<ErrorMessageModel, String> { + + /** + * This is a findByDomains method + * + * @param domainId domainId + * @return List<T> + */ + fun findByDomainsId(domainId: String): List<ErrorMessageModel> +} diff --git a/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/utils/ErrorCatalogUtils.kt b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/utils/ErrorCatalogUtils.kt new file mode 100644 index 000000000..673082eed --- /dev/null +++ b/ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/error/catalog/services/utils/ErrorCatalogUtils.kt @@ -0,0 +1,39 @@ +/* + * Copyright © 2020 IBM, 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.error.catalog.services.utils + +object ErrorCatalogUtils { + private const val REGEX_PATTERN = "^cause=(.*),action=(.*)" + private val regex = REGEX_PATTERN.toRegex() + + fun readErrorCauseFromMessage(message: String): String { + val matchResults = regex.matchEntire(message) + return matchResults!!.groupValues[1] + } + + fun readErrorActionFromMessage(message: String): String { + val matchResults = regex.matchEntire(message) + return matchResults!!.groupValues[2] + } +} + +fun Exception.errorCauseOrDefault(): Throwable { + return this.cause ?: Throwable() +} + +fun Exception.errorMessageOrDefault(): String { + return this.message ?: "" +} diff --git a/ms/pom.xml b/ms/pom.xml index 7ec3f39a2..7a0168f5b 100644 --- a/ms/pom.xml +++ b/ms/pom.xml @@ -32,9 +32,29 @@ <description>Micro-services</description> <modules> + <module>error-catalog</module> <module>blueprintsprocessor</module> <module>py-executor</module> <module>command-executor</module> <module>sdclistener</module> </modules> + + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>pl.project13.maven</groupId> + <artifactId>git-commit-id-plugin</artifactId> + <version>4.0.0</version> + <configuration> + <includeOnlyProperties> + <includeOnlyProperty>^git.build.(time|version)$</includeOnlyProperty> + <includeOnlyProperty>^git.commit.id.(abbrev|full)$</includeOnlyProperty> + </includeOnlyProperties> + <commitIdGenerationMode>full</commitIdGenerationMode> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> </project> diff --git a/ms/py-executor/resource_resolution/README b/ms/py-executor/resource_resolution/README index 222dae499..353600445 100644 --- a/ms/py-executor/resource_resolution/README +++ b/ms/py-executor/resource_resolution/README @@ -77,4 +77,67 @@ if __name__ == "__main__": for response in client.process(generate_messages()): print(response) +``` + +### Authorizarion header + +``` +from proto.BluePrintCommon_pb2 import ActionIdentifiers, CommonHeader +from proto.BluePrintProcessing_pb2 import ExecutionServiceInput +from resource_resolution.client import Client as ResourceResolutionClient + + +def generate_messages(): + commonHeader = CommonHeader() + commonHeader.requestId = "1234" + commonHeader.subRequestId = "1234-1" + commonHeader.originatorId = "CDS" + + actionIdentifiers = ActionIdentifiers() + actionIdentifiers.blueprintName = "sample-cba" + actionIdentifiers.blueprintVersion = "1.0.0" + actionIdentifiers.actionName = "SampleScript" + + input = ExecutionServiceInput(commonHeader=commonHeader, actionIdentifiers=actionIdentifiers) + + commonHeader2 = CommonHeader() + commonHeader2.requestId = "1235" + commonHeader2.subRequestId = "1234-2" + commonHeader2.originatorId = "CDS" + + input2 = ExecutionServiceInput(commonHeader=commonHeader2, actionIdentifiers=actionIdentifiers) + + yield from [input, input2] + + +if __name__ == "__main__": + with ResourceResolutionClient("127.0.0.1:9111", use_header_auth=True, header_auth_token="Token test") as client: + for response in client.process(generate_messages()): + print(response) + +``` + +# ResourceResoulution helper class + +## How to use examples + +### Insecure channel + +``` +from resource_resolution.resource_resolution import ResourceResolution, WorkflowExecution, WorkflowExecutionResult + + +if __name__ == "__main__": + with ResourceResolution(use_header_auth=True, header_auth_token="Basic token") as rr: + for response in rr.execute_workflows( # type: WorkflowExecutionResult + WorkflowExecution( + blueprint_name="blueprintName", + blueprint_version="1.0", + workflow_name="resource-assignment" + ) + ): + if response.has_error: + print(response.error_message) + else: + print(response.payload) ```
\ No newline at end of file diff --git a/ms/py-executor/resource_resolution/authorization.py b/ms/py-executor/resource_resolution/authorization.py new file mode 100644 index 000000000..ae5954ecc --- /dev/null +++ b/ms/py-executor/resource_resolution/authorization.py @@ -0,0 +1,64 @@ +"""Copyright 2020 Deutsche Telekom. + +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. +""" +from collections import namedtuple +from typing import Any, Callable, List + +from grpc import ClientCallDetails, StreamStreamClientInterceptor + + +class NewClientCallDetails( + namedtuple("_ClientCallDetails", ("method", "timeout", "metadata", "credentials")), ClientCallDetails +): + """Namedtuple class to store metadata. + + It's impossible to change original metadata in ClientCallDetails object + passed as a parameter to intercept method, so this class is going to get + original metadata tuple and add the authorization one. + """ + + pass + + +class AuthTokenInterceptor(StreamStreamClientInterceptor): + """Interceptor class to set authorization header. + + Set authorization header (but it can be any header also) for a gRPC call. + """ + + def __init__(self, token: str, header: str = "authorization") -> None: + """Initialize interceptor. + + Set token and header which should be set into call. By default header is "authorization". + Header have to be lowercase. + + Args: + token (str): Token value to be set. + header (str, optional): Header name. It must be lowercase. Defaults to "authorization". + """ + self.token: str = token + if not header.islower(): + raise ValueError("Header must be lowercase.") + self.header: str = header + + def intercept_stream_stream( + self, continuation: Callable, client_call_details: ClientCallDetails, request_iterator: Any + ) -> Any: + """Add header into metadata.""" + metadata: List = list(client_call_details.metadata) if client_call_details.metadata is not None else [] + metadata.append((self.header, self.token,)) + new_client_call_details: NewClientCallDetails = NewClientCallDetails( + client_call_details.method, client_call_details.timeout, metadata, client_call_details.credentials + ) + return continuation(new_client_call_details, request_iterator) diff --git a/ms/py-executor/resource_resolution/client.py b/ms/py-executor/resource_resolution/client.py index 89087745c..fee168628 100644 --- a/ms/py-executor/resource_resolution/client.py +++ b/ms/py-executor/resource_resolution/client.py @@ -14,12 +14,20 @@ limitations under the License. """ from logging import Logger, getLogger from types import TracebackType -from typing import Iterable, List, Optional, Type - -from grpc import Channel, insecure_channel, secure_channel, ssl_channel_credentials +from typing import Iterable, Optional, Type + +from grpc import ( + Channel, + insecure_channel, + intercept_channel, + secure_channel, + ssl_channel_credentials, +) from proto.BluePrintProcessing_pb2 import ExecutionServiceInput, ExecutionServiceOutput from proto.BluePrintProcessing_pb2_grpc import BluePrintProcessingServiceStub +from .authorization import AuthTokenInterceptor + class Client: """Resource resoulution client class.""" @@ -28,20 +36,29 @@ class Client: self, server_address: str, *, + # TLS/SSL configuration use_ssl: bool = False, root_certificates: bytes = None, private_key: bytes = None, certificate_chain: bytes = None, + # Authentication header configuration + use_header_auth: bool = False, + header_auth_token: str = None, ) -> None: """Client class initialization. :param server_address: Address to server to connect. :param use_ssl: Boolean flag to determine if secure channel should be created or not. Keyword argument. :param root_certificates: The PEM-encoded root certificates. None if it shouldn't be used. Keyword argument. - :param private_key: The PEM-encoded private key as a byte string, or None if no private key should be used. Keyword argument. - :param certificate_chain: The PEM-encoded certificate chain as a byte string to use or or None if no certificate chain should be used. Keyword argument. + :param private_key: The PEM-encoded private key as a byte string, or None if no private key should be used. + Keyword argument. + :param certificate_chain: The PEM-encoded certificate chain as a byte string to use or or None if + no certificate chain should be used. Keyword argument. + :param use_header_auth: Boolean flag to determine if authorization headed shoud be added for every call or not. + Keyword argument. + :param header_auth_token: Authorization token value. Keyword argument. """ - self.logger = getLogger(__name__) + self.logger: Logger = getLogger(__name__) if use_ssl: self.channel: Channel = secure_channel( server_address, ssl_channel_credentials(root_certificates, private_key, certificate_chain) @@ -50,6 +67,8 @@ class Client: else: self.channel: Channel = insecure_channel(server_address) self.logger.debug(f"Create insecure channel to connect to {server_address}") + if use_header_auth: + self.channel: Channel = intercept_channel(self.channel, AuthTokenInterceptor(header_auth_token)) self.stub: BluePrintProcessingServiceStub = BluePrintProcessingServiceStub(self.channel) def close(self) -> None: diff --git a/ms/py-executor/resource_resolution/resource_resolution.py b/ms/py-executor/resource_resolution/resource_resolution.py new file mode 100644 index 000000000..e4f162f8f --- /dev/null +++ b/ms/py-executor/resource_resolution/resource_resolution.py @@ -0,0 +1,294 @@ +"""Copyright 2020 Deutsche Telekom. + +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. +""" + +from enum import Enum, unique +from logging import Logger, getLogger +from types import TracebackType +from typing import Any, Dict, Generator, Optional, Type + +from google.protobuf import json_format + +from proto.BluePrintProcessing_pb2 import ExecutionServiceInput, ExecutionServiceOutput + +from .client import Client + + +@unique +class WorkflowMode(Enum): + """Workflow mode enumerator. + + Workflow can be executed in two modes: synchronously and asynchronously. + This enumerator stores valid values to set the mode: SYNC for synchronously mode and ASYNC for asynchronously. + """ + + SYNC = "sync" + ASYNC = "async" + + +class WorkflowExecution: + """Wokflow execution class. + + Describes workflow to call. Set blueprint name and version and workflow name to execute. + Workflow inputs are optional, by default set to empty directory. + Workflow mode is also optional. It is set by default to call workflow synchronously. + """ + + def __init__( + self, + blueprint_name: str, + blueprint_version: str, + workflow_name: str, + workflow_inputs: Dict[str, Any] = None, + workflow_mode: WorkflowMode = WorkflowMode.SYNC, + ) -> None: + """Initialize workflow execution. + + Get all needed information to execute workflow. + + Args: + blueprint_name (str): Blueprint name to execute workflow from. + blueprint_version (str): Blueprint version. + workflow_name (str): Name of the workflow to execute + workflow_inputs (Dict[str, Any], optional): Key-value workflow inputs. Defaults to None. + workflow_mode (WorkflowMode, optional): Workflow execution mode. It can be run synchronously or + asynchronously. Defaults to WorkflowMode.SYNC. + """ + self.blueprint_name: str = blueprint_name + self.blueprint_version: str = blueprint_version + self.workflow_name: str = workflow_name + if workflow_inputs is None: + workflow_inputs = {} + self.workflow_inputs: Dict[str, Any] = workflow_inputs + self.workflow_mode: WorkflowMode = workflow_mode + + @property + def message(self) -> ExecutionServiceInput: + """Workflow execution protobuf message. + + This message is going to be sent to gRPC server to execute workflow. + + Returns: + ExecutionServiceInput: Properly filled protobuf message. + """ + execution_msg: ExecutionServiceInput = ExecutionServiceInput() + execution_msg.actionIdentifiers.mode = self.workflow_mode.value + execution_msg.actionIdentifiers.blueprintName = self.blueprint_name + execution_msg.actionIdentifiers.blueprintVersion = self.blueprint_version + execution_msg.actionIdentifiers.actionName = self.workflow_name + execution_msg.payload.update({f"{self.workflow_name}-request": self.workflow_inputs}) + return execution_msg + + +class WorkflowExecutionResult: + """Result of workflow execution. + + Store both workflow data and the result returns by server. + """ + + def __init__(self, workflow_execution: WorkflowExecution, execution_output: ExecutionServiceOutput) -> None: + """Initialize workflow execution result object. + + Stores workflow execution data and execution result. + + Args: + workflow_execution (WorkflowExecution): WorkflowExecution object which was used to call request. + execution_output (ExecutionServiceOutput): gRPC server response. + """ + self.workflow_execution: WorkflowExecution = workflow_execution + self.execution_output: ExecutionServiceOutput = execution_output + + @property + def blueprint_name(self) -> str: + """Name of blueprint used to call workflow. + + This value is taken from server response not request (should be the same). + + Returns: + str: Blueprint name + """ + return self.execution_output.actionIdentifiers.blueprintName + + @property + def blueprint_version(self) -> str: + """Blueprint version. + + This value is taken from server response not request (should be the same). + + Returns: + str: Blueprint version + """ + return self.execution_output.actionIdentifiers.blueprintVersion + + @property + def workflow_name(self) -> str: + """Workflow name. + + This value is taken from server response not request (should be the same). + + Returns: + str: Workflow name + """ + return self.execution_output.actionIdentifiers.actionName + + @property + def has_error(self) -> bool: + """Returns bool if request returns error or not. + + Returns: + bool: True if response has status code different than 200 + """ + return self.execution_output.status.code != 200 + + @property + def error_message(self) -> str: + """Error message. + + This property is available only if response has error. Otherwise AttributeError will be raised. + + Raises: + AttributeError: Response has 200 response code and hasn't error message. + + Returns: + str: Error message returned by server + """ + if self.has_error: + return self.execution_output.status.errorMessage + raise AttributeError("Execution does not finish with error") + + @property + def payload(self) -> dict: + """Response payload. + + Payload retured by the server is migrated to Python dict. + + Returns: + dict: Response's payload. + """ + return json_format.MessageToDict(self.execution_output.payload) + + +class ResourceResolution: + """Resource resolution class. + + Helper class to connect to blueprintprocessor's gRPC server, send request to execute workflow and parse responses. + Blueprint with workflow must be deployed before workflow request. + It's possible to create both secre or unsecure connection (without SSL/TLS). + """ + + def __init__( + self, + *, + server_address: str = "127.0.0.1", + server_port: int = "9111", + use_ssl: bool = False, + root_certificates: bytes = None, + private_key: bytes = None, + certificate_chain: bytes = None, + # Authentication header configuration + use_header_auth: bool = False, + header_auth_token: str = None, + ) -> None: + """Resource resolution object initialization. + + Args: + server_address (str, optional): gRPC server address. Defaults to "127.0.0.1". + server_port (int, optional): gRPC server address port. Defaults to "9111". + use_ssl (bool, optional): Boolean flag to determine if secure channel should be created or not. + Defaults to False. + root_certificates (bytes, optional): The PEM-encoded root certificates. None if it shouldn't be used. + Defaults to None. + private_key (bytes, optional): The PEM-encoded private key as a byte string, or None if no private key + should be used. Defaults to None. + certificate_chain (bytes, optional): The PEM-encoded certificate chain as a byte string to use or or None if + no certificate chain should be used. Defaults to None. + use_header_auth (bool, optional): Boolean flag to determine if authorization headed shoud be added for + every call or not. Defaults to False. + header_auth_token (str, optional): Authorization token value. Defaults to None. + """ + # Logger + self.logger: Logger = getLogger(__name__) + # Client settings + self.client_server_address: str = server_address + self.client_server_port: str = server_port + self.client_use_ssl: bool = use_ssl + self.client_root_certificates: bytes = root_certificates + self.client_private_key: bytes = private_key + self.client_certificate_chain: bytes = certificate_chain + self.client_use_header_auth: bool = use_header_auth + self.client_header_auth_token: str = header_auth_token + self.client: Client = None + + def __enter__(self) -> "ResourceResolution": + """Enter ResourceResolution instance context. + + Client connection is created. + """ + self.client = Client( + server_address=f"{self.client_server_address}:{self.client_server_port}", + use_ssl=self.client_use_ssl, + root_certificates=self.client_root_certificates, + private_key=self.client_private_key, + certificate_chain=self.client_certificate_chain, + use_header_auth=self.client_use_header_auth, + header_auth_token=self.client_header_auth_token, + ) + return self + + def __exit__( + self, + unused_exc_type: Optional[Type[BaseException]], + unused_exc_value: Optional[BaseException], + unused_traceback: Optional[TracebackType], + ) -> None: + """Exit ResourceResolution instance context. + + Client connection is closed. + """ + self.client.close() + + def execute_workflows(self, *workflows: WorkflowExecution) -> Generator[WorkflowExecutionResult, None, None]: + """Execute provided workflows. + + Workflows are going to be execured using one gRPC API call. Depends of implementation that may has + some consequences. In some cases if any request fails all requests after that won't be called. + + Responses and zipped with workflows and WorkflowExecutionResult object is initialized and yielded. + + Raises: + AttributeError: Raises if client object is not created. It occurs only if you not uses context manager. + Then user have to create client instance for ResourceResolution object by himself calling: + ``` + resource_resoulution.client = Client( + server_address=f"{resource_resoulution.client_server_address}:{resource_resoulution.client_server_port}", + use_ssl=resource_resoulution.client_use_ssl, + root_certificates=resource_resoulution.client_root_certificates, + private_key=resource_resoulution.client_private_key, + certificate_chain=resource_resoulution.client_certificate_chain, + use_header_auth=resource_resoulution.client_use_header_auth, + header_auth_token=resource_resoulution.client_header_auth_token, + ) + ``` + Remeber also to close client connection. + + Returns: + Generator[WorkflowExecutionResult, None, None]: WorkflowExecutionResult object + with both WorkflowExection object and server response for it's request. + """ + self.logger.debug("Execute workflows") + if not self.client: + raise AttributeError("gRPC client not connected") + + for response, workflow in zip(self.client.process((workflow.message for workflow in workflows)), workflows): + yield WorkflowExecutionResult(workflow, response) diff --git a/ms/py-executor/resource_resolution/tests/authorization_interceptor_test.py b/ms/py-executor/resource_resolution/tests/authorization_interceptor_test.py new file mode 100644 index 000000000..4b03f0b36 --- /dev/null +++ b/ms/py-executor/resource_resolution/tests/authorization_interceptor_test.py @@ -0,0 +1,50 @@ +"""Copyright 2020 Deutsche Telekom. + +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. +""" + +from unittest.mock import MagicMock, _Call + +import pytest + +from resource_resolution.authorization import AuthTokenInterceptor, NewClientCallDetails + + +def test_resource_resolution_auth_token_interceptor(): + """Test AuthTokenInterceptor class. + + - Checks if it's correctly set default value. + - Checks if it's correctly set passed values. + - Checks if it's correctly checked if all header characters are lowercase. + - Checks if continuation function is called with headers setted + """ + interceptor: AuthTokenInterceptor = AuthTokenInterceptor("test_token", header="header") + assert interceptor.token == "test_token" + assert interceptor.header == "header" + + interceptor: AuthTokenInterceptor = AuthTokenInterceptor("test_token") + assert interceptor.token == "test_token" + assert interceptor.header == "authorization" + + with pytest.raises(ValueError): + AuthTokenInterceptor("test_token", header="Auth") + + continuation_mock: MagicMock = MagicMock() + client_call_details: MagicMock = MagicMock() + request_iterator: MagicMock = MagicMock() + + interceptor.intercept_stream_stream(continuation_mock, client_call_details, request_iterator) + continuation_mock.assert_called_once() + client_call_details_argument: _Call = continuation_mock.call_args_list[0][0][0] # Get NewClientCallDetails instance + assert isinstance(client_call_details_argument, NewClientCallDetails) + assert client_call_details_argument.metadata[0] == (interceptor.header, interceptor.token) diff --git a/ms/py-executor/resource_resolution/tests/resource_resolution_test.py b/ms/py-executor/resource_resolution/tests/resource_resolution_test.py new file mode 100644 index 000000000..8a41357e6 --- /dev/null +++ b/ms/py-executor/resource_resolution/tests/resource_resolution_test.py @@ -0,0 +1,105 @@ +"""Copyright 2020 Deutsche Telekom. + +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. +""" + +from google.protobuf import json_format +from pytest import raises + +from resource_resolution.resource_resolution import ( + ExecutionServiceInput, + ExecutionServiceOutput, + WorkflowExecution, + WorkflowExecutionResult, + WorkflowMode, +) + + +def test_workflow_execution_class(): + """Workflow execution class tests. + + - Test initialization and default values + - Test request message formatting + """ + # Without inputs + workflow_execution: WorkflowExecution = WorkflowExecution("test blueprint", "test version", "test workflow") + assert workflow_execution.blueprint_name == "test blueprint" + assert workflow_execution.blueprint_version == "test version" + assert workflow_execution.workflow_name == "test workflow" + assert workflow_execution.workflow_inputs == {} + assert workflow_execution.workflow_mode == WorkflowMode.SYNC + + msg: ExecutionServiceInput = workflow_execution.message + msg_dict: dict = json_format.MessageToDict(msg) + assert msg_dict["actionIdentifiers"]["blueprintName"] == "test blueprint" + assert msg_dict["actionIdentifiers"]["blueprintVersion"] == "test version" + assert msg_dict["actionIdentifiers"]["actionName"] == "test workflow" + assert msg_dict["actionIdentifiers"]["mode"] == "sync" + assert list(msg_dict["payload"].keys())[0] == "test workflow-request" + assert msg_dict["payload"]["test workflow-request"] == {} + + # With inputs + workflow_execution: WorkflowExecution = WorkflowExecution( + "test blueprint2", + "test version2", + "test workflow2", + workflow_inputs={"test": "test"}, + workflow_mode=WorkflowMode.ASYNC, + ) + assert workflow_execution.blueprint_name == "test blueprint2" + assert workflow_execution.blueprint_version == "test version2" + assert workflow_execution.workflow_name == "test workflow2" + assert workflow_execution.workflow_inputs == {"test": "test"} + assert workflow_execution.workflow_mode == WorkflowMode.ASYNC + + msg: ExecutionServiceInput = workflow_execution.message + msg_dict: dict = json_format.MessageToDict(msg) + assert msg_dict["actionIdentifiers"]["blueprintName"] == "test blueprint2" + assert msg_dict["actionIdentifiers"]["blueprintVersion"] == "test version2" + assert msg_dict["actionIdentifiers"]["actionName"] == "test workflow2" + assert msg_dict["actionIdentifiers"]["mode"] == "async" + assert list(msg_dict["payload"].keys())[0] == "test workflow2-request" + assert msg_dict["payload"]["test workflow2-request"] == {"test": "test"} + + +def test_workflow_execution_result_class(): + """Workflow execution result class tests. + + - Test initizalization and default values + - Test `has_error` property + - Test `error_message` property + - Test payload formatting + """ + workflow_execution: WorkflowExecution = WorkflowExecution("test blueprint", "test version", "test workflow") + execution_output: ExecutionServiceOutput = ExecutionServiceOutput() + execution_output.actionIdentifiers.blueprintName = "test blueprint" + execution_output.actionIdentifiers.blueprintVersion = "test version" + execution_output.actionIdentifiers.actionName = "test workflow" + execution_output.status.code = 200 + + execution_result: WorkflowExecutionResult = WorkflowExecutionResult(workflow_execution, execution_output) + assert not execution_result.has_error + with raises(AttributeError): + execution_result.error_message + assert execution_result.payload == {} + assert execution_result.blueprint_name == "test blueprint" + assert execution_result.blueprint_version == "test version" + assert execution_result.workflow_name == "test workflow" + + execution_output.payload.update({"test_key": "test_value"}) + execution_result: WorkflowExecutionResult = WorkflowExecutionResult(workflow_execution, execution_output) + assert execution_result.payload == {"test_key": "test_value"} + + execution_output.status.code = 500 + assert execution_result.has_error + assert execution_result.error_message == "" diff --git a/ms/sdclistener/application/pom.xml b/ms/sdclistener/application/pom.xml index 88d8d1b2f..72f552cdd 100644 --- a/ms/sdclistener/application/pom.xml +++ b/ms/sdclistener/application/pom.xml @@ -63,7 +63,6 @@ <dependency> <groupId>org.onap.sdc.sdc-distribution-client</groupId> <artifactId>sdc-distribution-client</artifactId> - <version>1.3.0</version> </dependency> <dependency> @@ -112,6 +111,11 @@ </dependency> <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </dependency> + + <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> <scope>compile</scope> diff --git a/ms/sdclistener/application/src/main/resources/application.yaml b/ms/sdclistener/application/src/main/resources/application.yaml index 424f0a5c0..d07d8ae61 100644 --- a/ms/sdclistener/application/src/main/resources/application.yaml +++ b/ms/sdclistener/application/src/main/resources/application.yaml @@ -2,7 +2,7 @@ listenerservice: config: asdcAddress: ${asdcAddress:localhost:8443} messageBusAddress: ${messageBusAddress:localhost} - user: ${sdcusername:vid} + user: ${sdcusername:cds} password: ${password:Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U} pollingInterval: ${pollingInterval:15} pollingTimeout: ${pollingTimeout:60} diff --git a/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java index 26757a657..8275bc084 100644 --- a/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java +++ b/ms/sdclistener/application/src/test/java/org/onap/ccsdk/cds/sdclistener/SdcListenerConfigurationTest.java @@ -37,7 +37,7 @@ public class SdcListenerConfigurationTest { public void testCdsSdcListenerConfiguration() { assertEquals(listenerConfiguration.getAsdcAddress(), "localhost:8443"); assertEquals(listenerConfiguration.getMsgBusAddress().stream().findFirst().get(), "localhost"); - assertEquals(listenerConfiguration.getUser(), "vid"); + assertEquals(listenerConfiguration.getUser(), "cds"); assertEquals(listenerConfiguration.getPassword(), "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"); assertEquals(listenerConfiguration.getPollingInterval(), 15); assertEquals(listenerConfiguration.getPollingTimeout(), 60); diff --git a/ms/sdclistener/parent/pom.xml b/ms/sdclistener/parent/pom.xml index eaa1d60f4..2cbc79dcc 100755 --- a/ms/sdclistener/parent/pom.xml +++ b/ms/sdclistener/parent/pom.xml @@ -40,7 +40,7 @@ <mockk.version>1.9</mockk.version> <dmaap.client.version>1.1.5</dmaap.client.version> <mockkserver.version>5.5.1</mockkserver.version> - <sdc-distribution-client.version>1.3.0</sdc-distribution-client.version> + <sdc-distribution-client.version>1.4.0</sdc-distribution-client.version> <jmockit.version>1.19</jmockit.version> <reactorcore.version>3.2.6.RELEASE</reactorcore.version> </properties> |