Revert "Renaming Files having BluePrint to have Blueprint"
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / restconf-executor / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / restconf / executor / RestconfExecutor.kt
1 package org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor
2
3 import com.fasterxml.jackson.databind.JsonNode
4 import com.fasterxml.jackson.databind.node.TextNode
5 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
6 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_DATASTORE
7 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_INPUT
8 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_OUTPUT
9 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_PATH
10 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_PAYLOAD
11 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_TYPE
12 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.NODE_ID
13 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.FAIL_FAST
14 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.HTTP_SUCCESS_RANGE
15 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.MOUNT_PAYLOAD
16 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.RESTCONF_CONNECTION_CONFIG
17 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
18 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
19 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ComponentRemoteScriptExecutor
20 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ComponentScriptExecutor
21 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
22 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants.PROPERTY_CONNECTION_CONFIG
23 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
24 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
25 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
26 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils.Companion.jsonNodeFromObject
27 import org.slf4j.LoggerFactory
28
29 open class Mount : AbstractScriptComponentFunction() {
30
31     val log = LoggerFactory.getLogger(Mount::class.java)!!
32
33     override fun getName(): String {
34         return "Mount"
35     }
36
37     override suspend fun processNB(executionRequest: ExecutionServiceInput) {
38         log.info("Mounting ODL restconf node process")
39
40         val deviceInformation = relationshipProperty(RESTCONF_CONNECTION_CONFIG, PROPERTY_CONNECTION_CONFIG)
41         val webclientService = restconfClientService(deviceInformation)
42
43         val nodeId = requestPayloadActionProperty(NODE_ID)?.first()?.textValue()
44             ?: throw BluePrintProcessorException("Failed to load $NODE_ID properties.")
45         val mountPayload = requestPayloadActionProperty(MOUNT_PAYLOAD)?.first()
46             ?: throw BluePrintProcessorException("Failed to load $MOUNT_PAYLOAD properties.")
47         restconfMountDeviceJson(webclientService, nodeId, mountPayload.toString())
48
49         setAttribute(
50             ComponentRemoteScriptExecutor.ATTRIBUTE_STATUS,
51             BluePrintConstants.STATUS_SUCCESS.asJsonPrimitive()
52         )
53     }
54
55     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
56         addError("failed in restconf execution : ${runtimeException.message}")
57     }
58 }
59
60 open class Execute : AbstractScriptComponentFunction() {
61
62     val log = LoggerFactory.getLogger(Execute::class.java)!!
63
64     override fun getName(): String {
65         return "Execute"
66     }
67
68     override suspend fun processNB(executionRequest: ExecutionServiceInput) {
69         val nodeIdJson = requestPayloadActionProperty(NODE_ID)?.first()
70             ?: throw BluePrintProcessorException("Failed to load $NODE_ID properties.")
71
72         val failFastJsonNode = requestPayloadActionProperty(FAIL_FAST)!!
73         val failFast = if (failFastJsonNode.isEmpty) false else failFastJsonNode.first().booleanValue()
74
75         val deviceInformation = relationshipProperty(RESTCONF_CONNECTION_CONFIG, PROPERTY_CONNECTION_CONFIG)
76
77         val webclientService = restconfClientService(deviceInformation)
78         val nodeId = nodeIdJson.textValue()
79
80         val actionList = requestPayloadActionProperty("action")?.first()
81             ?: throw BluePrintProcessorException("Failed to load action properties.")
82         validateActionList(actionList)
83
84         val actionListResults: MutableList<Map<String, JsonNode>> = mutableListOf()
85
86         for (action in actionList) {
87             val actionTypeJsonNode = action.get(ACTION_TYPE)
88             val actionPathJsonNode = action.get(ACTION_PATH)
89             val actionType = RestconfRequestType.valueOf(actionTypeJsonNode.asText().toUpperCase())
90             val dsJsonNode = action.get(ACTION_DATASTORE)
91             val path = restconfPath(
92                 RestconfRequestDatastore.valueOf(dsJsonNode.asText().toUpperCase()),
93                 nodeId, actionPathJsonNode.asText()
94             )
95             val payload = action.get(ACTION_PAYLOAD)
96
97             log.info("Processing Restconf action : $actionType $path" + if (payload != null) " $payload" else "")
98             val response = executeAction(webclientService, path, actionType, payload)
99             val responseBody = response.body
100
101             val actionInput: MutableMap<String, JsonNode> = hashMapOf()
102             actionInput[ACTION_TYPE] = actionTypeJsonNode
103             actionInput[ACTION_PATH] = actionPathJsonNode
104             actionInput[ACTION_DATASTORE] = dsJsonNode
105
106             val actionResult: MutableMap<String, JsonNode> = hashMapOf()
107             val actionResponse = responseBody.asJsonType()
108             if (actionResponse !is TextNode && actionResponse.toString().isNotBlank()) {
109                 actionResult[ACTION_OUTPUT] = actionResponse
110             }
111             actionResult[ACTION_INPUT] = jsonNodeFromObject(actionInput)
112
113             if (response.status in HTTP_SUCCESS_RANGE) {
114                 log.info("\nRestconf execution response : \n{}", responseBody.asJsonType().toPrettyString())
115                 actionResult[ComponentScriptExecutor.ATTRIBUTE_STATUS] =
116                     BluePrintConstants.STATUS_SUCCESS.asJsonPrimitive()
117             } else {
118                 actionResult[ComponentScriptExecutor.ATTRIBUTE_STATUS] =
119                     BluePrintConstants.STATUS_FAILURE.asJsonPrimitive()
120                 addError(
121                     BluePrintConstants.STATUS_FAILURE,
122                     ComponentScriptExecutor.ATTRIBUTE_STATUS,
123                     actionResponse.asText()
124                 )
125                 if (failFast) {
126                     actionListResults.add(actionResult)
127                     break
128                 }
129             }
130             actionListResults.add(actionResult)
131         }
132
133         setAttribute(ComponentScriptExecutor.ATTRIBUTE_RESPONSE_DATA, jsonNodeFromObject(actionListResults))
134         setAttribute(ComponentScriptExecutor.ATTRIBUTE_STATUS, BluePrintConstants.STATUS_SUCCESS.asJsonPrimitive())
135         actionListResults.forEach { actionResult ->
136             val actionResultStatus = actionResult[ComponentScriptExecutor.ATTRIBUTE_STATUS]
137             if (BluePrintConstants.STATUS_SUCCESS.asJsonPrimitive() != actionResultStatus) {
138                 setAttribute(
139                     ComponentScriptExecutor.ATTRIBUTE_STATUS,
140                     BluePrintConstants.STATUS_FAILURE.asJsonPrimitive()
141                 )
142                 val errorResponse = actionResult[ACTION_OUTPUT]!!
143                 addError(
144                     BluePrintConstants.STATUS_FAILURE, ComponentScriptExecutor.ATTRIBUTE_STATUS,
145                     errorResponse.asText()
146                 )
147             }
148         }
149     }
150
151     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
152         addError("failed in restconf execution : ${runtimeException.message}")
153     }
154
155     private suspend fun executeAction(
156         webClientService: BlueprintWebClientService,
157         path: String,
158         actionType: RestconfRequestType,
159         payload: JsonNode?
160     ): BlueprintWebClientService.WebClientResponse<String> {
161         var headers = mutableMapOf("Content-Type" to "application/json")
162         return when (actionType) {
163             RestconfRequestType.PATCH -> {
164                 headers = mutableMapOf("Content-Type" to "application/yang.patch-status+json")
165                 genericPutPatchPostRequest(webClientService, path, actionType, payload.toString(), headers)
166             }
167             RestconfRequestType.PUT, RestconfRequestType.POST -> {
168                 genericPutPatchPostRequest(webClientService, path, actionType, payload.toString(), headers)
169             }
170             RestconfRequestType.GET -> {
171                 getRequest(webClientService, path)
172             }
173             RestconfRequestType.DELETE -> {
174                 genericGetOrDeleteRequest(webClientService, path, RestconfRequestType.DELETE)
175             }
176         }
177     }
178
179     private fun validateActionList(actionList: JsonNode) {
180         if (actionList.isEmpty) {
181             throw BluePrintProcessorException("No actions defined")
182         }
183         actionList.forEach { action ->
184             action.get(ACTION_PATH)
185                 ?: throw BluePrintProcessorException("Failed to load action path.")
186             action.get(ACTION_DATASTORE)
187                 ?: throw BluePrintProcessorException("Failed to load action datastore.")
188             val actionTypeJsonNode = action.get(ACTION_TYPE)
189                 ?: throw BluePrintProcessorException("Failed to load action type.")
190             when (val actionType = RestconfRequestType.valueOf(actionTypeJsonNode.asText().toUpperCase())) {
191                 RestconfRequestType.PATCH, RestconfRequestType.PUT, RestconfRequestType.POST -> {
192                     action.get(ACTION_PAYLOAD)
193                         ?: throw BluePrintProcessorException("Failed to load action $actionType payload.")
194                 }
195             }
196         }
197     }
198 }