714cf3a46f74741764d666ec48d4d575d2681534
[ccsdk/cds.git] /
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2019 Bell Canada.
4  * Modifications Copyright © 2019 IBM.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 package org.onap.ccsdk.cds.blueprintsprocessor.designer.api
20
21 import com.google.protobuf.ByteString
22 import com.google.protobuf.util.JsonFormat
23 import io.grpc.stub.StreamObserver
24 import kotlinx.coroutines.runBlocking
25 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler.BluePrintModelHandler
26 import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader
27 import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
28 import org.onap.ccsdk.cds.controllerblueprints.common.api.Status
29 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
30 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
31 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonString
32 import org.onap.ccsdk.cds.controllerblueprints.core.emptyTONull
33 import org.onap.ccsdk.cds.controllerblueprints.core.utils.currentTimestamp
34 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintBootstrapInput
35 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintDownloadInput
36 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementOutput
37 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintManagementServiceGrpc
38 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintRemoveInput
39 import org.onap.ccsdk.cds.controllerblueprints.management.api.BluePrintUploadInput
40 import org.onap.ccsdk.cds.controllerblueprints.management.api.DownloadAction
41 import org.onap.ccsdk.cds.controllerblueprints.management.api.FileChunk
42 import org.onap.ccsdk.cds.controllerblueprints.management.api.RemoveAction
43 import org.onap.ccsdk.cds.controllerblueprints.management.api.UploadAction
44 import org.onap.ccsdk.cds.error.catalog.core.ErrorCatalogCodes
45 import org.onap.ccsdk.cds.error.catalog.core.GrpcErrorCodes
46 import org.onap.ccsdk.cds.error.catalog.core.utils.errorMessageOrDefault
47 import org.onap.ccsdk.cds.error.catalog.services.ErrorCatalogService
48 import org.slf4j.LoggerFactory
49 import org.springframework.security.access.prepost.PreAuthorize
50 import org.springframework.stereotype.Service
51
52 // TODO("Convert to coroutines handler")
53 @Service
54 open class BluePrintManagementGRPCHandler(
55     private val bluePrintModelHandler: BluePrintModelHandler,
56     private val errorCatalogService: ErrorCatalogService
57 ) :
58     BluePrintManagementServiceGrpc.BluePrintManagementServiceImplBase() {
59
60     private val log = LoggerFactory.getLogger(BluePrintManagementGRPCHandler::class.java)
61
62     @PreAuthorize("hasRole('USER')")
63     override fun uploadBlueprint(
64         request: BluePrintUploadInput,
65         responseObserver: StreamObserver<BluePrintManagementOutput>
66     ) {
67
68         runBlocking {
69             // TODO("catch if request id is missing")
70             log.info("request(${request.commonHeader.requestId})")
71             try {
72                 /** Get the file byte array */
73                 val byteArray = request.fileChunk.chunk.toByteArray()
74                 /** Get the Upload Action */
75                 val uploadAction = request.actionIdentifiers?.actionName.emptyTONull()
76                     ?: UploadAction.DRAFT.toString()
77
78                 when (uploadAction) {
79                     UploadAction.DRAFT.toString() -> {
80                         val blueprintModel = bluePrintModelHandler.upload(byteArray, false)
81                         responseObserver.onNext(successStatus(request.commonHeader, blueprintModel.asJsonString()))
82                     }
83                     UploadAction.PUBLISH.toString() -> {
84                         val blueprintModel = bluePrintModelHandler.upload(byteArray, true)
85                         responseObserver.onNext(successStatus(request.commonHeader, blueprintModel.asJsonString()))
86                     }
87                     UploadAction.VALIDATE.toString() -> {
88                         // TODO("Not Implemented")
89                         responseObserver.onNext(
90                             failStatus(
91                                 request.commonHeader,
92                                 "Upload action($uploadAction) not implemented",
93                                 BluePrintProcessorException("Not Implemented")
94                             )
95                         )
96                     }
97                     UploadAction.ENRICH.toString() -> {
98                         val enrichedByteArray = bluePrintModelHandler.enrichBlueprintFileSource(byteArray)
99                         responseObserver.onNext(outputWithFileBytes(request.commonHeader, enrichedByteArray))
100                     }
101                     else -> {
102                         responseObserver.onNext(
103                             failStatus(
104                                 request.commonHeader,
105                                 "Upload action($uploadAction) not implemented",
106                                 BluePrintProcessorException("Not implemented")
107                             )
108                         )
109                     }
110                 }
111             } catch (e: Exception) {
112                 responseObserver.onNext(
113                     failStatus(
114                         request.commonHeader,
115                         "request(${request.commonHeader.requestId}): Failed to upload CBA", e
116                     )
117                 )
118             } finally {
119                 responseObserver.onCompleted()
120             }
121         }
122     }
123
124     @PreAuthorize("hasRole('USER')")
125     override fun downloadBlueprint(
126         request: BluePrintDownloadInput,
127         responseObserver: StreamObserver<BluePrintManagementOutput>
128     ) {
129         runBlocking {
130             val blueprintName = request.actionIdentifiers.blueprintName
131             val blueprintVersion = request.actionIdentifiers.blueprintVersion
132             val blueprint = "blueprint $blueprintName:$blueprintVersion"
133
134             /** Get the Search Action */
135             val searchAction = request.actionIdentifiers?.actionName.emptyTONull()
136                 ?: DownloadAction.SEARCH.toString()
137
138             log.info("request(${request.commonHeader.requestId}): Received download $blueprint")
139             try {
140                 when (searchAction) {
141                     DownloadAction.SEARCH.toString() -> {
142                         val downloadByteArray = bluePrintModelHandler.download(blueprintName, blueprintVersion)
143                         responseObserver.onNext(outputWithFileBytes(request.commonHeader, downloadByteArray))
144                     }
145                     else -> {
146                         responseObserver.onNext(
147                             failStatus(
148                                 request.commonHeader,
149                                 "Search action($searchAction) not implemented",
150                                 BluePrintProcessorException("Not implemented")
151                             )
152                         )
153                     }
154                 }
155             } catch (e: Exception) {
156                 responseObserver.onNext(
157                     failStatus(
158                         request.commonHeader,
159                         "request(${request.commonHeader.requestId}): Failed to delete $blueprint", e
160                     )
161                 )
162             } finally {
163                 responseObserver.onCompleted()
164             }
165         }
166     }
167
168     @PreAuthorize("hasRole('USER')")
169     override fun removeBlueprint(
170         request: BluePrintRemoveInput,
171         responseObserver:
172         StreamObserver<BluePrintManagementOutput>
173     ) {
174
175         runBlocking {
176             val blueprintName = request.actionIdentifiers.blueprintName
177             val blueprintVersion = request.actionIdentifiers.blueprintVersion
178             val blueprint = "blueprint $blueprintName:$blueprintVersion"
179
180             log.info("request(${request.commonHeader.requestId}): Received delete $blueprint")
181
182             /** Get the Remove Action */
183             val removeAction = request.actionIdentifiers?.actionName.emptyTONull()
184                 ?: RemoveAction.DEFAULT.toString()
185
186             try {
187                 when (removeAction) {
188                     RemoveAction.DEFAULT.toString() -> {
189                         bluePrintModelHandler.deleteBlueprintModel(blueprintName, blueprintVersion)
190                         responseObserver.onNext(successStatus(request.commonHeader))
191                     }
192                     else -> {
193                         responseObserver.onNext(
194                             failStatus(
195                                 request.commonHeader,
196                                 "Remove action($removeAction) not implemented",
197                                 BluePrintProcessorException("Not implemented")
198                             )
199                         )
200                     }
201                 }
202             } catch (e: Exception) {
203                 responseObserver.onNext(
204                     failStatus(
205                         request.commonHeader,
206                         "request(${request.commonHeader.requestId}): Failed to delete $blueprint", e
207                     )
208                 )
209             } finally {
210                 responseObserver.onCompleted()
211             }
212         }
213     }
214
215     override fun bootstrapBlueprint(
216         request: BluePrintBootstrapInput,
217         responseObserver: StreamObserver<BluePrintManagementOutput>
218     ) {
219         runBlocking {
220             try {
221                 log.info("request(${request.commonHeader.requestId}): Received bootstrap request")
222                 val bootstrapRequest = BootstrapRequest().apply {
223                     loadModelType = request.loadModelType
224                     loadResourceDictionary = request.loadResourceDictionary
225                     loadCBA = request.loadCBA
226                 }
227                 /** Perform bootstrap of Model Types, Resource Definitions and CBA */
228                 bluePrintModelHandler.bootstrapBlueprint(bootstrapRequest)
229                 responseObserver.onNext(successStatus(request.commonHeader))
230             } catch (e: Exception) {
231                 responseObserver.onNext(
232                     failStatus(
233                         request.commonHeader,
234                         "request(${request.commonHeader.requestId}): Failed to bootstrap", e
235                     )
236                 )
237             } finally {
238                 responseObserver.onCompleted()
239             }
240         }
241     }
242
243     private fun outputWithFileBytes(header: CommonHeader, byteArray: ByteArray): BluePrintManagementOutput =
244         BluePrintManagementOutput.newBuilder()
245             .setCommonHeader(header)
246             .setFileChunk(FileChunk.newBuilder().setChunk(ByteString.copyFrom(byteArray)))
247             .setStatus(
248                 Status.newBuilder()
249                     .setTimestamp(currentTimestamp())
250                     .setEventType(EventType.EVENT_COMPONENT_EXECUTED)
251                     .setMessage(BluePrintConstants.STATUS_SUCCESS)
252                     .setCode(200)
253                     .build()
254             )
255             .build()
256
257     private fun successStatus(header: CommonHeader, propertyContent: String? = null): BluePrintManagementOutput {
258         // Populate Response Payload
259         val propertiesBuilder = BluePrintManagementOutput.newBuilder().propertiesBuilder
260         propertyContent?.let {
261             JsonFormat.parser().merge(propertyContent, propertiesBuilder)
262         }
263         return BluePrintManagementOutput.newBuilder()
264             .setCommonHeader(header)
265             .setProperties(propertiesBuilder.build())
266             .setStatus(
267                 Status.newBuilder()
268                     .setTimestamp(currentTimestamp())
269                     .setMessage(BluePrintConstants.STATUS_SUCCESS)
270                     .setEventType(EventType.EVENT_COMPONENT_EXECUTED)
271                     .setCode(200)
272                     .build()
273             )
274             .build()
275     }
276
277     private fun failStatus(header: CommonHeader, message: String, e: Exception): BluePrintManagementOutput {
278         log.error(message, e)
279         return if (e is BluePrintProcessorException) onErrorCatalog(header, message, e) else onError(header, message, e)
280     }
281
282     private fun onError(header: CommonHeader, message: String, error: Exception): BluePrintManagementOutput {
283         val code = GrpcErrorCodes.code(ErrorCatalogCodes.GENERIC_FAILURE)
284         return BluePrintManagementOutput.newBuilder()
285                 .setCommonHeader(header)
286                 .setStatus(
287                         Status.newBuilder()
288                                 .setTimestamp(currentTimestamp())
289                                 .setMessage(BluePrintConstants.STATUS_FAILURE)
290                                 .setEventType(EventType.EVENT_COMPONENT_FAILURE)
291                                 .setErrorMessage("Error : $message \n Details: ${error.errorMessageOrDefault()}")
292                                 .setCode(code)
293                                 .build()
294                 )
295                 .build()
296     }
297
298     private fun onErrorCatalog(header: CommonHeader, message: String, error: BluePrintProcessorException):
299             BluePrintManagementOutput {
300         val err = if (error.protocol == "") {
301             error.grpc(ErrorCatalogCodes.GENERIC_FAILURE)
302         } else {
303             error.convertToGrpc()
304         }
305         val errorPayload = errorCatalogService.errorPayload(err.addErrorPayloadMessage(message))
306         return BluePrintManagementOutput.newBuilder()
307                 .setCommonHeader(header)
308                 .setStatus(
309                         Status.newBuilder()
310                                 .setTimestamp(currentTimestamp())
311                                 .setMessage(BluePrintConstants.STATUS_FAILURE)
312                                 .setEventType(EventType.EVENT_COMPONENT_FAILURE)
313                                 .setErrorMessage("Error : ${errorPayload.message}")
314                                 .setCode(errorPayload.code)
315                                 .build()
316                 )
317                 .build()
318     }
319 }