Enabling Code Formatter
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / inbounds / configs-api / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / configs / api / ResourceConfigSnapshotController.kt
1 /*
2  * Copyright © 2019 Bell Canada
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.ccsdk.cds.blueprintsprocessor.configs.api
18
19 import com.fasterxml.jackson.databind.JsonNode
20 import io.swagger.annotations.Api
21 import io.swagger.annotations.ApiOperation
22 import io.swagger.annotations.ApiParam
23 import kotlinx.coroutines.runBlocking
24 import org.onap.ccsdk.cds.blueprintsprocessor.functions.config.snapshots.db.ResourceConfigSnapshot
25 import org.onap.ccsdk.cds.blueprintsprocessor.functions.config.snapshots.db.ResourceConfigSnapshotService
26 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
27 import org.onap.ccsdk.cds.controllerblueprints.core.httpProcessorException
28 import org.onap.ccsdk.cds.error.catalog.core.ErrorCatalogCodes
29 import org.onap.ccsdk.cds.error.catalog.core.utils.errorCauseOrDefault
30 import org.springframework.http.MediaType
31 import org.springframework.http.ResponseEntity
32 import org.springframework.security.access.prepost.PreAuthorize
33 import org.springframework.web.bind.annotation.PathVariable
34 import org.springframework.web.bind.annotation.PostMapping
35 import org.springframework.web.bind.annotation.RequestBody
36 import org.springframework.web.bind.annotation.RequestMapping
37 import org.springframework.web.bind.annotation.RequestMethod
38 import org.springframework.web.bind.annotation.RequestParam
39 import org.springframework.web.bind.annotation.ResponseBody
40 import org.springframework.web.bind.annotation.RestController
41
42 /**
43  * Exposes Resource Configuration Snapshot API to store and retrieve stored resource configurations.
44  *
45  * @author Serge Simard
46  * @version 1.0
47  */
48 @RestController
49 @RequestMapping("/api/v1/configs")
50 @Api(
51     value = "/api/v1/configs",
52     description = "Interaction with stored configurations."
53 )
54 open class ResourceConfigSnapshotController(private val resourceConfigSnapshotService: ResourceConfigSnapshotService) {
55
56     private val JSON_MIME_TYPE = "application/json"
57
58     @RequestMapping(
59         path = ["/health-check"],
60         method = [RequestMethod.GET],
61         produces = [MediaType.APPLICATION_JSON_VALUE]
62     )
63     @ResponseBody
64     @ApiOperation(value = "Health Check", hidden = true)
65     fun ressCfgSnapshotControllerHealthCheck(): JsonNode = runBlocking {
66         "Success".asJsonPrimitive()
67     }
68
69     @RequestMapping(
70         path = [""],
71         method = [RequestMethod.GET],
72         produces = [MediaType.TEXT_PLAIN_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE]
73     )
74     @ApiOperation(
75         value = "Retrieve a resource configuration snapshot.",
76         notes = "Retrieve a config snapshot, identified by its Resource Id and Type. " +
77             "An extra 'format' parameter can be passed to tell what content-type is expected."
78     )
79     @ResponseBody
80     @PreAuthorize("hasRole('USER')")
81     fun get(
82         @ApiParam(value = "Resource Type associated of the resource configuration snapshot.", required = false)
83         @RequestParam(value = "resourceType", required = true) resourceType: String,
84
85         @ApiParam(value = "Resource Id associated of the resource configuration snapshot.", required = false)
86         @RequestParam(value = "resourceId", required = true) resourceId: String,
87
88         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "RUNNING", required = false)
89         @RequestParam(value = "status", required = false, defaultValue = "RUNNING") status: String,
90
91         @ApiParam(
92             value = "Expected format of the snapshot being retrieved.", defaultValue = MediaType.TEXT_PLAIN_VALUE,
93             required = false
94         )
95         @RequestParam(value = "format", required = false, defaultValue = MediaType.TEXT_PLAIN_VALUE) format: String
96     ):
97
98         ResponseEntity<String> = runBlocking {
99
100             var configSnapshot = ""
101
102             if (resourceType.isNotEmpty() && resourceId.isNotEmpty()) {
103                 try {
104                     configSnapshot = resourceConfigSnapshotService.findByResourceIdAndResourceTypeAndStatus(
105                         resourceId,
106                         resourceType, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
107                     )
108                 } catch (ex: NoSuchElementException) {
109                     throw httpProcessorException(
110                         ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
111                         "Could not find configuration snapshot entry for type $resourceType and Id $resourceId",
112                         ex.errorCauseOrDefault()
113                     )
114                 } catch (ex: Exception) {
115                     throw httpProcessorException(
116                         ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
117                         "Could not find configuration snapshot entry for type $resourceType and Id $resourceId",
118                         ex.errorCauseOrDefault()
119                     )
120                 }
121             } else {
122                 throw httpProcessorException(
123                     ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
124                     "Missing param. You must specify resource-id and resource-type."
125                 )
126             }
127
128             var expectedContentType = format
129             if (expectedContentType.indexOf('/') < 0) {
130                 expectedContentType = "application/$expectedContentType"
131             }
132             val expectedMediaType: MediaType = MediaType.valueOf(expectedContentType)
133
134             ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshot)
135         }
136
137     @PostMapping(
138         "/{resourceType}/{resourceId}/{status}",
139         produces = [MediaType.APPLICATION_JSON_VALUE]
140     )
141     @ApiOperation(
142         value = "Store a resource configuration snapshot identified by resourceId, resourceType, status.",
143         notes = "Store a resource configuration snapshot, identified by its resourceId and resourceType, " +
144             "and optionally its status, either RUNNING or CANDIDATE.",
145         response = ResourceConfigSnapshot::class, produces = MediaType.APPLICATION_JSON_VALUE
146     )
147     @ResponseBody
148     @PreAuthorize("hasRole('USER')")
149     fun postWithResourceIdAndResourceType(
150         @ApiParam(value = "Resource Type associated with the resolution.", required = false)
151         @PathVariable(value = "resourceType", required = true) resourceType: String,
152         @ApiParam(value = "Resource Id associated with the resolution.", required = false)
153         @PathVariable(value = "resourceId", required = true) resourceId: String,
154         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "RUNNING", required = true)
155         @PathVariable(value = "status", required = true) status: String,
156         @ApiParam(value = "Config snapshot to store.", required = true)
157         @RequestBody snapshot: String
158     ): ResponseEntity<ResourceConfigSnapshot> = runBlocking {
159
160         val resultStored =
161             resourceConfigSnapshotService.write(
162                 snapshot, resourceId, resourceType,
163                 ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
164             )
165
166         ResponseEntity.ok().body(resultStored)
167     }
168
169     @RequestMapping(
170         path = ["/allByID"],
171         method = [RequestMethod.GET],
172         produces = [MediaType.APPLICATION_JSON_VALUE]
173     )
174     @ApiOperation(
175         value = "Retrieve all resource configuration snapshots identified by a given resource_id",
176         notes = "Retrieve all config snapshots, identified by its Resource Id, ordered by most recently created/modified date. "
177     )
178     @ResponseBody
179     @PreAuthorize("hasRole('USER')")
180     fun getAllByID(
181         @ApiParam(value = "Resource Id associated of the resource configuration snapshots.", required = false)
182         @RequestParam(value = "resourceId", required = true) resourceId: String,
183         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "ANY", required = false)
184         @RequestParam(value = "status", required = false, defaultValue = "ANY") status: String
185     ): ResponseEntity<List<ResourceConfigSnapshot>?> = runBlocking {
186         var configSnapshots: List<ResourceConfigSnapshot>?
187
188         try {
189             if (status == "ANY") {
190                 configSnapshots = resourceConfigSnapshotService.findAllByResourceId(resourceId)
191             } else {
192                 configSnapshots = resourceConfigSnapshotService.findAllByResourceIdForStatus(
193                     resourceId, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
194                 )
195             }
196         } catch (ex: NoSuchElementException) {
197             throw httpProcessorException(
198                 ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
199                 "Could not find configuration snapshot entry for ID $resourceId",
200                 ex.errorCauseOrDefault()
201             )
202         } catch (ex: Exception) {
203             throw httpProcessorException(
204                 ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
205                 "Unexpected error while finding configuration snapshot entries for ID $resourceId",
206                 ex.errorCauseOrDefault()
207             )
208         }
209
210         val expectedMediaType: MediaType = MediaType.valueOf(JSON_MIME_TYPE)
211         ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshots)
212     }
213
214     @RequestMapping(
215         path = ["allByType"],
216         method = [RequestMethod.GET],
217         produces = [MediaType.APPLICATION_JSON_VALUE]
218     )
219     @ApiOperation(
220         value = "Retrieve all resource configuration snapshots for a given resource type.",
221         notes = "Retrieve all config snapshots matching a specified Resource Type, ordered by most recently created/modified date. "
222     )
223     @ResponseBody
224     @PreAuthorize("hasRole('USER')")
225     fun getAllByType(
226         @ApiParam(value = "Resource Type associated of the resource configuration snapshot.", required = false)
227         @RequestParam(value = "resourceType", required = true) resourceType: String,
228         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "ANY", required = false)
229         @RequestParam(value = "status", required = false, defaultValue = "ANY") status: String
230     ): ResponseEntity<List<ResourceConfigSnapshot>?> = runBlocking {
231         var configSnapshots: List<ResourceConfigSnapshot>?
232
233         try {
234             if (status == "ANY") {
235                 configSnapshots = resourceConfigSnapshotService.findAllByResourceType(resourceType)
236             } else {
237                 configSnapshots = resourceConfigSnapshotService.findAllByResourceTypeForStatus(
238                     resourceType, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
239                 )
240             }
241         } catch (ex: NoSuchElementException) {
242             throw httpProcessorException(
243                 ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
244                 "Could not find configuration snapshot entry for ID $resourceType",
245                 ex.errorCauseOrDefault()
246             )
247         } catch (ex: Exception) {
248             throw httpProcessorException(
249                 ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
250                 "Unexpected error while finding configuration snapshot entries for type $resourceType",
251                 ex.errorCauseOrDefault()
252             )
253         }
254
255         val expectedMediaType: MediaType = MediaType.valueOf(JSON_MIME_TYPE)
256         ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshots)
257     }
258 }