/*
- * 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.
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
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
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.
@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],
}
@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 {
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)
+ }
}