From 77ed352693e0ff917395f5cf2418e31c0fbe27f3 Mon Sep 17 00:00:00 2001 From: Alexis de Talhouët Date: Tue, 12 Feb 2019 23:05:01 -0500 Subject: Rework netconf-executor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .../Definitions/activation-blueprint.json | 4 +- .../baseconfiguration/Definitions/node_types.json | 2 +- .../Scripts/python/DefaultGetNetConfig.py | 41 --- .../Scripts/python/NetconfRpcExample.py | 52 +++ .../node_type/component-netconf-executor.json | 2 +- .../scripts/python/ccsdk_netconf/constant.py | 15 - .../scripts/python/ccsdk_netconf/netconfclient.py | 126 ++++--- ms/blueprintsprocessor/application/pom.xml | 4 + .../src/main/resources/application.properties | 7 +- ms/blueprintsprocessor/distribution/pom.xml | 2 +- .../netconf/executor/ComponentNetconfExecutor.kt | 2 +- .../netconf/executor/NetconfComponentFunction.kt | 46 ++- .../functions/netconf/executor/NetconfDevice.kt | 32 ++ .../functions/netconf/executor/NetconfException.kt | 45 --- .../executor/NetconfExecutorConfiguration.kt | 68 ---- .../netconf/executor/NetconfRpcService.kt | 375 -------------------- .../functions/netconf/executor/api/DeviceInfo.kt | 43 +++ .../netconf/executor/api/NetconfException.kt | 24 ++ .../netconf/executor/api/NetconfMessage.kt | 74 ++++ .../netconf/executor/api/NetconfRpcService.kt | 121 +++++++ .../netconf/executor/api/NetconfSession.kt | 86 +++++ .../netconf/executor/api/NetconfSessionListener.kt | 21 ++ .../executor/core/NetconfDeviceCommunicator.kt | 243 +++++++++++++ .../netconf/executor/core/NetconfRpcServiceImpl.kt | 265 +++++++++++++++ .../netconf/executor/core/NetconfSessionFactory.kt | 50 --- .../netconf/executor/core/NetconfSessionImpl.kt | 371 ++++++++++---------- .../netconf/executor/core/NetconfStreamThread.kt | 243 ------------- .../executor/data/NetconfAdaptorConstant.kt | 43 --- .../netconf/executor/data/NetconfExecutionData.kt | 122 ------- .../netconf/executor/data/NetconfSshClientLib.kt | 26 -- .../netconf/executor/interfaces/DeviceInfo.kt | 43 --- .../executor/interfaces/NetconfRpcClientService.kt | 131 ------- .../netconf/executor/interfaces/NetconfSession.kt | 110 ------ .../interfaces/NetconfSessionDelegate.java | 23 -- .../netconf/executor/utils/NetconfConstant.kt | 84 +++++ .../netconf/executor/utils/NetconfMessageUtils.kt | 376 +++++++++++++++++++++ .../netconf/executor/utils/RpcConstants.kt | 82 ----- .../netconf/executor/utils/RpcMessageUtils.kt | 358 -------------------- .../executor/ComponentNetconfExecutorTest.kt | 9 +- .../netconf/executor/NetconfSessionImplTest.kt | 14 +- .../executor/mocks/NetconfDeviceSimulator.kt | 9 +- .../netconf/executor/utils/RpcMessageUtilsTest.kt | 37 +- 42 files changed, 1731 insertions(+), 2100 deletions(-) delete mode 100644 components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/DefaultGetNetConfig.py create mode 100644 components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/NetconfRpcExample.py delete mode 100644 components/scripts/python/ccsdk_netconf/constant.py create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfDevice.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfException.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfExecutorConfiguration.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/NetconfRpcService.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/DeviceInfo.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfException.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfMessage.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfRpcService.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSession.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSessionListener.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicator.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfRpcServiceImpl.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionFactory.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfStreamThread.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfAdaptorConstant.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfExecutionData.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfSshClientLib.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/DeviceInfo.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfRpcClientService.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSession.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSessionDelegate.java create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfConstant.kt create mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtils.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcConstants.kt delete mode 100644 ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtils.kt diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json index 84c78c62..07c988b1 100644 --- a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json @@ -211,7 +211,7 @@ "activate-netconf": { "type": "component-netconf-executor", "interfaces": { - "NetconfExecutorComponent": { + "ComponentNetconfExecutor": { "operations": { "process": { "implementation": { @@ -240,7 +240,7 @@ "artifacts": { "component-script": { "type": "artifact-script-jython", - "file": "Scripts/python/DefaultGetNetConfig.py" + "file": "Scripts/python/NetconfRpcExample.py" } } }, diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/node_types.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/node_types.json index 400db435..52730704 100644 --- a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/node_types.json +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/node_types.json @@ -60,7 +60,7 @@ } }, "interfaces": { - "NetconfExecutorComponent": { + "ComponentNetconfExecutor": { "operations": { "process": { "inputs": { diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/DefaultGetNetConfig.py b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/DefaultGetNetConfig.py deleted file mode 100644 index c966b1a4..00000000 --- a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/DefaultGetNetConfig.py +++ /dev/null @@ -1,41 +0,0 @@ -import netconf_constant -from netconfclient import NetconfClient -from java.lang import Exception -from org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor import NetconfComponentFunction - -class DefaultGetNetConfig(NetconfComponentFunction): - - def process(self, execution_request): - try: - log = globals()[netconf_constant.SERVICE_LOG] - print(globals()) - #requestId = globals()[netconf_constant.PARAM_REQUEST_ID] - requestId = '1234' - nc = NetconfClient(log, self) - - # Create RPC Serivice - nc.createRPCServiceFromRequirement("netconf-connection") - - runningConfigTemplate = "runningconfig-template" - - runningConfigMessageId = "get-config-" + requestId - - deviceResponse = nc.getConfig(messageId=runningConfigMessageId, - filter=runningConfigTemplate) - - log.info("Get Running Config Response {} ", deviceResponse.responseMessage) - if(deviceResponse !='null') : - status = deviceResponse.status - responseData = "{}" - if (deviceResponse.status != netconf_constant.STATUS_SUCCESS and deviceResponse.errorMessage != 'null'): - errorMessage = "Get Running Config Failure ::"+ deviceResponse.errorMessage - - except Exception, err: - log.error("Exception in the script {}",err.getMessage()) - status = netconf_constant.STATUS_FAILURE - errorMessage = "Get Running Config Failure ::"+err.getMessage() - - def recover(self, runtime_exception, execution_request): - print "Recovering calling.." + PROPERTY_BLUEPRINT_BASE_PATH - return None - diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/NetconfRpcExample.py b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/NetconfRpcExample.py new file mode 100644 index 00000000..acdb94aa --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Scripts/python/NetconfRpcExample.py @@ -0,0 +1,52 @@ +# 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. + +import netconf_constant +from java.lang import Exception as JavaException +from netconfclient import NetconfClient +from org.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor import \ + NetconfComponentFunction + + +class NetconfRpcExample(NetconfComponentFunction): + + def process(self, execution_request): + try: + log = globals()[netconf_constant.SERVICE_LOG] + print(globals()) + nc = NetconfClient(log, self, "netconf-connection") + nc.connect() + + payload = "DEMO" + + response = nc.lock(message_id="lock-123") + if not response.isSuccess(): + log.error(response.errorMessage) + + # nc.edit_config(message_id="edit-config-1", message_content=payload,edit_default_peration="none") + # nc.validate(message_id="validate-123") + # nc.discard_change(message_id="discard-123") + # nc.validate(message_id="validate-123") + # nc.commit(message_id="commit-123") + # nc.unlock(message_id="unlock-123") + # nc.disconnect() + + except JavaException, err: + log.error("Java Exception in the script {}", err) + except Exception, err: + log.error("Python Exception in the script {}", err) + + def recover(self, runtime_exception, execution_request): + print "Recovering calling.." + PROPERTY_BLUEPRINT_BASE_PATH + return None diff --git a/components/model-catalog/definition-type/starter-type/node_type/component-netconf-executor.json b/components/model-catalog/definition-type/starter-type/node_type/component-netconf-executor.json index b8ac762e..9565f661 100644 --- a/components/model-catalog/definition-type/starter-type/node_type/component-netconf-executor.json +++ b/components/model-catalog/definition-type/starter-type/node_type/component-netconf-executor.json @@ -14,7 +14,7 @@ } }, "interfaces": { - "NetconfExecutorComponent": { + "ComponentNetconfExecutor": { "operations": { "process": { "inputs": { diff --git a/components/scripts/python/ccsdk_netconf/constant.py b/components/scripts/python/ccsdk_netconf/constant.py deleted file mode 100644 index 534ca9e1..00000000 --- a/components/scripts/python/ccsdk_netconf/constant.py +++ /dev/null @@ -1,15 +0,0 @@ -SERVICE_LOG = "log" -SERVICE_NETCONF = "netconfService" -SERVICE_MESSAGE = "messageService" - -PARAM_REQUEST_ID = "requestId" -PARAM_ACTION = "action" - -STATUS_SUCCESS = "success" -STATUS_FAILURE = "failure" - -CONFIG_TARGET_RUNNING = "running" -CONFIG_TARGET_CANDIDATE = "candidate" -CONFIG_DEFAULT_OPERATION_MERGE = "merge" -CONFIG_DEFAULT_OPERATION_REPLACE = "replace" -CONFIG_DEFAULT_OPERATION_NONE = "none" diff --git a/components/scripts/python/ccsdk_netconf/netconfclient.py b/components/scripts/python/ccsdk_netconf/netconfclient.py index 421e5009..cdaf8409 100644 --- a/components/scripts/python/ccsdk_netconf/netconfclient.py +++ b/components/scripts/python/ccsdk_netconf/netconfclient.py @@ -1,60 +1,74 @@ -from netconf_constant import CONFIG_TARGET_RUNNING, CONFIG_DEFAULT_OPERATION_REPLACE - +from netconf_constant import CONFIG_TARGET_RUNNING, CONFIG_TARGET_CANDIDATE, \ + CONFIG_DEFAULT_OPERATION_REPLACE class NetconfClient: - def __init__(self, log, componentFunction): - self.log = log - self.componentFunction = componentFunction - self.nc = None - - def createRPCServiceFromRequirement(self, requirementName): - self.nc = self.componentFunction.netconfRpcClientService(requirementName) - - def disconnect(self): - self.nc.disconnect() - return - - def connect(self, deviceInfo): - self.nc.connect(deviceInfo) - return - - def lock(self, messageId, configTarget, messageTimeout=30): - deviceResponse = self.nc.lock(messageId, configTarget, messageTimeout) - return deviceResponse - - def getConfig(self, messageId, filter, configTarget=CONFIG_TARGET_RUNNING, messageTimeout=30): - self.log.info("in the ncclient getConfig {}",messageId) - self.log.info("in the ncclient getConfig {}",filter) - deviceResponse = self.nc.getConfig(messageId, filter, configTarget, messageTimeout) - return deviceResponse - - def editConfig(self, messageId, messageContent, reConnect=False, wait=0, lock=False, - configTarget=CONFIG_TARGET_RUNNING, editDefaultOperation=CONFIG_DEFAULT_OPERATION_REPLACE, - deleteConfig= False, validate= False, commit=False, discardChanges =True, unlock=False, - preRestartWait=0, postRestartWait=0, messageTimeout=30): - deviceResponse = self.nc.editConfig(messageId, messageContent, reConnect, wait, lock, configTarget, - editDefaultOperation, deleteConfig, validate, commit, discardChanges, unlock, - preRestartWait, postRestartWait, messageTimeout) - return deviceResponse - - def commit(self, messageId, message, discardChanges =True, messageTimeout=30): - deviceResponse = self.nc.commit(messageId, message, discardChanges, messageTimeout) - return deviceResponse - - def unLock(self, messageId, configTarget, messageTimeout=30): - deviceResponse = self.nc.unLock(messageId, configTarget, messageTimeout) - return deviceResponse - - def discardChanges(self, messageId, messageTimeout=30): - deviceResponse = self.nc.discardChanges(messageId, messageTimeout) - return deviceResponse - - def close(self, messageId, force=False, messageTimeout=30): - deviceResponse = self.nc.close(messageId, force, messageTimeout) - return deviceResponse - - def rpc(self, request, messageId, messageTimeout=30): - deviceResponse = self.nc.rpc(request, messageId, messageTimeout) - return deviceResponse + def __init__(self, log, component_function, requirement_name): + self.log = log + self.component_function = component_function + netconf_device = self.component_function.initializeNetconfConnection( + requirement_name) + self.netconf_rpc_client = netconf_device.netconfRpcService + self.netconf_session = netconf_device.netconfSession + + def disconnect(self): + self.netconf_session.disconnect() + return + + def connect(self): + self.netconf_session.connect() + return + + def lock(self, message_id, config_target=CONFIG_TARGET_CANDIDATE, + message_timeout=30): + device_response = self.netconf_rpc_client.lock(message_id, config_target, + message_timeout) + return device_response + + def get_config(self, message_id, filter="", + config_target=CONFIG_TARGET_RUNNING, message_timeout=30): + self.log.info("in the ncclient getConfig {}", message_id) + device_response = self.netconf_rpc_client.getConfig(message_id, filter, + config_target, + message_timeout) + return device_response + + def edit_config(self, message_id, message_content, lock=False, + config_target=CONFIG_TARGET_CANDIDATE, + edit_default_peration=CONFIG_DEFAULT_OPERATION_REPLACE, + deleteConfig=False, validate=False, commit=False, discard_change=False, + unlock=False, message_timeout=30): + device_response = self.netconf_rpc_client.editConfig(message_id, + message_content, lock, + config_target, + edit_default_peration, + deleteConfig, validate, + commit, discard_change, + unlock, + message_timeout) + return device_response + + def commit(self, message_id, discard_change=True, + message_timeout=30): + device_response = self.netconf_rpc_client.commit(message_id, discard_change, + message_timeout) + return device_response + + def unlock(self, message_id, config_target=CONFIG_TARGET_CANDIDATE, + message_timeout=30): + device_response = self.netconf_rpc_client.unLock(message_id, config_target, + message_timeout) + return device_response + + def validate(self, message_id, config_target=CONFIG_TARGET_CANDIDATE, + message_timeout=30): + device_response = self.netconf_rpc_client.validate(message_id, + config_target, + message_timeout) + return device_response + + def discard_change(self, message_id, message_timeout=30): + device_response = self.netconf_rpc_client.discardConfig(message_id, + message_timeout) + return device_response diff --git a/ms/blueprintsprocessor/application/pom.xml b/ms/blueprintsprocessor/application/pom.xml index b02e9e98..83dc7061 100755 --- a/ms/blueprintsprocessor/application/pom.xml +++ b/ms/blueprintsprocessor/application/pom.xml @@ -49,6 +49,10 @@ org.onap.ccsdk.apps.blueprintsprocessor.functions python-executor + + org.onap.ccsdk.apps.blueprintsprocessor.functions + netconf-executor + org.onap.ccsdk.apps.blueprintsprocessor selfservice-api diff --git a/ms/blueprintsprocessor/application/src/main/resources/application.properties b/ms/blueprintsprocessor/application/src/main/resources/application.properties index e5c928d2..cfef4f82 100755 --- a/ms/blueprintsprocessor/application/src/main/resources/application.properties +++ b/ms/blueprintsprocessor/application/src/main/resources/application.properties @@ -1,6 +1,5 @@ # -# Copyright � 2017-2018 AT&T Intellectual Property. -# Modifications Copyright © 2019 IBM, Bell Canada. +# Copyright (c) 2017-2019 AT&T, 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. @@ -35,5 +34,5 @@ blueprintsprocessor.db.primary.hibernateDDLAuto=update blueprintsprocessor.db.primary.hibernateNamingStrategy=org.hibernate.cfg.ImprovedNamingStrategy blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.MySQL5InnoDBDialect # Python executor -blueprints.processor.functions.python.executor.executionPath=/opt/app/onap/scripts/jython -blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython \ No newline at end of file +blueprints.processor.functions.python.executor.executionPath=/opt/app/onap/scripts/jython/ccsdk_blueprints +blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython/ccsdk_blueprints,/opt/app/onap/scripts/jython/ccsdk_netconf diff --git a/ms/blueprintsprocessor/distribution/pom.xml b/ms/blueprintsprocessor/distribution/pom.xml index b3eabc10..97d4271d 100755 --- a/ms/blueprintsprocessor/distribution/pom.xml +++ b/ms/blueprintsprocessor/distribution/pom.xml @@ -29,7 +29,7 @@ Blueprints Processor Distribution maven - org.onap.ccsdk.apps + org.onap.ccsdk.apps blueprintsprocessor onap/ccsdk-blueprintsprocessor ${https_proxy} 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): DeviceInfo { + private fun deviceProperties(capabilityProperty: MutableMap): 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() - private val recordedApplyConfigIds = ArrayList() - 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/api/DeviceInfo.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/DeviceInfo.kt new file mode 100644 index 00000000..466e6b5e --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/DeviceInfo.kt @@ -0,0 +1,43 @@ +/* + * 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 com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonProperty + +class DeviceInfo { + @get:JsonProperty("login-account") + var username: String? = null + @get:JsonProperty("login-key") + var password: String? = null + @get:JsonProperty("target-ip-address") + var ipAddress: String? = null + @get:JsonProperty("port-number") + var port: Int = 0 + @get:JsonProperty("connection-time-out") + var connectTimeout: Long = 5 + @get:JsonIgnore + var source: String? = null + @get:JsonIgnore + var replyTimeout: Int = 5 + @get:JsonIgnore + 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/api/NetconfException.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfException.kt new file mode 100644 index 00000000..d7642e75 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfException.kt @@ -0,0 +1,24 @@ +/* + * 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 + +class NetconfException : Exception { + + 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? = 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/api/NetconfRpcService.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfRpcService.kt new file mode 100644 index 00000000..554368c7 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfRpcService.kt @@ -0,0 +1,121 @@ +/* + * 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 + +interface NetconfRpcService { + + /** + * Lock + * @param messageId message id of the request. + * @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 filter filter content. + * @param configTarget config target ( running or candidate) + * @param messageTimeout message timeout of the request. + * @return Device response + */ + 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. + * @return Device response + */ + fun deleteConfig(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse + + /** + * Edit-config + * @param messageId message id of the request. + * @param messageContent edit config content. + * @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 + * delete) + * @param clearCandidate commit after edit config + * @param commit clear candiate store before edit + * @param discardChanges Rollback on failure + * @param validate validate the config before commit + * @param unlock unlock device after edit + * @param messageTimeout message timeout of the request. + * @return Device response + */ + 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. + * @return Device response + */ + fun validate(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse + + /** + * Commit + * @param messageId message id of the request. + * @param discardChanges Rollback on failure + * @param messageTimeout message timeout of the request. + * @return Device response + */ + 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. + * @return Device response + */ + 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 + */ + fun discardConfig(messageId: String, messageTimeout: Int): DeviceResponse + + /** + * Close session + * @param messageId message id of the request. + * @param force force closeSession + * @param messageTimeout message timeout of the request. + * @return Device response + */ + fun closeSession(messageId: String, force: Boolean, messageTimeout: Int): DeviceResponse + + /** + * Executes an RPC request to the netconf server. + * + * @param request the XML containing the RPC request for the server. + * @param messageId message id of the request. + * @param messageTimeout message timeout of the request. + * @return Device response + */ + fun asyncRpc(request: String, messageId: String, messageTimeout: Int): DeviceResponse +} \ 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/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 + + /** + * 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 +} \ 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/NetconfSessionListener.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSessionListener.kt new file mode 100644 index 00000000..8854894f --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/api/NetconfSessionListener.kt @@ -0,0 +1,21 @@ +/* + * 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 + +interface NetconfSessionListener { + + fun notify(event: NetconfReceivedEvent) +} diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicator.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicator.kt new file mode 100644 index 00000000..69475619 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicator.kt @@ -0,0 +1,243 @@ +/* + * 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.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.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>) : Thread() { + + private val log = LoggerFactory.getLogger(NetconfDeviceCommunicator::class.java) + private var state = NetconfMessageState.NO_MATCHING_PATTERN + + init { + start() + } + + override fun run() { + var bufferReader: BufferedReader? = null + while (bufferReader == null) { + bufferReader = BufferedReader(InputStreamReader(inputStream, StandardCharsets.UTF_8)) + } + + try { + var socketClosed = false + val deviceReplyBuilder = StringBuilder() + while (!socketClosed) { + val cInt = bufferReader.read() + if (cInt == -1) { + log.error("$deviceInfo: Received cInt = -1") +// bufferReader.close() + socketClosed = true +// 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 == RpcMessageUtils.END_PATTERN) { + socketClosed = true + bufferReader.close() + sessionListener.notify(NetconfReceivedEvent( + NetconfReceivedEvent.Type.DEVICE_UNREGISTERED, + deviceInfo = deviceInfo)) + } else { + deviceReply = deviceReply.replace(RpcMessageUtils.END_PATTERN, "") + receivedMessage(deviceReply) + deviceReplyBuilder.setLength(0) + } + } else if (state === NetconfMessageState.END_CHUNKED_PATTERN) { + var deviceReply = deviceReplyBuilder.toString() + if (!NetconfMessageUtils.validateChunkedFraming(deviceReply)) { + log.debug("$deviceInfo: Received badly framed message $deviceReply") + socketClosed = true + sessionListener.notify(NetconfReceivedEvent( + NetconfReceivedEvent.Type.DEVICE_ERROR, + deviceInfo = deviceInfo)) + } else { + 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("$deviceInfo: Fail while reading from channel", e) + sessionListener.notify(NetconfReceivedEvent( + NetconfReceivedEvent.Type.DEVICE_ERROR, + deviceInfo = deviceInfo)) + } + + } + + private enum class NetconfMessageState { + NO_MATCHING_PATTERN { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == ']') { + FIRST_BRACKET + } else if (c == '\n') { + FIRST_LF + } else { + this + } + } + }, + FIRST_BRACKET { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == ']') { + SECOND_BRACKET + } else { + NO_MATCHING_PATTERN + } + } + }, + SECOND_BRACKET { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == '>') { + FIRST_BIGGER + } else { + NO_MATCHING_PATTERN + } + } + }, + FIRST_BIGGER { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == ']') { + THIRD_BRACKET + } else { + NO_MATCHING_PATTERN + } + } + }, + THIRD_BRACKET { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == ']') { + ENDING_BIGGER + } else { + NO_MATCHING_PATTERN + } + } + }, + ENDING_BIGGER { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == '>') { + END_PATTERN + } else { + NO_MATCHING_PATTERN + } + } + }, + FIRST_LF { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == '#') { + FIRST_HASH + } else if (c == ']') { + FIRST_BRACKET + } else if (c == '\n') { + this + } else { + NO_MATCHING_PATTERN + } + } + }, + FIRST_HASH { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == '#') { + SECOND_HASH + } else { + NO_MATCHING_PATTERN + } + } + }, + SECOND_HASH { + override fun evaluateChar(c: Char): NetconfMessageState { + return if (c == '\n') { + END_CHUNKED_PATTERN + } else { + NO_MATCHING_PATTERN + } + } + }, + END_CHUNKED_PATTERN { + override fun evaluateChar(c: Char): NetconfMessageState { + return NO_MATCHING_PATTERN + } + }, + END_PATTERN { + override fun evaluateChar(c: Char): NetconfMessageState { + return NO_MATCHING_PATTERN + } + }; + + internal abstract fun evaluateChar(c: Char): NetconfMessageState + } + + fun sendMessage(request: String, messageId: String): CompletableFuture { + log.info("$deviceInfo: Sending message: \n $request") + val future = CompletableFuture() + replies.put(messageId, future) + val outputStream = OutputStreamWriter(out, StandardCharsets.UTF_8) + synchronized(this) { + try { + outputStream.write(request) + outputStream.flush() + } catch (e: IOException) { + log.error("$deviceInfo: Failed to send message : \n $request", e) + future.completeExceptionally(e) + } + + } + return future + } + + 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() - - 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 = 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> = mutableListOf()>() - var replies: MutableMap> = ConcurrentHashMap() - val deviceCapabilities = LinkedHashSet() + private val errorReplies: MutableList = Collections.synchronizedList(listOf()) + private val replies: MutableMap> = ConcurrentHashMap() + private val deviceCapabilities = setOf() - 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(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 { + val formattedRequest = NetconfMessageUtils.formatRPCRequest(request, messageId, deviceCapabilities) - override fun asyncRpc( request: String, msgId: String): CompletableFuture { - //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("") - if (force) { - rpc.append("") - } else { - rpc.append("") - } - rpc.append("") - rpc.append(RpcConstants.END_PATTERN) - return RpcMessageUtils.checkReply(sendRequest(rpc.toString())) || close(true) - } - - - - override fun getSessionId(): String? { - return this.sessionID - } - - override fun getDeviceCapabilitiesSet(): Set { - return Collections.unmodifiableSet(deviceCapabilities); - } - - fun setCapabilities(capabilities: ImmutableList) { - 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) { - 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 { + 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/core/NetconfStreamThread.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfStreamThread.kt deleted file mode 100644 index cfcf24bb..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/core/NetconfStreamThread.kt +++ /dev/null @@ -1,243 +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.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.utils.RpcMessageUtils -import org.slf4j.LoggerFactory -import java.io.* -import java.nio.charset.StandardCharsets -import java.util.concurrent.CompletableFuture - - -class NetconfStreamThread(private var inputStream: InputStream, private var out : OutputStream, - private val netconfDeviceInfo: DeviceInfo, private val netconfSessionDelegate: NetconfSessionDelegate, - private var replies :MutableMap> ) : Thread() { - - val log = LoggerFactory.getLogger(NetconfStreamThread::class.java) - lateinit var state : NetconfMessageState - // val outputStream = OutputStreamWriter(out, StandardCharsets.UTF_8) - private var outputStream: OutputStreamWriter? = null - - override fun run() { - var bufferReader: BufferedReader? = null - while (bufferReader == null) { - bufferReader = BufferedReader(InputStreamReader(inputStream, StandardCharsets.UTF_8)) - } - - try { - var socketClosed = false - val deviceReplyBuilder = StringBuilder() - while (!socketClosed) { - 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) - socketClosed = true - log.debug("Netconf device {} ERROR cInt == -1 socketClosed = true", netconfDeviceInfo) - } - 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) { - socketClosed = true - close(deviceReply) - } else { - deviceReply = deviceReply.replace(RpcConstants.END_PATTERN, "") - dealWithReply(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) - socketClosed = true - close(deviceReply) - } else { - deviceReply = deviceReply.replace(RpcConstants.MSGLEN_REGEX_PATTERN.toRegex(), "") - deviceReply = deviceReply.replace(RpcMessageUtils.CHUNKED_END_REGEX_PATTERN.toRegex(), "") - dealWithReply(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")) - } - - } - - enum class NetconfMessageState { - - NO_MATCHING_PATTERN { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == ']') { - FIRST_BRACKET - } else if (c == '\n') { - FIRST_LF - } else { - this - } - } - }, - FIRST_BRACKET { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == ']') { - SECOND_BRACKET - } else { - NO_MATCHING_PATTERN - } - } - }, - SECOND_BRACKET { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == '>') { - FIRST_BIGGER - } else { - NO_MATCHING_PATTERN - } - } - }, - FIRST_BIGGER { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == ']') { - THIRD_BRACKET - } else { - NO_MATCHING_PATTERN - } - } - }, - THIRD_BRACKET { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == ']') { - ENDING_BIGGER - } else { - NO_MATCHING_PATTERN - } - } - }, - ENDING_BIGGER { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == '>') { - END_PATTERN - } else { - NO_MATCHING_PATTERN - } - } - }, - FIRST_LF { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == '#') { - FIRST_HASH - } else if (c == ']') { - FIRST_BRACKET - } else if (c == '\n') { - this - } else { - NO_MATCHING_PATTERN - } - } - }, - FIRST_HASH { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == '#') { - SECOND_HASH - } else { - NO_MATCHING_PATTERN - } - } - }, - SECOND_HASH { - override fun evaluateChar(c: Char): NetconfMessageState { - return if (c == '\n') { - END_CHUNKED_PATTERN - } else { - NO_MATCHING_PATTERN - } - } - }, - END_CHUNKED_PATTERN { - override fun evaluateChar(c: Char): NetconfMessageState { - return NO_MATCHING_PATTERN - } - }, - END_PATTERN { - override fun evaluateChar(c: Char): NetconfMessageState { - return NO_MATCHING_PATTERN - } - }; - - 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 { - val messageId = RpcMessageUtils.getMsgId(request) - return sendMessage(request, messageId.get()) - } - - fun sendMessage(request: String, messageId: String): CompletableFuture { - log.info("Sending message: \n {} \n to NETCONF Device: {}", request, netconfDeviceInfo) - val cf = CompletableFuture() - replies.put(messageId, cf) - // outputStream = OutputStreamWriter(out, StandardCharsets.UTF_8) - synchronized(OutputStreamWriter(out, StandardCharsets.UTF_8)) { - try { - - OutputStreamWriter(out, StandardCharsets.UTF_8).write(request) - OutputStreamWriter(out, StandardCharsets.UTF_8).flush() - } catch (e: IOException) { - log.error("Writing to NETCONF Device {} failed", netconfDeviceInfo, e) - cf.completeExceptionally(e) - } - - } - return cf - } - -} \ 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? = 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, 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/data/NetconfSshClientLib.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfSshClientLib.kt deleted file mode 100644 index f21cce4a..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/data/NetconfSshClientLib.kt +++ /dev/null @@ -1,26 +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 - -enum class NetconfSshClientLib(val sshClientString :String) { - APACHE_MINA("apache-mina"), - ETHZ_SSH2("ethz-ssh2"); - - fun getEnum(valueOf: String): NetconfSshClientLib { - return NetconfSshClientLib.valueOf(valueOf.toUpperCase().replace('-', '_')) - } - -} \ 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/interfaces/DeviceInfo.kt deleted file mode 100644 index f4360c7e..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/DeviceInfo.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.interfaces - -import com.fasterxml.jackson.annotation.JsonIgnore -import com.fasterxml.jackson.annotation.JsonProperty - -class DeviceInfo { - @get:JsonProperty("login-account") - var name: String? = null - @get:JsonProperty("login-key") - var pass: 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 - @get:JsonIgnore - var replyTimeout: Int = 60 - @get:JsonIgnore - var idleTimeout: Int = 45 - @get:JsonIgnore - var deviceId: String = "$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/interfaces/NetconfRpcClientService.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfRpcClientService.kt deleted file mode 100644 index 668fb552..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfRpcClientService.kt +++ /dev/null @@ -1,131 +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.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() - - /** - * @param messageId message id of the request. - * @param configTarget config target ( running or candidate) - * @param messageTimeout message timeout of the request. - * @return Device response - */ - fun lock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse - - /** - * @param messageId message id of the request. - * @param messageContent 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 - - /** - * @param messageId message id of the request. - * @param configTarget config target ( running or candidate) - * @param messageTimeout message timeout of the request. - * @return Device response - */ - fun deleteConfig(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse - - /** - * @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 - * delete) - * @param clearCandidate commit after edit config - * @param commit clear candiate store before edit - * @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 - - /** - * @param messageId message id of the request. - * @param configTarget config target ( running or candidate) - * @param messageTimeout message timeout of the request. - * @return Device response - */ - fun validate(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse - - /** - * @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 - - /** - * @param messageId message id of the request. - * @param configTarget config target ( running or candidate) - * @param messageTimeout message timeout of the request. - * @return Device response - */ - fun unLock(messageId: String, configTarget: String, messageTimeout: Int): DeviceResponse - - /** - * @param messageId message id of the request. - * @param messageTimeout message timeout of the request. - * @return Device response - */ - fun discardConfig(messageId: String, messageTimeout: Int): DeviceResponse - - /** - * @param messageId message id of the request. - * @param force force close - * @param messageTimeout message timeout of the request. - * @return Device response - */ - fun close(messageId: String, force: Boolean, messageTimeout: Int): DeviceResponse - - /** - * Executes an RPC request to the netconf server. - * - * @param request the XML containing the RPC request for the server. - * @param messageId message id of the request. - * @param messageTimeout message timeout of the request. - * @return Device response - */ - fun asyncRpc(request: String, messageId: String, messageTimeout: Int): DeviceResponse -} \ 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 - - /** - * 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 - - /** - * 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) { - // 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/interfaces/NetconfSessionDelegate.java b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSessionDelegate.java deleted file mode 100644 index 47955804..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/interfaces/NetconfSessionDelegate.java +++ /dev/null @@ -1,23 +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.onap.ccsdk.apps.blueprintsprocessor.functions.netconf.executor.data.NetconfDeviceOutputEvent; - -public interface NetconfSessionDelegate { - - void notify(NetconfDeviceOutputEvent event); -} 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 = "" + const val SUBTREE_FILTER_CLOSE = "" + const val TARGET_OPEN = "" + const val TARGET_CLOSE = "" + const val SOURCE_OPEN = "" + const val SOURCE_CLOSE = "" + const val CONFIG_OPEN = "" + const val CONFIG_CLOSE = "" + const val MSGLEN_REGEX_PATTERN = "\n#\\d+\n" + + const val NUMBER_BETWEEN_QUOTES_MATCHER = "\"+([0-9]+)+\"" + + const val XML_HEADER = "" + 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 = + "" + + 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/NetconfMessageUtils.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtils.kt new file mode 100644 index 00000000..b0310d78 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtils.kt @@ -0,0 +1,376 @@ +/* + * 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 + +import org.apache.commons.lang3.StringUtils +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.regex.MatchResult +import java.util.regex.Pattern +import javax.xml.XMLConstants +import javax.xml.parsers.DocumentBuilderFactory +import kotlin.text.Charsets.UTF_8 + + +class NetconfMessageUtils { + + companion object { + 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("").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.isNullOrEmpty()) { + request.append(RpcMessageUtils.SUBTREE_FILTER_OPEN).append(NEW_LINE) + request.append(filterContent).append(NEW_LINE) + request.append(RpcMessageUtils.SUBTREE_FILTER_CLOSE).append(NEW_LINE) + } + request.append("").append(NEW_LINE) + + return doWrappedRpc(messageId, request.toString()) + } + + fun doWrappedRpc(messageId: String, request: String): String { + 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(RpcMessageUtils.RPC_CLOSE) + // rpc.append(NEW_LINE).append(END_PATTERN); + + return rpc.toString() + } + + fun editConfig(messageId: String, configType: String, defaultOperation: String?, + newConfiguration: String): String { + + val request = StringBuilder() + + request.append("").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(RpcMessageUtils.DEFAULT_OPERATION_OPEN).append(defaultOperation) + .append(RpcMessageUtils.DEFAULT_OPERATION_CLOSE) + request.append(NEW_LINE) + } + + request.append(RpcMessageUtils.CONFIG_OPEN).append(NEW_LINE) + request.append(newConfiguration.trim { it <= ' ' }).append(NEW_LINE) + request.append(RpcMessageUtils.CONFIG_CLOSE).append(NEW_LINE) + request.append("").append(NEW_LINE) + + return doWrappedRpc(messageId, request.toString()) + } + + fun validate(messageId: String, configType: String): String { + val request = StringBuilder() + + request.append("").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("").append(NEW_LINE) + + return doWrappedRpc(messageId, request.toString()) + } + + fun commit(messageId: String): String { + val request = StringBuilder() + + request.append("").append(NEW_LINE) + request.append("").append(NEW_LINE) + + return doWrappedRpc(messageId, request.toString()) + } + + + fun unlock(messageId: String, configType: String): String { + val request = StringBuilder() + + request.append("").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("").append(NEW_LINE) + + return doWrappedRpc(messageId, request.toString()) + } + + @Throws(NetconfException::class) + fun deleteConfig(messageId: String, netconfTargetConfig: String): String { + 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") + } + + val request = StringBuilder() + + request.append("").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("").append(NEW_LINE) + + return doWrappedRpc(messageId, request.toString()) + } + + fun discardChanges(messageId: String): String { + val request = StringBuilder() + request.append("").append(NEW_LINE) + return doWrappedRpc(messageId, request.toString()) + } + + fun lock(messageId: String, configType: String): String { + val request = StringBuilder() + + request.append("").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("").append(NEW_LINE) + + return doWrappedRpc(messageId, request.toString()) + } + + fun closeSession(messageId: String, force: Boolean): String { + val request = StringBuilder() + + if (force) { + request.append("").append(NEW_LINE) + } else { + request.append("").append(NEW_LINE) + } + + return doWrappedRpc(messageId, request.toString()) + } + + fun validateRPCXML(rpcRequest: String): Boolean { + try { + if (StringUtils.isBlank(rpcRequest)) { + return false + } + val dbf = DocumentBuilderFactory.newInstance() + 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(RpcMessageUtils.END_PATTERN, "")))) + return true + } catch (e: Exception) { + return false + } + + } + + fun getMsgId(message: String): String { + val matcher = MSG_ID_STRING_PATTERN.matcher(message) + if (matcher.find()) { + return matcher.group(1) + } + return if (message.contains(RpcMessageUtils.HELLO)) { + (-1).toString() + } else "" + } + + fun validateChunkedFraming(reply: String): Boolean { + val matcher = CHUNKED_FRAMING_PATTERN.matcher(reply) + if (!matcher.matches()) { + log.debug("Error Reply: {}", reply) + return false + } + val chunkM = CHUNKED_SIZE_PATTERN.matcher(reply) + val chunks = ArrayList() + var chunkdataStr = "" + while (chunkM.find()) { + chunks.add(chunkM.toMatchResult()) + // extract chunk-data (and later) in bytes + val bytes = Integer.parseInt(chunkM.group(1)) + 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))) { + log.debug("Error Reply: {}", reply) + return false + } + return true + } + + fun createHelloString(capabilities: List): String { + val helloMessage = StringBuilder() + helloMessage.append(RpcMessageUtils.XML_HEADER).append(NEW_LINE) + helloMessage.append("").append(NEW_LINE) + helloMessage.append(" ").append(NEW_LINE) + if (capabilities.isNotEmpty()) { + capabilities.forEach { cap -> + helloMessage.append(" ").append(cap).append("").append(NEW_LINE) + } + } + helloMessage.append(" ").append(NEW_LINE) + helloMessage.append("").append(NEW_LINE) + helloMessage.append(RpcMessageUtils.END_PATTERN) + return helloMessage.toString() + } + + fun formatRPCRequest(request: String, messageId: String, deviceCapabilities: Set): String { + var request = request + request = NetconfMessageUtils.formatNetconfMessage(deviceCapabilities, request) + request = NetconfMessageUtils.formatXmlHeader(request) + request = NetconfMessageUtils.formatRequestMessageId(request, messageId) + + return request + } + + /** + * Validate and format netconf message. - NC1.0 if no EOM sequence present on `message`, + * append. - NC1.1 chunk-encode given message unless it already is chunk encoded + * + * @param deviceCapabilities Set containing Device Capabilities + * @param message to format + * @return formated message + */ + fun formatNetconfMessage(deviceCapabilities: Set, message: String): String { + var message = message + if (deviceCapabilities.contains(RpcMessageUtils.NETCONF_11_CAPABILITY)) { + message = formatChunkedMessage(message) + } else if (!message.endsWith(RpcMessageUtils.END_PATTERN)) { + message = message + NEW_LINE + RpcMessageUtils.END_PATTERN + } + return message + } + + /** + * Validate and format message according to chunked framing mechanism. + * + * @param message to format + * @return formated message + */ + fun formatChunkedMessage(message: String): String { + var message = message + if (message.endsWith(RpcMessageUtils.END_PATTERN)) { + // message given had Netconf 1.0 EOM pattern -> remove + message = message.substring(0, message.length - RpcMessageUtils.END_PATTERN.length) + } + if (!message.startsWith(RpcMessageUtils.NEW_LINE + RpcMessageUtils.HASH)) { + // chunk encode message + //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 + } + + /** + * Ensures xml start directive/declaration appears in the `request`. + * + * @param request RPC request message + * @return XML RPC message + */ + fun formatXmlHeader(request: String): String { + var request = request + 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 = RpcMessageUtils.XML_HEADER + "\n" + request + } + } + return request + } + + fun formatRequestMessageId(request: String, messageId: String): String { + var request = request + 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 + 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(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 + RpcMessageUtils.HASH + newLen + NEW_LINE + rpcWithEnding + } + } + return request + } + + fun checkReply(reply: String?): Boolean { + return if (reply != null) { + !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 = "" - const val SUBTREE_FILTER_CLOSE = "" - const val TARGET_OPEN = "" - const val TARGET_CLOSE = "" - const val SOURCE_OPEN = "" - const val SOURCE_CLOSE = "" - const val CONFIG_OPEN = "" - const val CONFIG_CLOSE = "" - const val MSGLEN_REGEX_PATTERN = "\n#\\d+\n" - - - const val NUMBER_BETWEEN_QUOTES_MATCHER = "\"+([0-9]+)+\"" - - const val XML_HEADER = "" - 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 = "" - - 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/RpcMessageUtils.kt deleted file mode 100644 index 28e1361c..00000000 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/netconf/executor/utils/RpcMessageUtils.kt +++ /dev/null @@ -1,358 +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 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.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 { - - 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" - - fun getConfig(messageId: String, configType: String, filterContent: String?): String { - val request = StringBuilder() - - request.append("").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) - - if (filterContent != null) { - request.append(RpcConstants.SUBTREE_FILTER_OPEN).append(NEW_LINE) - request.append(filterContent).append(NEW_LINE) - request.append(RpcConstants.SUBTREE_FILTER_CLOSE).append(NEW_LINE) - } - request.append("").append(NEW_LINE) - - return doWrappedRpc(messageId, request.toString()) - } - - 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) - rpc.append(request) - rpc.append(RpcConstants.RPC_CLOSE) - // rpc.append(NEW_LINE).append(END_PATTERN); - - return rpc.toString() - } - - fun editConfig(messageId: String, configType: String, defaultOperation: String?, - newConfiguration: String): String { - - val request = StringBuilder() - - request.append("").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) - - if (defaultOperation != null) { - request.append(RpcConstants.DEFAULT_OPERATION_OPEN).append(defaultOperation).append(RpcConstants.DEFAULT_OPERATION_CLOSE) - request.append(NEW_LINE) - } - - request.append(RpcConstants.CONFIG_OPEN).append(NEW_LINE) - request.append(newConfiguration.trim { it <= ' ' }).append(NEW_LINE) - request.append(RpcConstants.CONFIG_CLOSE).append(NEW_LINE) - request.append("").append(NEW_LINE) - - return doWrappedRpc(messageId, request.toString()) - } - - fun validate(messageId: String, configType: String): String { - val request = StringBuilder() - - request.append("").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("").append(NEW_LINE) - - return doWrappedRpc(messageId, request.toString()) - } - - fun commit(messageId: String, message: String): String { - val request = StringBuilder() - - request.append("").append(NEW_LINE) - request.append("").append(NEW_LINE) - - return doWrappedRpc(messageId, request.toString()) - } - - - fun unlock(messageId: String, configType: String): String { - val request = StringBuilder() - - request.append("").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("").append(NEW_LINE) - - return doWrappedRpc(messageId, request.toString()) - } - - @Throws(NetconfException::class) - fun deleteConfig(messageId: String, netconfTargetConfig: String): String { - if (netconfTargetConfig == NetconfAdaptorConstant.CONFIG_TARGET_RUNNING) { - log.warn("Target configuration for delete operation can't be \"running\" {}", netconfTargetConfig) - throw NetconfException("Target configuration for delete operation can't be running") - } - - val request = StringBuilder() - - request.append("").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("").append(NEW_LINE) - - return doWrappedRpc(messageId, request.toString()) - } - - fun discardChanges(messageId: String): String { - val request = StringBuilder() - request.append("").append(NEW_LINE) - return doWrappedRpc(messageId, request.toString()) - } - - fun lock(messageId: String, configType: String): String { - val request = StringBuilder() - - request.append("").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("").append(NEW_LINE) - - return doWrappedRpc(messageId, request.toString()) - } - - fun closeSession(messageId: String, force: Boolean): String { - val request = StringBuilder() - - if (force) { - request.append("").append(NEW_LINE) - } else { - request.append("").append(NEW_LINE) - } - - return doWrappedRpc(messageId, request.toString()) - } - - fun validateRPCXML(rpcRequest: String): Boolean { - try { - if (StringUtils.isBlank(rpcRequest)) { - return false - } - val dbf = DocumentBuilderFactory.newInstance() - 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, "")))) - return true - } catch (e: Exception) { - return false - } - - } - - fun getMsgId(message: String): Optional { - val matcher = MSGID_STRING_PATTERN.matcher(message) - if (matcher.find()) { - return Optional.of(matcher.group(1)) - } - return if (message.contains(RpcConstants.HELLO)) { - Optional.of((-1).toString()) - } else Optional.empty() - } - - fun validateChunkedFraming(reply: String): Boolean { - val matcher = CHUNKED_FRAMING_PATTERN.matcher(reply) - if (!matcher.matches()) { - log.debug("Error Reply: {}", reply) - return false - } - var chunkM = CHUNKED_SIZE_PATTERN.matcher(reply) - var chunks = ArrayList() - 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) - 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))) { - log.debug("Error Reply: {}", reply) - return false - } - return true - } - - - fun createHelloString(capabilities: List): String { - val hellobuffer = StringBuilder() - hellobuffer.append(RpcConstants.XML_HEADER).append(NEW_LINE) - hellobuffer.append("").append(NEW_LINE) - hellobuffer.append(" ").append(NEW_LINE) - if (capabilities.isNotEmpty()) { - capabilities.forEach { cap -> hellobuffer.append(" ").append(cap).append("").append(NEW_LINE) } - } - hellobuffer.append(" ").append(NEW_LINE) - hellobuffer.append("").append(NEW_LINE) - hellobuffer.append(RpcConstants.END_PATTERN) - return hellobuffer.toString() - } - fun formatRPCRequest(request: String, messageId: String, deviceCapabilities: Set): String { - var request = request - request = RpcMessageUtils.formatNetconfMessage(deviceCapabilities, request) - request = RpcMessageUtils.formatXmlHeader(request) - request = RpcMessageUtils.formatRequestMessageId(request, messageId) - - return request - } - - /** - * Validate and format netconf message. - NC1.0 if no EOM sequence present on `message`, - * append. - NC1.1 chunk-encode given message unless it already is chunk encoded - * - * @param deviceCapabilities Set containing Device Capabilities - * @param message to format - * @return formated message - */ - fun formatNetconfMessage(deviceCapabilities: Set, message: String): String { - var message = message - if (deviceCapabilities.contains(RpcConstants.NETCONF_11_CAPABILITY)) { - message = formatChunkedMessage(message) - } else if (!message.endsWith(RpcConstants.END_PATTERN)) { - message = message + NEW_LINE + RpcConstants.END_PATTERN - } - return message - } - - /** - * Validate and format message according to chunked framing mechanism. - * - * @param message to format - * @return formated message - */ - fun formatChunkedMessage(message: String): String { - var message = message - if (message.endsWith(RpcConstants.END_PATTERN)) { - // message given had Netconf 1.0 EOM pattern -> remove - message = message.substring(0, message.length - RpcConstants.END_PATTERN.length) - } - if (!message.startsWith(RpcConstants.NEW_LINE + RpcConstants.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) - } - return message - } - - /** - * Ensures xml start directive/declaration appears in the `request`. - * - * @param request RPC request message - * @return XML RPC message - */ - 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) - } else { - request = RpcConstants.XML_HEADER + "\n" + request - } - } - return request - } - - 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 + ">") - } - 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]) - 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] - var newLen = 0 - newLen = firstBlock.toByteArray(UTF_8).size - if (oldLen != newLen) { - return NEW_LINE + RpcConstants.HASH + newLen + NEW_LINE + rpcWithEnding - } - } - return request - } - - fun checkReply(reply: String?): Boolean { - return if (reply != null) { - !reply.contains("") || reply.contains("warning") || reply.contains("") - } else false - } - - - } - -} \ 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 = 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 { + "") 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) } -- cgit 1.2.3-korg