aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaudio D. Gasparini <claudio.gasparini@intl.att.com>2021-03-29 10:02:17 +0200
committerClaudio David Gasparini <claudio.gasparini@intl.att.com>2021-03-30 14:56:08 +0000
commit3ca2faef79e4a69cd03f202ab1ae26b4e564e743 (patch)
tree87791fd1befe7c697c29d8e0d33b4aaa2cc90e1b
parent53341bfd9e0ed5511ae5246cecc6a840e0dd1136 (diff)
Extend Restconf executor function
provide capability to - execute a sorted array of restconf actions - mount odl restconf node Issue-ID: CCSDK-3241 Signed-off-by: Claudio D. Gasparini <claudio.gasparini@intl.att.com> Change-Id: I1999195f7b84a259d82f9c5aa31e9fa892e9c3df
-rw-r--r--components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt2
-rw-r--r--components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt2
-rw-r--r--components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Scripts/kotlin/RestconfConfigDeploy.kt2
-rw-r--r--ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfConstants.kt21
-rw-r--r--ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutor.kt198
-rw-r--r--ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutorExtensions.kt201
-rw-r--r--ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfRequestType.kt14
7 files changed, 366 insertions, 74 deletions
diff --git a/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt
index 78ab34e9e..d422b7d67 100644
--- a/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt
+++ b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt
@@ -77,7 +77,7 @@ class RestconfConfigDeploy : AbstractScriptComponentFunction() {
log.error("an error occurred while configuring device {}", err)
} finally {
// Un mount device
- restconfUnMountDevice(webclientService, deviceID, "")
+ restconfUnMountDevice(webclientService, deviceID)
}
} catch (bpe: BlueprintProcessorException) {
log.error("Error looking up server identifier ", bpe)
diff --git a/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt
index 96345f0d3..f2335c138 100644
--- a/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt
+++ b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt
@@ -66,7 +66,7 @@ class RestconfSoftwareUpgrade : AbstractScriptComponentFunction() {
} catch (err: Exception) {
log.error("an error occurred while configuring device {}", err)
} finally {
- restconfUnMountDevice(model.client, model.deviceId, "")
+ restconfUnMountDevice(model.client, model.deviceId)
}
}
diff --git a/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Scripts/kotlin/RestconfConfigDeploy.kt b/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Scripts/kotlin/RestconfConfigDeploy.kt
index 2ba527ac1..039685575 100644
--- a/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Scripts/kotlin/RestconfConfigDeploy.kt
+++ b/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Scripts/kotlin/RestconfConfigDeploy.kt
@@ -66,7 +66,7 @@ class RestconfConfigDeploy : AbstractScriptComponentFunction() {
log.error("an error occurred while configuring device {}", err)
} finally {
// Un mount device
- restconfUnMountDevice(webclientService, deviceID, "")
+ restconfUnMountDevice(webclientService, deviceID)
}
} catch (bpe: BlueprintProcessorException) {
log.error("Error looking up server identifier ", bpe)
diff --git a/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfConstants.kt b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfConstants.kt
new file mode 100644
index 000000000..2c52b52a0
--- /dev/null
+++ b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfConstants.kt
@@ -0,0 +1,21 @@
+package org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor
+
+class RestconfConstants {
+ companion object {
+ const val NODE_ID = "node-id"
+ const val FAIL_FAST = "fail-fast"
+ const val RESTCONF_CONNECTION_CONFIG = "restconf-connection-config"
+ const val MOUNT_PAYLOAD = "mount-payload"
+ const val ACTION_INPUT = "action-input"
+ const val ACTION_OUTPUT = "action-output"
+ const val ACTION_TYPE = "action-type"
+ const val ACTION_DATASTORE = "action-datastore"
+ const val ACTION_PATH = "action-path"
+ const val ACTION_PAYLOAD = "action-payload"
+ const val RESTCONF_TOPOLOGY_CONFIG_PATH =
+ "/restconf/config/network-topology:network-topology/topology/topology-netconf/node"
+ const val RESTCONF_TOPOLOGY_OPER_PATH =
+ "/restconf/operational/network-topology:network-topology/topology/topology-netconf/node"
+ val HTTP_SUCCESS_RANGE = 200..204
+ }
+}
diff --git a/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutor.kt b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutor.kt
new file mode 100644
index 000000000..f9c9ce88d
--- /dev/null
+++ b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutor.kt
@@ -0,0 +1,198 @@
+package org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor
+
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.node.TextNode
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_DATASTORE
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_INPUT
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_OUTPUT
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_PATH
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_PAYLOAD
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.ACTION_TYPE
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.NODE_ID
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.FAIL_FAST
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.HTTP_SUCCESS_RANGE
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.MOUNT_PAYLOAD
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.RESTCONF_CONNECTION_CONFIG
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ComponentRemoteScriptExecutor
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ComponentScriptExecutor
+import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants.PROPERTY_CONNECTION_CONFIG
+import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
+import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils.Companion.jsonNodeFromObject
+import org.slf4j.LoggerFactory
+
+open class Mount : AbstractScriptComponentFunction() {
+
+ val log = LoggerFactory.getLogger(Mount::class.java)!!
+
+ override fun getName(): String {
+ return "Mount"
+ }
+
+ override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+ log.info("Mounting ODL restconf node process")
+
+ val deviceInformation = relationshipProperty(RESTCONF_CONNECTION_CONFIG, PROPERTY_CONNECTION_CONFIG)
+ val webclientService = restconfClientService(deviceInformation)
+
+ val nodeId = requestPayloadActionProperty(NODE_ID)?.first()?.textValue()
+ ?: throw BlueprintProcessorException("Failed to load $NODE_ID properties.")
+ val mountPayload = requestPayloadActionProperty(MOUNT_PAYLOAD)?.first()
+ ?: throw BlueprintProcessorException("Failed to load $MOUNT_PAYLOAD properties.")
+ restconfMountDeviceJson(webclientService, nodeId, mountPayload.toString())
+
+ setAttribute(
+ ComponentRemoteScriptExecutor.ATTRIBUTE_STATUS,
+ BlueprintConstants.STATUS_SUCCESS.asJsonPrimitive()
+ )
+ }
+
+ override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+ addError("failed in restconf execution : ${runtimeException.message}")
+ }
+}
+
+open class Execute : AbstractScriptComponentFunction() {
+
+ val log = LoggerFactory.getLogger(Execute::class.java)!!
+
+ override fun getName(): String {
+ return "Execute"
+ }
+
+ override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+ val nodeIdJson = requestPayloadActionProperty(NODE_ID)?.first()
+ ?: throw BlueprintProcessorException("Failed to load $NODE_ID properties.")
+
+ val failFastJsonNode = requestPayloadActionProperty(FAIL_FAST)!!
+ val failFast = if (failFastJsonNode.isEmpty) false else failFastJsonNode.first().booleanValue()
+
+ val deviceInformation = relationshipProperty(RESTCONF_CONNECTION_CONFIG, PROPERTY_CONNECTION_CONFIG)
+
+ val webclientService = restconfClientService(deviceInformation)
+ val nodeId = nodeIdJson.textValue()
+
+ val actionList = requestPayloadActionProperty("action")?.first()
+ ?: throw BlueprintProcessorException("Failed to load action properties.")
+ validateActionList(actionList)
+
+ val actionListResults: MutableList<Map<String, JsonNode>> = mutableListOf()
+
+ for (action in actionList) {
+ val actionTypeJsonNode = action.get(ACTION_TYPE)
+ val actionPathJsonNode = action.get(ACTION_PATH)
+ val actionType = RestconfRequestType.valueOf(actionTypeJsonNode.asText().toUpperCase())
+ val dsJsonNode = action.get(ACTION_DATASTORE)
+ val path = restconfPath(
+ RestconfRequestDatastore.valueOf(dsJsonNode.asText().toUpperCase()),
+ nodeId, actionPathJsonNode.asText()
+ )
+ val payload = action.get(ACTION_PAYLOAD)
+
+ log.info("Processing Restconf action : $actionType $path" + if (payload != null) " $payload" else "")
+ val response = executeAction(webclientService, path, actionType, payload)
+ val responseBody = response.body
+
+ val actionInput: MutableMap<String, JsonNode> = hashMapOf()
+ actionInput[ACTION_TYPE] = actionTypeJsonNode
+ actionInput[ACTION_PATH] = actionPathJsonNode
+ actionInput[ACTION_DATASTORE] = dsJsonNode
+
+ val actionResult: MutableMap<String, JsonNode> = hashMapOf()
+ val actionResponse = responseBody.asJsonType()
+ if (actionResponse !is TextNode && actionResponse.toString().isNotBlank()) {
+ actionResult[ACTION_OUTPUT] = actionResponse
+ }
+ actionResult[ACTION_INPUT] = jsonNodeFromObject(actionInput)
+
+ if (response.status in HTTP_SUCCESS_RANGE) {
+ log.info("\nRestconf execution response : \n{}", responseBody.asJsonType().toPrettyString())
+ actionResult[ComponentScriptExecutor.ATTRIBUTE_STATUS] =
+ BlueprintConstants.STATUS_SUCCESS.asJsonPrimitive()
+ } else {
+ actionResult[ComponentScriptExecutor.ATTRIBUTE_STATUS] =
+ BlueprintConstants.STATUS_FAILURE.asJsonPrimitive()
+ addError(
+ BlueprintConstants.STATUS_FAILURE,
+ ComponentScriptExecutor.ATTRIBUTE_STATUS,
+ actionResponse.asText()
+ )
+ if (failFast) {
+ actionListResults.add(actionResult)
+ break
+ }
+ }
+ actionListResults.add(actionResult)
+ }
+
+ setAttribute(ComponentScriptExecutor.ATTRIBUTE_RESPONSE_DATA, jsonNodeFromObject(actionListResults))
+ setAttribute(ComponentScriptExecutor.ATTRIBUTE_STATUS, BlueprintConstants.STATUS_SUCCESS.asJsonPrimitive())
+ actionListResults.forEach { actionResult ->
+ val actionResultStatus = actionResult[ComponentScriptExecutor.ATTRIBUTE_STATUS]
+ if (BlueprintConstants.STATUS_SUCCESS.asJsonPrimitive() != actionResultStatus) {
+ setAttribute(
+ ComponentScriptExecutor.ATTRIBUTE_STATUS,
+ BlueprintConstants.STATUS_FAILURE.asJsonPrimitive()
+ )
+ val errorResponse = actionResult[ACTION_OUTPUT]!!
+ addError(
+ BlueprintConstants.STATUS_FAILURE, ComponentScriptExecutor.ATTRIBUTE_STATUS,
+ errorResponse.asText()
+ )
+ }
+ }
+ }
+
+ override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+ addError("failed in restconf execution : ${runtimeException.message}")
+ }
+
+ private suspend fun executeAction(
+ webClientService: BlueprintWebClientService,
+ path: String,
+ actionType: RestconfRequestType,
+ payload: JsonNode?
+ ): BlueprintWebClientService.WebClientResponse<String> {
+ var headers = mutableMapOf("Content-Type" to "application/json")
+ return when (actionType) {
+ RestconfRequestType.PATCH -> {
+ headers = mutableMapOf("Content-Type" to "application/yang.patch-status+json")
+ genericPutPatchPostRequest(webClientService, path, actionType, payload.toString(), headers)
+ }
+ RestconfRequestType.PUT, RestconfRequestType.POST -> {
+ genericPutPatchPostRequest(webClientService, path, actionType, payload.toString(), headers)
+ }
+ RestconfRequestType.GET -> {
+ getRequest(webClientService, path)
+ }
+ RestconfRequestType.DELETE -> {
+ genericGetOrDeleteRequest(webClientService, path, RestconfRequestType.DELETE)
+ }
+ }
+ }
+
+ private fun validateActionList(actionList: JsonNode) {
+ if (actionList.isEmpty) {
+ throw BlueprintProcessorException("No actions defined")
+ }
+ actionList.forEach { action ->
+ action.get(ACTION_PATH)
+ ?: throw BlueprintProcessorException("Failed to load action path.")
+ action.get(ACTION_DATASTORE)
+ ?: throw BlueprintProcessorException("Failed to load action datastore.")
+ val actionTypeJsonNode = action.get(ACTION_TYPE)
+ ?: throw BlueprintProcessorException("Failed to load action type.")
+ when (val actionType = RestconfRequestType.valueOf(actionTypeJsonNode.asText().toUpperCase())) {
+ RestconfRequestType.PATCH, RestconfRequestType.PUT, RestconfRequestType.POST -> {
+ action.get(ACTION_PAYLOAD)
+ ?: throw BlueprintProcessorException("Failed to load action $actionType payload.")
+ }
+ }
+ }
+ }
+}
diff --git a/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutorExtensions.kt b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutorExtensions.kt
index 61ab4c11c..aade8965b 100644
--- a/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutorExtensions.kt
+++ b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfExecutorExtensions.kt
@@ -17,7 +17,10 @@
package org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor
+import com.fasterxml.jackson.databind.JsonNode
import org.hibernate.annotations.common.util.impl.LoggerFactory
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.RESTCONF_TOPOLOGY_CONFIG_PATH
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.RESTCONF_TOPOLOGY_OPER_PATH
import org.onap.ccsdk.cds.blueprintsprocessor.rest.restClientService
import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
@@ -28,44 +31,75 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintDependencyS
/**
* Register the Restconf module exposed dependency
*/
-
val log = LoggerFactory.logger(AbstractScriptComponentFunction::class.java)!!
fun AbstractScriptComponentFunction.restconfClientService(selector: String): BlueprintWebClientService {
return BlueprintDependencyService.restClientService(selector)
}
+fun AbstractScriptComponentFunction.restconfClientService(jsonNode: JsonNode): BlueprintWebClientService {
+ return BlueprintDependencyService.restClientService(jsonNode)
+}
+
/**
* Generic Mount function
*/
+suspend fun AbstractScriptComponentFunction.restconfMountDeviceJson(
+ webClientService: BlueprintWebClientService,
+ deviceId: String,
+ payload: Any
+) {
+ restconfMountDevice(webClientService, deviceId, payload, mutableMapOf("Content-Type" to "application/json"))
+}
+/**
+ * Generic Mount function
+ */
suspend fun AbstractScriptComponentFunction.restconfMountDevice(
webClientService: BlueprintWebClientService,
deviceId: String,
payload: Any,
headers: Map<String, String> = mutableMapOf("Content-Type" to "application/xml")
) {
+ val mountUrl = restconfDeviceConfigPath(deviceId)
+ val mountCheckUrl = restconfDeviceOperPath(deviceId)
+ restconfMountDevice(webClientService, payload, mountUrl, mountCheckUrl, headers)
+}
- val mountUrl = "/restconf/config/network-topology:network-topology/topology/topology-netconf/node/$deviceId"
+/**
+ * Generic Mount function
+ * This function mount the given deviceId and verify if device mounted successfully.
+ * This function take mount url and mount verify url as parameters.
+ */
+suspend fun AbstractScriptComponentFunction.restconfMountDevice(
+ webClientService: BlueprintWebClientService,
+ payload: Any,
+ mountUrl: String,
+ mountVerifyUrl: String,
+ headers: Map<String, String> = mutableMapOf("Content-Type" to "application/xml"),
+ expectedMountResult: String = """netconf-node-topology:connection-status":"connected"""
+) {
log.info("sending mount request, url: $mountUrl")
- webClientService.exchangeResource("PUT", mountUrl, payload as String, headers)
+ log.debug("sending mount request, payload: $payload")
+ val mountResult =
+ webClientService.exchangeResource(RestconfRequestType.PUT.name, mountUrl, payload as String, headers)
- /** Check device has mounted */
- val mountCheckUrl = "/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/$deviceId"
+ if (mountResult.status !in RestconfConstants.HTTP_SUCCESS_RANGE) {
+ throw BlueprintProcessorException("Failed to mount device with url($mountUrl) ")
+ }
- val expectedResult = """"netconf-node-topology:connection-status":"connected""""
- val mountCheckExecutionBlock: suspend (Int) -> String = { tryCount: Int ->
- val result = webClientService.exchangeResource("GET", mountCheckUrl, "")
- if (result.body.contains(expectedResult)) {
- log.info("NF was mounted successfully on ODL")
- result.body
- } else {
- throw BlueprintRetryException("Wait for device($deviceId) to mount")
+ /** Check device has mounted */
+ val mountCheckExecutionBlock: suspend (Int) -> String = {
+ val result = webClientService.exchangeResource(RestconfRequestType.GET.name, mountVerifyUrl, "")
+ if (!result.body.contains(expectedMountResult)) {
+ throw BlueprintRetryException("Wait for device with url($mountUrl) to mount")
}
+ log.info("NF was mounted successfully on ODL")
+ result.body
}
- log.info("url for ODL status check: $mountCheckUrl")
- webClientService.retry<String>(10, 0, 1000, mountCheckExecutionBlock)
+ log.info("url for ODL status check: $mountVerifyUrl")
+ webClientService.retry(10, 0, 1000, mountCheckExecutionBlock)
}
/**
@@ -81,35 +115,26 @@ suspend fun AbstractScriptComponentFunction.restconfApplyDeviceConfig(
): BlueprintWebClientService.WebClientResponse<String> {
log.debug("headers: $additionalHeaders")
log.info("configuring device: $deviceId, Configlet: $configletToApply")
- val applyConfigUrl = "/restconf/config/network-topology:network-topology/topology/topology-netconf/node/" +
- "$deviceId/$configletResourcePath"
- return webClientService.exchangeResource("PATCH", applyConfigUrl, configletToApply as String, additionalHeaders)
+ val applyConfigUrl = restconfDeviceConfigPath(deviceId, configletResourcePath)
+ return webClientService.exchangeResource(RestconfRequestType.PATCH.name, applyConfigUrl, configletToApply as String, additionalHeaders)
}
suspend fun AbstractScriptComponentFunction.restconfDeviceConfig(
webClientService: BlueprintWebClientService,
deviceId: String,
configletResourcePath: String
-):
- BlueprintWebClientService.WebClientResponse<String> {
-
- val configPathUrl = "/restconf/config/network-topology:network-topology/topology/topology-netconf/node/" +
- "$deviceId/$configletResourcePath"
- log.debug("sending GET request, url: $configPathUrl")
- return webClientService.exchangeResource("GET", configPathUrl, "")
- }
+): BlueprintWebClientService.WebClientResponse<String> {
+ return getRequest(webClientService, restconfDeviceConfigPath(deviceId, configletResourcePath))
+}
/**
* Generic UnMount function
*/
suspend fun AbstractScriptComponentFunction.restconfUnMountDevice(
webClientService: BlueprintWebClientService,
- deviceId: String,
- payload: String
+ deviceId: String
) {
- val unMountUrl = "/restconf/config/network-topology:network-topology/topology/topology-netconf/node/$deviceId"
- log.info("sending unMount request, url: $unMountUrl")
- webClientService.exchangeResource("DELETE", unMountUrl, "")
+ deleteRequest(webClientService, restconfDeviceConfigPath(deviceId))
}
/**
@@ -118,65 +143,99 @@ suspend fun AbstractScriptComponentFunction.restconfUnMountDevice(
suspend fun AbstractScriptComponentFunction.genericPutPatchPostRequest(
webClientService: BlueprintWebClientService,
requestUrl: String,
- requestType: String,
+ requestType: RestconfRequestType,
payload: Any,
headers: Map<String, String> = mutableMapOf("Content-Type" to "application/xml")
): BlueprintWebClientService.WebClientResponse<String> {
- when (requestType.toUpperCase()) {
- "PUT" -> log.info("sending PUT request, url: $requestUrl")
- "PATCH" -> log.info("sending PATCH request, url: $requestUrl")
- "POST" -> log.info("sending POST request, url: $requestUrl")
+ when (requestType) {
+ RestconfRequestType.PUT -> log.info("sending PUT request, url: $requestUrl")
+ RestconfRequestType.PATCH -> log.info("sending PATCH request, url: $requestUrl")
+ RestconfRequestType.POST -> log.info("sending POST request, url: $requestUrl")
else -> throw BlueprintProcessorException("Illegal request type, only POST, PUT or PATCH allowed.")
}
- return webClientService.exchangeResource(requestType, requestUrl, payload as String, headers)
+ return webClientService.exchangeResource(requestType.name, requestUrl, payload as String, headers)
}
/**
- * Generic GET/DELETE request function
+ * GET request function
*/
-
-suspend fun AbstractScriptComponentFunction.genericGetOrDeleteRequest(
+suspend fun AbstractScriptComponentFunction.getRequest(
webClientService: BlueprintWebClientService,
- requestUrl: String,
- requestType: String
+ requestUrl: String
): BlueprintWebClientService.WebClientResponse<String> {
- when (requestType.toUpperCase()) {
- "GET" -> log.info("sending GET request, url: $requestUrl")
- "DELETE" -> log.info("sending DELETE request, url: $requestUrl")
- else -> throw BlueprintProcessorException("Illegal request type, only GET and DELETE allowed.")
- }
- return webClientService.exchangeResource(requestType, requestUrl, "")
+ val retryTimes = 10
+ val mountCheckExecutionBlock: suspend (Int) -> BlueprintWebClientService.WebClientResponse<String> =
+ { tryCount: Int ->
+ val result = genericGetOrDeleteRequest(webClientService, requestUrl, RestconfRequestType.GET)
+ if (result.status !in RestconfConstants.HTTP_SUCCESS_RANGE && tryCount < retryTimes - 1) {
+ throw BlueprintRetryException("Failed to read url($requestUrl) to mount")
+ }
+ log.info("NF was mounted successfully on ODL")
+ result
+ }
+
+ return webClientService.retry(retryTimes, 0, 1000, mountCheckExecutionBlock)
}
/**
- * Generic Mount function
- * This function mount the given deviceId and verify if device mounted successfully.
- * This function take mount url and mount verify url as parameters.
+ * DELETE request function
*/
-
-suspend fun AbstractScriptComponentFunction.restconfMountDevice(
+suspend fun AbstractScriptComponentFunction.deleteRequest(
webClientService: BlueprintWebClientService,
- payload: Any,
- mountUrl: String,
- mountVerifyUrl: String,
- headers: Map<String, String> = mutableMapOf("Content-Type" to "application/xml"),
- expectedMountResult: String = """"netconf-node-topology:connection-status":"connected""""
-) {
+ requestUrl: String
+): BlueprintWebClientService.WebClientResponse<String> {
+ return genericGetOrDeleteRequest(webClientService, requestUrl, RestconfRequestType.DELETE)
+}
- log.info("sending mount request, url: $mountUrl")
- webClientService.exchangeResource("PUT", mountUrl, payload as String, headers)
+/**
+ * Generic GET/DELETE request function
+ */
+suspend fun AbstractScriptComponentFunction.genericGetOrDeleteRequest(
+ webClientService: BlueprintWebClientService,
+ requestUrl: String,
+ requestType: RestconfRequestType
+): BlueprintWebClientService.WebClientResponse<String> {
+ when (requestType) {
+ RestconfRequestType.GET -> log.info("sending GET request, url: $requestUrl")
+ RestconfRequestType.DELETE -> log.info("sending DELETE request, url: $requestUrl")
+ else -> throw BlueprintProcessorException("Illegal request type, only GET and DELETE allowed.")
+ }
+ return webClientService.exchangeResource(requestType.name, requestUrl, "")
+}
- /** Check device has mounted */
- val mountCheckExecutionBlock: suspend (Int) -> String = { tryCount: Int ->
- val result = webClientService.exchangeResource("GET", mountVerifyUrl, "")
- if (result.body.contains(expectedMountResult)) {
- log.info("NF was mounted successfully on ODL")
- result.body
- } else {
- throw BlueprintRetryException("Wait for device with url($mountUrl) to mount")
+suspend fun AbstractScriptComponentFunction.restconfPath(
+ restconfDatastore: RestconfRequestDatastore,
+ deviceId: String,
+ specificPath: String = ""
+): String {
+ return when (restconfDatastore) {
+ RestconfRequestDatastore.OPERATIONAL -> {
+ restconfDeviceOperPath(deviceId, specificPath)
+ }
+ RestconfRequestDatastore.CONFIG -> {
+ restconfDeviceConfigPath(deviceId, specificPath)
}
}
+}
- log.info("url for ODL status check: $mountVerifyUrl")
- webClientService.retry<String>(10, 0, 1000, mountCheckExecutionBlock)
+private fun AbstractScriptComponentFunction.restconfDeviceConfigPath(
+ deviceId: String,
+ specificPath: String = ""
+): String {
+ val configPath = "$RESTCONF_TOPOLOGY_CONFIG_PATH/$deviceId"
+ if (specificPath.isBlank()) {
+ return configPath
+ }
+ return "$configPath/$specificPath"
+}
+
+private fun AbstractScriptComponentFunction.restconfDeviceOperPath(
+ deviceId: String,
+ specificPath: String = ""
+): String {
+ val operPath = "$RESTCONF_TOPOLOGY_OPER_PATH/$deviceId"
+ if (specificPath.isBlank()) {
+ return operPath
+ }
+ return "$operPath/$specificPath"
}
diff --git a/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfRequestType.kt b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfRequestType.kt
new file mode 100644
index 000000000..277f97814
--- /dev/null
+++ b/ms/blueprintsprocessor/functions/restconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/restconf/executor/RestconfRequestType.kt
@@ -0,0 +1,14 @@
+package org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor
+
+enum class RestconfRequestType {
+ PUT,
+ PATCH,
+ POST,
+ GET,
+ DELETE
+}
+
+enum class RestconfRequestDatastore {
+ CONFIG,
+ OPERATIONAL
+}