584df27ed62364c89572e48a9022b4725d3299f5
[ccsdk/cds.git] /
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 = "Resource configuration",
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         method = [RequestMethod.GET],
71         produces = [MediaType.TEXT_PLAIN_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE]
72     )
73     @ApiOperation(
74         value = "Retrieve a resource configuration snapshot.",
75         notes = "Retrieve a config snapshot, identified by its Resource Id and Type. " +
76             "An extra 'format' parameter can be passed to tell what content-type is expected."
77     )
78     @ResponseBody
79     @PreAuthorize("hasRole('USER')")
80     fun get(
81         @ApiParam(value = "Resource Type associated of the resource configuration snapshot.", required = false, example = "\"PNF\"")
82         @RequestParam(value = "resourceType", required = true) resourceType: String,
83
84         @ApiParam(value = "Resource Id associated of the resource configuration snapshot.", required = false, example = "\"1\"")
85         @RequestParam(value = "resourceId", required = true) resourceId: String,
86
87         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "RUNNING", required = false)
88         @RequestParam(value = "status", required = false, defaultValue = "RUNNING") status: String,
89
90         @ApiParam(
91             value = "Expected format of the snapshot being retrieved.", defaultValue = MediaType.TEXT_PLAIN_VALUE,
92             required = false
93         )
94         @RequestParam(value = "format", required = false, defaultValue = MediaType.TEXT_PLAIN_VALUE) format: String
95     ):
96
97         ResponseEntity<String> = runBlocking {
98
99             var configSnapshot = ""
100
101             if (resourceType.isNotEmpty() && resourceId.isNotEmpty()) {
102                 try {
103                     configSnapshot = resourceConfigSnapshotService.findByResourceIdAndResourceTypeAndStatus(
104                         resourceId,
105                         resourceType, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
106                     )
107                 } catch (ex: NoSuchElementException) {
108                     throw httpProcessorException(
109                         ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
110                         "Could not find configuration snapshot entry for type $resourceType and Id $resourceId",
111                         ex.errorCauseOrDefault()
112                     )
113                 } catch (ex: Exception) {
114                     throw httpProcessorException(
115                         ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
116                         "Could not find configuration snapshot entry for type $resourceType and Id $resourceId",
117                         ex.errorCauseOrDefault()
118                     )
119                 }
120             } else {
121                 throw httpProcessorException(
122                     ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
123                     "Missing param. You must specify resource-id and resource-type."
124                 )
125             }
126
127             var expectedContentType = format
128             if (expectedContentType.indexOf('/') < 0) {
129                 expectedContentType = "application/$expectedContentType"
130             }
131             val expectedMediaType: MediaType = MediaType.valueOf(expectedContentType)
132
133             ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshot)
134         }
135
136     @PostMapping(
137         "/{resourceType}/{resourceId}/{status}",
138         produces = [MediaType.APPLICATION_JSON_VALUE]
139     )
140     @ApiOperation(
141         value = "Store a resource configuration snapshot identified by resourceId, resourceType, status.",
142         notes = "Store a resource configuration snapshot, identified by its resourceId and resourceType, " +
143             "and optionally its status, either RUNNING or CANDIDATE.",
144         response = ResourceConfigSnapshot::class
145     )
146     @ResponseBody
147     @PreAuthorize("hasRole('USER')")
148     fun postWithResourceIdAndResourceType(
149         @ApiParam(value = "Resource Type associated with the resolution.", required = false, example = "\"PNF\"")
150         @PathVariable(value = "resourceType", required = true) resourceType: String,
151         @ApiParam(value = "Resource Id associated with the resolution.", required = false, example = "\"1\"")
152         @PathVariable(value = "resourceId", required = true) resourceId: String,
153         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "RUNNING", required = true)
154         @PathVariable(value = "status", required = true) status: String,
155         @ApiParam(value = "Config snapshot to store.", required = true, example = "\"config_snapshot\"")
156         @RequestBody snapshot: String
157     ): ResponseEntity<ResourceConfigSnapshot> = runBlocking {
158
159         val resultStored =
160             resourceConfigSnapshotService.write(
161                 snapshot, resourceId, resourceType,
162                 ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
163             )
164
165         ResponseEntity.ok().body(resultStored)
166     }
167
168     @RequestMapping(
169         path = ["/allByID"],
170         method = [RequestMethod.GET],
171         produces = [MediaType.APPLICATION_JSON_VALUE]
172     )
173     @ApiOperation(
174         value = "Retrieve all resource configuration snapshots identified by a given resource_id",
175         notes = "Retrieve all config snapshots, identified by its Resource Id, ordered by most recently created/modified date. "
176     )
177     @ResponseBody
178     @PreAuthorize("hasRole('USER')")
179     fun getAllByID(
180         @ApiParam(value = "Resource Id associated of the resource configuration snapshots.", required = false, example = "\"1\"")
181         @RequestParam(value = "resourceId", required = true) resourceId: String,
182         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "ANY", required = false)
183         @RequestParam(value = "status", required = false, defaultValue = "ANY") status: String
184     ): ResponseEntity<List<ResourceConfigSnapshot>?> = runBlocking {
185         var configSnapshots: List<ResourceConfigSnapshot>?
186
187         try {
188             if (status == "ANY") {
189                 configSnapshots = resourceConfigSnapshotService.findAllByResourceId(resourceId)
190             } else {
191                 configSnapshots = resourceConfigSnapshotService.findAllByResourceIdForStatus(
192                     resourceId, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
193                 )
194             }
195         } catch (ex: NoSuchElementException) {
196             throw httpProcessorException(
197                 ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
198                 "Could not find configuration snapshot entry for ID $resourceId",
199                 ex.errorCauseOrDefault()
200             )
201         } catch (ex: Exception) {
202             throw httpProcessorException(
203                 ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
204                 "Unexpected error while finding configuration snapshot entries for ID $resourceId",
205                 ex.errorCauseOrDefault()
206             )
207         }
208
209         val expectedMediaType: MediaType = MediaType.valueOf(JSON_MIME_TYPE)
210         ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshots)
211     }
212
213     @RequestMapping(
214         path = ["allByType"],
215         method = [RequestMethod.GET],
216         produces = [MediaType.APPLICATION_JSON_VALUE]
217     )
218     @ApiOperation(
219         value = "Retrieve all resource configuration snapshots for a given resource type.",
220         notes = "Retrieve all config snapshots matching a specified Resource Type, ordered by most recently created/modified date. "
221     )
222     @ResponseBody
223     @PreAuthorize("hasRole('USER')")
224     fun getAllByType(
225         @ApiParam(value = "Resource Type associated of the resource configuration snapshot.", required = false, example = "\"PNF\"")
226         @RequestParam(value = "resourceType", required = true) resourceType: String,
227         @ApiParam(value = "Status of the snapshot being retrieved.", defaultValue = "ANY", required = false)
228         @RequestParam(value = "status", required = false, defaultValue = "ANY") status: String
229     ): ResponseEntity<List<ResourceConfigSnapshot>?> = runBlocking {
230         var configSnapshots: List<ResourceConfigSnapshot>?
231
232         try {
233             if (status == "ANY") {
234                 configSnapshots = resourceConfigSnapshotService.findAllByResourceType(resourceType)
235             } else {
236                 configSnapshots = resourceConfigSnapshotService.findAllByResourceTypeForStatus(
237                     resourceType, ResourceConfigSnapshot.Status.valueOf(status.toUpperCase())
238                 )
239             }
240         } catch (ex: NoSuchElementException) {
241             throw httpProcessorException(
242                 ErrorCatalogCodes.RESOURCE_NOT_FOUND, ConfigsApiDomains.CONFIGS_API,
243                 "Could not find configuration snapshot entry for ID $resourceType",
244                 ex.errorCauseOrDefault()
245             )
246         } catch (ex: Exception) {
247             throw httpProcessorException(
248                 ErrorCatalogCodes.INVALID_REQUEST_FORMAT, ConfigsApiDomains.CONFIGS_API,
249                 "Unexpected error while finding configuration snapshot entries for type $resourceType",
250                 ex.errorCauseOrDefault()
251             )
252         }
253
254         val expectedMediaType: MediaType = MediaType.valueOf(JSON_MIME_TYPE)
255         ResponseEntity.ok().contentType(expectedMediaType).body(configSnapshots)
256     }
257 }