diff options
author | Alexis de Talhouët <adetalhouet89@gmail.com> | 2019-02-12 23:05:01 -0500 |
---|---|---|
committer | Alexis de Talhouët <adetalhouet89@gmail.com> | 2019-02-16 19:08:17 -0500 |
commit | 77ed352693e0ff917395f5cf2418e31c0fbe27f3 (patch) | |
tree | affed0dee74ff7e415fc3a375fcea09a0236792a /ms/blueprintsprocessor/functions/netconf-executor | |
parent | 1fc8a79dd315c07a53db1c758dc3ffdb7c5c6a48 (diff) |
Rework netconf-executor
- rework connection logic
- rework rpc service
- rework netconf session handling
- rework netconf device communicator
- rework python netconf bindings
- rework python netconf client
- add python script showcasing netconf functions
Change-Id: Ibb9bf811e7d96e993aa866371d56c172de83be2c
Issue-ID: CCSDK-790:x
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
Diffstat (limited to 'ms/blueprintsprocessor/functions/netconf-executor')
26 files changed, 1002 insertions, 1384 deletions
diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutor.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutor.kt index ab3372e9..c32aa9d5 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutor.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutor.kt @@ -35,7 +35,7 @@ open class ComponentNetconfExecutor(private val blueprintJythonService: Blueprin lateinit var scriptComponent: NetconfComponentFunction - override fun process(executionServiceInput: ExecutionServiceInput) { + override fun process(executionRequest: ExecutionServiceInput) { scriptComponent = blueprintJythonService.jythonComponentInstance(this) as NetconfComponentFunction checkNotNull(scriptComponent) { "failed to get netconf script component" } diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfComponentFunction.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfComponentFunction.kt index d480bdd4..c98009fe 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfComponentFunction.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfComponentFunction.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2018 IBM. + * Copyright © 2018-2019 IBM, Bell Canada. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,47 +17,39 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor import com.fasterxml.jackson.databind.JsonNode -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.DeviceInfo -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.NetconfRpcClientService +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo import org.onap.ccsdk.apps.blueprintsprocessor.services.execution.AbstractComponentFunction import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils - abstract class NetconfComponentFunction : AbstractComponentFunction() { - fun deviceProperties(requirementName: String): DeviceInfo { + // Called from python script + fun initializeNetconfConnection(requirementName: String): NetconfDevice { + val deviceInfo = deviceProperties(requirementName) + return NetconfDevice(deviceInfo) + } + + fun generateMessage(): String { + TODO() + } + + fun resolveAndGenerateMesssage(): String { + TODO() + } + + private fun deviceProperties(requirementName: String): DeviceInfo { val blueprintContext = bluePrintRuntimeService.bluePrintContext() val requirement = blueprintContext.nodeTemplateRequirement(nodeTemplateName, requirementName) val capabilityProperties = bluePrintRuntimeService.resolveNodeTemplateCapabilityProperties(requirement - .node!!, requirement.capability!!) + .node!!, requirement.capability!!) return deviceProperties(capabilityProperties) } - fun deviceProperties(capabilityProperty: MutableMap<String, JsonNode>): DeviceInfo { + private fun deviceProperties(capabilityProperty: MutableMap<String, JsonNode>): DeviceInfo { return JacksonUtils.getInstanceFromMap(capabilityProperty, DeviceInfo::class.java) } - - fun netconfRpcClientService(): NetconfRpcClientService { - return NetconfRpcService() - } - - fun netconfRpcClientService(requirementName: String): NetconfRpcClientService { - val deviceProperties = deviceProperties(requirementName) - val netconfRpcClientService = NetconfRpcService() - netconfRpcClientService.connect(deviceProperties) - return netconfRpcClientService - } - - fun generateMessage(): String { - TODO() - } - - fun resolveAndGenerateMesssage(): String { - TODO() - } - }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfDevice.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfDevice.kt new file mode 100644 index 00000000..54776621 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfDevice.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Bell Canada. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor + +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfSession +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core.NetconfRpcServiceImpl +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core.NetconfSessionImpl + +class NetconfDevice(deviceInfo: DeviceInfo) { + val netconfRpcService: NetconfRpcServiceImpl + val netconfSession: NetconfSession + + init { + netconfRpcService = NetconfRpcServiceImpl(deviceInfo) + netconfSession = NetconfSessionImpl(deviceInfo, netconfRpcService) + netconfRpcService.setNetconfSession(netconfSession) + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfException.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfException.kt deleted file mode 100644 index 37aa63da..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfException.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor - -import java.io.IOException - -class NetconfException : IOException { - - var code: Int = 100 - - constructor(cause: Throwable) : super(cause) - constructor(message: String) : super(message) - constructor(message: String, cause: Throwable) : super(message, cause) - constructor(cause: Throwable, message: String, vararg args: Any?) : super(String.format(message, *args), cause) - - constructor(code: Int, cause: Throwable) : super(cause) { - this.code = code - } - - constructor(code: Int, message: String) : super(message) { - this.code = code - } - - constructor(code: Int, message: String, cause: Throwable) : super(message, cause) { - this.code = code - } - - constructor(code: Int, cause: Throwable, message: String, vararg args: Any?) - : super(String.format(message, *args), cause) { - this.code = code - } -} diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfExecutorConfiguration.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfExecutorConfiguration.kt deleted file mode 100644 index 562dd768..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfExecutorConfiguration.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor - -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.context.annotation.ComponentScan -import org.springframework.context.annotation.Configuration - -@Configuration -@ComponentScan -@EnableConfigurationProperties -open class NetconfExecutorConfiguration - - -class NetconfExecutorConstants { - companion object { - const val CONTEX_PARAM_MESSAGE = "message" - const val COMPONENT_SCRIPT_PATH = "component-scripts" - - const val REQ_NETCONF_CONNECTION = "netconf-connection" - const val NETCONF_CONNECTION_SOURCE = "source" - const val NETCONF_CONNECTION_LOGIN_KEY = "login-key" - const val NETCONF_CONNECTION_LOGIN_ACCOUNT = "login-account" - const val NETCONF_CONNECTION_TARGET_IP = "target-ip-address" - const val NETCONF_CONNECTION_MESSAGE_PORT = "port-number" - const val NETCONF_CONNECTION_TIMEOUT = "connection-time-out" - - const val INPUT_PARAM_REQUEST_ID = "request-id" - const val INPUT_PARAM_RESOURCE_ID = "resource-id" - const val INPUT_PARAM_RESERVATION_ID = "reservation-id" - const val INPUT_PARAM_RESOURCE_TYPE = "resource-type" - const val INPUT_PARAM_ACTION_NAME = "action-name" - const val INPUT_PARAM_TEMPLATE_NAME = "template-name" - const val INPUT_PARAM_ASSIGNMENT_ACTION_NAME = "assignment-action-name" - - const val SCRIPT_OUTPUT_RESPONSE_DATA = "responseData" - const val SCRIPT_OUTPUT_ERROR_MESSAGE = "errorMessage" - - const val OUTPUT_PARAM_RESPONSE_DATA = "response-data" - const val OUTPUT_PARAM_ERROR_MESSAGE = "error-message" - const val OUTPUT_PARAM_STATUS = "status" - const val OUTPUT_STATUS_SUCCESS = "success" - const val OUTPUT_STATUS_FAILURE = "failure" - - const val CONFIG_DATA_TYPE_XML = "XML" - const val CONFIG_DATA_TYPE_JSON = "JSON" - - const val CONFIG_TARGET_RUNNING = "running" - const val CONFIG_TARGET_CANDIDATE = "candidate" - const val CONFIG_DEFAULT_OPERATION_MERGE = "merge" - const val CONFIG_DEFAULT_OPERATION_REPLACE = "replace" - const val DEFAULT_NETCONF_SESSION_MANAGER_TYPE = "DEFAULT_NETCONF_SESSION" - } -}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfRpcService.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfRpcService.kt deleted file mode 100644 index 0e264bcb..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfRpcService.kt +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor - -import org.apache.commons.collections.CollectionUtils -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core.NetconfSessionFactory -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.DeviceResponse -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.NetconfAdaptorConstant -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.DeviceInfo -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.NetconfRpcClientService -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.NetconfSession -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcMessageUtils -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.config.ConfigurableBeanFactory -import org.springframework.context.annotation.Scope -import org.springframework.stereotype.Service -import java.util.* -import java.util.concurrent.TimeUnit - - -@Service("netconf-rpc-service") -@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) -class NetconfRpcService : NetconfRpcClientService { - - val log = LoggerFactory.getLogger(NetconfRpcService::class.java) - - lateinit var deviceInfo: DeviceInfo - lateinit var netconfSession: NetconfSession - - private val applyConfigIds = ArrayList<String>() - private val recordedApplyConfigIds = ArrayList<String>() - private val DEFAULT_MESSAGE_TIME_OUT = 30 - - - override fun connect(deviceInfo: DeviceInfo): NetconfSession { - try { - - this.deviceInfo = deviceInfo - - log.info("Connecting Netconf Device .....") - this.netconfSession = NetconfSessionFactory.instance("DEFAULT_NETCONF_SESSION", deviceInfo) - publishMessage("Netconf Device Connection Established") - return this.netconfSession - } catch (e: NetconfException) { - publishMessage(String.format("Netconf Device Connection Failed, %s", e.message)) - throw NetconfException("Netconf Device Connection Failed,$deviceInfo",e) - } - } - - override fun disconnect() { - netconfSession.close() - } - - override fun reconnect() { - disconnect() - connect(deviceInfo) - } - - override fun getConfig(messageId: String, messageContent: String, configTarget: String, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - log.info("in the NetconfRpcService "+messageId) - try { - val message = RpcMessageUtils.getConfig(messageId, configTarget, messageContent) - output = asyncRpc(message, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.errorMessage = e.message - } - - return output - } - - override fun deleteConfig(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - try { - val deleteConfigMessage = RpcMessageUtils.deleteConfig(messageId, configTarget) - output.requestMessage = deleteConfigMessage - output = asyncRpc(deleteConfigMessage, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.errorMessage = "failed in delete config command " + e.message - } - - return output - } - - override fun lock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - try { - val lockMessage = RpcMessageUtils.lock(messageId, configTarget) - output.requestMessage = lockMessage - output = asyncRpc(lockMessage, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.errorMessage = "failed in lock command " + e.message - } - - return output - } - - override fun unLock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - try { - val unlockMessage = RpcMessageUtils.unlock(messageId, configTarget) - output.requestMessage = unlockMessage - output = asyncRpc(unlockMessage, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.errorMessage = "failed in lock command " + e.message - } - - return output - } - - override fun commit(messageId: String, message: String, discardChanges: Boolean, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - try { - val messageContent = RpcMessageUtils.commit(messageId, message) - output = asyncRpc(messageContent, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.errorMessage = "failed in commit command " + e.message - } finally { - // Update the Apply Config status - if (CollectionUtils.isNotEmpty(applyConfigIds)) { - val status = if (NetconfAdaptorConstant.STATUS_SUCCESS.equals(output.status,ignoreCase = true)) - NetconfAdaptorConstant.CONFIG_STATUS_SUCCESS - else - NetconfAdaptorConstant.CONFIG_STATUS_FAILED - - applyConfigIds.forEach{ - recordedApplyConfigIds.add(it) - try { - //TODO persistance logic - // configPersistService.updateApplyConfig(applyConfigId, status) - } catch (e: Exception) { - log.error("failed to update apply config ($it) status ($status)") - } - - } - applyConfigIds.clear() - } - // TODO - // Update the Configuration in Running Config Table from 1810 release - // String recordMessageId = "recoded-running-config-" + messageId; - // recordRunningConfig(recordMessageId, null); - } - - // If commit failed apply discard changes - if (discardChanges && NetconfAdaptorConstant.STATUS_FAILURE.equals(output.status,ignoreCase = true)) { - try { - val discardChangesConfigMessageId = "$messageId-discard-changes" - discardConfig(discardChangesConfigMessageId, NetconfAdaptorConstant.DEFAULT_MESSAGE_TIME_OUT) - } catch (e: Exception) { - log.error("failed to rollback ($e) ") - } - - } - - return output - } - override fun discardConfig(messageId: String, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - try { - val discardChangesMessage = RpcMessageUtils.discardChanges(messageId) - output.requestMessage = discardChangesMessage - output = asyncRpc(discardChangesMessage, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.errorMessage = "failed in discard changes command " + e.message - } - - return output - } - - override fun close(messageId: String, force: Boolean, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - try { - val messageContent = RpcMessageUtils.closeSession(messageId, force) - output = asyncRpc(messageContent, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.responseMessage = "failed in close command " + e.message - } - - return output - } - - - override fun asyncRpc(request: String, msgId: String, timeOut: Int): DeviceResponse { - val response = DeviceResponse() - try { - recordMessage("RPC request $request") - response.requestMessage = request - publishMessage("Netconf RPC InProgress") - - val rpcResponse = netconfSession.asyncRpc(request, msgId).get(timeOut.toLong(), TimeUnit.SECONDS) - response.responseMessage = rpcResponse - - if (!RpcMessageUtils.checkReply(rpcResponse)) { - throw NetconfException(rpcResponse) - } - response.status = NetconfAdaptorConstant.STATUS_SUCCESS - response.errorMessage = null - } catch (e: Exception) { - response.status = NetconfAdaptorConstant.STATUS_FAILURE - response.errorMessage = e.message - } finally { - recordMessage(String.format("RPC Response status (%s) reply (%s), error message (%s)", response.status, - response.responseMessage, response.errorMessage)) - - when { - NetconfAdaptorConstant.STATUS_FAILURE.equals(response.status,ignoreCase = true) -> publishMessage(String.format("Netconf RPC Failed for messgaeID (%s) with (%s)", msgId, - response.errorMessage)) - else -> publishMessage(String.format("Netconf RPC Success for messgaeID (%s)", msgId)) - } - } - - return response - } - - override fun editConfig(messageId: String, messageContent: String, reConnect: Boolean, wait: Int, lock: Boolean, configTarget: String, editDefaultOperation: String, clearCandidate: Boolean, validate: Boolean, commit: Boolean, discardChanges: Boolean, unlock: Boolean, preRestartWait: Int, postRestartWait: Int, messageTimeout: Int): DeviceResponse { - var editConfigDeviceResponse = DeviceResponse() - - try { - val editMessage = RpcMessageUtils.editConfig(messageId, NetconfAdaptorConstant.CONFIG_TARGET_CANDIDATE, - editDefaultOperation, messageContent) - editConfigDeviceResponse.requestMessage = editMessage - - /* val applyConfigId = configPersistService.saveApplyConfig(netconfExecutionRequest.getRequestId(), - netconfDeviceInfo.getName(), netconfDeviceInfo.getDeviceId(), ConfigModelConstant.PROTOCOL_NETCONF, - configTarget, editMessage) - - applyConfigIds.add(applyConfigId) */ - - // Reconnect Client Session - if (reConnect) { - reconnect() - } - // Provide invocation Delay - if (wait > 0) { - log.info("Waiting for {} sec for the transaction to start", wait) - Thread.sleep(wait * 1000L) - } - - if (lock) { - val lockMessageId = "$messageId-lock" - val lockDeviceResponse = lock(lockMessageId, configTarget, DEFAULT_MESSAGE_TIME_OUT) - editConfigDeviceResponse.addSubDeviceResponse(lockMessageId, lockDeviceResponse) - if (!NetconfAdaptorConstant.STATUS_SUCCESS.equals(lockDeviceResponse.status,ignoreCase = true)) { - throw NetconfException(lockDeviceResponse.errorMessage!!) - } - } - - if (clearCandidate) { - val deleteConfigMessageId = "$messageId-delete" - val deleteConfigDeviceResponse = deleteConfig(deleteConfigMessageId, - NetconfAdaptorConstant.CONFIG_TARGET_CANDIDATE, DEFAULT_MESSAGE_TIME_OUT) - editConfigDeviceResponse.addSubDeviceResponse(deleteConfigMessageId, deleteConfigDeviceResponse) - if (!NetconfAdaptorConstant.STATUS_SUCCESS.equals(deleteConfigDeviceResponse.status,ignoreCase = true)) { - throw NetconfException(deleteConfigDeviceResponse.errorMessage!!) - } - } - - if (discardChanges) { - val discardConfigMessageId = "$messageId-discard" - val discardConfigDeviceResponse = discardConfig(discardConfigMessageId, DEFAULT_MESSAGE_TIME_OUT) - editConfigDeviceResponse.addSubDeviceResponse(discardConfigMessageId, discardConfigDeviceResponse) - if (!NetconfAdaptorConstant.STATUS_SUCCESS.equals(discardConfigDeviceResponse.status,ignoreCase = true)) { - throw NetconfException(discardConfigDeviceResponse.errorMessage!!) - } - } - - editConfigDeviceResponse = asyncRpc(editMessage, messageId, messageTimeout) - if (!NetconfAdaptorConstant.STATUS_SUCCESS.equals(editConfigDeviceResponse.status,ignoreCase = true)) { - throw NetconfException(editConfigDeviceResponse.errorMessage!!) - } - - if (validate) { - val validateMessageId = "$messageId-validate" - val validateDeviceResponse = validate(validateMessageId, - NetconfAdaptorConstant.CONFIG_TARGET_CANDIDATE, DEFAULT_MESSAGE_TIME_OUT) - editConfigDeviceResponse.addSubDeviceResponse(validateMessageId, validateDeviceResponse) - if (!NetconfAdaptorConstant.STATUS_SUCCESS.equals(validateDeviceResponse.status,ignoreCase = true)) { - throw NetconfException(validateDeviceResponse.errorMessage!!) - } - } - - /** - * If Commit is enable, the commit response is treated as Edit config response, If commit failed, we - * need not to throw an exception, until we unlock the device. - */ - if (commit) { - val commitMessageId = "$messageId-commit" - val commitDeviceResponse = commit(commitMessageId, commitMessageId, discardChanges, DEFAULT_MESSAGE_TIME_OUT) - editConfigDeviceResponse.addSubDeviceResponse(commitMessageId, commitDeviceResponse) - if (!NetconfAdaptorConstant.STATUS_SUCCESS.equals(commitDeviceResponse.status,ignoreCase = true)) { - throw NetconfException(commitDeviceResponse.errorMessage!!) - } - } - - // Provide pre restart Delay - if (preRestartWait > 0) { - log.info("Waiting for {} sec for restart", wait) - Thread.sleep(preRestartWait * 1000L) - } - // TODO Restart Device - // Provide post restart Delay - if (postRestartWait > 0) { - log.info("Waiting for {} sec for the post restart", wait) - Thread.sleep(postRestartWait * 1000L) - } - - } catch (e: Exception) { - editConfigDeviceResponse.status = NetconfAdaptorConstant.STATUS_FAILURE - editConfigDeviceResponse.errorMessage = e.message - } finally { - if (unlock) { - val unlockMessageId = "$messageId-unlock" - val unlockDeviceResponse = unLock(unlockMessageId, configTarget, DEFAULT_MESSAGE_TIME_OUT) - editConfigDeviceResponse.addSubDeviceResponse(unlockMessageId, unlockDeviceResponse) - if (!NetconfAdaptorConstant.STATUS_SUCCESS.equals(unlockDeviceResponse.status,ignoreCase = true)) { - editConfigDeviceResponse.status = NetconfAdaptorConstant.STATUS_FAILURE - editConfigDeviceResponse.errorMessage = unlockDeviceResponse.errorMessage - } - } - } - return editConfigDeviceResponse - } - - override fun validate(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { - var output = DeviceResponse() - try { - val validateMessage = RpcMessageUtils.validate(messageId, configTarget) - output.requestMessage = validateMessage - output = asyncRpc(validateMessage, messageId, messageTimeout) - } catch (e: Exception) { - output.status = NetconfAdaptorConstant.STATUS_FAILURE - output.errorMessage = "failed in validate command " + e.message - } - - return output - } - - - fun recordMessage(message: String) { - recordMessage(NetconfAdaptorConstant.LOG_MESSAGE_TYPE_LOG, message) - } - - fun recordMessage(messageType: String, message: String) { - //TODO - //eventPublishService.recordMessage(netconfExecutionRequest.getRequestId(), messageType, message) - } - - fun publishMessage(message: String) { - //TODO - //eventPublishService.publishMessage(netconfExecutionRequest.getRequestId(), message) - } - - -}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/DeviceInfo.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/DeviceInfo.kt index f4360c7e..466e6b5e 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/DeviceInfo.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/DeviceInfo.kt @@ -14,30 +14,30 @@ * limitations under the License. */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonProperty class DeviceInfo { @get:JsonProperty("login-account") - var name: String? = null + var username: String? = null @get:JsonProperty("login-key") - var pass: String? = null + var password: String? = null @get:JsonProperty("target-ip-address") var ipAddress: String? = null @get:JsonProperty("port-number") var port: Int = 0 - @get:JsonIgnore - var key: String? = null - @get:JsonProperty("source") - var source: String? = null @get:JsonProperty("connection-time-out") - var connectTimeoutSec: Long = 30 + var connectTimeout: Long = 5 @get:JsonIgnore - var replyTimeout: Int = 60 + var source: String? = null @get:JsonIgnore - var idleTimeout: Int = 45 + var replyTimeout: Int = 5 @get:JsonIgnore - var deviceId: String = "$ipAddress:$port" + var idleTimeout: Int = 99999 + + override fun toString(): String { + return "$ipAddress:$port" + } }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfSshClientLib.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfException.kt index f21cce4a..d7642e75 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfSshClientLib.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfException.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2018 AT&T Intellectual Property. + * Copyright © 2017-2019 AT&T, Bell Canada * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api -enum class NetconfSshClientLib(val sshClientString :String) { - APACHE_MINA("apache-mina"), - ETHZ_SSH2("ethz-ssh2"); +class NetconfException : Exception { - fun getEnum(valueOf: String): NetconfSshClientLib { - return NetconfSshClientLib.valueOf(valueOf.toUpperCase().replace('-', '_')) - } + constructor(cause: Throwable) : super(cause) + constructor(message: String) : super(message) + constructor(message: String, cause: Throwable) : super(message, cause) }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfMessage.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfMessage.kt new file mode 100644 index 00000000..da746614 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfMessage.kt @@ -0,0 +1,74 @@ +/* + * Copyright © 2017-2019 AT&T, Bell Canada + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api + +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcStatus + +class DeviceResponse { + var status: String? = null + var errorMessage: String? = null + var responseMessage: String? = null + var requestMessage: String? = null + private var subDeviceResponse: MutableMap<Any, Any>? = null + + fun addSubDeviceResponse(key: String, subDeviceResponse: DeviceResponse) { + if (this.subDeviceResponse == null) { + this.subDeviceResponse = hashMapOf() + } + this.subDeviceResponse!![key] = subDeviceResponse + } + + fun isSuccess(): Boolean { + if (this.status != RpcStatus.SUCCESS && !this.errorMessage.isNullOrEmpty()) { + return false + } + return true + } +} + + +/** + * Creates an event of a given type and for the specified subject and the current time. + * + * @param type event type + * @param payload message from the device + * @param messageId id of the message related to the event + * @param deviceInfo device of event + */ +class NetconfReceivedEvent + (private var type: Type, private var payload: String = "", private var messageId: String = "", + private var deviceInfo: DeviceInfo) { + + enum class Type { + DEVICE_REPLY, + DEVICE_UNREGISTERED, + DEVICE_ERROR, + SESSION_CLOSED + } + + fun getType(): Type { + return type + } + + fun getMessagePayload(): String { + return payload + } + + fun getMessageID(): String { + return messageId + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfRpcClientService.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfRpcService.kt index 668fb552..554368c7 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfRpcClientService.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfRpcService.kt @@ -13,42 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.DeviceResponse - -interface NetconfRpcClientService { - - /** - * @param deviceProperties deviceProperties - * @return NetconfSession - */ - fun connect(deviceInfo: DeviceInfo): NetconfSession - - - fun disconnect() - - - fun reconnect() +interface NetconfRpcService { /** + * Lock * @param messageId message id of the request. - * @param configTarget config target ( running or candidate) + * @param configTarget datastore ( running or candidate) * @param messageTimeout message timeout of the request. * @return Device response */ fun lock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse /** + * Get-config * @param messageId message id of the request. - * @param messageContent filter content. + * @param filter filter content. * @param configTarget config target ( running or candidate) * @param messageTimeout message timeout of the request. * @return Device response */ - fun getConfig(messageId: String, messageContent: String, configTarget: String, messageTimeout: Int): DeviceResponse + fun getConfig(messageId: String, filter: String, configTarget: String, messageTimeout: Int): DeviceResponse /** + * Delete config from datastore * @param messageId message id of the request. * @param configTarget config target ( running or candidate) * @param messageTimeout message timeout of the request. @@ -57,10 +46,9 @@ interface NetconfRpcClientService { fun deleteConfig(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse /** + * Edit-config * @param messageId message id of the request. * @param messageContent edit config content. - * @param reConnect reconnect session - * @param wait waiting time to perform operation ( 0 indicates no wait ) * @param lock lock the device before performing edit. * @param configTarget config target ( running or candidate) * @param editDefaultOperation edit default operation (merge | replace | create | delete | remove or @@ -70,16 +58,15 @@ interface NetconfRpcClientService { * @param discardChanges Rollback on failure * @param validate validate the config before commit * @param unlock unlock device after edit - * @param preRestartWait - * @param postRestartWait * @param messageTimeout message timeout of the request. * @return Device response */ - fun editConfig(messageId: String, messageContent: String, reConnect: Boolean, wait: Int, lock: Boolean, - configTarget: String, editDefaultOperation: String, clearCandidate: Boolean, validate: Boolean, commit: Boolean, - discardChanges: Boolean, unlock: Boolean, preRestartWait: Int, postRestartWait: Int, messageTimeout: Int): DeviceResponse + fun editConfig(messageId: String, messageContent: String, lock: Boolean, configTarget: String, + editDefaultOperation: String, deleteConfig: Boolean, validate: Boolean, commit: Boolean, + discardChanges: Boolean, unlock: Boolean, messageTimeout: Int): DeviceResponse /** + * Validate * @param messageId message id of the request. * @param configTarget config target ( running or candidate) * @param messageTimeout message timeout of the request. @@ -88,15 +75,16 @@ interface NetconfRpcClientService { fun validate(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse /** + * Commit * @param messageId message id of the request. - * @param message optional commit message * @param discardChanges Rollback on failure * @param messageTimeout message timeout of the request. * @return Device response */ - fun commit(messageId: String, message: String, discardChanges: Boolean, messageTimeout: Int): DeviceResponse + fun commit(messageId: String, discardChanges: Boolean, messageTimeout: Int): DeviceResponse /** + * Unlock * @param messageId message id of the request. * @param configTarget config target ( running or candidate) * @param messageTimeout message timeout of the request. @@ -105,6 +93,7 @@ interface NetconfRpcClientService { fun unLock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse /** + * Discard config * @param messageId message id of the request. * @param messageTimeout message timeout of the request. * @return Device response @@ -112,12 +101,13 @@ interface NetconfRpcClientService { fun discardConfig(messageId: String, messageTimeout: Int): DeviceResponse /** + * Close session * @param messageId message id of the request. - * @param force force close + * @param force force closeSession * @param messageTimeout message timeout of the request. * @return Device response */ - fun close(messageId: String, force: Boolean, messageTimeout: Int): DeviceResponse + fun closeSession(messageId: String, force: Boolean, messageTimeout: Int): DeviceResponse /** * Executes an RPC request to the netconf server. diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSession.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSession.kt new file mode 100644 index 00000000..6a655d91 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSession.kt @@ -0,0 +1,86 @@ +/* + * Copyright © 2017-2018 AT&T Intellectual Property. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api + +import java.util.concurrent.CompletableFuture + +interface NetconfSession { + + /** + * Establish netconf session + */ + fun connect() + + + /** + * Disconnect netconf session + */ + fun disconnect() + + /** + * Reconnect netconf session + */ + fun reconnect() + + /** + * Executes an synchronous RPC request. + * + * @param request the XML request + * @param messageId message id of the request. + * @return Response + */ + @Throws(NetconfException::class) + fun syncRpc(request: String, messageId: String): String + + /** + * Executes an asynchronous RPC request. + * + * @param request the XML request + * @param messageId message id of the request. + * @return Response + */ + @Throws(NetconfException::class) + fun asyncRpc(request: String, messageId: String): CompletableFuture<String> + + /** + * Checks the state of the underlying SSH session and connection and if necessary it reestablishes + * it. + */ + @Throws(NetconfException::class) + fun checkAndReestablish() + + /** + * Get the device information for initialised session. + * + * @return DeviceInfo as device information + */ + fun getDeviceInfo(): DeviceInfo + + /** + * Gets the session ID of the Netconf session. + * + * @return Session ID as a string. + */ + fun getSessionId(): String + + /** + * Gets the capabilities of the remote Netconf device associated to this session. + * + * @return Network capabilities as strings in a Set. + */ + fun getDeviceCapabilitiesSet(): Set<String> +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSessionDelegate.java b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSessionListener.kt index 47955804..8854894f 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSessionDelegate.java +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSessionListener.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2018 AT&T Intellectual Property. + * Copyright © 2017-2019 AT&T, Bell Canada * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces; +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.NetconfDeviceOutputEvent; +interface NetconfSessionListener { -public interface NetconfSessionDelegate { - - void notify(NetconfDeviceOutputEvent event); + fun notify(event: NetconfReceivedEvent) } diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfStreamThread.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicator.kt index cfcf24bb..69475619 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfStreamThread.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicator.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2018 AT&T Intellectual Property. + * Copyright © 2017-2019 AT&T, Bell Canada * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,26 +16,33 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.NetconfException -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.NetconfDeviceOutputEvent -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.DeviceInfo -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.NetconfSessionDelegate -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcConstants +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfReceivedEvent +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfSessionListener +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.NetconfMessageUtils import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcMessageUtils import org.slf4j.LoggerFactory -import java.io.* +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStream +import java.io.InputStreamReader +import java.io.OutputStream +import java.io.OutputStreamWriter import java.nio.charset.StandardCharsets import java.util.concurrent.CompletableFuture +class NetconfDeviceCommunicator(private var inputStream: InputStream, + private var out: OutputStream, + private val deviceInfo: DeviceInfo, + private val sessionListener: NetconfSessionListener, + private var replies: MutableMap<String, CompletableFuture<String>>) : Thread() { -class NetconfStreamThread(private var inputStream: InputStream, private var out : OutputStream, - private val netconfDeviceInfo: DeviceInfo, private val netconfSessionDelegate: NetconfSessionDelegate, - private var replies :MutableMap<String, CompletableFuture<String>> ) : Thread() { + private val log = LoggerFactory.getLogger(NetconfDeviceCommunicator::class.java) + private var state = NetconfMessageState.NO_MATCHING_PATTERN - val log = LoggerFactory.getLogger(NetconfStreamThread::class.java) - lateinit var state : NetconfMessageState - // val outputStream = OutputStreamWriter(out, StandardCharsets.UTF_8) - private var outputStream: OutputStreamWriter? = null + init { + start() + } override fun run() { var bufferReader: BufferedReader? = null @@ -47,52 +54,58 @@ class NetconfStreamThread(private var inputStream: InputStream, private var out var socketClosed = false val deviceReplyBuilder = StringBuilder() while (!socketClosed) { - val cInt = bufferReader!!.read() + val cInt = bufferReader.read() if (cInt == -1) { - log.debug("Netconf device {} sent error char in session will need to be reopend", - netconfDeviceInfo) - NetconfDeviceOutputEvent(NetconfDeviceOutputEvent.Type.SESSION_CLOSED, null!!, null!!, - null !!, netconfDeviceInfo) + log.error("$deviceInfo: Received cInt = -1") +// bufferReader.close() socketClosed = true - log.debug("Netconf device {} ERROR cInt == -1 socketClosed = true", netconfDeviceInfo) +// sessionListener.notify(NetconfReceivedEvent( +// NetconfReceivedEvent.Type.SESSION_CLOSED, +// deviceInfo = deviceInfo)) } val c = cInt.toChar() state = state.evaluateChar(c) deviceReplyBuilder.append(c) if (state === NetconfMessageState.END_PATTERN) { var deviceReply = deviceReplyBuilder.toString() - if (deviceReply == RpcConstants.END_PATTERN) { + if (deviceReply == RpcMessageUtils.END_PATTERN) { socketClosed = true - close(deviceReply) + bufferReader.close() + sessionListener.notify(NetconfReceivedEvent( + NetconfReceivedEvent.Type.DEVICE_UNREGISTERED, + deviceInfo = deviceInfo)) } else { - deviceReply = deviceReply.replace(RpcConstants.END_PATTERN, "") - dealWithReply(deviceReply) + deviceReply = deviceReply.replace(RpcMessageUtils.END_PATTERN, "") + receivedMessage(deviceReply) deviceReplyBuilder.setLength(0) } } else if (state === NetconfMessageState.END_CHUNKED_PATTERN) { var deviceReply = deviceReplyBuilder.toString() - if (!RpcMessageUtils.validateChunkedFraming(deviceReply)) { - log.debug("Netconf device {} send badly framed message {}", netconfDeviceInfo, deviceReply) + if (!NetconfMessageUtils.validateChunkedFraming(deviceReply)) { + log.debug("$deviceInfo: Received badly framed message $deviceReply") socketClosed = true - close(deviceReply) + sessionListener.notify(NetconfReceivedEvent( + NetconfReceivedEvent.Type.DEVICE_ERROR, + deviceInfo = deviceInfo)) } else { - deviceReply = deviceReply.replace(RpcConstants.MSGLEN_REGEX_PATTERN.toRegex(), "") - deviceReply = deviceReply.replace(RpcMessageUtils.CHUNKED_END_REGEX_PATTERN.toRegex(), "") - dealWithReply(deviceReply) + deviceReply = deviceReply.replace(RpcMessageUtils.MSGLEN_REGEX_PATTERN.toRegex(), "") + deviceReply = deviceReply.replace(NetconfMessageUtils.CHUNKED_END_REGEX_PATTERN.toRegex(), "") + receivedMessage(deviceReply) deviceReplyBuilder.setLength(0) } } } + } catch (e: IOException) { - log.warn("Error in reading from the session for device {} ", netconfDeviceInfo, e) - throw IllegalStateException( - NetconfException(message = "Error in reading from the session for device {}$netconfDeviceInfo")) + log.warn("$deviceInfo: Fail while reading from channel", e) + sessionListener.notify(NetconfReceivedEvent( + NetconfReceivedEvent.Type.DEVICE_ERROR, + deviceInfo = deviceInfo)) } } - enum class NetconfMessageState { - + private enum class NetconfMessageState { NO_MATCHING_PATTERN { override fun evaluateChar(c: Char): NetconfMessageState { return if (c == ']') { @@ -194,50 +207,37 @@ class NetconfStreamThread(private var inputStream: InputStream, private var out internal abstract fun evaluateChar(c: Char): NetconfMessageState } - private fun close(deviceReply: String) { - log.debug("Netconf device {} socketClosed = true DEVICE_UNREGISTERED {}", netconfDeviceInfo, deviceReply) - NetconfDeviceOutputEvent(NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED, null!!, null!!, null!!, - netconfDeviceInfo) - this.interrupt() - } - - private fun dealWithReply(deviceReply: String) { - if (deviceReply.contains(RpcConstants.RPC_REPLY) || deviceReply.contains(RpcConstants.RPC_ERROR) - || deviceReply.contains(RpcConstants.HELLO)) { - log.info("From Netconf Device: {} \n for Message-ID: {} \n Device-Reply: \n {} \n ", netconfDeviceInfo, - RpcMessageUtils.getMsgId(deviceReply), deviceReply) - val event = NetconfDeviceOutputEvent(NetconfDeviceOutputEvent.Type.DEVICE_REPLY, - null!!, deviceReply, RpcMessageUtils.getMsgId(deviceReply), netconfDeviceInfo) - netconfSessionDelegate.notify(event) - } else { - log.debug("Error Reply: \n {} \n from Netconf Device: {}", deviceReply, netconfDeviceInfo) - } - } - - @SuppressWarnings("squid:S3655") - @Override - fun sendMessage(request: String): CompletableFuture<String> { - val messageId = RpcMessageUtils.getMsgId(request) - return sendMessage(request, messageId.get()) - } - fun sendMessage(request: String, messageId: String): CompletableFuture<String> { - log.info("Sending message: \n {} \n to NETCONF Device: {}", request, netconfDeviceInfo) - val cf = CompletableFuture<String>() - replies.put(messageId, cf) - // outputStream = OutputStreamWriter(out, StandardCharsets.UTF_8) - synchronized(OutputStreamWriter(out, StandardCharsets.UTF_8)) { + log.info("$deviceInfo: Sending message: \n $request") + val future = CompletableFuture<String>() + replies.put(messageId, future) + val outputStream = OutputStreamWriter(out, StandardCharsets.UTF_8) + synchronized(this) { try { - - OutputStreamWriter(out, StandardCharsets.UTF_8).write(request) - OutputStreamWriter(out, StandardCharsets.UTF_8).flush() + outputStream.write(request) + outputStream.flush() } catch (e: IOException) { - log.error("Writing to NETCONF Device {} failed", netconfDeviceInfo, e) - cf.completeExceptionally(e) + log.error("$deviceInfo: Failed to send message : \n $request", e) + future.completeExceptionally(e) } } - return cf + return future } -}
\ No newline at end of file + private fun receivedMessage(deviceReply: String) { + if (deviceReply.contains(RpcMessageUtils.RPC_REPLY) || deviceReply.contains(RpcMessageUtils.RPC_ERROR) + || deviceReply.contains(RpcMessageUtils.HELLO)) { + log.info("$deviceInfo: Received message with messageId: {} \n $deviceReply", + NetconfMessageUtils.getMsgId(deviceReply)) + + } else { + log.error("$deviceInfo: Invalid message received: \n $deviceReply") + } + sessionListener.notify(NetconfReceivedEvent( + NetconfReceivedEvent.Type.DEVICE_REPLY, + deviceReply, + NetconfMessageUtils.getMsgId(deviceReply), + deviceInfo)) + } +} diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfRpcServiceImpl.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfRpcServiceImpl.kt new file mode 100644 index 00000000..5c633a5b --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfRpcServiceImpl.kt @@ -0,0 +1,265 @@ +/* + * Copyright © 2017-2019 AT&T, Bell Canada + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core + +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.DeviceResponse +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfException +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfRpcService +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfSession +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.NetconfDatastore +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.NetconfMessageUtils +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcStatus +import org.slf4j.LoggerFactory +import java.util.concurrent.TimeUnit + +class NetconfRpcServiceImpl(private val deviceInfo: DeviceInfo) : NetconfRpcService { + + private val log = LoggerFactory.getLogger(NetconfRpcService::class.java) + + private lateinit var netconfSession: NetconfSession + + fun setNetconfSession(netconfSession: NetconfSession) { + this.netconfSession = netconfSession + } + + override fun getConfig(messageId: String, filter: String, configTarget: String, + messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + log.info("$deviceInfo: getConfig: messageId($messageId)") + try { + val message = NetconfMessageUtils.getConfig(messageId, configTarget, filter) + output = asyncRpc(message, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in get-config command $e.message" + } + return output + } + + override fun deleteConfig(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + log.info("$deviceInfo: deleteConfig: messageId($messageId)") + try { + val deleteConfigMessage = NetconfMessageUtils.deleteConfig(messageId, configTarget) + output.requestMessage = deleteConfigMessage + output = asyncRpc(deleteConfigMessage, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in delete config command $e.message" + } + return output + } + + override fun lock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + log.info("$deviceInfo: lock: messageId($messageId)") + try { + val lockMessage = NetconfMessageUtils.lock(messageId, configTarget) + output.requestMessage = lockMessage + output = asyncRpc(lockMessage, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in lock command $e.message" + } + + return output + } + + override fun unLock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + log.info("$deviceInfo: unLock: messageId($messageId)") + try { + val unlockMessage = NetconfMessageUtils.unlock(messageId, configTarget) + output.requestMessage = unlockMessage + output = asyncRpc(unlockMessage, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in lock command $e.message" + } + return output + } + + override fun commit(messageId: String, discardChanges: Boolean, messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + log.info("$deviceInfo: commit: messageId($messageId)") + try { + val messageContent = NetconfMessageUtils.commit(messageId) + output = asyncRpc(messageContent, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in commit command $e.message" + + // If commit failed apply discard changes + if (discardChanges) { + val discardChangesConfigMessageId = "$messageId-discard-changes" + val discardOutput = discardConfig(discardChangesConfigMessageId, deviceInfo.replyTimeout) + output.addSubDeviceResponse(discardChangesConfigMessageId, discardOutput) + } + } + return output + } + + override fun discardConfig(messageId: String, messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + log.info("$deviceInfo: discard: messageId($messageId)") + try { + val discardChangesMessage = NetconfMessageUtils.discardChanges(messageId) + output.requestMessage = discardChangesMessage + output = asyncRpc(discardChangesMessage, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in discard changes command " + e.message + } + return output + } + + override fun closeSession(messageId: String, force: Boolean, messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + log.info("$deviceInfo: closeSession: messageId($messageId)") + try { + val messageContent = NetconfMessageUtils.closeSession(messageId, force) + output = asyncRpc(messageContent, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in closeSession command " + e.message + } + return output + } + + @Throws(NetconfException::class) + override fun asyncRpc(request: String, messageId: String, messageTimeout: Int): DeviceResponse { + val response = DeviceResponse() + log.info("$deviceInfo: send asyncRpc with messageId($messageId)") + response.requestMessage = request + + val rpcResponse = netconfSession.asyncRpc(request, messageId).get(messageTimeout.toLong(), TimeUnit.SECONDS) + if (!NetconfMessageUtils.checkReply(rpcResponse)) { + throw NetconfException(rpcResponse) + } + response.responseMessage = rpcResponse + response.status = RpcStatus.SUCCESS + response.errorMessage = null + return response + } + + override fun editConfig(messageId: String, messageContent: String, lock: Boolean, configTarget: String, + editDefaultOperation: String, deleteConfig: Boolean, validate: Boolean, commit: Boolean, + discardChanges: Boolean, unlock: Boolean, messageTimeout: Int): DeviceResponse { + var editConfigDeviceResponse = + DeviceResponse() + + try { + val editMessage = + NetconfMessageUtils.editConfig(messageId, configTarget, editDefaultOperation, messageContent) + editConfigDeviceResponse.requestMessage = editMessage + + if (lock) { + val lockMessageId = "$messageId-lock" + val lockDeviceResponse = lock(lockMessageId, configTarget, deviceInfo.replyTimeout) + editConfigDeviceResponse.addSubDeviceResponse(lockMessageId, lockDeviceResponse) + if (!RpcStatus.SUCCESS.equals(lockDeviceResponse.status, ignoreCase = true)) { + throw NetconfException( + lockDeviceResponse.errorMessage!!) + } + } + + if (deleteConfig) { + val deleteConfigMessageId = "$messageId-delete" + val deleteConfigDeviceResponse = deleteConfig(deleteConfigMessageId, + NetconfDatastore.CANDIDATE, deviceInfo.replyTimeout) + editConfigDeviceResponse.addSubDeviceResponse(deleteConfigMessageId, deleteConfigDeviceResponse) + if (!RpcStatus.SUCCESS.equals(deleteConfigDeviceResponse.status, + ignoreCase = true)) { + throw NetconfException( + deleteConfigDeviceResponse.errorMessage!!) + } + } + + if (discardChanges) { + val discardConfigMessageId = "$messageId-discard" + val discardConfigDeviceResponse = discardConfig(discardConfigMessageId, deviceInfo.replyTimeout) + editConfigDeviceResponse.addSubDeviceResponse(discardConfigMessageId, discardConfigDeviceResponse) + if (!RpcStatus.SUCCESS.equals(discardConfigDeviceResponse.status, + ignoreCase = true)) { + throw NetconfException( + discardConfigDeviceResponse.errorMessage!!) + } + } + + editConfigDeviceResponse = asyncRpc(editMessage, messageId, messageTimeout) + if (!RpcStatus.SUCCESS.equals(editConfigDeviceResponse.status, ignoreCase = true)) { + throw NetconfException( + editConfigDeviceResponse.errorMessage!!) + } + + if (validate) { + val validateMessageId = "$messageId-validate" + val validateDeviceResponse = validate(validateMessageId, + NetconfDatastore.CANDIDATE, deviceInfo.replyTimeout) + editConfigDeviceResponse.addSubDeviceResponse(validateMessageId, validateDeviceResponse) + if (!RpcStatus.SUCCESS.equals(validateDeviceResponse.status, ignoreCase = true)) { + throw NetconfException( + validateDeviceResponse.errorMessage!!) + } + } + + /** + * If Commit is enable, the commit response is treated as Edit config response, If commit failed, we + * need not to throw an exception, until we unlock the device. + */ + if (commit) { + val commitMessageId = "$messageId-commit" + val commitDeviceResponse = + commit(commitMessageId, discardChanges, deviceInfo.replyTimeout) + editConfigDeviceResponse.addSubDeviceResponse(commitMessageId, commitDeviceResponse) + if (!RpcStatus.SUCCESS.equals(commitDeviceResponse.status, ignoreCase = true)) { + throw NetconfException( + commitDeviceResponse.errorMessage!!) + } + } + + } catch (e: Exception) { + editConfigDeviceResponse.status = RpcStatus.FAILURE + editConfigDeviceResponse.errorMessage = e.message + } finally { + if (unlock) { + val unlockMessageId = "$messageId-unlock" + val unlockDeviceResponse = unLock(unlockMessageId, configTarget, deviceInfo.replyTimeout) + editConfigDeviceResponse.addSubDeviceResponse(unlockMessageId, unlockDeviceResponse) + if (!RpcStatus.SUCCESS.equals(unlockDeviceResponse.status, ignoreCase = true)) { + editConfigDeviceResponse.status = RpcStatus.FAILURE + editConfigDeviceResponse.errorMessage = unlockDeviceResponse.errorMessage + } + } + } + return editConfigDeviceResponse + } + + override fun validate(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse { + var output = DeviceResponse() + try { + val validateMessage = NetconfMessageUtils.validate(messageId, configTarget) + output.requestMessage = validateMessage + output = asyncRpc(validateMessage, messageId, messageTimeout) + } catch (e: Exception) { + output.status = RpcStatus.FAILURE + output.errorMessage = "$deviceInfo: failed in validate command " + e.message + } + return output + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionFactory.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionFactory.kt deleted file mode 100644 index 370ea7a5..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionFactory.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core - -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.NetconfException -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.DeviceInfo -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.NetconfSession -import java.util.* - -object NetconfSessionFactory { - - private fun NetconfSessionFactory() {} - - val netConfSessionManagerMap = HashMap<String, NetconfSession>() - - fun registerNetConfSessionManager(type: String, netconfSession: NetconfSession) { - netConfSessionManagerMap[type] = netconfSession - } - - /** - * Creates a new NETCONF session for the specified device. - * - * @param type type of the session. - * @param netconfDeviceInfo information of the device to create the session for. - * @return Instance of NetconfSession. - * @throws NetconfException when problems arise establishing the connection. - */ - @Throws(NetconfException::class) - fun instance(type: String, netconfDeviceInfo: DeviceInfo): NetconfSession { - return if (netConfSessionManagerMap.containsKey(type)) { - netConfSessionManagerMap[type]!! - } else { - return NetconfSessionImpl(netconfDeviceInfo) - } - } -}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt index 34c01813..21570a23 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2018 AT&T Intellectual Property. + * Copyright © 2017-2019 AT&T, Bell Canada * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,200 +18,141 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableSet -import org.apache.sshd.client.ClientBuilder import org.apache.sshd.client.SshClient import org.apache.sshd.client.channel.ClientChannel import org.apache.sshd.client.session.ClientSession -import org.apache.sshd.client.simple.SimpleClient import org.apache.sshd.common.FactoryManager import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.NetconfException -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.NetconfDeviceOutputEvent -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.DeviceInfo -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.NetconfSession -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.NetconfSessionDelegate -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcConstants +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfException +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfReceivedEvent +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfRpcService +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfSession +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfSessionListener +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.NetconfMessageUtils import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcMessageUtils +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.RpcStatus import org.slf4j.LoggerFactory import java.io.IOException import java.util.* -import java.util.concurrent.* +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ExecutionException +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException import java.util.concurrent.atomic.AtomicInteger +class NetconfSessionImpl(private val deviceInfo: DeviceInfo, private val rpcService: NetconfRpcService) : + NetconfSession { -class NetconfSessionImpl(private val deviceInfo: DeviceInfo ): NetconfSession { - val log = LoggerFactory.getLogger(NetconfSessionImpl::class.java) - var connectTimeout: Long = 0 - var replyTimeout: Int = 0 - var idleTimeout: Int = 0 - var sessionID: String? = null - var errorReplies: MutableList<String> = mutableListOf() - var netconfCapabilities = ImmutableList.of("urn:ietf:params:netconf:base:1.0", "urn:ietf:params:netconf:base:1.1") + private val log = LoggerFactory.getLogger(NetconfSessionImpl::class.java) - // var replies: MutableMap<String, CompletableFuture<String>> = mutableListOf<String,CompletableFuture<String>()>() - var replies: MutableMap<String, CompletableFuture<String>> = ConcurrentHashMap() - val deviceCapabilities = LinkedHashSet<String>() + private val errorReplies: MutableList<String> = Collections.synchronizedList(listOf()) + private val replies: MutableMap<String, CompletableFuture<String>> = ConcurrentHashMap() + private val deviceCapabilities = setOf<String>() - lateinit var session: ClientSession - lateinit var client: SshClient - lateinit var channel: ClientChannel - var streamHandler: NetconfStreamThread? = null + private var connectionTimeout: Long = 0 + private var replyTimeout: Int = 0 + private var idleTimeout: Int = 0 + private var sessionId: String? = null - val messageIdInteger = AtomicInteger(1) - private var onosCapabilities = ImmutableList.of<String>(RpcConstants.NETCONF_10_CAPABILITY, RpcConstants.NETCONF_11_CAPABILITY) + private lateinit var session: ClientSession + private lateinit var client: SshClient + private lateinit var channel: ClientChannel + private lateinit var streamHandler: NetconfDeviceCommunicator + private val messageIdInteger = AtomicInteger(1) + private var capabilities = + ImmutableList.of(RpcMessageUtils.NETCONF_10_CAPABILITY, RpcMessageUtils.NETCONF_11_CAPABILITY) - init { - startConnection() - } - - private fun startConnection() { - connectTimeout = deviceInfo.connectTimeoutSec - replyTimeout = deviceInfo.replyTimeout - idleTimeout = deviceInfo.idleTimeout - log.info("Connecting to NETCONF Device {} with timeouts C:{}, R:{}, I:{}", deviceInfo, connectTimeout, - replyTimeout, idleTimeout) + override fun connect() { try { - startClient() - } catch (e: IOException) { - throw NetconfException("Failed to establish SSH with device ${deviceInfo.deviceId}",e) - } catch (e:Exception){ - throw NetconfException("Failed to establish SSH with device $deviceInfo",e) + log.info("$deviceInfo: Connecting to Netconf Device with timeouts C:${deviceInfo.connectTimeout}, " + + "R:${deviceInfo.replyTimeout}, I:${deviceInfo.idleTimeout}") + startConnection() + log.info("$deviceInfo: Connected to Netconf Device") + } catch (e: NetconfException) { + log.error("$deviceInfo: Netconf Device Connection Failed. ${e.message}") + throw NetconfException(e) } - } - private fun startClient() { - log.info("in the startClient") - // client = SshClient.setUpDefaultClient().toInt() - client = SshClient.setUpDefaultClient() + override fun disconnect() { + if (rpcService.closeSession(messageIdInteger.incrementAndGet().toString(), false, replyTimeout).status.equals( + RpcStatus.FAILURE, true)) { + rpcService.closeSession(messageIdInteger.incrementAndGet().toString(), true, replyTimeout) + } - client = ClientBuilder.builder().build() as SshClient - log.info("client {}>>",client) - client.getProperties().putIfAbsent(FactoryManager.IDLE_TIMEOUT, TimeUnit.SECONDS.toMillis(idleTimeout.toLong())) - client.getProperties().putIfAbsent(FactoryManager.NIO2_READ_TIMEOUT, - TimeUnit.SECONDS.toMillis(idleTimeout + 15L)) - client.start() - client.setKeyPairProvider(SimpleGeneratorHostKeyProvider()) - log.info("client {}>>",client.isOpen) - startSession() + session.close() + // Closes the socket which should interrupt the streamHandler + channel.close() + client.close() } - private fun startSession() { - log.info("in the startSession") - val connectFuture = client.connect(deviceInfo.name, deviceInfo.ipAddress, deviceInfo.port) - .verify(connectTimeout, TimeUnit.SECONDS) - log.info("connectFuture {}>>"+connectFuture) - session = connectFuture.session - - session.addPasswordIdentity(deviceInfo.pass) - session.auth().verify(connectTimeout, TimeUnit.SECONDS) - - val event = session.waitFor(ImmutableSet.of(ClientSession.ClientSessionEvent.WAIT_AUTH, - ClientSession.ClientSessionEvent.CLOSED, ClientSession.ClientSessionEvent.AUTHED), 0) - - if (!event.contains(ClientSession.ClientSessionEvent.AUTHED)) { - log.debug("Session closed {} for event {}", session.isClosed(), event) - throw NetconfException(String - .format("Failed to authenticate session with device (%s) check the user/pwd or key", deviceInfo)) - } - openChannel() + override fun reconnect() { + disconnect() + connect() } - private fun openChannel() { - log.info("in the open Channel") - channel = session.createSubsystemChannel("netconf") - val channeuture = channel.open() - - if (channeuture!!.await(connectTimeout, TimeUnit.SECONDS) && channeuture.isOpened) { - val netconfSessionDelegate:NetconfSessionDelegate = NetconfSessionDelegateImpl() - streamHandler = NetconfStreamThread(channel.getInvertedOut(), channel.getInvertedIn(), deviceInfo, - netconfSessionDelegate, replies) - sendHello() - } else { - throw NetconfException(String.format("Failed to open channel with device (%s) $deviceInfo", deviceInfo)) - } - } + override fun syncRpc(request: String, messageId: String): String { + val formattedRequest = NetconfMessageUtils.formatRPCRequest(request, messageId, deviceCapabilities) - private fun sendHello() { - sessionID = (-1).toString() + checkAndReestablish() - val serverHelloResponse = syncRpc(RpcMessageUtils.createHelloString(onosCapabilities), (-1).toString()) - val sessionIDMatcher = RpcMessageUtils.SESSION_ID_REGEX_PATTERN.matcher(serverHelloResponse) + try { + return streamHandler.sendMessage(formattedRequest, messageId).get(replyTimeout.toLong(), TimeUnit.SECONDS) +// replies.remove(messageId) + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + throw NetconfException("$deviceInfo: Interrupted while waiting for reply for request: $formattedRequest", e) + } catch (e: TimeoutException) { + throw NetconfException("$deviceInfo: Timed out while waiting for reply for request $formattedRequest after $replyTimeout sec.", + e) + } catch (e: ExecutionException) { + log.warn("$deviceInfo: Closing session($sessionId) due to unexpected Error", e) + try { + session.close() + // Closes the socket which should interrupt the streamHandler + channel.close() + client.close() + } catch (ioe: IOException) { + log.warn("$deviceInfo: Error closing session($sessionId) for host($deviceInfo)", ioe) + } - if (sessionIDMatcher.find()) { - sessionID = sessionIDMatcher.group(1) - } else { - throw NetconfException("Missing SessionID in server hello reponse.") - } +// NetconfReceivedEvent(NetconfReceivedEvent.Type.SESSION_CLOSED, "", +// "Closed due to unexpected error " + e.cause, "-1", deviceInfo) + errorReplies.clear() // move to cleanUp()? + replies.clear() - val capabilityMatcher = RpcMessageUtils.CAPABILITY_REGEX_PATTERN.matcher(serverHelloResponse) - while (capabilityMatcher.find()) { - deviceCapabilities.add(capabilityMatcher.group(1)) + throw NetconfException("$deviceInfo: Closing session $sessionId for request $formattedRequest", e) } } + override fun asyncRpc(request: String, messageId: String): CompletableFuture<String> { + val formattedRequest = NetconfMessageUtils.formatRPCRequest(request, messageId, deviceCapabilities) - override fun asyncRpc( request: String, msgId: String): CompletableFuture<String> { - //return close(false); - var request = RpcMessageUtils.formatRPCRequest(request, msgId, deviceCapabilities) - /** - * Checking Liveliness of the Session - */ checkAndReestablish() - return streamHandler!!.sendMessage(request, msgId).handleAsync { reply, t -> + return streamHandler.sendMessage(formattedRequest, messageId).handleAsync { reply, t -> if (t != null) { - //throw NetconfTransportException(t) - throw NetconfException(msgId) + throw NetconfException(messageId, t) } reply } } - override fun close(): Boolean { - return close(false); - } - @Throws(NetconfException::class) - private fun close(force: Boolean): Boolean { - val rpc = StringBuilder() - rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">") - if (force) { - rpc.append("<kill-session/>") - } else { - rpc.append("<close-session/>") - } - rpc.append("</rpc>") - rpc.append(RpcConstants.END_PATTERN) - return RpcMessageUtils.checkReply(sendRequest(rpc.toString())) || close(true) - } - - - - override fun getSessionId(): String? { - return this.sessionID - } - - override fun getDeviceCapabilitiesSet(): Set<String> { - return Collections.unmodifiableSet(deviceCapabilities); - } - - fun setCapabilities(capabilities: ImmutableList<String>) { - onosCapabilities = capabilities - } - override fun checkAndReestablish() { try { if (client.isClosed) { - log.debug("Trying to restart the whole SSH connection with {}", deviceInfo.deviceId) + log.info("Trying to restart the whole SSH connection with {}", deviceInfo) replies.clear() startConnection() } else if (session.isClosed) { - log.debug("Trying to restart the session with {}", deviceInfo.deviceId) + log.info("Trying to restart the session with {}", deviceInfo) replies.clear() startSession() } else if (channel.isClosed) { - log.debug("Trying to reopen the channel with {}", deviceInfo.deviceId) + log.info("Trying to reopen the channel with {}", deviceInfo) replies.clear() openChannel() } else { @@ -227,73 +168,111 @@ class NetconfSessionImpl(private val deviceInfo: DeviceInfo ): NetconfSession { } - override fun setCapabilities(capabilities: List<String>) { - super.setCapabilities(capabilities) - } - override fun getDeviceInfo(): DeviceInfo { return deviceInfo } - @Throws(NetconfException::class) - private fun sendRequest(request: String): String { - return syncRpc(request, messageIdInteger.getAndIncrement().toString()) + override fun getSessionId(): String { + return this.sessionId!! } - @Throws(NetconfException::class) - override fun syncRpc(request: String, messageId: String): String { - var request = request - request = RpcMessageUtils.formatRPCRequest(request, messageId, deviceCapabilities) - - /** - * Checking Liveliness of the Session - */ - checkAndReestablish() + override fun getDeviceCapabilitiesSet(): Set<String> { + return Collections.unmodifiableSet(deviceCapabilities) + } - val response: String + private fun startConnection() { + connectionTimeout = deviceInfo.connectTimeout + replyTimeout = deviceInfo.replyTimeout + idleTimeout = deviceInfo.idleTimeout try { - response = streamHandler!!.sendMessage(request, messageId).get(replyTimeout.toLong(), TimeUnit.SECONDS) - replies.remove(messageId) // Why here??? - } catch (e: InterruptedException) { - Thread.currentThread().interrupt() - throw NetconfException("Interrupted waiting for reply for request$request",e) - } catch (e: TimeoutException) { - throw NetconfException( - "Timed out waiting for reply for request $request after $replyTimeout sec.",e) - } catch (e: ExecutionException) { - log.warn("Closing session {} for {} due to unexpected Error", sessionID, deviceInfo, e) - try { - session.close() - channel.close() // Closes the socket which should interrupt NetconfStreamThread - client.close() - } catch (ioe: IOException) { - log.warn("Error closing session {} on {}", sessionID, deviceInfo, ioe) - } + startClient() + } catch (e: Exception) { + throw NetconfException("$deviceInfo: Failed to establish SSH session", e) + } - NetconfDeviceOutputEvent(NetconfDeviceOutputEvent.Type.SESSION_CLOSED, null!!, - "Closed due to unexpected error " + e.cause, Optional.of("-1"), deviceInfo) - errorReplies.clear() // move to cleanUp()? - replies.clear() + } + + private fun startClient() { + client = SshClient.setUpDefaultClient() + client.properties.putIfAbsent(FactoryManager.IDLE_TIMEOUT, TimeUnit.SECONDS.toMillis(idleTimeout.toLong())) + client.properties.putIfAbsent(FactoryManager.NIO2_READ_TIMEOUT, TimeUnit.SECONDS.toMillis(idleTimeout + 15L)) + client.keyPairProvider = SimpleGeneratorHostKeyProvider() + client.start() + + startSession() + } + + private fun startSession() { + log.info("$deviceInfo: Starting SSH session") + val connectFuture = client.connect(deviceInfo.username, deviceInfo.ipAddress, deviceInfo.port) + .verify(connectionTimeout, TimeUnit.SECONDS) + session = connectFuture.session + log.info("$deviceInfo: SSH session created") + + authSession() + } + + private fun authSession() { + session.addPasswordIdentity(deviceInfo.password) + session.auth().verify(connectionTimeout, TimeUnit.SECONDS) + val event = session.waitFor(ImmutableSet.of(ClientSession.ClientSessionEvent.WAIT_AUTH, + ClientSession.ClientSessionEvent.CLOSED, ClientSession.ClientSessionEvent.AUTHED), 0) + if (!event.contains(ClientSession.ClientSessionEvent.AUTHED)) { + throw NetconfException("$deviceInfo: Failed to authenticate session.") + } + log.info("$deviceInfo: SSH session authenticated") + + openChannel() + } + + private fun openChannel() { + channel = session.createSubsystemChannel("netconf") + val channelFuture = channel.open() + if (channelFuture.await(connectionTimeout, TimeUnit.SECONDS) && channelFuture.isOpened) { + log.info("$deviceInfo: SSH NETCONF subsystem channel opened") + setupHandler() + } else { + throw NetconfException("$deviceInfo: Failed to open SSH subsystem channel") + } + } + + private fun setupHandler() { + val sessionListener: NetconfSessionListener = NetconfSessionListenerImpl() + streamHandler = NetconfDeviceCommunicator(channel.invertedOut, channel.invertedIn, deviceInfo, + sessionListener, replies) + + exchangeHelloMessage() + } + + private fun exchangeHelloMessage() { + sessionId = "-1" + val messageId = "-1" - throw NetconfException( - "Closing session $sessionID for $deviceInfo for request $request",e) + val serverHelloResponse = syncRpc(NetconfMessageUtils.createHelloString(capabilities), messageId) + val sessionIDMatcher = NetconfMessageUtils.SESSION_ID_REGEX_PATTERN.matcher(serverHelloResponse) + + if (sessionIDMatcher.find()) { + sessionId = sessionIDMatcher.group(1) + } else { + throw NetconfException("$deviceInfo: Missing sessionId in server hello message: $serverHelloResponse") } - log.debug("Response from NETCONF Device: \n {} \n", response) - return response.trim { it <= ' ' } + val capabilityMatcher = NetconfMessageUtils.CAPABILITY_REGEX_PATTERN.matcher(serverHelloResponse) + while (capabilityMatcher.find()) { + deviceCapabilities.plus(capabilityMatcher.group(1)) + } } - inner class NetconfSessionDelegateImpl : NetconfSessionDelegate { - override fun notify(event: NetconfDeviceOutputEvent) { + inner class NetconfSessionListenerImpl : NetconfSessionListener { + override fun notify(event: NetconfReceivedEvent) { val messageId = event.getMessageID() - log.debug("messageID {}, waiting replies messageIDs {}", messageId, replies.keys) - if (messageId.isNullOrBlank()) { - errorReplies.add(event.getMessagePayload().toString()) - log.error("Device {} sent error reply {}", event.getDeviceInfo(), event.getMessagePayload()) - return + + when (event.getType()) { + NetconfReceivedEvent.Type.DEVICE_UNREGISTERED -> disconnect() + NetconfReceivedEvent.Type.DEVICE_ERROR -> errorReplies.add(event.getMessagePayload()) + NetconfReceivedEvent.Type.DEVICE_REPLY -> replies[messageId]?.complete(event.getMessagePayload()) + NetconfReceivedEvent.Type.SESSION_CLOSED -> disconnect() } - val completedReply = replies[messageId] // remove(..)? - completedReply?.complete(event.getMessagePayload()) } } - }
\ No newline at end of file +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfAdaptorConstant.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfAdaptorConstant.kt deleted file mode 100644 index d49c9915..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfAdaptorConstant.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data - -class NetconfAdaptorConstant { - companion object{ - const val STATUS_CODE_SUCCESS = "200" - const val STATUS_CODE_FAILURE = "400" - - const val STATUS_SUCCESS = "success" - const val STATUS_FAILURE = "failure" - const val STATUS_SKIPPED = "skipped" - const val LOG_MESSAGE_TYPE_LOG = "Log" - - const val CONFIG_TARGET_RUNNING = "running" - const val CONFIG_TARGET_CANDIDATE = "candidate" - const val CONFIG_DEFAULT_OPERATION_MERGE = "merge" - const val CONFIG_DEFAULT_OPERATION_REPLACE = "replace" - - const val DEFAULT_NETCONF_SESSION_MANAGER_TYPE = "DEFAULT_NETCONF_SESSION" - - const val CONFIG_STATUS_PENDING = "pending" - const val CONFIG_STATUS_FAILED = "failed" - const val CONFIG_STATUS_SUCCESS = "success" - - const val DEFAULT_MESSAGE_TIME_OUT = 30 - - - } -}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfExecutionData.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfExecutionData.kt deleted file mode 100644 index f66c14a5..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfExecutionData.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data - -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.DeviceInfo -import java.util.* - - -class DeviceResponse { - lateinit var deviceInfo: DeviceInfo - lateinit var status: String - var errorMessage: String? = null - var responseMessage: String? = null - var requestMessage: String? = null - var subDeviceResponse: MutableMap<Any, Any>? = null - - fun addSubDeviceResponse(key: String, subDeviceResponse: DeviceResponse) { - if (this.subDeviceResponse == null) { - this.subDeviceResponse = hashMapOf() - } - this.subDeviceResponse!![key] = subDeviceResponse - } -} - -class NetconfDeviceOutputEvent { - - private var type: NetconfDeviceOutputEvent.Type - private var messagePayload: String? = null - private var messageID: String? = null - private var deviceInfo: DeviceInfo? = null - private var subject: Any? = null - private var time: Long = 0 - - /** - * Type of device related events. - */ - enum class Type { - DEVICE_REPLY, - DEVICE_NOTIFICATION, - DEVICE_UNREGISTERED, - DEVICE_ERROR, - SESSION_CLOSED - } - - /** - * Creates an event of a given type and for the specified subject and the current time. - * - * @param type event type - * @param subject event subject - * @param payload message from the device - * @param msgID id of the message related to the event - * @param netconfDeviceInfo device of event - */ - constructor(type: Type, subject: String, payload: String, msgID: Optional<String>, netconfDeviceInfo: DeviceInfo) { - this.type = type - this.subject = subject - this.messagePayload = payload - this.deviceInfo = netconfDeviceInfo - this.messageID = msgID.get() - } - - /** - * Creates an event of a given type and for the specified subject and time. - * - * @param type event type - * @param subject event subject - * @param payload message from the device - * @param msgID id of the message related to the event - * @param netconfDeviceInfo device of event - * @param time occurrence time - */ - constructor(type: Type, subject: Any, payload: String, msgID: String, netconfDeviceInfo: DeviceInfo, time: Long) { - this.type = type - this.subject = subject - this.time = time - this.messagePayload = payload - this.deviceInfo = netconfDeviceInfo - this.messageID = msgID - } - - /** - * return the message payload of the reply form the device. - * - * @return reply - */ - fun getMessagePayload(): String? { - return messagePayload - } - - /** - * Event-related device information. - * - * @return information about the device - */ - fun getDeviceInfo(): DeviceInfo? { - return deviceInfo - } - - /** - * Reply messageId. - * - * @return messageId - */ - fun getMessageID(): String? { - return messageID - } - -}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSession.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSession.kt deleted file mode 100644 index 8e16ab73..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSession.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces - -import org.slf4j.LoggerFactory -import java.util.concurrent.CompletableFuture - -interface NetconfSession { - - /** - * Executes an asynchronous RPC request to the server and obtains a future for it's response. - * - * @param request the XML containing the RPC request for the server. - * @param msgId message id of the request. - * @return Server response or ERROR - * @throws NetconfException when there is a problem in the communication process on the underlying - * connection - * @throws NetconfTransportException on secure transport-layer error - */ - fun asyncRpc(request: String, msgId: String): CompletableFuture<String> - - /** - * Closes the Netconf session with the device. the first time it tries gracefully, then kills it - * forcefully - * - * @return true if closed - * @throws NetconfException when there is a problem in the communication process on the underlying - * connection - */ - fun close(): Boolean - - /** - * Gets the session ID of the Netconf session. - * - * @return Session ID as a string. - */ - fun getSessionId(): String? - - /** - * Gets the capabilities of the remote Netconf device associated to this session. - * - * @return Network capabilities as strings in a Set. - */ - fun getDeviceCapabilitiesSet(): Set<String> - - /** - * Checks the state of the underlying SSH session and connection and if necessary it reestablishes - * it. Should be implemented, providing a default here for retro compatibility. - * - * @throws NetconfException when there is a problem in reestablishing the connection or the session - * to the device. - */ - fun checkAndReestablish() { - val log = LoggerFactory.getLogger(NetconfSession::class.java) - log.error("Not implemented/exposed by the underlying ({}) implementation", "NetconfSession") - } - - /** - * Sets the ONOS side capabilities. - * - * @param capabilities list of capabilities has. - */ - fun setCapabilities(capabilities: List<String>) { - // default implementation should be removed in the future - // no-op - } - - /** - * Get the device information for initialised session. - * - * @return DeviceInfo as device information - */ - fun getDeviceInfo(): DeviceInfo - - - /** - * Executes an asynchronous RPC request to the server and obtains a future for it's response. - * - * @param request the XML containing the RPC request for the server. - * @param msgId message id of the request. - * @return Server response or ERROR - * @throws NetconfException when there is a problem in the communication process on the underlying - * connection - * @throws NetconfTransportException on secure transport-layer error - */ - fun syncRpc(request: String, msgId: String): String - - /** - * Closes the Netconf session with the device. the first time it tries gracefully, then kills it - * forcefully - * - * @return true if closed - * @throws NetconfException when there is a problem in the communication process on the underlying - * connection - */ -}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfConstant.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfConstant.kt new file mode 100644 index 00000000..e0cbde53 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfConstant.kt @@ -0,0 +1,84 @@ +/* + * Copyright © 2017-2019 AT&T, Bell Canada + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils + +object NetconfDatastore { + const val RUNNING = "running" + const val CANDIDATE = "candidate" +} + +object RpcStatus { + const val SUCCESS = "success" + const val FAILURE = "failure" +} + +object RpcMessageUtils { + const val OPEN = "<" + const val CLOSE = ">" + const val EQUAL = "=" + + const val HASH = "#" + const val HASH_CHAR = '#' + + const val LF_CHAR = '\n' + const val NEW_LINE = "\n" + + const val QUOTE = "\"" + const val QUOTE_SPACE = "\" " + + const val TAG_CLOSE = "/>" + const val END_OF_RPC_OPEN_TAG = "\">" + const val END_PATTERN = "]]>]]>" + + const val HELLO = "hello" + const val RPC_REPLY = "rpc-reply" + const val RPC_ERROR = "rpc-error" + + const val RPC_OPEN = "<rpc " + const val RPC_CLOSE = "</rpc>" + const val WITH_DEFAULT_OPEN = "<with-defaults " + const val WITH_DEFAULT_CLOSE = "</with-defaults>" + const val DEFAULT_OPERATION_OPEN = "<default-operation>" + const val DEFAULT_OPERATION_CLOSE = "</default-operation>" + const val SUBTREE_FILTER_OPEN = "<filter type=\"subtree\">" + const val SUBTREE_FILTER_CLOSE = "</filter>" + const val TARGET_OPEN = "<target>" + const val TARGET_CLOSE = "</target>" + const val SOURCE_OPEN = "<source>" + const val SOURCE_CLOSE = "</source>" + const val CONFIG_OPEN = "<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">" + const val CONFIG_CLOSE = "</config>" + const val MSGLEN_REGEX_PATTERN = "\n#\\d+\n" + + const val NUMBER_BETWEEN_QUOTES_MATCHER = "\"+([0-9]+)+\"" + + const val XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + const val NETCONF_BASE_NAMESPACE = "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"" + const val NETCONF_WITH_DEFAULTS_NAMESPACE = "xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\"" + const val SUBSCRIPTION_SUBTREE_FILTER_OPEN = + "<filter xmlns:base10=\"urn:ietf:params:xml:ns:netconf:base:1.0\" base10:type=\"subtree\">" + + const val INTERLEAVE_CAPABILITY_STRING = "urn:ietf:params:netconf:capability:interleave:1.0" + + const val CAPABILITY_REGEX = "capability>\\s*(.*?)\\s*capability>" + + const val SESSION_ID_REGEX = "session-id>\\s*(.*?)\\s*session-id>" + + const val MESSAGE_ID_STRING = "message-id" + + const val NETCONF_10_CAPABILITY = "urn:ietf:params:netconf:base:1.0" + const val NETCONF_11_CAPABILITY = "urn:ietf:params:netconf:base:1.1" +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtils.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtils.kt index 28e1361c..b0310d78 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtils.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2018 AT&T Intellectual Property. + * Copyright © 2017-2019 AT&T, Bell Canada * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,47 +16,47 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils import org.apache.commons.lang3.StringUtils -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.NetconfException -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.NetconfAdaptorConstant +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.NetconfException import org.slf4j.LoggerFactory import org.xml.sax.InputSource import java.io.StringReader import java.nio.charset.StandardCharsets -import java.util.Optional import java.util.regex.MatchResult import java.util.regex.Pattern import javax.xml.XMLConstants import javax.xml.parsers.DocumentBuilderFactory -import kotlin.collections.ArrayList import kotlin.text.Charsets.UTF_8 -class RpcMessageUtils { +class NetconfMessageUtils { companion object { - val log = LoggerFactory.getLogger(RpcMessageUtils::class.java) - // pattern to verify whole Chunked-Message format - val CHUNKED_FRAMING_PATTERN = Pattern.compile("(\\n#([1-9][0-9]*)\\n(.+))+\\n##\\n", Pattern.DOTALL) - val CHUNKED_END_REGEX_PATTERN = "\n##\n" - // pattern to parse each chunk-size in ChunkedMessage chunk - val CHUNKED_SIZE_PATTERN = Pattern.compile("\\n#([1-9][0-9]*)\\n") - val CAPABILITY_REGEX_PATTERN = Pattern.compile(RpcConstants.CAPABILITY_REGEX) - val SESSION_ID_REGEX_PATTERN = Pattern.compile(RpcConstants.SESSION_ID_REGEX) - val MSGID_STRING_PATTERN = Pattern.compile("${RpcConstants.MESSAGE_ID_STRING}=\"(.*?)\"") - val NEW_LINE = "\n" + val log = LoggerFactory.getLogger(NetconfMessageUtils::class.java) + + const val NEW_LINE = "\n" + const val CHUNKED_END_REGEX_PATTERN = "\n##\n" + + val CAPABILITY_REGEX_PATTERN: Pattern = Pattern.compile(RpcMessageUtils.CAPABILITY_REGEX) + val SESSION_ID_REGEX_PATTERN: Pattern = Pattern.compile(RpcMessageUtils.SESSION_ID_REGEX) + + private val CHUNKED_FRAMING_PATTERN: Pattern = + Pattern.compile("(\\n#([1-9][0-9]*)\\n(.+))+\\n##\\n", Pattern.DOTALL) + private val CHUNKED_SIZE_PATTERN: Pattern = Pattern.compile("\\n#([1-9][0-9]*)\\n") + private val MSG_ID_STRING_PATTERN = Pattern.compile("${RpcMessageUtils.MESSAGE_ID_STRING}=\"(.*?)\"") fun getConfig(messageId: String, configType: String, filterContent: String?): String { val request = StringBuilder() request.append("<get-config>").append(NEW_LINE) - request.append(RpcConstants.SOURCE_OPEN).append(NEW_LINE) - request.append(RpcConstants.OPEN).append(configType).append(RpcConstants.TAG_CLOSE).append(NEW_LINE) - request.append(RpcConstants.SOURCE_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.SOURCE_OPEN).append(NEW_LINE) + request.append(RpcMessageUtils.OPEN).append(configType).append(RpcMessageUtils.TAG_CLOSE) + .append(NEW_LINE) + request.append(RpcMessageUtils.SOURCE_CLOSE).append(NEW_LINE) - if (filterContent != null) { - request.append(RpcConstants.SUBTREE_FILTER_OPEN).append(NEW_LINE) + if (!filterContent.isNullOrEmpty()) { + request.append(RpcMessageUtils.SUBTREE_FILTER_OPEN).append(NEW_LINE) request.append(filterContent).append(NEW_LINE) - request.append(RpcConstants.SUBTREE_FILTER_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.SUBTREE_FILTER_CLOSE).append(NEW_LINE) } request.append("</get-config>").append(NEW_LINE) @@ -64,13 +64,14 @@ class RpcMessageUtils { } fun doWrappedRpc(messageId: String, request: String): String { - val rpc = StringBuilder(RpcConstants.XML_HEADER).append(NEW_LINE) - rpc.append(RpcConstants.RPC_OPEN) - rpc.append(RpcConstants.MESSAGE_ID_STRING).append(RpcConstants.EQUAL) - rpc.append(RpcConstants.QUOTE).append(messageId).append(RpcConstants.QUOTE_SPACE) - rpc.append(RpcConstants.NETCONF_BASE_NAMESPACE).append(RpcConstants.CLOSE).append(NEW_LINE) + val rpc = StringBuilder(RpcMessageUtils.XML_HEADER).append(NEW_LINE) + rpc.append(RpcMessageUtils.RPC_OPEN) + rpc.append(RpcMessageUtils.MESSAGE_ID_STRING).append(RpcMessageUtils.EQUAL) + rpc.append(RpcMessageUtils.QUOTE).append(messageId).append(RpcMessageUtils.QUOTE_SPACE) + rpc.append(RpcMessageUtils.NETCONF_BASE_NAMESPACE).append(RpcMessageUtils.CLOSE) + .append(NEW_LINE) rpc.append(request) - rpc.append(RpcConstants.RPC_CLOSE) + rpc.append(RpcMessageUtils.RPC_CLOSE) // rpc.append(NEW_LINE).append(END_PATTERN); return rpc.toString() @@ -82,18 +83,20 @@ class RpcMessageUtils { val request = StringBuilder() request.append("<edit-config>").append(NEW_LINE) - request.append(RpcConstants.TARGET_OPEN).append(NEW_LINE) - request.append(RpcConstants.OPEN).append(configType).append(RpcConstants.TAG_CLOSE).append(NEW_LINE) - request.append(RpcConstants.TARGET_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_OPEN).append(NEW_LINE) + request.append(RpcMessageUtils.OPEN).append(configType).append(RpcMessageUtils.TAG_CLOSE) + .append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_CLOSE).append(NEW_LINE) if (defaultOperation != null) { - request.append(RpcConstants.DEFAULT_OPERATION_OPEN).append(defaultOperation).append(RpcConstants.DEFAULT_OPERATION_CLOSE) + request.append(RpcMessageUtils.DEFAULT_OPERATION_OPEN).append(defaultOperation) + .append(RpcMessageUtils.DEFAULT_OPERATION_CLOSE) request.append(NEW_LINE) } - request.append(RpcConstants.CONFIG_OPEN).append(NEW_LINE) + request.append(RpcMessageUtils.CONFIG_OPEN).append(NEW_LINE) request.append(newConfiguration.trim { it <= ' ' }).append(NEW_LINE) - request.append(RpcConstants.CONFIG_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.CONFIG_CLOSE).append(NEW_LINE) request.append("</edit-config>").append(NEW_LINE) return doWrappedRpc(messageId, request.toString()) @@ -103,15 +106,16 @@ class RpcMessageUtils { val request = StringBuilder() request.append("<validate>").append(NEW_LINE) - request.append(RpcConstants.SOURCE_OPEN).append(NEW_LINE) - request.append(RpcConstants.OPEN).append(configType).append(RpcConstants.TAG_CLOSE).append(NEW_LINE) - request.append(RpcConstants.SOURCE_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.SOURCE_OPEN).append(NEW_LINE) + request.append(RpcMessageUtils.OPEN).append(configType).append(RpcMessageUtils.TAG_CLOSE) + .append(NEW_LINE) + request.append(RpcMessageUtils.SOURCE_CLOSE).append(NEW_LINE) request.append("</validate>").append(NEW_LINE) return doWrappedRpc(messageId, request.toString()) } - fun commit(messageId: String, message: String): String { + fun commit(messageId: String): String { val request = StringBuilder() request.append("<commit>").append(NEW_LINE) @@ -125,9 +129,10 @@ class RpcMessageUtils { val request = StringBuilder() request.append("<unlock>").append(NEW_LINE) - request.append(RpcConstants.TARGET_OPEN).append(NEW_LINE) - request.append(RpcConstants.OPEN).append(configType).append(RpcConstants.TAG_CLOSE).append(NEW_LINE) - request.append(RpcConstants.TARGET_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_OPEN).append(NEW_LINE) + request.append(RpcMessageUtils.OPEN).append(configType).append(RpcMessageUtils.TAG_CLOSE) + .append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_CLOSE).append(NEW_LINE) request.append("</unlock>").append(NEW_LINE) return doWrappedRpc(messageId, request.toString()) @@ -135,7 +140,7 @@ class RpcMessageUtils { @Throws(NetconfException::class) fun deleteConfig(messageId: String, netconfTargetConfig: String): String { - if (netconfTargetConfig == NetconfAdaptorConstant.CONFIG_TARGET_RUNNING) { + if (netconfTargetConfig == NetconfDatastore.RUNNING) { log.warn("Target configuration for delete operation can't be \"running\" {}", netconfTargetConfig) throw NetconfException("Target configuration for delete operation can't be running") } @@ -143,9 +148,11 @@ class RpcMessageUtils { val request = StringBuilder() request.append("<delete-config>").append(NEW_LINE) - request.append(RpcConstants.TARGET_OPEN).append(NEW_LINE) - request.append(RpcConstants.OPEN).append(netconfTargetConfig).append(RpcConstants.TAG_CLOSE).append(NEW_LINE) - request.append(RpcConstants.TARGET_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_OPEN).append(NEW_LINE) + request.append(RpcMessageUtils.OPEN).append(netconfTargetConfig) + .append(RpcMessageUtils.TAG_CLOSE) + .append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_CLOSE).append(NEW_LINE) request.append("</delete-config>").append(NEW_LINE) return doWrappedRpc(messageId, request.toString()) @@ -161,9 +168,10 @@ class RpcMessageUtils { val request = StringBuilder() request.append("<lock>").append(NEW_LINE) - request.append(RpcConstants.TARGET_OPEN).append(NEW_LINE) - request.append(RpcConstants.OPEN).append(configType).append(RpcConstants.TAG_CLOSE).append(NEW_LINE) - request.append(RpcConstants.TARGET_CLOSE).append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_OPEN).append(NEW_LINE) + request.append(RpcMessageUtils.OPEN).append(configType).append(RpcMessageUtils.TAG_CLOSE) + .append(NEW_LINE) + request.append(RpcMessageUtils.TARGET_CLOSE).append(NEW_LINE) request.append("</lock>").append(NEW_LINE) return doWrappedRpc(messageId, request.toString()) @@ -190,7 +198,8 @@ class RpcMessageUtils { dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true) dbf.setFeature("http://xml.org/sax/features/external-general-entities", false) dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false) - dbf.newDocumentBuilder().parse(InputSource(StringReader(rpcRequest.replace(RpcConstants.END_PATTERN, "")))) + dbf.newDocumentBuilder() + .parse(InputSource(StringReader(rpcRequest.replace(RpcMessageUtils.END_PATTERN, "")))) return true } catch (e: Exception) { return false @@ -198,14 +207,14 @@ class RpcMessageUtils { } - fun getMsgId(message: String): Optional<String> { - val matcher = MSGID_STRING_PATTERN.matcher(message) + fun getMsgId(message: String): String { + val matcher = MSG_ID_STRING_PATTERN.matcher(message) if (matcher.find()) { - return Optional.of(matcher.group(1)) + return matcher.group(1) } - return if (message.contains(RpcConstants.HELLO)) { - Optional.of((-1).toString()) - } else Optional.empty() + return if (message.contains(RpcMessageUtils.HELLO)) { + (-1).toString() + } else "" } fun validateChunkedFraming(reply: String): Boolean { @@ -214,52 +223,51 @@ class RpcMessageUtils { log.debug("Error Reply: {}", reply) return false } - var chunkM = CHUNKED_SIZE_PATTERN.matcher(reply) - var chunks = ArrayList<MatchResult>() + val chunkM = CHUNKED_SIZE_PATTERN.matcher(reply) + val chunks = ArrayList<MatchResult>() var chunkdataStr = "" while (chunkM.find()) { chunks.add(chunkM.toMatchResult()) // extract chunk-data (and later) in bytes val bytes = Integer.parseInt(chunkM.group(1)) - // var chunkdata = reply.substring(chunkM.end()).getBytes(StandardCharsets.UTF_8) - var chunkdata = reply.substring(chunkM.end()).toByteArray(StandardCharsets.UTF_8) + val chunkdata = reply.substring(chunkM.end()).toByteArray(StandardCharsets.UTF_8) if (bytes > chunkdata.size) { log.debug("Error Reply - wrong chunk size {}", reply) return false } // convert (only) chunk-data part into String - chunkdataStr = String(chunkdata, 0, bytes, StandardCharsets.UTF_8) // skip chunk-data part from next match chunkM.region(chunkM.end() + chunkdataStr.length, reply.length) } - if (!CHUNKED_END_REGEX_PATTERN - .equals(reply.substring(chunks[chunks.size - 1].end() + chunkdataStr.length))) { + if (!CHUNKED_END_REGEX_PATTERN.equals(reply.substring(chunks[chunks.size - 1].end() + chunkdataStr.length))) { log.debug("Error Reply: {}", reply) return false } return true } - fun createHelloString(capabilities: List<String>): String { - val hellobuffer = StringBuilder() - hellobuffer.append(RpcConstants.XML_HEADER).append(NEW_LINE) - hellobuffer.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">").append(NEW_LINE) - hellobuffer.append(" <capabilities>").append(NEW_LINE) + val helloMessage = StringBuilder() + helloMessage.append(RpcMessageUtils.XML_HEADER).append(NEW_LINE) + helloMessage.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">").append(NEW_LINE) + helloMessage.append(" <capabilities>").append(NEW_LINE) if (capabilities.isNotEmpty()) { - capabilities.forEach { cap -> hellobuffer.append(" <capability>").append(cap).append("</capability>").append(NEW_LINE) } + capabilities.forEach { cap -> + helloMessage.append(" <capability>").append(cap).append("</capability>").append(NEW_LINE) + } } - hellobuffer.append(" </capabilities>").append(NEW_LINE) - hellobuffer.append("</hello>").append(NEW_LINE) - hellobuffer.append(RpcConstants.END_PATTERN) - return hellobuffer.toString() + helloMessage.append(" </capabilities>").append(NEW_LINE) + helloMessage.append("</hello>").append(NEW_LINE) + helloMessage.append(RpcMessageUtils.END_PATTERN) + return helloMessage.toString() } + fun formatRPCRequest(request: String, messageId: String, deviceCapabilities: Set<String>): String { var request = request - request = RpcMessageUtils.formatNetconfMessage(deviceCapabilities, request) - request = RpcMessageUtils.formatXmlHeader(request) - request = RpcMessageUtils.formatRequestMessageId(request, messageId) + request = NetconfMessageUtils.formatNetconfMessage(deviceCapabilities, request) + request = NetconfMessageUtils.formatXmlHeader(request) + request = NetconfMessageUtils.formatRequestMessageId(request, messageId) return request } @@ -274,10 +282,10 @@ class RpcMessageUtils { */ fun formatNetconfMessage(deviceCapabilities: Set<String>, message: String): String { var message = message - if (deviceCapabilities.contains(RpcConstants.NETCONF_11_CAPABILITY)) { + if (deviceCapabilities.contains(RpcMessageUtils.NETCONF_11_CAPABILITY)) { message = formatChunkedMessage(message) - } else if (!message.endsWith(RpcConstants.END_PATTERN)) { - message = message + NEW_LINE + RpcConstants.END_PATTERN + } else if (!message.endsWith(RpcMessageUtils.END_PATTERN)) { + message = message + NEW_LINE + RpcMessageUtils.END_PATTERN } return message } @@ -290,16 +298,17 @@ class RpcMessageUtils { */ fun formatChunkedMessage(message: String): String { var message = message - if (message.endsWith(RpcConstants.END_PATTERN)) { + if (message.endsWith(RpcMessageUtils.END_PATTERN)) { // message given had Netconf 1.0 EOM pattern -> remove - message = message.substring(0, message.length - RpcConstants.END_PATTERN.length) + message = message.substring(0, message.length - RpcMessageUtils.END_PATTERN.length) } - if (!message.startsWith(RpcConstants.NEW_LINE + RpcConstants.HASH)) { + if (!message.startsWith(RpcMessageUtils.NEW_LINE + RpcMessageUtils.HASH)) { // chunk encode message - //message = (RpcConstants.NEW_LINE + RpcConstants.HASH + message.getBytes(UTF_8).size + RpcConstants.NEW_LINE + message +RpcConstants. NEW_LINE + RpcConstants.HASH + RpcConstants.HASH - // + RpcConstants.NEW_LINE) - message = (RpcConstants.NEW_LINE + RpcConstants.HASH + message.toByteArray(UTF_8).size + RpcConstants.NEW_LINE + message +RpcConstants. NEW_LINE + RpcConstants.HASH + RpcConstants.HASH - + RpcConstants.NEW_LINE) + //message = (RpcMessageUtils.NEW_LINE + RpcMessageUtils.HASH + message.getBytes(UTF_8).size + RpcMessageUtils.NEW_LINE + message +RpcMessageUtils. NEW_LINE + RpcMessageUtils.HASH + RpcMessageUtils.HASH + // + RpcMessageUtils.NEW_LINE) + message = + (RpcMessageUtils.NEW_LINE + RpcMessageUtils.HASH + message.toByteArray(UTF_8).size + RpcMessageUtils.NEW_LINE + message + RpcMessageUtils.NEW_LINE + RpcMessageUtils.HASH + RpcMessageUtils.HASH + + RpcMessageUtils.NEW_LINE) } return message } @@ -312,11 +321,13 @@ class RpcMessageUtils { */ fun formatXmlHeader(request: String): String { var request = request - if (!request.contains(RpcConstants.XML_HEADER)) { - if (request.startsWith(RpcConstants.NEW_LINE + RpcConstants.HASH)) { - request = request.split("<".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0] + RpcConstants.XML_HEADER + request.substring(request.split("<".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].length) + if (!request.contains(RpcMessageUtils.XML_HEADER)) { + if (request.startsWith(RpcMessageUtils.NEW_LINE + RpcMessageUtils.HASH)) { + request = + request.split("<".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0] + RpcMessageUtils.XML_HEADER + request.substring( + request.split("<".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].length) } else { - request = RpcConstants.XML_HEADER + "\n" + request + request = RpcMessageUtils.XML_HEADER + "\n" + request } } return request @@ -324,23 +335,32 @@ class RpcMessageUtils { fun formatRequestMessageId(request: String, messageId: String): String { var request = request - if (request.contains(RpcConstants.MESSAGE_ID_STRING)) { - request = request.replaceFirst((RpcConstants.MESSAGE_ID_STRING + RpcConstants.EQUAL + RpcConstants.NUMBER_BETWEEN_QUOTES_MATCHER).toRegex(), RpcConstants.MESSAGE_ID_STRING +RpcConstants. EQUAL + RpcConstants.QUOTE + messageId + RpcConstants.QUOTE) - } else if (!request.contains(RpcConstants.MESSAGE_ID_STRING) && !request.contains(RpcConstants.HELLO)) { - request = request.replaceFirst(RpcConstants.END_OF_RPC_OPEN_TAG.toRegex(), RpcConstants.QUOTE_SPACE + RpcConstants.MESSAGE_ID_STRING + RpcConstants.EQUAL + RpcConstants.QUOTE + messageId + RpcConstants.QUOTE + ">") + if (request.contains(RpcMessageUtils.MESSAGE_ID_STRING)) { + request = + request.replaceFirst((RpcMessageUtils.MESSAGE_ID_STRING + RpcMessageUtils.EQUAL + RpcMessageUtils.NUMBER_BETWEEN_QUOTES_MATCHER).toRegex(), + RpcMessageUtils.MESSAGE_ID_STRING + RpcMessageUtils.EQUAL + RpcMessageUtils.QUOTE + messageId + RpcMessageUtils.QUOTE) + } else if (!request.contains(RpcMessageUtils.MESSAGE_ID_STRING) && !request.contains( + RpcMessageUtils.HELLO)) { + request = request.replaceFirst(RpcMessageUtils.END_OF_RPC_OPEN_TAG.toRegex(), + RpcMessageUtils.QUOTE_SPACE + RpcMessageUtils.MESSAGE_ID_STRING + RpcMessageUtils.EQUAL + RpcMessageUtils.QUOTE + messageId + RpcMessageUtils.QUOTE + ">") } return updateRequestLength(request) } fun updateRequestLength(request: String): String { - if (request.contains(NEW_LINE + RpcConstants.HASH + RpcConstants.HASH + NEW_LINE)) { - val oldLen = Integer.parseInt(request.split(RpcConstants.HASH.toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[1].split(NEW_LINE.toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[0]) + if (request.contains(NEW_LINE + RpcMessageUtils.HASH + RpcMessageUtils.HASH + NEW_LINE)) { + val oldLen = + Integer.parseInt(request.split(RpcMessageUtils.HASH.toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[1].split( + NEW_LINE.toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[0]) val rpcWithEnding = request.substring(request.indexOf('<')) - val firstBlock = request.split(RpcConstants.MSGLEN_REGEX_PATTERN.toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[1].split((NEW_LINE + RpcConstants.HASH +RpcConstants. HASH + NEW_LINE).toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[0] + val firstBlock = + request.split(RpcMessageUtils.MSGLEN_REGEX_PATTERN.toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[1].split( + (NEW_LINE + RpcMessageUtils.HASH + RpcMessageUtils.HASH + NEW_LINE).toRegex()).dropLastWhile( + { it.isEmpty() }).toTypedArray()[0] var newLen = 0 newLen = firstBlock.toByteArray(UTF_8).size if (oldLen != newLen) { - return NEW_LINE + RpcConstants.HASH + newLen + NEW_LINE + rpcWithEnding + return NEW_LINE + RpcMessageUtils.HASH + newLen + NEW_LINE + rpcWithEnding } } return request @@ -348,11 +368,9 @@ class RpcMessageUtils { fun checkReply(reply: String?): Boolean { return if (reply != null) { - !reply.contains("<rpc-error>") || reply.contains("warning") || reply.contains("<ok/>") + !reply.contains("rpc-error>") || reply.contains("warning") || reply.contains("ok/>") } else false } - - } }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcConstants.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcConstants.kt deleted file mode 100644 index 25715c9c..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcConstants.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright © 2017-2018 AT&T Intellectual Property. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils - -import java.util.regex.Pattern; - class RpcConstants { - companion object { - const val OPEN = "<" - const val CLOSE = ">" - const val EQUAL = "=" - - const val HASH = "#" - const val HASH_CHAR = '#' - - const val LF_CHAR = '\n' - const val NEW_LINE = "\n" - - const val QUOTE = "\"" - const val QUOTE_SPACE = "\" " - - const val TAG_CLOSE = "/>" - const val END_OF_RPC_OPEN_TAG = "\">" - const val END_PATTERN = "]]>]]>" - - const val HELLO = "hello" - const val RPC_REPLY = "rpc-reply" - const val RPC_ERROR = "rpc-error" - - const val RPC_OPEN = "<rpc " - const val RPC_CLOSE = "</rpc>" - const val WITH_DEFAULT_OPEN = "<with-defaults " - const val WITH_DEFAULT_CLOSE = "</with-defaults>" - const val DEFAULT_OPERATION_OPEN = "<default-operation>" - const val DEFAULT_OPERATION_CLOSE = "</default-operation>" - const val SUBTREE_FILTER_OPEN = "<filter type=\"subtree\">" - const val SUBTREE_FILTER_CLOSE = "</filter>" - const val TARGET_OPEN = "<target>" - const val TARGET_CLOSE = "</target>" - const val SOURCE_OPEN = "<source>" - const val SOURCE_CLOSE = "</source>" - const val CONFIG_OPEN = "<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">" - const val CONFIG_CLOSE = "</config>" - const val MSGLEN_REGEX_PATTERN = "\n#\\d+\n" - - - const val NUMBER_BETWEEN_QUOTES_MATCHER = "\"+([0-9]+)+\"" - - const val XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - const val NETCONF_BASE_NAMESPACE = "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"" - const val NETCONF_WITH_DEFAULTS_NAMESPACE = "xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults\"" - const val SUBSCRIPTION_SUBTREE_FILTER_OPEN = "<filter xmlns:base10=\"urn:ietf:params:xml:ns:netconf:base:1.0\" base10:type=\"subtree\">" - - const val INTERLEAVE_CAPABILITY_STRING = "urn:ietf:params:netconf:capability:interleave:1.0" - - const val CAPABILITY_REGEX = "capability>\\s*(.*?)\\s*capability>" - - - const val SESSION_ID_REGEX = "session-id>\\s*(.*?)\\s*session-id>" - - - const val MESSAGE_ID_STRING = "message-id" - - - const val NETCONF_10_CAPABILITY = "urn:ietf:params:netconf:base:1.0" - const val NETCONF_11_CAPABILITY = "urn:ietf:params:netconf:base:1.1" - - - } -}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt index d6f737fd..7b31610c 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/ComponentNetconfExecutorTest.kt @@ -35,8 +35,7 @@ import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner @RunWith(SpringRunner::class) -@ContextConfiguration(classes = [NetconfExecutorConfiguration::class, BlueprintJythonService::class, - PythonExecutorProperty::class]) +@ContextConfiguration(classes = [BlueprintJythonService::class, PythonExecutorProperty::class, ComponentNetconfExecutor::class, JsonParserService::class]) @TestPropertySource(properties = ["blueprints.processor.functions.python.executor.modulePaths=./../../../../components/scripts/python/ccsdk_netconf,./../../../../components/scripts/python/ccsdk_blueprints", "blueprints.processor.functions.python.executor.executionPath=./../../../../components/scripts/python/ccsdk_netconf"]) @@ -50,10 +49,10 @@ class ComponentNetconfExecutorTest { fun testComponentNetconfExecutor() { val executionServiceInput = JacksonUtils.readValueFromClassPathFile("requests/sample-activate-request.json", - ExecutionServiceInput::class.java)!! + ExecutionServiceInput::class.java)!! val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("1234", - "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration") + "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration") val executionContext = bluePrintRuntimeService.getExecutionContext() @@ -63,7 +62,7 @@ class ComponentNetconfExecutorTest { val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "activate-netconf") - stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "NetconfExecutorComponent") + stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentNetconfExecutor") stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") // Set Step Inputs in Blueprint Runtime Service bluePrintRuntimeService.put("activate-netconf-step-inputs", stepMetaData.asJsonNode()) diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfSessionImplTest.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfSessionImplTest.kt index 4ee48bc8..045725c7 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfSessionImplTest.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfSessionImplTest.kt @@ -18,10 +18,10 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor import org.junit.After import org.junit.Assert import org.junit.Before +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core.NetconfRpcServiceImpl import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.core.NetconfSessionImpl -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.interfaces.DeviceInfo -import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.NetconfDeviceSimulator - +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.mocks.NetconfDeviceSimulator class NetconfSessionImplTest { @@ -31,11 +31,11 @@ class NetconfSessionImplTest { @Before fun before() { deviceInfo = DeviceInfo().apply { - name = "name" - pass = "password" + username = "username" + password = "password" ipAddress = "localhost" port = 2224 - connectTimeoutSec = 10 + connectTimeout = 10 } device = NetconfDeviceSimulator(deviceInfo!!.port) @@ -49,7 +49,7 @@ class NetconfSessionImplTest { @Throws(Exception::class) fun testNetconfSession() { - val netconfSession = NetconfSessionImpl(deviceInfo!!) + val netconfSession = NetconfSessionImpl(deviceInfo!!, NetconfRpcServiceImpl(DeviceInfo())) Assert.assertNotNull(netconfSession.getSessionId()) Assert.assertEquals("localhost:2224", netconfSession.getDeviceInfo().toString()) diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/mocks/NetconfDeviceSimulator.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/mocks/NetconfDeviceSimulator.kt index 6471df3e..a2a3946d 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/mocks/NetconfDeviceSimulator.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/mocks/NetconfDeviceSimulator.kt @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils +package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.mocks import org.apache.sshd.common.NamedFactory import org.apache.sshd.server.Command -import java.util.ArrayList -import org.apache.sshd.server.auth.UserAuthNoneFactory -import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider import org.apache.sshd.server.SshServer import org.apache.sshd.server.auth.UserAuth +import org.apache.sshd.server.auth.UserAuthNoneFactory +import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider +import org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils.NetconfSubsystemFactory +import java.util.* class NetconfDeviceSimulator(private val port: Int) { diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtilsTest.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtilsTest.kt index 08a2e686..20b04fb5 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtilsTest.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtilsTest.kt @@ -16,11 +16,9 @@ package org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.utils import org.junit.Assert +import org.junit.Assert.assertTrue import org.junit.Test -import org.junit.Assert.* -import org.springframework.beans.factory.annotation.Autowired - class RpcMessageUtilsTest { @Test @@ -34,9 +32,9 @@ class RpcMessageUtilsTest { val configType = "candidate" val filterContent = "Test-Filter-Content" - val result = RpcMessageUtils.getConfig(messageId, configType, filterContent).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.getConfig(messageId, configType, filterContent).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } @@ -53,9 +51,9 @@ class RpcMessageUtilsTest { val configType = "candidate" val filterContent = "Test-Filter-Content" - val result = RpcMessageUtils.getConfig(messageId, configType, filterContent).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.getConfig(messageId, configType, filterContent).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } @@ -68,9 +66,9 @@ class RpcMessageUtilsTest { val messageId = "Test-Message-ID" val configType = "candidate" - val result = RpcMessageUtils.validate(messageId, configType).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.validate(messageId, configType).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } @@ -81,11 +79,10 @@ class RpcMessageUtilsTest { + "<commit></commit></rpc>") val messageId = "Test-Message-ID" - val message = "Test-Message" - val result = RpcMessageUtils.commit(messageId, message).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.commit(messageId).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } @@ -99,9 +96,9 @@ class RpcMessageUtilsTest { val messageId = "Test-Message-ID" val configType = "candidate" - val result = RpcMessageUtils.unlock(messageId, configType).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.unlock(messageId, configType).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } @@ -114,9 +111,9 @@ class RpcMessageUtilsTest { val messageId = "Test-Message-ID" val netconfTargetConfig = "candidate" - val result = RpcMessageUtils.deleteConfig(messageId, netconfTargetConfig).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.deleteConfig(messageId, netconfTargetConfig).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } @@ -128,9 +125,9 @@ class RpcMessageUtilsTest { val messageId = "Test-Message-ID" - val result = RpcMessageUtils.discardChanges(messageId).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.discardChanges(messageId).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } @@ -142,9 +139,9 @@ class RpcMessageUtilsTest { val messageId = "Test-Message-ID" val configType = "candidate" - val result = RpcMessageUtils.lock(messageId, configType).replace("[\n\r\t]".toRegex(), "") + val result = NetconfMessageUtils.lock(messageId, configType).replace("[\n\r\t]".toRegex(), "") - assertTrue(RpcMessageUtils.validateRPCXML(result)) + assertTrue(NetconfMessageUtils.validateRPCXML(result)) Assert.assertEquals(checkString, result) } |