2 * Copyright © 2019 IBM.
3 * Modifications Copyright © 2018-2019 IBM, Bell Canada
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor
20 import com.fasterxml.jackson.databind.JsonNode
21 import org.hibernate.annotations.common.util.impl.LoggerFactory
22 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.RESTCONF_TOPOLOGY_CONFIG_PATH
23 import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.RestconfConstants.Companion.RESTCONF_TOPOLOGY_OPER_PATH
24 import org.onap.ccsdk.cds.blueprintsprocessor.rest.restClientService
25 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
26 import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
27 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
28 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintRetryException
29 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService
32 * Register the Restconf module exposed dependency
34 val log = LoggerFactory.logger(AbstractScriptComponentFunction::class.java)!!
36 fun AbstractScriptComponentFunction.restconfClientService(selector: String): BlueprintWebClientService {
37 return BluePrintDependencyService.restClientService(selector)
40 fun AbstractScriptComponentFunction.restconfClientService(jsonNode: JsonNode): BlueprintWebClientService {
41 return BluePrintDependencyService.restClientService(jsonNode)
45 * Generic Mount function
47 suspend fun AbstractScriptComponentFunction.restconfMountDeviceJson(
48 webClientService: BlueprintWebClientService,
52 restconfMountDevice(webClientService, deviceId, payload, mutableMapOf("Content-Type" to "application/json"))
56 * Generic Mount function
58 suspend fun AbstractScriptComponentFunction.restconfMountDevice(
59 webClientService: BlueprintWebClientService,
62 headers: Map<String, String> = mutableMapOf("Content-Type" to "application/xml")
64 val mountUrl = restconfDeviceConfigPath(deviceId)
65 val mountCheckUrl = restconfDeviceOperPath(deviceId)
66 restconfMountDevice(webClientService, payload, mountUrl, mountCheckUrl, headers)
70 * Generic Mount function
71 * This function mount the given deviceId and verify if device mounted successfully.
72 * This function take mount url and mount verify url as parameters.
74 suspend fun AbstractScriptComponentFunction.restconfMountDevice(
75 webClientService: BlueprintWebClientService,
78 mountVerifyUrl: String,
79 headers: Map<String, String> = mutableMapOf("Content-Type" to "application/xml"),
80 expectedMountResult: String = """netconf-node-topology:connection-status":"connected"""
82 log.info("sending mount request, url: $mountUrl")
83 log.debug("sending mount request, payload: $payload")
85 webClientService.exchangeResource(RestconfRequestType.PUT.name, mountUrl, payload as String, headers)
87 if (mountResult.status !in RestconfConstants.HTTP_SUCCESS_RANGE) {
88 throw BluePrintProcessorException("Failed to mount device with url($mountUrl) ")
91 /** Check device has mounted */
92 val mountCheckExecutionBlock: suspend (Int) -> String = {
93 val result = webClientService.exchangeResource(RestconfRequestType.GET.name, mountVerifyUrl, "")
94 if (!result.body.contains(expectedMountResult)) {
95 throw BluePrintRetryException("Wait for device with url($mountUrl) to mount")
97 log.info("NF was mounted successfully on ODL")
101 log.info("url for ODL status check: $mountVerifyUrl")
102 webClientService.retry(10, 0, 1000, mountCheckExecutionBlock)
106 * Generic Configure function
107 * @return The WebClientResponse from the request
109 suspend fun AbstractScriptComponentFunction.restconfApplyDeviceConfig(
110 webClientService: BlueprintWebClientService,
112 configletResourcePath: String,
113 configletToApply: Any,
114 additionalHeaders: Map<String, String> = mutableMapOf("Content-Type" to "application/yang.patch+xml")
115 ): BlueprintWebClientService.WebClientResponse<String> {
116 log.debug("headers: $additionalHeaders")
117 log.info("configuring device: $deviceId, Configlet: $configletToApply")
118 val applyConfigUrl = restconfDeviceConfigPath(deviceId, configletResourcePath)
119 return webClientService.exchangeResource(RestconfRequestType.PATCH.name, applyConfigUrl, configletToApply as String, additionalHeaders)
122 suspend fun AbstractScriptComponentFunction.restconfDeviceConfig(
123 webClientService: BlueprintWebClientService,
125 configletResourcePath: String
126 ): BlueprintWebClientService.WebClientResponse<String> {
127 return getRequest(webClientService, restconfDeviceConfigPath(deviceId, configletResourcePath))
131 * Generic UnMount function
133 suspend fun AbstractScriptComponentFunction.restconfUnMountDevice(
134 webClientService: BlueprintWebClientService,
137 deleteRequest(webClientService, restconfDeviceConfigPath(deviceId))
141 * Generic PUT/PATCH/POST request function
143 suspend fun AbstractScriptComponentFunction.genericPutPatchPostRequest(
144 webClientService: BlueprintWebClientService,
146 requestType: RestconfRequestType,
148 headers: Map<String, String> = mutableMapOf("Content-Type" to "application/xml")
149 ): BlueprintWebClientService.WebClientResponse<String> {
151 RestconfRequestType.PUT -> log.info("sending PUT request, url: $requestUrl")
152 RestconfRequestType.PATCH -> log.info("sending PATCH request, url: $requestUrl")
153 RestconfRequestType.POST -> log.info("sending POST request, url: $requestUrl")
154 else -> throw BluePrintProcessorException("Illegal request type, only POST, PUT or PATCH allowed.")
156 return webClientService.exchangeResource(requestType.name, requestUrl, payload as String, headers)
160 * GET request function
162 suspend fun AbstractScriptComponentFunction.getRequest(
163 webClientService: BlueprintWebClientService,
165 ): BlueprintWebClientService.WebClientResponse<String> {
167 val mountCheckExecutionBlock: suspend (Int) -> BlueprintWebClientService.WebClientResponse<String> =
169 val result = genericGetOrDeleteRequest(webClientService, requestUrl, RestconfRequestType.GET)
170 if (result.status !in RestconfConstants.HTTP_SUCCESS_RANGE && tryCount < retryTimes - 1) {
171 throw BluePrintRetryException("Failed to read url($requestUrl) to mount")
173 log.info("NF was mounted successfully on ODL")
177 return webClientService.retry(retryTimes, 0, 1000, mountCheckExecutionBlock)
181 * DELETE request function
183 suspend fun AbstractScriptComponentFunction.deleteRequest(
184 webClientService: BlueprintWebClientService,
186 ): BlueprintWebClientService.WebClientResponse<String> {
187 return genericGetOrDeleteRequest(webClientService, requestUrl, RestconfRequestType.DELETE)
191 * Generic GET/DELETE request function
193 suspend fun AbstractScriptComponentFunction.genericGetOrDeleteRequest(
194 webClientService: BlueprintWebClientService,
196 requestType: RestconfRequestType
197 ): BlueprintWebClientService.WebClientResponse<String> {
199 RestconfRequestType.GET -> log.info("sending GET request, url: $requestUrl")
200 RestconfRequestType.DELETE -> log.info("sending DELETE request, url: $requestUrl")
201 else -> throw BluePrintProcessorException("Illegal request type, only GET and DELETE allowed.")
203 return webClientService.exchangeResource(requestType.name, requestUrl, "")
206 suspend fun AbstractScriptComponentFunction.restconfPath(
207 restconfDatastore: RestconfRequestDatastore,
209 specificPath: String = ""
211 return when (restconfDatastore) {
212 RestconfRequestDatastore.OPERATIONAL -> {
213 restconfDeviceOperPath(deviceId, specificPath)
215 RestconfRequestDatastore.CONFIG -> {
216 restconfDeviceConfigPath(deviceId, specificPath)
221 private fun AbstractScriptComponentFunction.restconfDeviceConfigPath(
223 specificPath: String = ""
225 val configPath = "$RESTCONF_TOPOLOGY_CONFIG_PATH/$deviceId"
226 if (specificPath.isBlank()) {
229 return "$configPath/$specificPath"
232 private fun AbstractScriptComponentFunction.restconfDeviceOperPath(
234 specificPath: String = ""
236 val operPath = "$RESTCONF_TOPOLOGY_OPER_PATH/$deviceId"
237 if (specificPath.isBlank()) {
240 return "$operPath/$specificPath"