diff --git a/.travis.yml b/.travis.yml index 808b75f32..8ff26c2ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ os: before_install: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update && sudo apt-get install -y python-pip zlib1g-dev python-lxml libxml2-dev libxslt1-dev python-dev libboost-dev libboost-python-dev libssh-dev libcurl4-openssl-dev libtool python3-lxml; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python boost-python jq ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install jq ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH=$PATH:~/Library/Python; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull ydkdev/confd-beta; fi diff --git a/sdk/python/core/tests/test_sanity_netconf.py b/sdk/python/core/tests/test_sanity_netconf.py index 1d293b5a9..6178f1317 100644 --- a/sdk/python/core/tests/test_sanity_netconf.py +++ b/sdk/python/core/tests/test_sanity_netconf.py @@ -22,7 +22,7 @@ import unittest from compare import is_equal -from ydk.errors import YPYModelError, YPYError +from ydk.errors import YPYModelError, YPYError, YPYServiceError from ydk.models import ydktest_sanity as ysanity from ydk.providers import NetconfServiceProvider, NativeNetconfServiceProvider from ydk.services import NetconfService @@ -145,6 +145,62 @@ def test_copy_config(self): op = self.netconf_service.copy_config(self.ncc, Datastore.candidate, Datastore.running) self.assertIn('ok', op) + def test_delete_config(self): + pass + # startup and candidate cannot be both enabled in ConfD + # op = self.netconf_service.delete_config(self.ncc, Datastore.startup) + # self.assertIn('ok', op) + + def test_delete_config_fail(self): + self.assertRaises(YPYServiceError, + self.netconf_service.delete_config, + self.ncc, + Datastore.running) + self.assertRaises(YPYServiceError, + self.netconf_service.delete_config, + self.ncc, + Datastore.candidate) + + def test_copy_config_fail(self): + self.assertRaises(YPYServiceError, + self.netconf_service.copy_config, + self.ncc, + target=123, + source=456) + + def test_edit_config_fail(self): + self.assertRaises(YPYServiceError, + self.netconf_service.edit_config, + self.ncc, + Datastore.startup, + Datastore.candidate) + + def test_get_config_fail(self): + runner = ysanity.Runner() + self.assertRaises(YPYServiceError, + self.netconf_service.get_config, + self.ncc, + "invalid-input", + runner) + + def test_lock_fail(self): + self.assertRaises(YPYServiceError, + self.netconf_service.lock, + self.ncc, + "invalid-input") + + def test_unlock_fail(self): + self.assertRaises(YPYServiceError, + self.netconf_service.unlock, + self.ncc, + "invalid-input") + + def test_validate_fail(self): + self.assertRaises(YPYServiceError, + self.netconf_service.validate, + self.ncc, + source=123) + if __name__ == '__main__': import sys diff --git a/sdk/python/core/ydk/services/netconf_service.py b/sdk/python/core/ydk/services/netconf_service.py index e6b5642f2..736ec9363 100644 --- a/sdk/python/core/ydk/services/netconf_service.py +++ b/sdk/python/core/ydk/services/netconf_service.py @@ -178,6 +178,8 @@ def copy_config(self, provider, target, source, with_defaults_option=None): self.service_logger.info('Executing copy-config RPC') rpc = ietf_netconf.CopyConfigRpc() + _validate_datastore_options(source, 'copy-config:source') + _validate_datastore_options(target, 'copy-config:target') rpc.input.source = _get_rpc_datastore_object(source, rpc.input.source) rpc.input.target = _get_rpc_datastore_object(target, rpc.input.target) rpc.input.with_defaults_option = with_defaults_option @@ -205,6 +207,7 @@ def delete_config(self, provider, target): self.service_logger.info('Executing delete-config RPC') rpc = ietf_netconf.DeleteConfigRpc() + _validate_datastore_options(target, 'delete-config:target') rpc.input.target = _get_rpc_datastore_object(target, rpc.input.target) return self.executor.execute_rpc(provider, rpc) @@ -267,6 +270,7 @@ def edit_config(self, provider, target, config, default_operation=None, error_op self.service_logger.info('Executing edit-config RPC') rpc = ietf_netconf.EditConfigRpc() + _validate_datastore_options(target, 'edit-config:target') rpc.input.target = _get_rpc_datastore_object(target, rpc.input.target) rpc.input.config = config rpc.input.default_operation = default_operation @@ -304,6 +308,7 @@ def get_config(self, provider, source, get_filter, with_defaults_option=None): rpc = ietf_netconf.GetConfigRpc() rpc.input.filter = get_filter + _validate_datastore_options(source, 'get-config:source') rpc.input.source = _get_rpc_datastore_object(source, rpc.input.source) rpc.input.with_defaults_option = with_defaults_option @@ -384,6 +389,7 @@ def lock(self, provider, target): self.service_logger.info('Executing lock RPC') rpc = ietf_netconf.LockRpc() + _validate_datastore_options(target, 'lock:target') rpc.input.target = _get_rpc_datastore_object(target, rpc.input.target) return self.executor.execute_rpc(provider, rpc) @@ -410,6 +416,7 @@ def unlock(self, provider, target): self.service_logger.info('Executing unlock RPC') rpc = ietf_netconf.UnlockRpc() + _validate_datastore_options(target, 'unlock:target') rpc.input.target = _get_rpc_datastore_object(target, rpc.input.target) return self.executor.execute_rpc(provider, rpc) @@ -437,6 +444,7 @@ def validate(self, provider, source=None, config=None): rpc = ietf_netconf.ValidateRpc() if source is not None: + _validate_datastore_options(source, 'validate:source') rpc.input.source = _get_rpc_datastore_object(source, rpc.input.source) if config is not None: rpc.input.source.config = config @@ -467,3 +475,37 @@ def payload_convert(payload): rt = etree.fromstring(payload.encode('utf-8')) chchs = rt.getchildren()[0].getchildren() return etree.tostring(chchs[0], pretty_print=True, encoding='utf-8').decode('utf-8') + + +def _validate_datastore_options(datastore, option): + res = True + if option == 'copy-config:target': + res = isinstance(datastore, (str, Datastore)) + elif option == 'copy-config:source': + res = isinstance(datastore, (str, Datastore)) + elif option == 'delete-config:target': + res = isinstance(datastore, str) or datastore == Datastore.startup + elif option == 'edit-config:target': + res = datastore in (Datastore.candidate, Datastore.running) + elif option == 'get-config:source': + res = isinstance(datastore, Datastore) + elif option == 'lock:target': + res = isinstance(datastore, Datastore) + elif option == 'unlock:target': + res = isinstance(datastore, Datastore) + elif option == 'validate:source': + res = isinstance(datastore, (str, Datastore)) + + if not res: + err_msg = _get_datastore_errmsg(option, datastore) + raise YPYServiceError(error_msg=err_msg) + + +def _get_datastore_errmsg(option, datastore): + if isinstance(datastore, Datastore): + pass + elif isinstance(datastore, str): + datastore = 'url' + if ':' in option: + option = option[:option.find(':')] + return "%s datastore is not supported by Netconf %s operation" % (datastore, option)