Support saving blueprints without workflows 29/143529/1
authorFiete Ostkamp <fiete.ostkamp@telekom.de>
Sat, 7 Mar 2026 08:26:55 +0000 (09:26 +0100)
committerFiete Ostkamp <fiete.ostkamp@telekom.de>
Sat, 7 Mar 2026 08:26:55 +0000 (09:26 +0100)
- saving blueprints without workflows failed with a generic
  internal server error due to a nullpointer exception
- allow saving blueprints without workflows
- enhance the global catalog exception handler to log an error
  message for `Exception`

Issue-ID: CCSDK-4178
Change-Id: I0869fb7ffd1f6a7593919aed39bf24b4501fac83
Signed-off-by: Fiete Ostkamp <fiete.ostkamp@telekom.de>
components/model-catalog/blueprint-model/test-blueprint/baseconfiguration-no-workflows/Definitions/empty-blueprint.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/baseconfiguration-no-workflows/TOSCA-Metadata/TOSCA.meta [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/db-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/primary/service/BlueprintCatalogServiceImpl.kt
ms/blueprintsprocessor/modules/commons/db-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/db/BlueprintProcessorCatalogServiceImplTest.kt
ms/error-catalog/services/src/main/kotlin/org/onap/ccsdk/cds/error/catalog/services/ErrorCatalogExceptionHandler.kt

diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration-no-workflows/Definitions/empty-blueprint.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration-no-workflows/Definitions/empty-blueprint.json
new file mode 100644 (file)
index 0000000..11581f3
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "metadata": {
+    "template_author": "Test",
+    "author-email": "test@test.com",
+    "user-groups": "ADMIN, OPERATION",
+    "template_name": "baseconfiguration-no-workflows",
+    "template_version": "1.0.0",
+    "template_tags": "test, no-workflows"
+  },
+  "imports": [],
+  "topology_template": {}
+}
diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration-no-workflows/TOSCA-Metadata/TOSCA.meta b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration-no-workflows/TOSCA-Metadata/TOSCA.meta
new file mode 100644 (file)
index 0000000..b8d5498
--- /dev/null
@@ -0,0 +1,8 @@
+TOSCA-Meta-File-Version: 1.0.0
+CSAR-Version: 1.0
+Created-By: Test
+Entry-Definitions: Definitions/empty-blueprint.json
+Template-Name: baseconfiguration-no-workflows
+Template-Version: 1.0.0
+Template-Type: DEFAULT
+Template-Tags: test, no-workflows
index 2c0fc8e..3221eae 100644 (file)
@@ -72,7 +72,7 @@ abstract class BlueprintCatalogServiceImpl(
 
         val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(processingId, workingDir!!)
         val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
-        val workflows = bluePrintRuntimeService.bluePrintContext().workflows()!!
+        val workflows = bluePrintRuntimeService.bluePrintContext().workflows() ?: emptyMap()
         metadata[BluePrintConstants.PROPERTY_BLUEPRINT_PROCESS_ID] = processingId
         metadata[BluePrintConstants.PROPERTY_BLUEPRINT_VALID] = valid
 
index 5f1d095..1e5dc28 100644 (file)
@@ -72,6 +72,10 @@ class BlueprintProcessorCatalogServiceImplTest {
         normalizedFile("./../../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration")
             .compress(normalizedFile("./target/blueprints/generated-cba.zip"))
 
+        // Create sample CBA zip without workflows
+        normalizedFile("./../../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration-no-workflows")
+            .compress(normalizedFile("./target/blueprints/generated-cba-no-workflows.zip"))
+
         bluePrintRuntimeService = BluePrintMetadataUtils.bluePrintRuntime(
             blueprintId,
             "./../../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration"
@@ -135,6 +139,19 @@ class BlueprintProcessorCatalogServiceImplTest {
         )
     }
 
+    @Test
+    fun `test save CBA without workflows`() {
+        runBlocking {
+            val file = normalizedFile("./target/blueprints/generated-cba-no-workflows.zip")
+            assertTrue(file.exists(), "couldn't get file ${file.absolutePath}")
+
+            blueprintsProcessorCatalogService.saveToDatabase("5678", file)
+            blueprintsProcessorCatalogService.getFromDatabase("baseconfiguration-no-workflows", "1.0.0")
+
+            blueprintsProcessorCatalogService.deleteFromDatabase("baseconfiguration-no-workflows", "1.0.0")
+        }
+    }
+
     @Test
     fun `test delete function`() {
         runBlocking {
index 161b6b8..264db67 100644 (file)
@@ -26,11 +26,14 @@ import org.springframework.dao.EmptyResultDataAccessException
 import org.springframework.dao.IncorrectResultSizeDataAccessException
 import org.springframework.http.ResponseEntity
 import org.springframework.orm.jpa.JpaObjectRetrievalFailureException
+import org.slf4j.LoggerFactory
 import org.springframework.web.bind.annotation.ExceptionHandler
 import org.springframework.web.server.ServerWebInputException
 
 abstract class ErrorCatalogExceptionHandler(private val errorCatalogService: ErrorCatalogService) {
 
+    private val log = LoggerFactory.getLogger(ErrorCatalogExceptionHandler::class.java)
+
     @ExceptionHandler(ErrorCatalogException::class)
     fun errorCatalogException(e: ErrorCatalogException): ResponseEntity<ErrorPayload> {
         val errorPayload = errorCatalogService.errorPayload(e)
@@ -79,6 +82,7 @@ abstract class ErrorCatalogExceptionHandler(private val errorCatalogService: Err
 
     @ExceptionHandler
     fun errorCatalogException(e: Exception): ResponseEntity<ErrorPayload> {
+        log.error("Unhandled exception: ${e.message}", e)
         val error = ErrorCatalogException(
             HttpErrorCodes.code(ErrorCatalogCodes.GENERIC_FAILURE),
             e.errorMessageOrDefault(), e.errorCauseOrDefault()