Fix: Run both sonar and clm scans in parallel
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / inbounds / configs-api / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / configs / api / ResourceConfigSnapshotController.kt
index 2a5f4c3..8b976e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Bell Canada
+ * Copyright © 2021 Bell Canada
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import io.swagger.annotations.ApiParam
 import kotlinx.coroutines.runBlocking
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.config.snapshots.db.ResourceConfigSnapshot
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.config.snapshots.db.ResourceConfigSnapshotService
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.mdcWebCoroutineScope
 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
 import org.onap.ccsdk.cds.controllerblueprints.core.httpProcessorException
 import org.onap.ccsdk.cds.error.catalog.core.ErrorCatalogCodes
@@ -30,6 +31,7 @@ import org.onap.ccsdk.cds.error.catalog.core.utils.errorCauseOrDefault
 import org.springframework.http.MediaType
 import org.springframework.http.ResponseEntity
 import org.springframework.security.access.prepost.PreAuthorize
+import org.springframework.web.bind.annotation.DeleteMapping
 import org.springframework.web.bind.annotation.PathVariable
 import org.springframework.web.bind.annotation.PostMapping
 import org.springframework.web.bind.annotation.RequestBody
@@ -38,6 +40,7 @@ import org.springframework.web.bind.annotation.RequestMethod
 import org.springframework.web.bind.annotation.RequestParam
 import org.springframework.web.bind.annotation.ResponseBody
 import org.springframework.web.bind.annotation.RestController
