1 package org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor
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
29 open class Mount : AbstractScriptComponentFunction() {
31 val log = LoggerFactory.getLogger(Mount::class.java)!!
33 override fun getName(): String {
37 override suspend fun processNB(executionRequest: ExecutionServiceInput) {
38 log.info("Mounting ODL restconf node process")
40 val deviceInformation = relationshipProperty(RESTCONF_CONNECTION_CONFIG, PROPERTY_CONNECTION_CONFIG)
41 val webclientService = restconfClientService(deviceInformation)
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())
50 ComponentRemoteScriptExecutor.ATTRIBUTE_STATUS,
51 BluePrintConstants.STATUS_SUCCESS.asJsonPrimitive()
55 override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
56 addError("failed in restconf execution : ${runtimeException.message}")
60 open class Execute : AbstractScriptComponentFunction() {
62 val log = LoggerFactory.getLogger(Execute::class.java)!!
64 override fun getName(): String {
68 override suspend fun processNB(executionRequest: ExecutionServiceInput) {
69 val nodeIdJson = requestPayloadActionProperty(NODE_ID)?.first()
70 ?: throw BluePrintProcessorException("Failed to load $NODE_ID properties.")
72 val failFastJsonNode = requestPayloadActionProperty(FAIL_FAST)!!
73 val failFast = if (failFastJsonNode.isEmpty) false else failFastJsonNode.first().booleanValue()
75 val deviceInformation = relationshipProperty(RESTCONF_CONNECTION_CONFIG, PROPERTY_CONNECTION_CONFIG)
77 val webclientService = restconfClientService(deviceInformation)
78 val nodeId = nodeIdJson.textValue()
80 val actionList = requestPayloadActionProperty("action")?.first()
81 ?: throw BluePrintProcessorException("Failed to load action properties.")
82 validateActionList(actionList)
84 val actionListResults: MutableList<Map<String, JsonNode>> = mutableListOf()
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()
95 val payload = action.get(ACTION_PAYLOAD)
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
101 val actionInput: MutableMap<String, JsonNode> = hashMapOf()
102 actionInput[ACTION_TYPE] = actionTypeJsonNode
103 actionInput[ACTION_PATH] = actionPathJsonNode
104 actionInput[ACTION_DATASTORE] = dsJsonNode
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
111 actionResult[ACTION_INPUT] = jsonNodeFromObject(actionInput)
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()
118 actionResult[ComponentScriptExecutor.ATTRIBUTE_STATUS] =
119 BluePrintConstants.STATUS_FAILURE.asJsonPrimitive()
121 BluePrintConstants.STATUS_FAILURE,
122 ComponentScriptExecutor.ATTRIBUTE_STATUS,
123 actionResponse.asText()
126 actionListResults.add(actionResult)
130 actionListResults.add(actionResult)
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) {
139 ComponentScriptExecutor.ATTRIBUTE_STATUS,
140 BluePrintConstants.STATUS_FAILURE.asJsonPrimitive()
142 val errorResponse = actionResult[ACTION_OUTPUT]!!
144 BluePrintConstants.STATUS_FAILURE, ComponentScriptExecutor.ATTRIBUTE_STATUS,
145 errorResponse.asText()
151 override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
152 addError("failed in restconf execution : ${runtimeException.message}")
155 private suspend fun executeAction(
156 webClientService: BlueprintWebClientService,
158 actionType: RestconfRequestType,
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)
167 RestconfRequestType.PUT, RestconfRequestType.POST -> {
168 genericPutPatchPostRequest(webClientService, path, actionType, payload.toString(), headers)
170 RestconfRequestType.GET -> {
171 getRequest(webClientService, path)
173 RestconfRequestType.DELETE -> {
174 genericGetOrDeleteRequest(webClientService, path, RestconfRequestType.DELETE)
179 private fun validateActionList(actionList: JsonNode) {
180 if (actionList.isEmpty) {
181 throw BluePrintProcessorException("No actions defined")
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.")