Add delete endpoint for config snapshot API 33/118833/2
authorJulien Fontaine <julien.fontaine@bell.ca>
Tue, 2 Mar 2021 23:18:30 +0000 (18:18 -0500)
committerKAPIL SINGAL <ks220y@att.com>
Tue, 9 Mar 2021 18:20:18 +0000 (18:20 +0000)
Add delete endpoint to delete config-snapshots based on resource-type, resource-id and resources-status.

Issue-ID: CCSDK-3205
Signed-off-by: Julien Fontaine <julien.fontaine@bell.ca>
Change-Id: Id7954694bc93beba08a79139834cb6477cb8e44b

ms/blueprintsprocessor/functions/config-snapshots/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/config/snapshots/db/ResourceConfigSnapshotService.kt
ms/blueprintsprocessor/functions/config-snapshots/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/config/snapshots/db/ResourceConfigSnapshotServiceTest.kt
ms/blueprintsprocessor/modules/inbounds/configs-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/configs/api/ResourceConfigSnapshotController.kt
ms/blueprintsprocessor/modules/inbounds/configs-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/configs/api/ResourceConfigSnapshotControllerTest.kt

index 382a131..cf7de67 100644 (file)
@@ -115,4 +115,16 @@ open class ResourceConfigSnapshotService(private val resourceConfigSnapshotRepos
             }
             storedSnapshot
         }
+
+    suspend fun deleteByResourceIdAndResourceTypeAndStatus(
+        resourceId: String,
+        resourceType: String,
+        status: ResourceConfigSnapshot.Status
+    ) {
+        resourceConfigSnapshotRepository.deleteByResourceIdAndResourceTypeAndStatus(resourceId, resourceType, status)
+        log.info(
+            "Deleted configuration snapshot for resourceId=($resourceId), " +
+                "resourceType=($resourceType), status=($status)"
+        )
+    }
 }
index f25b6f9..403f92b 100644 (file)
@@ -78,4 +78,17 @@ class ResourceConfigSnapshotServiceTest {
             assertEquals(tr, res)
         }
     }
+
+    @Test
+    fun deleteResourceConfigSnapshot() {
+        runBlocking {
+            every {
+                cfgRepository.deleteByResourceIdAndResourceTypeAndStatus(any(), any(), any())
+            } returns Unit
+            cfgService.deleteByResourceIdAndResourceTypeAndStatus(resourceId, resourceType, resourceStatus)
+            verify {
+                cfgRepository.deleteByResourceIdAndResourceTypeAndStatus(eq(resourceId), eq(resourceType), eq(resourceStatus))
+            }
+        }
+    }
 }
index 9dadd39..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.
@@ -165,6 +168,57 @@ 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],
index 58d5726..1a2fb61 100644 (file)
@@ -246,6 +246,50 @@ class ResourceConfigSnapshotControllerTest {
         }
     }
 
+    @Test
+    fun `deleteWithResourceIdAndResourceType returns 200 if valid path`() {
+        webTestClient
+            .delete()
+            .uri("/api/v1/configs/$resourceType/$resourceId/running")
+            .exchange()
+            .expectStatus().is2xxSuccessful
+            .expectBody()
+        webTestClient
+            .delete()
+            .uri("/api/v1/configs/$resourceType/$resourceId/candidate")
+            .exchange()
+            .expectStatus().is2xxSuccessful
+            .expectBody()
+        webTestClient
+            .delete()
+            .uri("/api/v1/configs/$resourceType/$resourceId")
+            .exchange()
+            .expectStatus().is2xxSuccessful
+            .expectBody()
+    }
+
+    @Test
+    fun `deleteWithResourceIdAndResourceType returns 400 if invalid path`() {
+        webTestClient
+            .delete()
+            .uri("/api/v1/configs/ /$resourceId/running")
+            .exchange()
+            .expectStatus().is4xxClientError
+            .expectBody()
+        webTestClient
+            .delete()
+            .uri("/api/v1/configs/$resourceType/ /running")
+            .exchange()
+            .expectStatus().is4xxClientError
+            .expectBody()
+        webTestClient
+            .delete()
+            .uri("/api/v1/configs/$resourceType/$resourceId/qwerty")
+            .exchange()
+            .expectStatus().is4xxClientError
+            .expectBody()
+    }
+
     private fun post(resourceType: String, resourceId: String, status: String) {
         webTestClient
             .post()