+import java.util.Optional
 
 /**
  * Exposes Resource Configuration Snapshot API to store and retrieve stored resource configurations.
@@ -48,11 +51,13 @@ import org.springframework.web.bind.annotation.RestController
 @RestController
 @RequestMapping("/api/v1/configs")
 @Api(
-    value = "/api/v1/configs",
-    description = "Interaction with stored configurations."
+    value = "Resource configuration",
+    description = "Interaction with stored configurations"
 )
 open class ResourceConfigSnapshotController(private val resourceConfigSnapshotService: ResourceConfigSnapshotService) {
 
+    private val JSON_MIME_TYPE = "application/json"
+
     @RequestMapping(
         path = ["/health-check"],
         method = [RequestMethod.GET],
@@ -65,87 +70,92 @@ open class ResourceConfigSnapshotController(private val resourceConfigSnapshotSe
     }
 
     @RequestMapping(
-        path = [""],
         method = [RequestMethod.GET],
         produces = [MediaType.TEXT_PLAIN_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE]
     )
     @ApiOperation(
-        value = "Retrieve a resource configuration snapshot.",
+        value = "Retrieve a resource configuration snapshot",
         notes = "Retrieve a config snapshot, identified by its Resource Id and Type. " +
-                "An extra 'format' parameter can be passed to tell what content-type is expected."
+            "An extra 'format' parameter can be passed to tell what content-type is expected."
     )
     @ResponseBody
     @PreAuthorize("hasRole('USER')")
     fun get(
-        @ApiParam(value = "Resource Type associated of the resource configuration snapshot.", required = false)
+        @ApiParam(value = "Resource Type associated of the resource configuration snapshot", required = false, example = "\"PNF\"")
         @RequestParam(value = "resourceType", required = true) resourceType: String,
 
-        @ApiParam(value = "Resource Id associated of the resource configuration snapshot.", required = false)
+        @ApiParam(value = "Resource Id associated of the resource configuration snapshot", required = false, example = "\"1\"")
         @RequestParam(value = "resourceId", required = true) resourceId: String,
 
-        @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "RUNNING", required = false)
+        @ApiParam(value = "Status of the snapshot being retrieved", defaultValue = "RUNNING", required = false)
         @RequestParam(value = "status", required = false, defaultValue = "RUNNING") status: String,
 
         @ApiParam(
-            value = "Expected format of the snapshot being retrieved.", defaultValue = MediaType.TEXT_PLAIN_VALUE,
+            value = "Expected format of the snapshot being retrieved", defaultValue = MediaType.TEXT_PLAIN_VALUE,
             required = false
         )
         @RequestParam(value = "format", required = false, defaultValue = MediaType.TEXT_PLAIN_VALUE) format: String
     ):
 
-            ResponseEntity<String> = runBlocking {
+        ResponseEntity<String> = runBlocking {
 
-        var configSnapshot = ""
+            var configSnapshot = ""
 
-        if (resourceType.isNotEmpty() && resourceId.isNotEmpty()) {
-            try {
-                configSnapshot = resourceConfigSnapshotService.findByResourceIdAndResourceTypeAndStatus(
-                    resourceId,
-                    resourceType, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
-                )
-            } catch (ex: NoSuchElementException) {
-                throw httpProcessorException(ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
+            if (resourceType.isNotEmpty() && resourceId.isNotEmpty()) {
+                try {
+                    configSnapshot = resourceConfigSnapshotService.findByResourceIdAndResourceTypeAndStatus(
+                        resourceId,
+                        resourceType, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
+                    )
+                } catch (ex: NoSuchElementException) {
+                    throw httpProcessorException(
+                        ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
                         "Could not find configuration snapshot entry for type $resourceType and Id $resourceId",
-                        ex.errorCauseOrDefault())
-            } catch (ex: Exception) {
-                throw httpProcessorException(ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
+                        ex.errorCauseOrDefault()
+                    )
+                } catch (ex: Exception) {
+                    throw httpProcessorException(
+                        ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
                         "Could not find configuration snapshot entry for type $resourceType and Id $resourceId",
-                        ex.errorCauseOrDefault())
+                        ex.errorCauseOrDefault()
+                    )
+                }
+            } else {
+                throw httpProcessorException(
+                    ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
+                    "Missing param. You must specify resource-id and resource-type."
+                )
             }
-        } else {
-            throw httpProcessorException(ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
-                    "Missing param. You must specify resource-id and resource-type.")
-        }
 
-        var expectedContentType = format
-        if (expectedContentType.indexOf('/') < 0) {
-            expectedContentType = "application/$expectedContentType"
-        }
-        val expectedMediaType: MediaType = MediaType.valueOf(expectedContentType)
+            var expectedContentType = format
+            if (expectedContentType.indexOf('/') < 0) {
+                expectedContentType = "application/$expectedContentType"
+            }
+            val expectedMediaType: MediaType = MediaType.valueOf(expectedContentType)
 
-        ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshot)
-    }
+            ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshot)
+        }
 
     @PostMapping(
         "/{resourceType}/{resourceId}/{status}",
         produces = [MediaType.APPLICATION_JSON_VALUE]
     )
     @ApiOperation(
-        value = "Store a resource configuration snapshot identified by resourceId, resourceType, status.",
+        value = "Store a resource configuration snapshot identified by resourceId, resourceType, status",
         notes = "Store a resource configuration snapshot, identified by its resourceId and resourceType, " +
-                "and optionally its status, either RUNNING or CANDIDATE.",
-        response = ResourceConfigSnapshot::class, produces = MediaType.APPLICATION_JSON_VALUE
+            "and optionally its status, either RUNNING or CANDIDATE.",
+        response = ResourceConfigSnapshot::class
     )
     @ResponseBody
     @PreAuthorize("hasRole('USER')")
     fun postWithResourceIdAndResourceType(
-        @ApiParam(value = "Resource Type associated with the resolution.", required = false)
+        @ApiParam(value = "Resource Type associated with the resolution", required = false, example = "\"PNF\"")
         @PathVariable(value = "resourceType", required = true) resourceType: String,
-        @ApiParam(value = "Resource Id associated with the resolution.", required = false)
+        @ApiParam(value = "Resource Id associated with the resolution", required = false, example = "\"1\"")
         @PathVariable(value = "resourceId", required = true) resourceId: String,
-        @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "RUNNING", required = true)
+        @ApiParam(value = "Status of the snapshot being retrieved", defaultValue = "RUNNING", required = true)
         @PathVariable(value = "status", required = true) status: String,
-        @ApiParam(value = "Config snapshot to store.", required = true)
+        @ApiParam(value = "Config snapshot to store", required = true, example = "\"config_snapshot\"")
         @RequestBody snapshot: String
     ): ResponseEntity<ResourceConfigSnapshot> = runBlocking {
 
@@ -157,4 +167,145 @@ open class ResourceConfigSnapshotController(private val resourceConfigSnapshotSe
 
         ResponseEntity.ok().body(resultStored)
     }
+
+    @DeleteMapping(
+        "/{resourceType}/{resourceId}/{status}",
+        "/{resourceType}/{resourceId}"
+    )
+    @ApiOperation(
+        value = "Delete a resource configuration snapshot identified by resourceId, resourceType, status.",
+        notes = "Delete a resource configuration snapshot, identified by its resourceId and resourceType, " +
+            "and optionally its status, either RUNNING or CANDIDATE."
+    )
+    @ResponseBody
+    @PreAuthorize("hasRole('USER')")
+    suspend fun deleteWithResourceIdAndResourceType(
+        @ApiParam(value = "Resource Type associated with the resolution.", required = true)
+        @PathVariable(value = "resourceType", required = true) resourceType: String,
+        @ApiParam(value = "Resource Id associated with the resolution.", required = true)
+        @PathVariable(value = "resourceId", required = true) resourceId: String,
+        @ApiParam(value = "Status of the snapshot being deleted.", required = false)
+        @PathVariable(value = "status", required = false) status: Optional<String>
+    ) = mdcWebCoroutineScope {
+
+        if (resourceId.isBlank() || resourceType.isBlank())
+            throw httpProcessorException(
+                ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
+                "You must specify path variables resource-id and resource-type."
+            )
+
+        try {
+            if (status.isPresent)
+                resourceConfigSnapshotService.deleteByResourceIdAndResourceTypeAndStatus(
+                    resourceId, resourceType,
+                    ResourceConfigSnapshot.Status.valueOf(status.get().toUpperCase())
+                )
+            else {
+                resourceConfigSnapshotService.deleteByResourceIdAndResourceTypeAndStatus(
+                    resourceId, resourceType,
+                    ResourceConfigSnapshot.Status.RUNNING
+                )
+                resourceConfigSnapshotService.deleteByResourceIdAndResourceTypeAndStatus(
+                    resourceId, resourceType,
+                    ResourceConfigSnapshot.Status.CANDIDATE
+                )
+            }
+        } catch (ex: Exception) {
+            throw httpProcessorException(
+                ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
+                "Could not delete configuration snapshot entry for type $resourceType and Id $resourceId",
+                ex.errorCauseOrDefault()
+            )
+        }
+    }
+
+    @RequestMapping(
+        path = ["/allByID"],
+        method = [RequestMethod.GET],
+        produces = [MediaType.APPLICATION_JSON_VALUE]
+    )
+    @ApiOperation(
+        value = "Retrieve all resource configuration snapshots identified by a given resource_id",
+        notes = "Retrieve all config snapshots, identified by its Resource Id, ordered by most recently created/modified date. "
+    )
+    @ResponseBody
+    @PreAuthorize("hasRole('USER')")
+    fun getAllByID(
+        @ApiParam(value = "Resource Id associated of the resource configuration snapshots", required = false, example = "\"1\"")
+        @RequestParam(value = "resourceId", required = true) resourceId: String,
+        @ApiParam(value = "Status of the snapshot being retrieved", defaultValue = "ANY", required = false)
+        @RequestParam(value = "status", required = false, defaultValue = "ANY") status: String
+    ): ResponseEntity<List<ResourceConfigSnapshot>?> = runBlocking {
+        var configSnapshots: List<ResourceConfigSnapshot>?
+
+        try {
+            if (status == "ANY") {
+                configSnapshots = resourceConfigSnapshotService.findAllByResourceId(resourceId)
+            } else {
+                configSnapshots = resourceConfigSnapshotService.findAllByResourceIdForStatus(
+                    resourceId, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
+                )
+            }
+        } catch (ex: NoSuchElementException) {
+            throw httpProcessorException(
+                ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
+                "Could not find configuration snapshot entry for ID $resourceId",
+                ex.errorCauseOrDefault()
+            )
+        } catch (ex: Exception) {
+            throw httpProcessorException(
+                ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
+                "Unexpected error while finding configuration snapshot entries for ID $resourceId",
+                ex.errorCauseOrDefault()
+            )
+        }
+
+        val expectedMediaType: MediaType = MediaType.valueOf(JSON_MIME_TYPE)
+        ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshots)
+    }
+
+    @RequestMapping(
+        path = ["allByType"],
+        method = [RequestMethod.GET],
+        produces = [MediaType.APPLICATION_JSON_VALUE]
+    )
+    @ApiOperation(
+        value = "Retrieve all resource configuration snapshots for a given resource type",
+        notes = "Retrieve all config snapshots matching a specified Resource Type, ordered by most recently created/modified date. "
+    )
+    @ResponseBody
+    @PreAuthorize("hasRole('USER')")
+    fun getAllByType(
+        @ApiParam(value = "Resource Type associated of the resource configuration snapshot", required = false, example = "\"PNF\"")
+        @RequestParam(value = "resourceType", required = true) resourceType: String,
+        @ApiParam(value = "Status of the snapshot being retrieved", defaultValue = "ANY", required = false)
+        @RequestParam(value = "status", required = false, defaultValue = "ANY") status: String
+    ): ResponseEntity<List<ResourceConfigSnapshot>?> = runBlocking {
+        var configSnapshots: List<ResourceConfigSnapshot>?
+
+        try {
+            if (status == "ANY") {
+                configSnapshots = resourceConfigSnapshotService.findAllByResourceType(resourceType)
+            } else {
+                configSnapshots = resourceConfigSnapshotService.findAllByResourceTypeForStatus(
+                    resourceType, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
+                )
+            }
+        } catch (ex: NoSuchElementException) {
+            throw httpProcessorException(
+                ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
+                "Could not find configuration snapshot entry for ID $resourceType",
+                ex.errorCauseOrDefault()
+            )
+        } catch (ex: Exception) {
+            throw httpProcessorException(
+                ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
+                "Unexpected error while finding configuration snapshot entries for type $resourceType",
+                ex.errorCauseOrDefault()
+            )
+        }
+
+        val expectedMediaType: MediaType = MediaType.valueOf(JSON_MIME_TYPE)
+        ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshots)
+    }
 }