summaryrefslogtreecommitdiffstats
path: root/collections-debian-merged/ansible_collections/cisco/nso/tests
diff options
context:
space:
mode:
Diffstat (limited to 'collections-debian-merged/ansible_collections/cisco/nso/tests')
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/builtins.py33
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/mock.py122
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/unittest.py38
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/loader.py116
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/path.py8
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/procenv.py90
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/vault_helper.py39
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/yaml_helper.py124
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/test_nso.py660
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/__init__.py0
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/complex_schema.json212
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config.json20
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config_changes.json46
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_empty_data.json1
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/description_schema.json28
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/device_schema.json1
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/devices_schema.json1
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json1
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json1
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_schema.json1
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/sync_from_schema.json178
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/verify_violation_data.json10
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/nso_module.py132
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_action.py167
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_config.py138
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_query.py57
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_show.py98
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_verify.py110
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/utils.py50
-rw-r--r--collections-debian-merged/ansible_collections/cisco/nso/tests/unit/requirements.txt1
34 files changed, 2483 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/builtins.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/builtins.py
new file mode 100644
index 00000000..f60ee678
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/builtins.py
@@ -0,0 +1,33 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+#
+# Compat for python2.7
+#
+
+# One unittest needs to import builtins via __import__() so we need to have
+# the string that represents it
+try:
+ import __builtin__
+except ImportError:
+ BUILTINS = 'builtins'
+else:
+ BUILTINS = '__builtin__'
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/mock.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/mock.py
new file mode 100644
index 00000000..0972cd2e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/mock.py
@@ -0,0 +1,122 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+'''
+Compat module for Python3.x's unittest.mock module
+'''
+import sys
+
+# Python 2.7
+
+# Note: Could use the pypi mock library on python3.x as well as python2.x. It
+# is the same as the python3 stdlib mock library
+
+try:
+ # Allow wildcard import because we really do want to import all of mock's
+ # symbols into this compat shim
+ # pylint: disable=wildcard-import,unused-wildcard-import
+ from unittest.mock import *
+except ImportError:
+ # Python 2
+ # pylint: disable=wildcard-import,unused-wildcard-import
+ try:
+ from mock import *
+ except ImportError:
+ print('You need the mock library installed on python2.x to run tests')
+
+
+# Prior to 3.4.4, mock_open cannot handle binary read_data
+if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
+ file_spec = None
+
+ def _iterate_read_data(read_data):
+ # Helper for mock_open:
+ # Retrieve lines from read_data via a generator so that separate calls to
+ # readline, read, and readlines are properly interleaved
+ sep = b'\n' if isinstance(read_data, bytes) else '\n'
+ data_as_list = [l + sep for l in read_data.split(sep)]
+
+ if data_as_list[-1] == sep:
+ # If the last line ended in a newline, the list comprehension will have an
+ # extra entry that's just a newline. Remove this.
+ data_as_list = data_as_list[:-1]
+ else:
+ # If there wasn't an extra newline by itself, then the file being
+ # emulated doesn't have a newline to end the last line remove the
+ # newline that our naive format() added
+ data_as_list[-1] = data_as_list[-1][:-1]
+
+ for line in data_as_list:
+ yield line
+
+ def mock_open(mock=None, read_data=''):
+ """
+ A helper function to create a mock to replace the use of `open`. It works
+ for `open` called directly or used as a context manager.
+
+ The `mock` argument is the mock object to configure. If `None` (the
+ default) then a `MagicMock` will be created for you, with the API limited
+ to methods or attributes available on standard file handles.
+
+ `read_data` is a string for the `read` methoddline`, and `readlines` of the
+ file handle to return. This is an empty string by default.
+ """
+ def _readlines_side_effect(*args, **kwargs):
+ if handle.readlines.return_value is not None:
+ return handle.readlines.return_value
+ return list(_data)
+
+ def _read_side_effect(*args, **kwargs):
+ if handle.read.return_value is not None:
+ return handle.read.return_value
+ return type(read_data)().join(_data)
+
+ def _readline_side_effect():
+ if handle.readline.return_value is not None:
+ while True:
+ yield handle.readline.return_value
+ for line in _data:
+ yield line
+
+ global file_spec
+ if file_spec is None:
+ import _io
+ file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
+
+ if mock is None:
+ mock = MagicMock(name='open', spec=open)
+
+ handle = MagicMock(spec=file_spec)
+ handle.__enter__.return_value = handle
+
+ _data = _iterate_read_data(read_data)
+
+ handle.write.return_value = None
+ handle.read.return_value = None
+ handle.readline.return_value = None
+ handle.readlines.return_value = None
+
+ handle.read.side_effect = _read_side_effect
+ handle.readline.side_effect = _readline_side_effect()
+ handle.readlines.side_effect = _readlines_side_effect
+
+ mock.return_value = handle
+ return mock
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/unittest.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/unittest.py
new file mode 100644
index 00000000..98f08ad6
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/compat/unittest.py
@@ -0,0 +1,38 @@
+# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+'''
+Compat module for Python2.7's unittest module
+'''
+
+import sys
+
+# Allow wildcard import because we really do want to import all of
+# unittests's symbols into this compat shim
+# pylint: disable=wildcard-import,unused-wildcard-import
+if sys.version_info < (2, 7):
+ try:
+ # Need unittest2 on python2.6
+ from unittest2 import *
+ except ImportError:
+ print('You need unittest2 installed on python2.6.x to run tests')
+else:
+ from unittest import *
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/loader.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/loader.py
new file mode 100644
index 00000000..0ee47fbb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/loader.py
@@ -0,0 +1,116 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+
+from ansible.errors import AnsibleParserError
+from ansible.parsing.dataloader import DataLoader
+from ansible.module_utils._text import to_bytes, to_text
+
+
+class DictDataLoader(DataLoader):
+
+ def __init__(self, file_mapping=None):
+ file_mapping = {} if file_mapping is None else file_mapping
+ assert type(file_mapping) == dict
+
+ super(DictDataLoader, self).__init__()
+
+ self._file_mapping = file_mapping
+ self._build_known_directories()
+ self._vault_secrets = None
+
+ def load_from_file(self, path, cache=True, unsafe=False):
+ path = to_text(path)
+ if path in self._file_mapping:
+ return self.load(self._file_mapping[path], path)
+ return None
+
+ # TODO: the real _get_file_contents returns a bytestring, so we actually convert the
+ # unicode/text it's created with to utf-8
+ def _get_file_contents(self, path):
+ path = to_text(path)
+ if path in self._file_mapping:
+ return (to_bytes(self._file_mapping[path]), False)
+ else:
+ raise AnsibleParserError("file not found: %s" % path)
+
+ def path_exists(self, path):
+ path = to_text(path)
+ return path in self._file_mapping or path in self._known_directories
+
+ def is_file(self, path):
+ path = to_text(path)
+ return path in self._file_mapping
+
+ def is_directory(self, path):
+ path = to_text(path)
+ return path in self._known_directories
+
+ def list_directory(self, path):
+ ret = []
+ path = to_text(path)
+ for x in (list(self._file_mapping.keys()) + self._known_directories):
+ if x.startswith(path):
+ if os.path.dirname(x) == path:
+ ret.append(os.path.basename(x))
+ return ret
+
+ def is_executable(self, path):
+ # FIXME: figure out a way to make paths return true for this
+ return False
+
+ def _add_known_directory(self, directory):
+ if directory not in self._known_directories:
+ self._known_directories.append(directory)
+
+ def _build_known_directories(self):
+ self._known_directories = []
+ for path in self._file_mapping:
+ dirname = os.path.dirname(path)
+ while dirname not in ('/', ''):
+ self._add_known_directory(dirname)
+ dirname = os.path.dirname(dirname)
+
+ def push(self, path, content):
+ rebuild_dirs = False
+ if path not in self._file_mapping:
+ rebuild_dirs = True
+
+ self._file_mapping[path] = content
+
+ if rebuild_dirs:
+ self._build_known_directories()
+
+ def pop(self, path):
+ if path in self._file_mapping:
+ del self._file_mapping[path]
+ self._build_known_directories()
+
+ def clear(self):
+ self._file_mapping = dict()
+ self._known_directories = []
+
+ def get_basedir(self):
+ return os.getcwd()
+
+ def set_vault_secrets(self, vault_secrets):
+ self._vault_secrets = vault_secrets
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/path.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/path.py
new file mode 100644
index 00000000..08b10e45
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/path.py
@@ -0,0 +1,8 @@
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.cisco.nso.tests.unit.compat.mock import MagicMock
+from ansible.utils.path import unfrackpath
+
+
+mock_unfrackpath_noop = MagicMock(spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x)
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/procenv.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/procenv.py
new file mode 100644
index 00000000..bdd78c7f
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/procenv.py
@@ -0,0 +1,90 @@
+# (c) 2016, Matt Davis <mdavis@ansible.com>
+# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import sys
+import json
+
+from contextlib import contextmanager
+from io import BytesIO, StringIO
+from ansible_collections.cisco.nso.tests.unit.compat import unittest
+from ansible.module_utils.six import PY3
+from ansible.module_utils._text import to_bytes
+
+
+@contextmanager
+def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
+ """
+ context manager that temporarily masks the test runner's values for stdin and argv
+ """
+ real_stdin = sys.stdin
+ real_argv = sys.argv
+
+ if PY3:
+ fake_stream = StringIO(stdin_data)
+ fake_stream.buffer = BytesIO(to_bytes(stdin_data))
+ else:
+ fake_stream = BytesIO(to_bytes(stdin_data))
+
+ try:
+ sys.stdin = fake_stream
+ sys.argv = argv_data
+
+ yield
+ finally:
+ sys.stdin = real_stdin
+ sys.argv = real_argv
+
+
+@contextmanager
+def swap_stdout():
+ """
+ context manager that temporarily replaces stdout for tests that need to verify output
+ """
+ old_stdout = sys.stdout
+
+ if PY3:
+ fake_stream = StringIO()
+ else:
+ fake_stream = BytesIO()
+
+ try:
+ sys.stdout = fake_stream
+
+ yield fake_stream
+ finally:
+ sys.stdout = old_stdout
+
+
+class ModuleTestCase(unittest.TestCase):
+ def setUp(self, module_args=None):
+ if module_args is None:
+ module_args = {'_ansible_remote_tmp': '/tmp', '_ansible_keep_remote_files': False}
+
+ args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args))
+
+ # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
+ self.stdin_swap = swap_stdin_and_argv(stdin_data=args)
+ self.stdin_swap.__enter__()
+
+ def tearDown(self):
+ # unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
+ self.stdin_swap.__exit__(None, None, None)
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/vault_helper.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/vault_helper.py
new file mode 100644
index 00000000..dcce9c78
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/vault_helper.py
@@ -0,0 +1,39 @@
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.module_utils._text import to_bytes
+
+from ansible.parsing.vault import VaultSecret
+
+
+class TextVaultSecret(VaultSecret):
+ '''A secret piece of text. ie, a password. Tracks text encoding.
+
+ The text encoding of the text may not be the default text encoding so
+ we keep track of the encoding so we encode it to the same bytes.'''
+
+ def __init__(self, text, encoding=None, errors=None, _bytes=None):
+ super(TextVaultSecret, self).__init__()
+ self.text = text
+ self.encoding = encoding or 'utf-8'
+ self._bytes = _bytes
+ self.errors = errors or 'strict'
+
+ @property
+ def bytes(self):
+ '''The text encoded with encoding, unless we specifically set _bytes.'''
+ return self._bytes or to_bytes(self.text, encoding=self.encoding, errors=self.errors)
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/yaml_helper.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/yaml_helper.py
new file mode 100644
index 00000000..bf0aa8d8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/mock/yaml_helper.py
@@ -0,0 +1,124 @@
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import io
+import yaml
+
+from ansible.module_utils.six import PY3
+from ansible.parsing.yaml.loader import AnsibleLoader
+from ansible.parsing.yaml.dumper import AnsibleDumper
+
+
+class YamlTestUtils(object):
+ """Mixin class to combine with a unittest.TestCase subclass."""
+ def _loader(self, stream):
+ """Vault related tests will want to override this.
+
+ Vault cases should setup a AnsibleLoader that has the vault password."""
+ return AnsibleLoader(stream)
+
+ def _dump_stream(self, obj, stream, dumper=None):
+ """Dump to a py2-unicode or py3-string stream."""
+ if PY3:
+ return yaml.dump(obj, stream, Dumper=dumper)
+ else:
+ return yaml.dump(obj, stream, Dumper=dumper, encoding=None)
+
+ def _dump_string(self, obj, dumper=None):
+ """Dump to a py2-unicode or py3-string"""
+ if PY3:
+ return yaml.dump(obj, Dumper=dumper)
+ else:
+ return yaml.dump(obj, Dumper=dumper, encoding=None)
+
+ def _dump_load_cycle(self, obj):
+ # Each pass though a dump or load revs the 'generation'
+ # obj to yaml string
+ string_from_object_dump = self._dump_string(obj, dumper=AnsibleDumper)
+
+ # wrap a stream/file like StringIO around that yaml
+ stream_from_object_dump = io.StringIO(string_from_object_dump)
+ loader = self._loader(stream_from_object_dump)
+ # load the yaml stream to create a new instance of the object (gen 2)
+ obj_2 = loader.get_data()
+
+ # dump the gen 2 objects directory to strings
+ string_from_object_dump_2 = self._dump_string(obj_2,
+ dumper=AnsibleDumper)
+
+ # The gen 1 and gen 2 yaml strings
+ self.assertEqual(string_from_object_dump, string_from_object_dump_2)
+ # the gen 1 (orig) and gen 2 py object
+ self.assertEqual(obj, obj_2)
+
+ # again! gen 3... load strings into py objects
+ stream_3 = io.StringIO(string_from_object_dump_2)
+ loader_3 = self._loader(stream_3)
+ obj_3 = loader_3.get_data()
+
+ string_from_object_dump_3 = self._dump_string(obj_3, dumper=AnsibleDumper)
+
+ self.assertEqual(obj, obj_3)
+ # should be transitive, but...
+ self.assertEqual(obj_2, obj_3)
+ self.assertEqual(string_from_object_dump, string_from_object_dump_3)
+
+ def _old_dump_load_cycle(self, obj):
+ '''Dump the passed in object to yaml, load it back up, dump again, compare.'''
+ stream = io.StringIO()
+
+ yaml_string = self._dump_string(obj, dumper=AnsibleDumper)
+ self._dump_stream(obj, stream, dumper=AnsibleDumper)
+
+ yaml_string_from_stream = stream.getvalue()
+
+ # reset stream
+ stream.seek(0)
+
+ loader = self._loader(stream)
+ # loader = AnsibleLoader(stream, vault_password=self.vault_password)
+ obj_from_stream = loader.get_data()
+
+ stream_from_string = io.StringIO(yaml_string)
+ loader2 = self._loader(stream_from_string)
+ # loader2 = AnsibleLoader(stream_from_string, vault_password=self.vault_password)
+ obj_from_string = loader2.get_data()
+
+ stream_obj_from_stream = io.StringIO()
+ stream_obj_from_string = io.StringIO()
+
+ if PY3:
+ yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper)
+ yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper)
+ else:
+ yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper, encoding=None)
+ yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper, encoding=None)
+
+ yaml_string_stream_obj_from_stream = stream_obj_from_stream.getvalue()
+ yaml_string_stream_obj_from_string = stream_obj_from_string.getvalue()
+
+ stream_obj_from_stream.seek(0)
+ stream_obj_from_string.seek(0)
+
+ if PY3:
+ yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper)
+ yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper)
+ else:
+ yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper, encoding=None)
+ yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper, encoding=None)
+
+ assert yaml_string == yaml_string_obj_from_stream
+ assert yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
+ assert (yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string == yaml_string_stream_obj_from_stream ==
+ yaml_string_stream_obj_from_string)
+ assert obj == obj_from_stream
+ assert obj == obj_from_string
+ assert obj == yaml_string_obj_from_stream
+ assert obj == yaml_string_obj_from_string
+ assert obj == obj_from_stream == obj_from_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
+ return {'obj': obj,
+ 'yaml_string': yaml_string,
+ 'yaml_string_from_stream': yaml_string_from_stream,
+ 'obj_from_stream': obj_from_stream,
+ 'obj_from_string': obj_from_string,
+ 'yaml_string_obj_from_string': yaml_string_obj_from_string}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/test_nso.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/test_nso.py
new file mode 100644
index 00000000..ee113aeb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/module_utils/test_nso.py
@@ -0,0 +1,660 @@
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible_collections.cisco.nso.tests.unit.compat import unittest
+from ansible_collections.cisco.nso.plugins.module_utils import nso
+
+
+MODULE_PREFIX_MAP = '''
+{
+ "ansible-nso": "an",
+ "test": "test",
+ "tailf-ncs": "ncs"
+}
+'''
+
+
+SCHEMA_DATA = {
+ '/an:id-name-leaf': '''
+{
+ "meta": {
+ "prefix": "an",
+ "namespace": "http://github.com/ansible/nso",
+ "types": {
+ "http://github.com/ansible/nso:id-name-t": [
+ {
+ "name": "http://github.com/ansible/nso:id-name-t",
+ "enumeration": [
+ {
+ "label": "id-one"
+ },
+ {
+ "label": "id-two"
+ }
+ ]
+ },
+ {
+ "name": "identityref"
+ }
+ ]
+ },
+ "keypath": "/an:id-name-leaf"
+ },
+ "data": {
+ "kind": "leaf",
+ "type": {
+ "namespace": "http://github.com/ansible/nso",
+ "name": "id-name-t"
+ },
+ "name": "id-name-leaf",
+ "qname": "an:id-name-leaf"
+ }
+}''',
+ '/an:id-name-values': '''
+{
+ "meta": {
+ "prefix": "an",
+ "namespace": "http://github.com/ansible/nso",
+ "types": {},
+ "keypath": "/an:id-name-values"
+ },
+ "data": {
+ "kind": "container",
+ "name": "id-name-values",
+ "qname": "an:id-name-values",
+ "children": [
+ {
+ "kind": "list",
+ "name": "id-name-value",
+ "qname": "an:id-name-value",
+ "key": [
+ "name"
+ ]
+ }
+ ]
+ }
+}
+''',
+ '/an:id-name-values/id-name-value': '''
+{
+ "meta": {
+ "prefix": "an",
+ "namespace": "http://github.com/ansible/nso",
+ "types": {
+ "http://github.com/ansible/nso:id-name-t": [
+ {
+ "name": "http://github.com/ansible/nso:id-name-t",
+ "enumeration": [
+ {
+ "label": "id-one"
+ },
+ {
+ "label": "id-two"
+ }
+ ]
+ },
+ {
+ "name": "identityref"
+ }
+ ]
+ },
+ "keypath": "/an:id-name-values/id-name-value"
+ },
+ "data": {
+ "kind": "list",
+ "name": "id-name-value",
+ "qname": "an:id-name-value",
+ "key": [
+ "name"
+ ],
+ "children": [
+ {
+ "kind": "key",
+ "name": "name",
+ "qname": "an:name",
+ "type": {
+ "namespace": "http://github.com/ansible/nso",
+ "name": "id-name-t"
+ }
+ },
+ {
+ "kind": "leaf",
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "name": "value",
+ "qname": "an:value"
+ }
+ ]
+ }
+}
+''',
+ '/test:test': '''
+{
+ "meta": {
+ "types": {
+ "http://example.com/test:t15": [
+ {
+ "leaf_type":[
+ {
+ "name":"string"
+ }
+ ],
+ "list_type":[
+ {
+ "name":"http://example.com/test:t15",
+ "leaf-list":true
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "data": {
+ "kind": "list",
+ "name":"test",
+ "qname":"test:test",
+ "key":["name"],
+ "children": [
+ {
+ "kind": "key",
+ "name": "name",
+ "qname": "test:name",
+ "type": {"name":"string","primitive":true}
+ },
+ {
+ "kind": "choice",
+ "name": "test-choice",
+ "qname": "test:test-choice",
+ "cases": [
+ {
+ "kind": "case",
+ "name": "direct-child-case",
+ "qname":"test:direct-child-case",
+ "children":[
+ {
+ "kind": "leaf",
+ "name": "direct-child",
+ "qname": "test:direct-child",
+ "type": {"name":"string","primitive":true}
+ }
+ ]
+ },
+ {
+ "kind":"case","name":"nested-child-case","qname":"test:nested-child-case",
+ "children": [
+ {
+ "kind": "choice",
+ "name": "nested-choice",
+ "qname": "test:nested-choice",
+ "cases": [
+ {
+ "kind":"case","name":"nested-child","qname":"test:nested-child",
+ "children": [
+ {
+ "kind": "leaf",
+ "name":"nested-child",
+ "qname":"test:nested-child",
+ "type":{"name":"string","primitive":true}}
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind":"leaf-list",
+ "name":"device-list",
+ "qname":"test:device-list",
+ "type": {
+ "namespace":"http://example.com/test",
+ "name":"t15"
+ }
+ }
+ ]
+ }
+}
+''',
+ '/test:test/device-list': '''
+{
+ "meta": {
+ "types": {
+ "http://example.com/test:t15": [
+ {
+ "leaf_type":[
+ {
+ "name":"string"
+ }
+ ],
+ "list_type":[
+ {
+ "name":"http://example.com/test:t15",
+ "leaf-list":true
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "data": {
+ "kind":"leaf-list",
+ "name":"device-list",
+ "qname":"test:device-list",
+ "type": {
+ "namespace":"http://example.com/test",
+ "name":"t15"
+ }
+ }
+}
+''',
+ '/test:deps': '''
+{
+ "meta": {
+ },
+ "data": {
+ "kind":"container",
+ "name":"deps",
+ "qname":"test:deps",
+ "children": [
+ {
+ "kind": "leaf",
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "name": "a",
+ "qname": "test:a",
+ "deps": ["/test:deps/c"]
+ },
+ {
+ "kind": "leaf",
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "name": "b",
+ "qname": "test:b",
+ "deps": ["/test:deps/a"]
+ },
+ {
+ "kind": "leaf",
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "name": "c",
+ "qname": "test:c"
+ }
+ ]
+ }
+}
+'''
+}
+
+
+class MockResponse(object):
+ def __init__(self, method, params, code, body, headers=None):
+ if headers is None:
+ headers = {}
+
+ self.method = method
+ self.params = params
+
+ self.code = code
+ self.body = body
+ self.headers = dict(headers)
+
+ def read(self):
+ return self.body
+
+
+def mock_call(calls, url, timeout, validate_certs, data=None, headers=None, method=None):
+ result = calls[0]
+ del calls[0]
+
+ request = json.loads(data)
+ if result.method != request['method']:
+ raise ValueError('expected method {0}({1}), got {2}({3})'.format(
+ result.method, result.params,
+ request['method'], request['params']))
+
+ for key, value in result.params.items():
+ if key not in request['params']:
+ raise ValueError('{0} not in parameters'.format(key))
+ if value != request['params'][key]:
+ raise ValueError('expected {0} to be {1}, got {2}'.format(
+ key, value, request['params'][key]))
+
+ return result
+
+
+def get_schema_response(path):
+ return MockResponse(
+ 'get_schema', {'path': path}, 200, '{{"result": {0}}}'.format(
+ SCHEMA_DATA[path]))
+
+
+class TestJsonRpc(unittest.TestCase):
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_exists(self, open_url_mock):
+ calls = [
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ MockResponse('exists', {'path': '/exists'}, 200, '{"result": {"exists": true}}'),
+ MockResponse('exists', {'path': '/not-exists'}, 200, '{"result": {"exists": false}}')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+ client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)
+ self.assertEqual(True, client.exists('/exists'))
+ self.assertEqual(False, client.exists('/not-exists'))
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_exists_data_not_found(self, open_url_mock):
+ calls = [
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ MockResponse('exists', {'path': '/list{missing-parent}/list{child}'}, 200, '{"error":{"type":"data.not_found"}}')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+ client = nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False)
+ self.assertEqual(False, client.exists('/list{missing-parent}/list{child}'))
+
+ self.assertEqual(0, len(calls))
+
+
+class TestValueBuilder(unittest.TestCase):
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_identityref_leaf(self, open_url_mock):
+ calls = [
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ get_schema_response('/an:id-name-leaf'),
+ MockResponse('get_module_prefix_map', {}, 200, '{{"result": {0}}}'.format(MODULE_PREFIX_MAP))
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+
+ parent = "/an:id-name-leaf"
+ schema_data = json.loads(
+ SCHEMA_DATA['/an:id-name-leaf'])
+ schema = schema_data['data']
+
+ vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
+ vb.build(parent, None, 'ansible-nso:id-two', schema)
+ values = list(vb.values)
+ self.assertEqual(1, len(values))
+ value = values[0]
+ self.assertEqual(parent, value.path)
+ self.assertEqual('set', value.state)
+ self.assertEqual('an:id-two', value.value)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_identityref_key(self, open_url_mock):
+ calls = [
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ get_schema_response('/an:id-name-values/id-name-value'),
+ MockResponse('get_module_prefix_map', {}, 200, '{{"result": {0}}}'.format(MODULE_PREFIX_MAP)),
+ MockResponse('exists', {'path': '/an:id-name-values/id-name-value{an:id-one}'}, 200, '{"result": {"exists": true}}')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+
+ parent = "/an:id-name-values"
+ schema_data = json.loads(
+ SCHEMA_DATA['/an:id-name-values/id-name-value'])
+ schema = schema_data['data']
+
+ vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
+ vb.build(parent, 'id-name-value', [{'name': 'ansible-nso:id-one', 'value': '1'}], schema)
+ values = list(vb.values)
+ self.assertEqual(1, len(values))
+ value = values[0]
+ self.assertEqual('{0}/id-name-value{{an:id-one}}/value'.format(parent), value.path)
+ self.assertEqual('set', value.state)
+ self.assertEqual('1', value.value)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nested_choice(self, open_url_mock):
+ calls = [
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ get_schema_response('/test:test'),
+ MockResponse('exists', {'path': '/test:test{direct}'}, 200, '{"result": {"exists": true}}'),
+ MockResponse('exists', {'path': '/test:test{nested}'}, 200, '{"result": {"exists": true}}')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+
+ parent = "/test:test"
+ schema_data = json.loads(
+ SCHEMA_DATA['/test:test'])
+ schema = schema_data['data']
+
+ vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
+ vb.build(parent, None, [{'name': 'direct', 'direct-child': 'direct-value'},
+ {'name': 'nested', 'nested-child': 'nested-value'}], schema)
+ values = list(vb.values)
+ self.assertEqual(2, len(values))
+ value = values[0]
+ self.assertEqual('{0}{{direct}}/direct-child'.format(parent), value.path)
+ self.assertEqual('set', value.state)
+ self.assertEqual('direct-value', value.value)
+
+ value = values[1]
+ self.assertEqual('{0}{{nested}}/nested-child'.format(parent), value.path)
+ self.assertEqual('set', value.state)
+ self.assertEqual('nested-value', value.value)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_leaf_list_type(self, open_url_mock):
+ calls = [
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.4"}'),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ get_schema_response('/test:test')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+
+ parent = "/test:test"
+ schema_data = json.loads(
+ SCHEMA_DATA['/test:test'])
+ schema = schema_data['data']
+
+ vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
+ vb.build(parent, None, {'device-list': ['one', 'two']}, schema)
+ values = list(vb.values)
+ self.assertEqual(1, len(values))
+ value = values[0]
+ self.assertEqual('{0}/device-list'.format(parent), value.path)
+ self.assertEqual(['one', 'two'], value.value)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_leaf_list_type_45(self, open_url_mock):
+ calls = [
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ get_schema_response('/test:test/device-list')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+
+ parent = "/test:test"
+ schema_data = json.loads(
+ SCHEMA_DATA['/test:test'])
+ schema = schema_data['data']
+
+ vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
+ vb.build(parent, None, {'device-list': ['one', 'two']}, schema)
+ values = list(vb.values)
+ self.assertEqual(3, len(values))
+ value = values[0]
+ self.assertEqual('{0}/device-list'.format(parent), value.path)
+ self.assertEqual(nso.State.ABSENT, value.state)
+ value = values[1]
+ self.assertEqual('{0}/device-list{{one}}'.format(parent), value.path)
+ self.assertEqual(nso.State.PRESENT, value.state)
+ value = values[2]
+ self.assertEqual('{0}/device-list{{two}}'.format(parent), value.path)
+ self.assertEqual(nso.State.PRESENT, value.state)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_sort_by_deps(self, open_url_mock):
+ calls = [
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ get_schema_response('/test:deps')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+
+ parent = "/test:deps"
+ schema_data = json.loads(
+ SCHEMA_DATA['/test:deps'])
+ schema = schema_data['data']
+
+ values = {
+ 'a': '1',
+ 'b': '2',
+ 'c': '3',
+ }
+
+ vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
+ vb.build(parent, None, values, schema)
+ values = list(vb.values)
+ self.assertEqual(3, len(values))
+ value = values[0]
+ self.assertEqual('{0}/c'.format(parent), value.path)
+ self.assertEqual('3', value.value)
+ value = values[1]
+ self.assertEqual('{0}/a'.format(parent), value.path)
+ self.assertEqual('1', value.value)
+ value = values[2]
+ self.assertEqual('{0}/b'.format(parent), value.path)
+ self.assertEqual('2', value.value)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_sort_by_deps_not_included(self, open_url_mock):
+ calls = [
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ get_schema_response('/test:deps')
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
+
+ parent = "/test:deps"
+ schema_data = json.loads(
+ SCHEMA_DATA['/test:deps'])
+ schema = schema_data['data']
+
+ values = {
+ 'a': '1',
+ 'b': '2'
+ }
+
+ vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc', 10, False))
+ vb.build(parent, None, values, schema)
+ values = list(vb.values)
+ self.assertEqual(2, len(values))
+ value = values[0]
+ self.assertEqual('{0}/a'.format(parent), value.path)
+ self.assertEqual('1', value.value)
+ value = values[1]
+ self.assertEqual('{0}/b'.format(parent), value.path)
+ self.assertEqual('2', value.value)
+
+ self.assertEqual(0, len(calls))
+
+
+class TestVerifyVersion(unittest.TestCase):
+ def test_valid_versions(self):
+ self.assertTrue(nso.verify_version_str('5.0', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('5.1.1', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('5.1.1.2', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('4.6', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('4.6.2', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('4.6.2.1', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('4.5.1', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('4.5.2', [(4, 6), (4, 5, 1)]))
+ self.assertTrue(nso.verify_version_str('4.5.1.2', [(4, 6), (4, 5, 1)]))
+
+ def test_invalid_versions(self):
+ self.assertFalse(nso.verify_version_str('4.4', [(4, 6), (4, 5, 1)]))
+ self.assertFalse(nso.verify_version_str('4.4.1', [(4, 6), (4, 5, 1)]))
+ self.assertFalse(nso.verify_version_str('4.4.1.2', [(4, 6), (4, 5, 1)]))
+ self.assertFalse(nso.verify_version_str('4.5.0', [(4, 6), (4, 5, 1)]))
+
+
+class TestValueSort(unittest.TestCase):
+ def test_sort_parent_depend(self):
+ values = [
+ nso.ValueBuilder.Value('/test/list{entry}', '/test/list', 'CREATE', ['']),
+ nso.ValueBuilder.Value('/test/list{entry}/description', '/test/list/description', 'TEST', ['']),
+ nso.ValueBuilder.Value('/test/entry', '/test/entry', 'VALUE', ['/test/list', '/test/list/name'])
+ ]
+
+ result = [v.path for v in nso.ValueBuilder.sort_values(values)]
+
+ self.assertEqual(['/test/list{entry}', '/test/entry', '/test/list{entry}/description'], result)
+
+ def test_sort_break_direct_cycle(self):
+ values = [
+ nso.ValueBuilder.Value('/test/a', '/test/a', 'VALUE', ['/test/c']),
+ nso.ValueBuilder.Value('/test/b', '/test/b', 'VALUE', ['/test/a']),
+ nso.ValueBuilder.Value('/test/c', '/test/c', 'VALUE', ['/test/a'])
+ ]
+
+ result = [v.path for v in nso.ValueBuilder.sort_values(values)]
+
+ self.assertEqual(['/test/a', '/test/b', '/test/c'], result)
+
+ def test_sort_break_indirect_cycle(self):
+ values = [
+ nso.ValueBuilder.Value('/test/c', '/test/c', 'VALUE', ['/test/a']),
+ nso.ValueBuilder.Value('/test/a', '/test/a', 'VALUE', ['/test/b']),
+ nso.ValueBuilder.Value('/test/b', '/test/b', 'VALUE', ['/test/c'])
+ ]
+
+ result = [v.path for v in nso.ValueBuilder.sort_values(values)]
+
+ self.assertEqual(['/test/a', '/test/c', '/test/b'], result)
+
+ def test_sort_depend_on_self(self):
+ values = [
+ nso.ValueBuilder.Value('/test/a', '/test/a', 'VALUE', ['/test/a']),
+ nso.ValueBuilder.Value('/test/b', '/test/b', 'VALUE', [])
+ ]
+
+ result = [v.path for v in nso.ValueBuilder.sort_values(values)]
+
+ self.assertEqual(['/test/a', '/test/b'], result)
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/__init__.py
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/complex_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/complex_schema.json
new file mode 100644
index 00000000..49a11765
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/complex_schema.json
@@ -0,0 +1,212 @@
+{
+ "meta": {
+ "prefix": "ansible",
+ "namespace": "http://example.com/ansible",
+ "types": {
+ },
+ "keypath": "/ansible:action/complex"
+ },
+ "data": {
+ "kind": "action",
+ "mandatory": true,
+ "name": "complex",
+ "qname": "ansible:complex",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": true,
+ "update": false,
+ "delete": false
+ },
+ "children": [
+ {
+ "kind": "leaf",
+ "is_action_input": true,
+ "name": "number",
+ "qname": "ansible:number",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "uint8"
+ }
+ },
+ {
+ "kind": "container",
+ "is_action_input": true,
+ "mandatory": true,
+ "name": "ansible",
+ "qname": "ansible:ansible",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "children": [
+ {
+ "kind": "choice",
+ "cases": [
+ {
+ "kind": "case",
+ "name": "version",
+ "children": [
+ {
+ "kind": "leaf",
+ "is_action_input": true,
+ "name": "version",
+ "qname": "ansible:version",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "string"
+ }
+ }
+ ]
+ },
+ {
+ "kind": "case",
+ "name": "release",
+ "children": [
+ {
+ "kind": "container",
+ "is_action_input": true,
+ "mandatory": true,
+ "name": "release",
+ "qname": "ansible:release",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "children": [
+ {
+ "kind": "leaf",
+ "is_action_input": true,
+ "name": "major",
+ "qname": "ansible:major",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "uint8"
+ }
+ },
+ {
+ "kind": "leaf",
+ "is_action_input": true,
+ "name": "minor",
+ "qname": "ansible:minor",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "uint8"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "name": "version-releae-choice"
+ }
+ ]
+ },
+ {
+ "kind": "choice",
+ "cases": [
+ {
+ "kind": "case",
+ "name": "version",
+ "children": [
+ {
+ "kind": "list",
+ "min_elements": 0,
+ "name": "version",
+ "max_elements": "unbounded",
+ "qname": "ansible:version",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": false,
+ "delete": false
+ },
+ "mandatory": true,
+ "children": [
+ {
+ "kind": "leaf",
+ "name": "name",
+ "qname": "ansible:name",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": false,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "is_action_output": true
+ }
+ ],
+ "is_action_output": true
+ }
+ ]
+ },
+ {
+ "kind": "case",
+ "name": "release",
+ "children": [
+ {
+ "kind": "leaf",
+ "name": "release",
+ "qname": "ansible:release",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": false,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "is_action_output": true
+ }
+ ]
+ }
+ ],
+ "name": "version-release-choice"
+ }
+ ]
+ }
+}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config.json
new file mode 100644
index 00000000..b7318586
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config.json
@@ -0,0 +1,20 @@
+{
+ "l3vpn:vpn": {
+ "l3vpn": [
+ {
+ "name": "company",
+ "route-distinguisher": 999,
+ "endpoint": [
+ {
+ "id": "branch-office1",
+ "ce-device": "ce6",
+ "ce-interface": "GigabitEthernet0/12",
+ "ip-network": "10.10.1.0/24",
+ "bandwidth": 12000000,
+ "as-number": 65101
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config_changes.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config_changes.json
new file mode 100644
index 00000000..3ef234b7
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_config_changes.json
@@ -0,0 +1,46 @@
+{
+ "changes": [
+ {
+ "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-device",
+ "old": "",
+ "value": "ce6",
+ "op": "value_set"
+ },
+ {
+ "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ip-network",
+ "old": "",
+ "value": "10.10.1.0/24",
+ "op": "value_set"
+ },
+ {
+ "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/as-number",
+ "old": "",
+ "value": "65101",
+ "op": "value_set"
+ },
+ {
+ "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-interface",
+ "old": "",
+ "value": "GigabitEthernet0/12",
+ "op": "value_set"
+ },
+ {
+ "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/bandwidth",
+ "old": "",
+ "value": "12000000",
+ "op": "value_set"
+ },
+ {
+ "path": "/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}",
+ "old": "",
+ "value": "",
+ "op": "created"
+ },
+ {
+ "path": "/l3vpn:vpn/l3vpn{company}",
+ "old": "",
+ "value": "",
+ "op": "modified"
+ }
+ ]
+}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_empty_data.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_empty_data.json
new file mode 100644
index 00000000..0967ef42
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/config_empty_data.json
@@ -0,0 +1 @@
+{}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/description_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/description_schema.json
new file mode 100644
index 00000000..2680a484
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/description_schema.json
@@ -0,0 +1,28 @@
+{
+ "meta": {
+ "prefix": "ncs",
+ "namespace": "http://tail-f.com/ns/ncs",
+ "types": {
+ },
+ "keypath": "/ncs:devices/device{ce0}/description"
+ },
+ "data": {
+ "info": {
+ "string": "Free form textual description"
+ },
+ "kind": "leaf",
+ "name": "description",
+ "qname": "ncs:description",
+ "access": {
+ "read": true,
+ "create": true,
+ "execute": false,
+ "update": true,
+ "delete": true
+ },
+ "type": {
+ "primitive": true,
+ "name": "string"
+ }
+ }
+}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/device_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/device_schema.json
new file mode 100644
index 00000000..d3bd2ac3
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/device_schema.json
@@ -0,0 +1 @@
+{"meta": {"prefix": "ncs", "namespace": "http://tail-f.com/ns/ncs", "types": {"http://tail-f.com/ns/ncs:t85": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t85"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number": [{"range": {"value": [["0", "65535"]]}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number"}, {"name": "uint16"}], "http://tail-f.com/ns/ncs:t83": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t83"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:node-name": [{"name": "http://tail-f.com/ns/ncs:node-name"}, {"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}], "http://tail-f.com/ns/ncs:t29": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t29"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t101": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t101"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t43": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t43"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t27": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t27"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t40": [{"name": "http://tail-f.com/ns/ncs:t40", "enumeration": [{"label": "reject"}, {"label": "accept"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t47": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t47"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:host": [{"union": [[{"name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:ip-address"}, {"name": "ip-address"}], [{"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}]]}], "http://tail-f.com/ns/ncs:t45": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t45"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t49": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t49"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:trace-flag": [{"name": "http://tail-f.com/ns/ncs:trace-flag", "enumeration": [{"info": "Trace is disabled", "label": "false"}, {"info": "Raw, unformatted data", "label": "raw"}, {"info": "Pretty-printed data", "label": "pretty"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t28": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t28"}, {"name": "uint32"}]}, "keypath": "/ncs:devices/device"}, "data": {"info": {"string": "The list of managed devices"}, "kind": "list", "leafref_groups": [["remote-node"], ["authgroup"], ["device-profile"]], "mandatory": true, "name": "device", "max_elements": "unbounded", "contains_when_statement": true, "qname": "ncs:device", "children": [{"info": {"string": "A string uniquely identifying the managed device"}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP address or host name for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Name of remote node which connects to device"}, "kind": "leaf", "name": "remote-node", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "node-name"}, "qname": "ncs:remote-node", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:cluster/remote-node/name", "is_leafref": true}, {"info": {"string": "SSH connection configuration"}, "kind": "container", "mandatory": true, "name": "ssh", "qname": "ncs:ssh", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Free form textual description"}, "kind": "leaf", "name": "description", "qname": "ncs:description", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Physical location of devices in the group"}, "kind": "container", "mandatory": true, "name": "location", "qname": "ncs:location", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "name": "device-profile", "type": {"primitive": true, "name": "string"}, "qname": "ncs:device-profile", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/profiles/profile/name", "is_leafref": true}, {"info": {"string": "Timeout in seconds for new connections"}, "kind": "leaf", "name": "connect-timeout", "qname": "ncs:connect-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t27"}}, {"info": {"string": "Timeout in seconds used when reading data"}, "kind": "leaf", "name": "read-timeout", "qname": "ncs:read-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t28"}}, {"info": {"string": "Timeout in seconds used when writing data"}, "kind": "leaf", "name": "write-timeout", "qname": "ncs:write-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t29"}}, {"info": {"string": "Controls SSH keep alive settings"}, "kind": "container", "mandatory": true, "name": "ssh-keep-alive", "qname": "ncs:ssh-keep-alive", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Trace the southbound communication to devices"}, "kind": "leaf", "name": "trace", "qname": "ncs:trace", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "trace-flag"}}, {"info": {"string": "Control which device capabilities NCS uses"}, "kind": "container", "mandatory": true, "name": "ned-settings", "qname": "ncs:ned-settings", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for the commit-queue"}, "kind": "container", "mandatory": true, "name": "commit-queue", "qname": "ncs:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control how sessions to related devices can be pooled."}, "kind": "container", "mandatory": true, "name": "session-pool", "qname": "ncs:session-pool", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for no-overwrite sync check"}, "kind": "container", "mandatory": true, "name": "no-overwrite", "qname": "ncs:no-overwrite", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Specifies the behaviour of a commit operation involving a\ndevice that is out of sync with NCS. Value accept assumes that\nthe device's sync state is unknown and it is cleared on commit.\nThe default behaviour is to reject such commits."}, "kind": "leaf", "name": "out-of-sync-commit-behaviour", "qname": "ncs:out-of-sync-commit-behaviour", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t40"}}, {"default": "use-lsa", "kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"info": {"string": "Handle the LSA nodes as such. This is the default"}, "kind": "leaf", "name": "use-lsa", "qname": "ncs:use-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"info": {"string": "Do not handle any of the LSA nodes as such. These nodes\nwill be handled as any other device. This has the same\nresult as adding the commit flag 'no-lsa' to every commit."}, "kind": "leaf", "name": "no-lsa", "qname": "ncs:no-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"info": {"string": "Show all active settings for the device"}, "kind": "container", "mandatory": true, "name": "active-settings", "qname": "ncs:active-settings", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Additional protocols for the live-tree (read-only)"}, "kind": "list", "leafref_groups": [["authgroup"]], "min_elements": 0, "name": "live-status-protocol", "max_elements": "unbounded", "qname": "ncs:live-status-protocol", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP Address for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "SSH host key configuration"}, "kind": "container", "name": "ssh", "presence": true, "qname": "ncs:ssh", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Operational State for the live protocol"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "List of capabillities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"info": {"string": "Capability URI"}, "kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Capability revision"}, "kind": "leaf", "name": "revision", "type": {"primitive": true, "name": "string"}, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability module"}, "kind": "leaf", "name": "module", "type": {"primitive": true, "name": "string"}, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability features"}, "kind": "leaf-list", "name": "feature", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t83"}, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability deviations"}, "kind": "leaf-list", "name": "deviation", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t85"}, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["authgroup"]]}, {"info": {"string": "Show states for the device"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "How the device was added to NCS"}, "kind": "container", "mandatory": true, "name": "source", "qname": "ncs:source", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "A list of capabilities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "name": "module", "config": false, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t43"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t45"}}, {"info": {"string": "This action removes a capability from the list of capabilities.\nIf leaf module is set then corresponding module is attempted to\nbe removed from the list of modules for this device. This action\nis only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "remove", "qname": "ncs:remove", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}, {"info": {"string": "This is a list of the YANG modules supported by the device.\n\nThis list is populated the first time NCS connects to the\ndevice."}, "kind": "list", "min_elements": 0, "name": "module", "max_elements": "unbounded", "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "name", "type": {"primitive": true, "name": "string"}, "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t47"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t49"}}]}, {"info": {"string": "Contains vendor-specific information for\nidentifying the system platform.\n\nNEDs MAY augment this container with more device-specific\nnodes."}, "kind": "container", "mandatory": true, "name": "platform", "qname": "ncs:platform", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "NCS copy of the device configuration"}, "kind": "container", "mandatory": true, "name": "config", "qname": "ncs:config", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Status data fetched from the device"}, "kind": "container", "mandatory": true, "name": "live-status", "qname": "ncs:live-status", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "RPCs from the device"}, "kind": "container", "mandatory": true, "name": "rpc", "qname": "ncs:rpc", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "NETCONF notifications from the device"}, "kind": "container", "mandatory": true, "name": "netconf-notifications", "qname": "ncs:netconf-notifications", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Show services that use this device"}, "kind": "leaf-list", "name": "service-list", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t101"}, "qname": "ncs:service-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Notification address if different from device address"}, "kind": "leaf", "name": "snmp-notification-address", "qname": "ncs:snmp-notification-address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Device specific information"}, "kind": "container", "name": "platform", "presence": true, "when_targets": ["/ncs:devices/device/device-type/cli/ned-id"], "qname": "alu-meta:platform", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "A summary of all active alarms per device."}, "kind": "container", "mandatory": true, "name": "alarm-summary", "qname": "al:alarm-summary", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action copies the list of capabilities and the list of modules\nfrom another device or profile. When used on a device, this action\nis only intended to be used for pre-provisioning: it is not possible\nto override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "copy-capabilities", "qname": "ncs:copy-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action populates the list of capabilities based on the\nconfigured ned-id for this device, if possible. NCS will look up\nthe package corresponding to the ned-id and add all the modules\nfrom this packages to the list of this device's capabilities and\nlist of modules. It is the responsibility of the caller to verify\nthat the automatically populated list of capabilities matches actual\ndevice's capabilities. The list of capabilities can then be\nfine-tuned using add-capability and capability/remove actions.\nCurrently this approach will only work for CLI and generic devices.\nThis action is only intended to be used for pre-provisioning:\nit is not possible to override capabilities and modules provided\nby the NED implementation using this action."}, "kind": "action", "mandatory": true, "name": "find-capabilities", "qname": "ncs:find-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "This action adds a capability to the list of capabilities.\nIf uri is specified, then it is parsed as YANG capability string\nand module, revision, feature and deviation parameters are derived\nfrom the string. If module is specified, then the namespace is\nlooked up in the list of loaded namespaces and capability string\nconstructed automatically. If the module is specified and the\nattempt to look it up failed, then the action does nothing.\nIf module is specified or can be derived from capability string,\nthen the module is also added/replaced in the list of modules. This\naction is only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the NED\nimplementation using this action."}, "kind": "action", "mandatory": true, "name": "add-capability", "qname": "ncs:add-capability", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Take a named template and copy it here"}, "kind": "action", "mandatory": true, "name": "apply-template", "leafrefGroups": [["template-name"]], "qname": "ncs:apply-template", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["template-name"]]}, {"info": {"string": "Instantiate the config for the device from existing device"}, "kind": "action", "mandatory": true, "name": "instantiate-from-other-device", "leafrefGroups": [["device-name"]], "qname": "ncs:instantiate-from-other-device", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device-name"]]}, {"info": {"string": "Compare the actual device config with the NCS copy"}, "kind": "action", "mandatory": true, "name": "compare-config", "qname": "ncs:compare-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pulling from the device"}, "kind": "action", "mandatory": true, "name": "sync-from", "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pushing to the device"}, "kind": "action", "mandatory": true, "name": "sync-to", "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if NCS and the device have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Connect to the device"}, "kind": "action", "mandatory": true, "name": "connect", "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Close all sessions to the device"}, "kind": "action", "mandatory": true, "name": "disconnect", "qname": "ncs:disconnect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "ICMP ping the device"}, "kind": "action", "mandatory": true, "name": "ping", "qname": "ncs:ping", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Delete the config in NCS without deleting it in the device"}, "kind": "action", "mandatory": true, "name": "delete-config", "qname": "ncs:delete-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-to", "qname": "ncs:scp-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-from", "qname": "ncs:scp-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "min_elements": 0, "leafrefGroups": [["remote-node"], ["authgroup"], ["device-profile"]]}}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/devices_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/devices_schema.json
new file mode 100644
index 00000000..541ba010
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/devices_schema.json
@@ -0,0 +1 @@
+{"meta": {"prefix": "ncs", "namespace": "http://tail-f.com/ns/ncs", "types": {"http://tail-f.com/ns/ncs:t68": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t68"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t85": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t85"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t83": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t83"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t60": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t60"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t101": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t101"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:host": [{"union": [[{"name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:ip-address"}, {"name": "ip-address"}], [{"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}]]}], "http://tail-f.com/ns/ncs:trace-flag": [{"name": "http://tail-f.com/ns/ncs:trace-flag", "enumeration": [{"info": "Trace is disabled", "label": "false"}, {"info": "Raw, unformatted data", "label": "raw"}, {"info": "Pretty-printed data", "label": "pretty"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t43": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t43"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t27": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t27"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t40": [{"name": "http://tail-f.com/ns/ncs:t40", "enumeration": [{"label": "reject"}, {"label": "accept"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:t47": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t47"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t45": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t45"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t49": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t49"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t29": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t29"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:t28": [{"range": {"value": [["1", "4294967"]]}, "name": "http://tail-f.com/ns/ncs:t28"}, {"name": "uint32"}], "http://tail-f.com/ns/ncs:node-name": [{"name": "http://tail-f.com/ns/ncs:node-name"}, {"max-length": {"value": 253}, "min-length": {"value": 1}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:domain-name", "pattern": {"value": "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."}}, {"name": "string"}], "http://tail-f.com/ns/ncs:t74": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t74"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t72": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t72"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t70": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t70"}], "leaf_type": [{"name": "string"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number": [{"range": {"value": [["0", "65535"]]}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number"}, {"name": "uint16"}], "http://tail-f.com/ns/ncs:t56": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t56"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:t58": [{"list_type": [{"leaf-list": true, "name": "http://tail-f.com/ns/ncs:t58"}], "leaf_type": [{"name": "string"}]}]}, "keypath": "/ncs:devices"}, "data": {"info": {"string": "The managed devices and device communication settings"}, "kind": "container", "mandatory": true, "name": "devices", "contains_when_statement": true, "qname": "ncs:devices", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "children": [{"info": {"string": "Global settings for all managed devices."}, "kind": "container", "mandatory": true, "name": "global-settings", "qname": "ncs:global-settings", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Device profile parameters"}, "kind": "container", "mandatory": true, "name": "profiles", "qname": "ncs:profiles", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Authentication for managed devices"}, "kind": "container", "mandatory": true, "name": "authgroups", "qname": "ncs:authgroups", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Named configuration templates for devices"}, "kind": "list", "min_elements": 0, "name": "template", "max_elements": "unbounded", "qname": "ncs:template", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "children": [{"info": {"string": "The name of a specific template configuration."}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "This container is augmented with data models from the devices."}, "kind": "container", "mandatory": true, "name": "config", "qname": "ncs:config", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}]}, {"info": {"string": "Groups of devices"}, "kind": "list", "leafref_groups": [["device-name"], ["device-group"], ["member"]], "min_elements": 0, "name": "device-group", "max_elements": "unbounded", "qname": "ncs:device-group", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Physical location of devices in the group"}, "kind": "container", "mandatory": true, "name": "location", "qname": "ncs:location", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Device within group"}, "kind": "leaf-list", "name": "device-name", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t56"}, "qname": "ncs:device-name", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"info": {"string": "Group within group"}, "kind": "leaf-list", "name": "device-group", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t58"}, "qname": "ncs:device-group", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/device-group/name", "is_leafref": true}, {"info": {"string": "Flattened list of all members"}, "kind": "leaf-list", "name": "member", "is_leafref": true, "qname": "ncs:member", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t60"}, "config": false}, {"info": {"string": "RPCs from the device's"}, "kind": "container", "mandatory": true, "name": "rpc", "qname": "ncs:rpc", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "A summary of all active alarms per device group."}, "kind": "container", "mandatory": true, "name": "alarm-summary", "qname": "al:alarm-summary", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Set up sessions to all unlocked devices"}, "kind": "action", "mandatory": true, "name": "connect", "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pushing to the devices"}, "kind": "action", "mandatory": true, "name": "sync-to", "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pulling from the devices"}, "kind": "action", "mandatory": true, "name": "sync-from", "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if NCS and the devices have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Retrieve SSH host keys from all devices"}, "kind": "action", "mandatory": true, "name": "fetch-ssh-host-keys", "qname": "ncs:fetch-ssh-host-keys", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Take a named template and copy it here"}, "kind": "action", "mandatory": true, "name": "apply-template", "leafrefGroups": [["template-name"]], "qname": "ncs:apply-template", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["template-name"]]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["device-name"], ["device-group"], ["member"]]}, {"info": {"string": "A list of named groups of MIBs"}, "kind": "list", "leafref_groups": [["mib-group"]], "min_elements": 0, "name": "mib-group", "max_elements": "unbounded", "qname": "ncs:mib-group", "children": [{"info": {"string": "An arbitrary name of the MIB group."}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "MIB module names or name prefixes"}, "kind": "leaf-list", "name": "mib-module", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t68"}, "qname": "ncs:mib-module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/device-module/mib-module", "is_leafref": true}, {"info": {"string": "A list of MIB groups contained in this MIB group"}, "kind": "leaf-list", "name": "mib-group", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t70"}, "qname": "ncs:mib-group", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/mib-group/name", "is_leafref": true}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["mib-group"]]}, {"info": {"string": "List the devices and supported modules"}, "kind": "list", "min_elements": 0, "name": "device-module", "max_elements": "unbounded", "qname": "ncs:device-module", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "children": [{"info": {"string": "The module name"}, "kind": "key", "mandatory": true, "name": "name", "type": {"primitive": true, "name": "string"}, "qname": "ncs:name", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "The module revision"}, "kind": "leaf-list", "name": "revision", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t72"}, "qname": "ncs:revision", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "The XML namespace uri for the module"}, "kind": "leaf", "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "The names of the devices that support this module"}, "kind": "leaf-list", "name": "devices", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t74"}, "qname": "ncs:devices", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}, {"info": {"string": "The list of managed devices"}, "kind": "list", "leafref_groups": [["remote-node"], ["authgroup"], ["device-profile"]], "min_elements": 0, "name": "device", "max_elements": "unbounded", "qname": "ncs:device", "children": [{"info": {"string": "A string uniquely identifying the managed device"}, "kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP address or host name for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Name of remote node which connects to device"}, "kind": "leaf", "name": "remote-node", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "node-name"}, "qname": "ncs:remote-node", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:cluster/remote-node/name", "is_leafref": true}, {"info": {"string": "SSH connection configuration"}, "kind": "container", "mandatory": true, "name": "ssh", "qname": "ncs:ssh", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Free form textual description"}, "kind": "leaf", "name": "description", "qname": "ncs:description", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Physical location of devices in the group"}, "kind": "container", "mandatory": true, "name": "location", "qname": "ncs:location", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "name": "device-profile", "type": {"primitive": true, "name": "string"}, "qname": "ncs:device-profile", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/profiles/profile/name", "is_leafref": true}, {"info": {"string": "Timeout in seconds for new connections"}, "kind": "leaf", "name": "connect-timeout", "qname": "ncs:connect-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t27"}}, {"info": {"string": "Timeout in seconds used when reading data"}, "kind": "leaf", "name": "read-timeout", "qname": "ncs:read-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t28"}}, {"info": {"string": "Timeout in seconds used when writing data"}, "kind": "leaf", "name": "write-timeout", "qname": "ncs:write-timeout", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "units": "seconds", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t29"}}, {"info": {"string": "Controls SSH keep alive settings"}, "kind": "container", "mandatory": true, "name": "ssh-keep-alive", "qname": "ncs:ssh-keep-alive", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Trace the southbound communication to devices"}, "kind": "leaf", "name": "trace", "qname": "ncs:trace", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "trace-flag"}}, {"info": {"string": "Control which device capabilities NCS uses"}, "kind": "container", "mandatory": true, "name": "ned-settings", "qname": "ncs:ned-settings", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for the commit-queue"}, "kind": "container", "mandatory": true, "name": "commit-queue", "qname": "ncs:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control how sessions to related devices can be pooled."}, "kind": "container", "mandatory": true, "name": "session-pool", "qname": "ncs:session-pool", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Control settings for no-overwrite sync check"}, "kind": "container", "mandatory": true, "name": "no-overwrite", "qname": "ncs:no-overwrite", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Specifies the behaviour of a commit operation involving a\ndevice that is out of sync with NCS. Value accept assumes that\nthe device's sync state is unknown and it is cleared on commit.\nThe default behaviour is to reject such commits."}, "kind": "leaf", "name": "out-of-sync-commit-behaviour", "qname": "ncs:out-of-sync-commit-behaviour", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t40"}}, {"default": "use-lsa", "kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"info": {"string": "Handle the LSA nodes as such. This is the default"}, "kind": "leaf", "name": "use-lsa", "qname": "ncs:use-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"info": {"string": "Do not handle any of the LSA nodes as such. These nodes\nwill be handled as any other device. This has the same\nresult as adding the commit flag 'no-lsa' to every commit."}, "kind": "leaf", "name": "no-lsa", "qname": "ncs:no-lsa", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"info": {"string": "Show all active settings for the device"}, "kind": "container", "mandatory": true, "name": "active-settings", "qname": "ncs:active-settings", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Additional protocols for the live-tree (read-only)"}, "kind": "list", "leafref_groups": [["authgroup"]], "min_elements": 0, "name": "live-status-protocol", "max_elements": "unbounded", "qname": "ncs:live-status-protocol", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "IP Address for the management interface"}, "kind": "leaf", "name": "address", "qname": "ncs:address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Port for the management interface"}, "kind": "leaf", "name": "port", "qname": "ncs:port", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "SSH host key configuration"}, "kind": "container", "name": "ssh", "presence": true, "qname": "ncs:ssh", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "Authentication credentials for the device"}, "kind": "leaf", "name": "authgroup", "type": {"primitive": true, "name": "string"}, "qname": "ncs:authgroup", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/ncs:devices/authgroups/group/name", "is_leafref": true}, {"info": {"string": "Management protocol for the device"}, "kind": "container", "mandatory": true, "name": "device-type", "qname": "ncs:device-type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Operational State for the live protocol"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "List of capabillities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"info": {"string": "Capability URI"}, "kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Capability revision"}, "kind": "leaf", "name": "revision", "type": {"primitive": true, "name": "string"}, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability module"}, "kind": "leaf", "name": "module", "type": {"primitive": true, "name": "string"}, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability features"}, "kind": "leaf-list", "name": "feature", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t83"}, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Capability deviations"}, "kind": "leaf-list", "name": "deviation", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t85"}, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["authgroup"]]}, {"info": {"string": "Show states for the device"}, "kind": "container", "mandatory": true, "name": "state", "qname": "ncs:state", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "How the device was added to NCS"}, "kind": "container", "mandatory": true, "name": "source", "qname": "ncs:source", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "A list of capabilities supported by the device"}, "kind": "list", "min_elements": 0, "name": "capability", "max_elements": "unbounded", "qname": "ncs:capability", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["uri"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "uri", "type": {"primitive": true, "name": "string"}, "qname": "ncs:uri", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "name": "module", "config": false, "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t43"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t45"}}, {"info": {"string": "This action removes a capability from the list of capabilities.\nIf leaf module is set then corresponding module is attempted to\nbe removed from the list of modules for this device. This action\nis only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "remove", "qname": "ncs:remove", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}, {"info": {"string": "This is a list of the YANG modules supported by the device.\n\nThis list is populated the first time NCS connects to the\ndevice."}, "kind": "list", "min_elements": 0, "name": "module", "max_elements": "unbounded", "qname": "ncs:module", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "name", "type": {"primitive": true, "name": "string"}, "qname": "ncs:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "revision", "config": false, "qname": "ncs:revision", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf-list", "name": "feature", "config": false, "qname": "ncs:feature", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t47"}}, {"kind": "leaf-list", "name": "deviation", "config": false, "qname": "ncs:deviation", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t49"}}]}, {"info": {"string": "Contains vendor-specific information for\nidentifying the system platform.\n\nNEDs MAY augment this container with more device-specific\nnodes."}, "kind": "container", "mandatory": true, "name": "platform", "qname": "ncs:platform", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "NCS copy of the device configuration"}, "kind": "container", "mandatory": true, "name": "config", "qname": "ncs:config", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Status data fetched from the device"}, "kind": "container", "mandatory": true, "name": "live-status", "qname": "ncs:live-status", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "RPCs from the device"}, "kind": "container", "mandatory": true, "name": "rpc", "qname": "ncs:rpc", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "NETCONF notifications from the device"}, "kind": "container", "mandatory": true, "name": "netconf-notifications", "qname": "ncs:netconf-notifications", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}}, {"info": {"string": "Show services that use this device"}, "kind": "leaf-list", "name": "service-list", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "t101"}, "qname": "ncs:service-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Notification address if different from device address"}, "kind": "leaf", "name": "snmp-notification-address", "qname": "ncs:snmp-notification-address", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "host"}}, {"info": {"string": "Device specific information"}, "kind": "container", "name": "platform", "presence": true, "when_targets": ["/ncs:devices/device/device-type/cli/ned-id"], "qname": "alu-meta:platform", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}}, {"info": {"string": "A summary of all active alarms per device."}, "kind": "container", "mandatory": true, "name": "alarm-summary", "qname": "al:alarm-summary", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action copies the list of capabilities and the list of modules\nfrom another device or profile. When used on a device, this action\nis only intended to be used for pre-provisioning: it is not possible\nto override capabilities and modules provided by the\nNED implementation using this action."}, "kind": "action", "mandatory": true, "name": "copy-capabilities", "qname": "ncs:copy-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Note: this action overwrites existing list of capabilities.\n\nThis action populates the list of capabilities based on the\nconfigured ned-id for this device, if possible. NCS will look up\nthe package corresponding to the ned-id and add all the modules\nfrom this packages to the list of this device's capabilities and\nlist of modules. It is the responsibility of the caller to verify\nthat the automatically populated list of capabilities matches actual\ndevice's capabilities. The list of capabilities can then be\nfine-tuned using add-capability and capability/remove actions.\nCurrently this approach will only work for CLI and generic devices.\nThis action is only intended to be used for pre-provisioning:\nit is not possible to override capabilities and modules provided\nby the NED implementation using this action."}, "kind": "action", "mandatory": true, "name": "find-capabilities", "qname": "ncs:find-capabilities", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "This action adds a capability to the list of capabilities.\nIf uri is specified, then it is parsed as YANG capability string\nand module, revision, feature and deviation parameters are derived\nfrom the string. If module is specified, then the namespace is\nlooked up in the list of loaded namespaces and capability string\nconstructed automatically. If the module is specified and the\nattempt to look it up failed, then the action does nothing.\nIf module is specified or can be derived from capability string,\nthen the module is also added/replaced in the list of modules. This\naction is only intended to be used for pre-provisioning: it is not\npossible to override capabilities and modules provided by the NED\nimplementation using this action."}, "kind": "action", "mandatory": true, "name": "add-capability", "qname": "ncs:add-capability", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Take a named template and copy it here"}, "kind": "action", "mandatory": true, "name": "apply-template", "leafrefGroups": [["template-name"]], "qname": "ncs:apply-template", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["template-name"]]}, {"info": {"string": "Instantiate the config for the device from existing device"}, "kind": "action", "mandatory": true, "name": "instantiate-from-other-device", "leafrefGroups": [["device-name"]], "qname": "ncs:instantiate-from-other-device", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device-name"]]}, {"info": {"string": "Compare the actual device config with the NCS copy"}, "kind": "action", "mandatory": true, "name": "compare-config", "qname": "ncs:compare-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pulling from the device"}, "kind": "action", "mandatory": true, "name": "sync-from", "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize the config by pushing to the device"}, "kind": "action", "mandatory": true, "name": "sync-to", "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if NCS and the device have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Connect to the device"}, "kind": "action", "mandatory": true, "name": "connect", "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Close all sessions to the device"}, "kind": "action", "mandatory": true, "name": "disconnect", "qname": "ncs:disconnect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "ICMP ping the device"}, "kind": "action", "mandatory": true, "name": "ping", "qname": "ncs:ping", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Delete the config in NCS without deleting it in the device"}, "kind": "action", "mandatory": true, "name": "delete-config", "qname": "ncs:delete-config", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-to", "qname": "ncs:scp-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Secure copy file to the device"}, "kind": "action", "mandatory": true, "name": "scp-from", "qname": "ncs:scp-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["remote-node"], ["authgroup"], ["device-profile"]]}, {"info": {"string": "List of queued and completed commits"}, "kind": "container", "mandatory": true, "name": "commit-queue", "qname": "ncs:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "List of pooled NED sessions"}, "kind": "container", "mandatory": true, "name": "session-pool", "qname": "ncs:session-pool", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"info": {"string": "Set up sessions to all unlocked devices"}, "kind": "action", "mandatory": true, "name": "connect", "leafrefGroups": [["device"]], "qname": "ncs:connect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Synchronize the config by pushing to the devices"}, "kind": "action", "mandatory": true, "name": "sync-to", "leafrefGroups": [["device"]], "qname": "ncs:sync-to", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Synchronize the config by pulling from the devices"}, "kind": "action", "mandatory": true, "name": "sync-from", "leafrefGroups": [["device"]], "qname": "ncs:sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Close all sessions to all devices"}, "kind": "action", "mandatory": true, "name": "disconnect", "qname": "ncs:disconnect", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if the NCS config is in sync with the device"}, "kind": "action", "mandatory": true, "name": "check-sync", "leafrefGroups": [["device"]], "qname": "ncs:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Check if NCS and the devices have compatible YANG modules"}, "kind": "action", "mandatory": true, "name": "check-yang-modules", "leafrefGroups": [["device"]], "qname": "ncs:check-yang-modules", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Retrieve SSH host keys from all devices"}, "kind": "action", "mandatory": true, "name": "fetch-ssh-host-keys", "leafrefGroups": [["device"]], "qname": "ncs:fetch-ssh-host-keys", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "leafref_groups": [["device"]]}, {"info": {"string": "Clear all trace files"}, "kind": "action", "mandatory": true, "name": "clear-trace", "qname": "ncs:clear-trace", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Synchronize parts of the devices' configuration by pulling from\nthe network."}, "kind": "action", "mandatory": true, "name": "partial-sync-from", "qname": "ncs:partial-sync-from", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json
new file mode 100644
index 00000000..0330aeb9
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_endpoint_schema.json
@@ -0,0 +1 @@
+{"meta": {"prefix": "l3vpn", "namespace": "http://com/example/l3vpn", "types": {}, "keypath": "/l3vpn:vpn/l3vpn/endpoint"}, "data": {"kind": "list", "leafref_groups": [["ce-device"]], "min_elements": 0, "name": "endpoint", "max_elements": "unbounded", "qname": "l3vpn:endpoint", "children": [{"info": {"string": "Endpoint identifier"}, "kind": "key", "mandatory": true, "name": "id", "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ce-device", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:ce-device", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"kind": "leaf", "mandatory": true, "name": "ce-interface", "qname": "l3vpn:ce-interface", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ip-network", "qname": "l3vpn:ip-network", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "ip-prefix"}}, {"info": {"string": "Bandwidth in bps"}, "kind": "leaf", "mandatory": true, "name": "bandwidth", "qname": "l3vpn:bandwidth", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"info": {"string": "CE Router as-number"}, "kind": "leaf", "name": "as-number", "qname": "l3vpn:as-number", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "uint32"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["id"], "mandatory": true, "leafrefGroups": [["ce-device"]]}}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json
new file mode 100644
index 00000000..2737e7a5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_l3vpn_schema.json
@@ -0,0 +1 @@
+{"meta": {"prefix": "l3vpn", "namespace": "http://com/example/l3vpn", "types": {"http://com/example/l3vpn:t19": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t19"}], "leaf_type": [{"name": "instance-identifier"}]}], "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number": [{"range": {"value": [["0", "65535"]]}, "name": "urn:ietf:params:xml:ns:yang:ietf-inet-types:port-number"}, {"name": "uint16"}], "http://tail-f.com/ns/ncs:outformat-deep-check-sync": [{"name": "http://tail-f.com/ns/ncs:outformat-deep-check-sync", "enumeration": [{"info": "The CLI config that would have to be applied\nto the device(s) in order for the service to\nbecome in sync with the network.", "label": "cli"}, {"info": "The XML (NETCONF format) that would have to be\napplied to the device(s) in order for the service to\nbecome in sync with the network.", "label": "xml"}, {"info": "Returns if the service is in sync or not.", "label": "boolean"}]}, {"name": "string"}], "http://com/example/l3vpn:t21": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t21"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:t15": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t15"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:protocol-type": [{"name": "http://com/example/l3vpn:protocol-type", "enumeration": [{"label": "icmp"}, {"label": "igmp"}, {"label": "ipip"}, {"label": "tcp"}, {"label": "egp"}, {"label": "udp"}, {"label": "rsvp"}, {"label": "gre"}, {"label": "esp"}, {"label": "ah"}, {"label": "icmp6"}, {"label": "ospf"}, {"label": "pim"}, {"label": "sctp"}]}, {"name": "string"}], "http://com/example/l3vpn:t17": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t17"}], "leaf_type": [{"name": "instance-identifier"}]}], "http://com/example/l3vpn:t23": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t23"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:t11": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t11"}], "leaf_type": [{"name": "instance-identifier"}]}], "http://com/example/l3vpn:t13": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t13"}], "leaf_type": [{"name": "instance-identifier"}]}], "http://com/example/l3vpn:t24": [{"name": "http://com/example/l3vpn:t24", "enumeration": [{"label": "waiting"}, {"label": "executing"}, {"label": "blocking"}, {"label": "blocked"}, {"label": "failed"}, {"label": "admin-cleared"}, {"label": "commit-queue-failed"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:log-entry-t": [{"info": "This leaf identifies the specific log entry.", "name": "http://tail-f.com/ns/ncs:log-entry-t", "enumeration": [{"label": "device-modified"}, {"label": "service-modified"}]}, {"name": "identityref"}], "http://com/example/l3vpn:t7": [{"name": "http://com/example/l3vpn:t7", "enumeration": [{"label": "async"}, {"label": "timeout"}, {"label": "deleted"}]}, {"name": "string"}], "http://com/example/l3vpn:qos-match-type": [{"union": [[{"name": "ipv4-address-and-prefix-length"}], [{"name": "http://com/example/l3vpn:t2", "enumeration": [{"label": "any"}]}, {"name": "string"}]]}], "http://com/example/l3vpn:t9": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t9"}], "leaf_type": [{"name": "string"}]}], "http://tail-f.com/ns/ncs:outformat4": [{"name": "http://tail-f.com/ns/ncs:outformat4", "enumeration": [{"info": "NCS CLI curly bracket format.", "label": "cli"}, {"info": "NETCONF XML edit-config format, i.e., the edit-config that\nwould be applied locally (at NCS) to get a config\nthat is equal to that of the managed device.", "label": "xml"}, {"info": "The actual data in native format that would be sent to\nthe device", "label": "native"}, {"label": "boolean"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:log-entry-level-t": [{"info": "Levels used for identifying the severity of an event.\nLevels are organized from least specific to most where\n'all' is least specific and 'error' is most specific.", "name": "http://tail-f.com/ns/ncs:log-entry-level-t", "enumeration": [{"label": "all"}, {"label": "trace"}, {"label": "debug"}, {"label": "info"}, {"label": "warn"}, {"label": "error"}]}, {"name": "string"}], "http://tail-f.com/ns/ncs:outformat2": [{"name": "http://tail-f.com/ns/ncs:outformat2", "enumeration": [{"info": "NCS CLI curly bracket format.", "label": "cli"}, {"info": "NETCONF XML edit-config format, i.e., the edit-config that\nwould be applied locally (at NCS) to get a config\nthat is equal to that of the managed device.", "label": "xml"}]}, {"name": "string"}]}, "keypath": "/l3vpn:vpn/l3vpn"}, "data": {"kind": "list", "leafref_groups": [["used-by-customer-service"]], "min_elements": 0, "name": "l3vpn", "max_elements": "unbounded", "qname": "l3vpn:l3vpn", "children": [{"info": {"string": "Unique service id"}, "kind": "key", "mandatory": true, "name": "name", "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Devices and other services this service modified directly or\nindirectly."}, "kind": "container", "mandatory": true, "name": "modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false, "children": [{"info": {"string": "Devices this service modified directly or indirectly"}, "kind": "leaf-list", "name": "devices", "is_leafref": true, "qname": "l3vpn:devices", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"namespace": "http://com/example/l3vpn", "name": "t9"}, "config": false}, {"info": {"string": "Services this service modified directly or indirectly"}, "kind": "leaf-list", "name": "services", "type": {"namespace": "http://com/example/l3vpn", "name": "t11"}, "qname": "l3vpn:services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Services residing on remote LSA nodes this service\nhas modified directly or indirectly."}, "kind": "leaf-list", "name": "lsa-services", "type": {"namespace": "http://com/example/l3vpn", "name": "t13"}, "qname": "l3vpn:lsa-services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}, {"info": {"string": "Devices and other services this service has explicitly\nmodified."}, "kind": "container", "mandatory": true, "name": "directly-modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:directly-modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false, "children": [{"info": {"string": "Devices this service has explicitly modified."}, "kind": "leaf-list", "name": "devices", "is_leafref": true, "qname": "l3vpn:devices", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"namespace": "http://com/example/l3vpn", "name": "t15"}, "config": false}, {"info": {"string": "Services this service has explicitly modified."}, "kind": "leaf-list", "name": "services", "type": {"namespace": "http://com/example/l3vpn", "name": "t17"}, "qname": "l3vpn:services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Services residing on remote LSA nodes this service\nhas explicitly modified."}, "kind": "leaf-list", "name": "lsa-services", "type": {"namespace": "http://com/example/l3vpn", "name": "t19"}, "qname": "l3vpn:lsa-services", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}]}, {"info": {"string": "A list of devices this service instance has manipulated"}, "kind": "leaf-list", "name": "device-list", "type": {"namespace": "http://com/example/l3vpn", "name": "t21"}, "qname": "l3vpn:device-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Customer facing services using this service"}, "kind": "leaf-list", "name": "used-by-customer-service", "is_leafref": true, "qname": "l3vpn:used-by-customer-service", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:services/customer-service/object-id", "type": {"namespace": "http://com/example/l3vpn", "name": "t23"}, "config": false}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false, "children": [{"kind": "list", "min_elements": 0, "name": "queue-item", "max_elements": "unbounded", "qname": "l3vpn:queue-item", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["id"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "status", "type": {"namespace": "http://com/example/l3vpn", "name": "t24"}, "qname": "l3vpn:status", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"kind": "list", "leafref_groups": [["name"]], "min_elements": 0, "name": "failed-device", "max_elements": "unbounded", "qname": "l3vpn:failed-device", "children": [{"kind": "key", "mandatory": true, "name": "name", "is_leafref": true, "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_target": "/ncs:devices/device/name", "type": {"primitive": true, "name": "string"}, "config": false}, {"kind": "leaf", "name": "time", "config": false, "qname": "l3vpn:time", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "date-and-time"}}, {"kind": "leaf", "name": "config-data", "is_cli_preformatted": true, "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:config-data", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"kind": "leaf", "name": "error", "config": false, "qname": "l3vpn:error", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["name"], "mandatory": true, "config": false, "leafrefGroups": [["name"]]}, {"access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "kind": "action", "mandatory": true, "name": "admin-clear", "qname": "l3vpn:admin-clear"}, {"access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "kind": "action", "mandatory": true, "name": "delete", "qname": "l3vpn:delete"}]}, {"access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "kind": "action", "mandatory": true, "name": "clear", "qname": "l3vpn:clear"}]}, {"kind": "container", "mandatory": true, "name": "log", "qname": "l3vpn:log", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false, "children": [{"kind": "list", "min_elements": 0, "name": "log-entry", "max_elements": "unbounded", "qname": "l3vpn:log-entry", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "key": ["when"], "mandatory": true, "config": false, "children": [{"kind": "key", "mandatory": true, "name": "when", "type": {"primitive": true, "name": "date-and-time"}, "qname": "l3vpn:when", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "mandatory": true, "name": "type", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "log-entry-t"}, "qname": "l3vpn:type", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "mandatory": true, "name": "level", "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "log-entry-level-t"}, "qname": "l3vpn:level", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "name": "message", "config": false, "qname": "l3vpn:message", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "type": {"primitive": true, "name": "string"}}]}, {"info": {"string": "Remove log entries"}, "kind": "action", "mandatory": true, "name": "purge", "qname": "l3vpn:purge", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}]}, {"kind": "leaf", "mandatory": true, "name": "route-distinguisher", "qname": "l3vpn:route-distinguisher", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"kind": "list", "leafref_groups": [["ce-device"]], "min_elements": 0, "name": "endpoint", "max_elements": "unbounded", "qname": "l3vpn:endpoint", "children": [{"info": {"string": "Endpoint identifier"}, "kind": "key", "mandatory": true, "name": "id", "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ce-device", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:ce-device", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"kind": "leaf", "mandatory": true, "name": "ce-interface", "qname": "l3vpn:ce-interface", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ip-network", "qname": "l3vpn:ip-network", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "ip-prefix"}}, {"info": {"string": "Bandwidth in bps"}, "kind": "leaf", "mandatory": true, "name": "bandwidth", "qname": "l3vpn:bandwidth", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"info": {"string": "CE Router as-number"}, "kind": "leaf", "name": "as-number", "qname": "l3vpn:as-number", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "uint32"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["id"], "mandatory": true, "leafrefGroups": [["ce-device"]]}, {"kind": "container", "mandatory": true, "name": "qos", "leafrefGroups": [["qos-policy"]], "qname": "l3vpn:qos", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_groups": [["qos-policy"]], "children": [{"kind": "leaf", "name": "qos-policy", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:qos-policy", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "leafref_target": "/l3vpn:qos/qos-policy/name", "is_leafref": true}, {"kind": "list", "leafref_groups": [["qos-class"]], "min_elements": 0, "name": "custom-qos-match", "max_elements": "unbounded", "qname": "l3vpn:custom-qos-match", "children": [{"kind": "key", "mandatory": true, "name": "name", "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "qos-class", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:qos-class", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/l3vpn:qos/qos-class/name", "is_leafref": true}, {"access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "kind": "leaf", "type": {"namespace": "http://com/example/l3vpn", "name": "qos-match-type"}, "name": "source-ip", "qname": "l3vpn:source-ip"}, {"access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "kind": "leaf", "type": {"namespace": "http://com/example/l3vpn", "name": "qos-match-type"}, "name": "destination-ip", "qname": "l3vpn:destination-ip"}, {"info": {"string": "Destination IP port"}, "kind": "leaf", "name": "port-start", "qname": "l3vpn:port-start", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Destination IP port"}, "kind": "leaf", "name": "port-end", "qname": "l3vpn:port-end", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", "name": "port-number"}}, {"info": {"string": "Source IP protocol"}, "kind": "leaf", "name": "protocol", "qname": "l3vpn:protocol", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"namespace": "http://com/example/l3vpn", "name": "protocol-type"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["qos-class"]]}]}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "l3vpn:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "is_action_input": true, "name": "outformat", "default": "boolean", "qname": "l3vpn:outformat", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "outformat4"}}, {"default": "deep", "kind": "choice", "cases": [{"kind": "case", "name": "deep", "children": [{"kind": "leaf", "is_action_input": true, "name": "deep", "qname": "l3vpn:deep", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "shallow", "children": [{"kind": "leaf", "is_action_input": true, "name": "shallow", "qname": "l3vpn:shallow", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "depth"}, {"info": {"string": "Return list only contains negatives"}, "kind": "leaf", "is_action_input": true, "name": "suppress-positive-result", "qname": "l3vpn:suppress-positive-result", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "choice", "cases": [{"kind": "case", "name": "in-sync", "children": [{"kind": "leaf", "name": "in-sync", "qname": "l3vpn:in-sync", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "boolean"}, "is_action_output": true}]}, {"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-native", "children": [{"kind": "container", "mandatory": true, "name": "native", "qname": "l3vpn:native", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}]}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "deep-check-sync", "qname": "l3vpn:deep-check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "is_action_input": true, "name": "outformat", "default": "boolean", "qname": "l3vpn:outformat", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "outformat-deep-check-sync"}}, {"info": {"string": "Return list only contains negatives"}, "kind": "leaf", "is_action_input": true, "name": "suppress-positive-result", "qname": "l3vpn:suppress-positive-result", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-sync", "children": [{"kind": "container", "mandatory": true, "name": "sync-result", "qname": "l3vpn:sync-result", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}]}, {"info": {"string": "Run/Dryrun the service logic again"}, "kind": "action", "mandatory": true, "name": "re-deploy", "qname": "l3vpn:re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "container", "is_action_input": true, "name": "dry-run", "presence": true, "qname": "l3vpn:dry-run", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "is_action_input": true, "name": "no-revision-drop", "qname": "l3vpn:no-revision-drop", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "leaf", "is_action_input": true, "name": "no-networking", "qname": "l3vpn:no-networking", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "no-overwrite", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-overwrite", "qname": "l3vpn:no-overwrite", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-out-of-sync-check", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-out-of-sync-check", "qname": "l3vpn:no-out-of-sync-check", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-sync-check"}, {"kind": "container", "is_action_input": true, "name": "commit-queue", "presence": true, "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"default": "deep", "kind": "choice", "cases": [{"kind": "case", "name": "deep", "children": [{"kind": "leaf", "is_action_input": true, "name": "deep", "qname": "l3vpn:deep", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "shallow", "children": [{"kind": "leaf", "is_action_input": true, "name": "shallow", "qname": "l3vpn:shallow", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "depth"}, {"kind": "container", "is_action_input": true, "name": "reconcile", "presence": true, "qname": "l3vpn:reconcile", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-native", "children": [{"kind": "container", "mandatory": true, "name": "native", "qname": "l3vpn:native", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}, {"kind": "leaf", "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "leafref_target": "/ncs:devices/commit-queue/queue-item/id", "is_leafref": true, "is_action_output": true}, {"kind": "leaf", "name": "tag", "qname": "l3vpn:tag", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "string"}, "is_action_output": true}, {"kind": "leaf", "name": "status", "qname": "l3vpn:status", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"namespace": "http://com/example/l3vpn", "name": "t7"}, "is_action_output": true}]}, {"info": {"string": "Reactive redeploy of service logic"}, "kind": "action", "mandatory": true, "name": "reactive-re-deploy", "qname": "l3vpn:reactive-re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "leafref_target": "/ncs:devices/commit-queue/queue-item/id", "is_leafref": true, "is_action_output": true}, {"kind": "leaf", "name": "tag", "qname": "l3vpn:tag", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "string"}, "is_action_output": true}, {"kind": "leaf", "name": "status", "qname": "l3vpn:status", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"namespace": "http://com/example/l3vpn", "name": "t7"}, "is_action_output": true}]}, {"info": {"string": "Touch a service"}, "kind": "action", "mandatory": true, "name": "touch", "qname": "l3vpn:touch", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": []}, {"info": {"string": "Get the data this service created"}, "kind": "action", "mandatory": true, "name": "get-modifications", "qname": "l3vpn:get-modifications", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "leaf", "is_action_input": true, "name": "outformat", "qname": "l3vpn:outformat", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"namespace": "http://tail-f.com/ns/ncs", "name": "outformat2"}}, {"kind": "leaf", "is_action_input": true, "name": "reverse", "qname": "l3vpn:reverse", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"default": "deep", "kind": "choice", "cases": [{"kind": "case", "name": "deep", "children": [{"kind": "leaf", "is_action_input": true, "name": "deep", "qname": "l3vpn:deep", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "shallow", "children": [{"kind": "leaf", "is_action_input": true, "name": "shallow", "qname": "l3vpn:shallow", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "depth"}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}]}, {"info": {"string": "Undo the effects of this service"}, "kind": "action", "mandatory": true, "name": "un-deploy", "qname": "l3vpn:un-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}, "children": [{"kind": "container", "is_action_input": true, "name": "dry-run", "presence": true, "qname": "l3vpn:dry-run", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "leaf", "is_action_input": true, "name": "no-revision-drop", "qname": "l3vpn:no-revision-drop", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "leaf", "is_action_input": true, "name": "no-networking", "qname": "l3vpn:no-networking", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "no-overwrite", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-overwrite", "qname": "l3vpn:no-overwrite", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-out-of-sync-check", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-out-of-sync-check", "qname": "l3vpn:no-out-of-sync-check", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-sync-check"}, {"kind": "container", "is_action_input": true, "name": "commit-queue", "presence": true, "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}}, {"kind": "choice", "cases": [{"kind": "case", "name": "use-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "use-lsa", "qname": "l3vpn:use-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}, {"kind": "case", "name": "no-lsa", "children": [{"kind": "leaf", "is_action_input": true, "name": "no-lsa", "qname": "l3vpn:no-lsa", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}]}], "name": "choice-lsa"}, {"kind": "leaf", "is_action_input": true, "name": "ignore-refcount", "qname": "l3vpn:ignore-refcount", "access": {"read": false, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "empty"}}, {"kind": "choice", "cases": [{"kind": "case", "name": "case-xml", "children": [{"kind": "container", "mandatory": true, "name": "result-xml", "qname": "l3vpn:result-xml", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-cli", "children": [{"kind": "container", "mandatory": true, "name": "cli", "qname": "l3vpn:cli", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}, {"kind": "case", "name": "case-native", "children": [{"kind": "container", "mandatory": true, "name": "native", "qname": "l3vpn:native", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}]}], "name": "outformat"}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "is_action_output": true}, {"kind": "leaf", "name": "id", "type": {"primitive": true, "name": "uint64"}, "qname": "l3vpn:id", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "leafref_target": "/ncs:devices/commit-queue/queue-item/id", "is_leafref": true, "is_action_output": true}, {"kind": "leaf", "name": "tag", "qname": "l3vpn:tag", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"primitive": true, "name": "string"}, "is_action_output": true}, {"kind": "leaf", "name": "status", "qname": "l3vpn:status", "access": {"read": false, "create": false, "execute": false, "update": false, "delete": false}, "type": {"namespace": "http://com/example/l3vpn", "name": "t7"}, "is_action_output": true}]}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["used-by-customer-service"]]}}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_schema.json
new file mode 100644
index 00000000..0e7e3703
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/l3vpn_schema.json
@@ -0,0 +1 @@
+{"meta": {"prefix": "l3vpn", "namespace": "http://com/example/l3vpn", "types": {"http://com/example/l3vpn:t21": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t21"}], "leaf_type": [{"name": "string"}]}], "http://com/example/l3vpn:t23": [{"list_type": [{"leaf-list": true, "name": "http://com/example/l3vpn:t23"}], "leaf_type": [{"name": "string"}]}]}, "keypath": "/l3vpn:vpn"}, "data": {"kind": "container", "mandatory": true, "name": "vpn", "qname": "l3vpn:vpn", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "children": [{"kind": "list", "leafref_groups": [["used-by-customer-service"]], "min_elements": 0, "name": "l3vpn", "max_elements": "unbounded", "qname": "l3vpn:l3vpn", "children": [{"info": {"string": "Unique service id"}, "kind": "key", "mandatory": true, "name": "name", "qname": "l3vpn:name", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"info": {"string": "Devices and other services this service modified directly or\nindirectly."}, "kind": "container", "mandatory": true, "name": "modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false}, {"info": {"string": "Devices and other services this service has explicitly\nmodified."}, "kind": "container", "mandatory": true, "name": "directly-modified", "leafrefGroups": [["devices"]], "qname": "l3vpn:directly-modified", "is_config_false_callpoint": true, "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "leafref_groups": [["devices"]], "config": false}, {"info": {"string": "A list of devices this service instance has manipulated"}, "kind": "leaf-list", "name": "device-list", "type": {"namespace": "http://com/example/l3vpn", "name": "t21"}, "qname": "l3vpn:device-list", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "config": false}, {"info": {"string": "Customer facing services using this service"}, "kind": "leaf-list", "name": "used-by-customer-service", "is_leafref": true, "qname": "l3vpn:used-by-customer-service", "is_config_false_callpoint": true, "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "readonly": true, "leafref_target": "/ncs:services/customer-service/object-id", "type": {"namespace": "http://com/example/l3vpn", "name": "t23"}, "config": false}, {"kind": "container", "mandatory": true, "name": "commit-queue", "qname": "l3vpn:commit-queue", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "container", "mandatory": true, "name": "log", "qname": "l3vpn:log", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "readonly": true, "config": false}, {"kind": "leaf", "mandatory": true, "name": "route-distinguisher", "qname": "l3vpn:route-distinguisher", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"kind": "list", "leafref_groups": [["ce-device"]], "min_elements": 0, "name": "endpoint", "max_elements": "unbounded", "qname": "l3vpn:endpoint", "children": [{"info": {"string": "Endpoint identifier"}, "kind": "key", "mandatory": true, "name": "id", "qname": "l3vpn:id", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ce-device", "type": {"primitive": true, "name": "string"}, "qname": "l3vpn:ce-device", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_target": "/ncs:devices/device/name", "is_leafref": true}, {"kind": "leaf", "mandatory": true, "name": "ce-interface", "qname": "l3vpn:ce-interface", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "string"}}, {"kind": "leaf", "mandatory": true, "name": "ip-network", "qname": "l3vpn:ip-network", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "ip-prefix"}}, {"info": {"string": "Bandwidth in bps"}, "kind": "leaf", "mandatory": true, "name": "bandwidth", "qname": "l3vpn:bandwidth", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "type": {"primitive": true, "name": "uint32"}}, {"info": {"string": "CE Router as-number"}, "kind": "leaf", "name": "as-number", "qname": "l3vpn:as-number", "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "type": {"primitive": true, "name": "uint32"}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["id"], "mandatory": true, "leafrefGroups": [["ce-device"]]}, {"kind": "container", "mandatory": true, "name": "qos", "leafrefGroups": [["qos-policy"]], "qname": "l3vpn:qos", "access": {"read": true, "create": false, "execute": false, "update": true, "delete": false}, "leafref_groups": [["qos-policy"]]}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "check-sync", "qname": "l3vpn:check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Check if device config is according to the service"}, "kind": "action", "mandatory": true, "name": "deep-check-sync", "qname": "l3vpn:deep-check-sync", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Run/Dryrun the service logic again"}, "kind": "action", "mandatory": true, "name": "re-deploy", "qname": "l3vpn:re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Reactive redeploy of service logic"}, "kind": "action", "mandatory": true, "name": "reactive-re-deploy", "qname": "l3vpn:reactive-re-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Touch a service"}, "kind": "action", "mandatory": true, "name": "touch", "qname": "l3vpn:touch", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Get the data this service created"}, "kind": "action", "mandatory": true, "name": "get-modifications", "qname": "l3vpn:get-modifications", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}, {"info": {"string": "Undo the effects of this service"}, "kind": "action", "mandatory": true, "name": "un-deploy", "qname": "l3vpn:un-deploy", "access": {"read": false, "create": false, "execute": true, "update": false, "delete": false}}], "access": {"read": true, "create": true, "execute": false, "update": true, "delete": true}, "key": ["name"], "mandatory": true, "leafrefGroups": [["used-by-customer-service"]]}]}}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/sync_from_schema.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/sync_from_schema.json
new file mode 100644
index 00000000..dc2206d4
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/sync_from_schema.json
@@ -0,0 +1,178 @@
+{
+ "meta": {
+ "prefix": "ncs",
+ "namespace": "http://tail-f.com/ns/ncs",
+ "types": {
+ "http://tail-f.com/ns/ncs:outformat2": [
+ {
+ "name": "http://tail-f.com/ns/ncs:outformat2",
+ "enumeration": [
+ {
+ "info": "NCS CLI curly bracket format.",
+ "label": "cli"
+ },
+ {
+ "info": "NETCONF XML edit-config format, i.e., the edit-config that\nwould be applied locally (at NCS) to get a config\nthat is equal to that of the managed device.",
+ "label": "xml"
+ }
+ ]
+ },
+ {
+ "name": "string"
+ }
+ ]
+ },
+ "keypath": "/ncs:devices/device{ce0}/sync-from"
+ },
+ "data": {
+ "info": {
+ "string": "Synchronize the config by pulling from the device"
+ },
+ "kind": "action",
+ "mandatory": true,
+ "name": "sync-from",
+ "qname": "ncs:sync-from",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": true,
+ "update": false,
+ "delete": false
+ },
+ "children": [
+ {
+ "kind": "container",
+ "is_action_input": true,
+ "name": "dry-run",
+ "presence": true,
+ "qname": "ncs:dry-run",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "children": [
+ {
+ "info": {
+ "string": "Report what would be done towards CDB, without\nactually doing anything."
+ },
+ "kind": "leaf",
+ "is_action_input": true,
+ "name": "outformat",
+ "qname": "ncs:outformat",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": true,
+ "delete": false
+ },
+ "type": {
+ "namespace": "http://tail-f.com/ns/ncs",
+ "name": "outformat2"
+ }
+ }
+ ]
+ },
+ {
+ "kind": "choice",
+ "cases": [
+ {
+ "kind": "case",
+ "name": "result",
+ "children": [
+ {
+ "kind": "leaf",
+ "name": "result",
+ "qname": "ncs:result",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": false,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "boolean"
+ },
+ "is_action_output": true
+ }
+ ]
+ },
+ {
+ "kind": "case",
+ "name": "result-xml",
+ "children": [
+ {
+ "kind": "leaf",
+ "name": "result-xml",
+ "is_cli_preformatted": true,
+ "qname": "ncs:result-xml",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": false,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "is_action_output": true
+ }
+ ]
+ },
+ {
+ "kind": "case",
+ "name": "cli",
+ "children": [
+ {
+ "kind": "leaf",
+ "name": "cli",
+ "is_cli_preformatted": true,
+ "qname": "ncs:cli",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": false,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "is_action_output": true
+ }
+ ]
+ }
+ ],
+ "name": "outformat"
+ },
+ {
+ "info": {
+ "string": "If present, contains additional information about the result."
+ },
+ "kind": "leaf",
+ "name": "info",
+ "qname": "ncs:info",
+ "access": {
+ "read": false,
+ "create": false,
+ "execute": false,
+ "update": false,
+ "delete": false
+ },
+ "type": {
+ "primitive": true,
+ "name": "string"
+ },
+ "is_action_output": true
+ }
+ ]
+ }
+}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/verify_violation_data.json b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/verify_violation_data.json
new file mode 100644
index 00000000..05742c11
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/fixtures/verify_violation_data.json
@@ -0,0 +1,10 @@
+{
+ "tailf-ncs:devices": {
+ "device": [
+ {
+ "name": "ce0",
+ "description": "Example Device"
+ }
+ ]
+ }
+}
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/nso_module.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/nso_module.py
new file mode 100644
index 00000000..87bcb27b
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/nso_module.py
@@ -0,0 +1,132 @@
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import os
+import json
+
+from ansible_collections.cisco.nso.tests.unit.compat import unittest
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible.module_utils import basic
+
+
+fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
+fixture_data = {}
+
+
+def load_fixture(name):
+ path = os.path.join(fixture_path, name)
+ if path not in fixture_data:
+ with open(path) as f:
+ data = json.load(f)
+ fixture_data[path] = data
+ return fixture_data[path]
+
+
+class MockResponse(object):
+ def __init__(self, method, params, code, body, headers=None):
+ if headers is None:
+ headers = {}
+
+ self.method = method
+ self.params = params
+
+ self.code = code
+ self.body = body
+ self.headers = dict(headers)
+
+ def read(self):
+ return self.body
+
+
+def mock_call(calls, url, timeout, validate_certs, data=None, headers=None, method=None):
+ if len(calls) == 0:
+ raise ValueError('no call mock for method {0}({1})'.format(
+ url, data))
+
+ result = calls[0]
+ del calls[0]
+
+ request = json.loads(data)
+ if result.method != request['method']:
+ raise ValueError('expected method {0}({1}), got {2}({3})'.format(
+ result.method, result.params,
+ request['method'], request['params']))
+
+ for key, value in result.params.items():
+ if key not in request['params']:
+ raise ValueError('{0} not in parameters'.format(key))
+ if value != request['params'][key]:
+ raise ValueError('expected {0} to be {1}, got {2}'.format(
+ key, value, request['params'][key]))
+
+ return result
+
+
+class AnsibleExitJson(Exception):
+ pass
+
+
+class AnsibleFailJson(Exception):
+ pass
+
+
+class TestNsoModule(unittest.TestCase):
+
+ def execute_module(self, failed=False, changed=False, **kwargs):
+ if failed:
+ result = self.failed()
+ self.assertTrue(result['failed'], result)
+ else:
+ result = self.changed(changed)
+ self.assertEqual(result['changed'], changed, result)
+
+ for key, value in kwargs.items():
+ if key not in result:
+ self.fail("{0} not in result {1}".format(key, result))
+ self.assertEqual(value, result[key])
+
+ return result
+
+ def failed(self):
+ def fail_json(*args, **kwargs):
+ kwargs['failed'] = True
+ raise AnsibleFailJson(kwargs)
+
+ with patch.object(basic.AnsibleModule, 'fail_json', fail_json):
+ with self.assertRaises(AnsibleFailJson) as exc:
+ self.module.main()
+
+ result = exc.exception.args[0]
+ self.assertTrue(result['failed'], result)
+ return result
+
+ def changed(self, changed=False):
+ def exit_json(*args, **kwargs):
+ if 'changed' not in kwargs:
+ kwargs['changed'] = False
+ raise AnsibleExitJson(kwargs)
+
+ with patch.object(basic.AnsibleModule, 'exit_json', exit_json):
+ with self.assertRaises(AnsibleExitJson) as exc:
+ self.module.main()
+
+ result = exc.exception.args[0]
+ self.assertEqual(result['changed'], changed, result)
+ return result
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_action.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_action.py
new file mode 100644
index 00000000..be93f3b8
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_action.py
@@ -0,0 +1,167 @@
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible_collections.cisco.nso.plugins.modules import nso_action
+from . import nso_module
+from .nso_module import MockResponse
+
+from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args
+
+
+class TestNsoAction(nso_module.TestNsoModule):
+ module = nso_action
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_action_missing(self, open_url_mock):
+ action_input = {}
+ path = '/ncs:devices/device{ce0}/missing'
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': path}, 200, '{"error": {"data": {"param": "path"}, "type": "rpc.method.invalid_params"}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path,
+ 'input': action_input,
+ 'validate_certs': False
+ })
+ self.execute_module(failed=True, msg='NSO get_schema invalid params. path = /ncs:devices/device{ce0}/missing')
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_action_not_action(self, open_url_mock):
+ action_input = {}
+ path = '/ncs:devices/device{ce0}/description'
+ schema = nso_module.load_fixture('description_schema.json')
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path,
+ 'input': action_input,
+ 'validate_certs': False
+ })
+ self.execute_module(failed=True, msg='/ncs:devices/device{ce0}/description is not an action')
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_action_ok(self, open_url_mock):
+ action_input = {}
+ path = '/ncs:devices/device{ce0}/sync-from'
+ output = {"result": True}
+ schema = nso_module.load_fixture('sync_from_schema.json')
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))),
+ MockResponse('run_action', {'path': path, 'params': action_input}, 200, '{"result": {"result": true}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path,
+ 'input': action_input,
+ 'validate_certs': False
+ })
+ self.execute_module(changed=True, output=output)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_action_validate_ok(self, open_url_mock):
+ action_input = {}
+ path = '/test:action'
+ output = {'version': [{'name': 'v1'}, {'name': 'v2'}]}
+ schema = nso_module.load_fixture('complex_schema.json')
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))),
+ MockResponse('run_action', {'path': path, 'params': action_input}, 200,
+ '{"result": {"version": [{"name": "v1"}, {"name": "v2"}]}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path,
+ 'input': action_input,
+ 'output_required': output,
+ 'validate_certs': False
+ })
+ self.execute_module(changed=True, output=output)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_action_validate_failed(self, open_url_mock):
+ action_input = {}
+ path = '/test:action'
+ output_mismatch = {'version': [{'name': 'v1'}, {'name': 'v3'}]}
+ schema = nso_module.load_fixture('complex_schema.json')
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': path}, 200, '{"result": %s}' % (json.dumps(schema, ))),
+ MockResponse('run_action', {'path': path, 'params': action_input}, 200,
+ '{"result": {"version": [{"name": "v1"}, {"name": "v2"}]}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path,
+ 'input': action_input,
+ 'output_required': output_mismatch,
+ 'validate_certs': False
+ })
+ self.execute_module(failed=True, msg="version value mismatch. expected [{'name': 'v1'}, {'name': 'v3'}] got [{'name': 'v1'}, {'name': 'v2'}]")
+
+ self.assertEqual(0, len(calls))
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_config.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_config.py
new file mode 100644
index 00000000..25087e8e
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_config.py
@@ -0,0 +1,138 @@
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible_collections.cisco.nso.plugins.modules import nso_config
+from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args
+from . import nso_module
+from .nso_module import MockResponse
+
+
+class TestNsoConfig(nso_module.TestNsoModule):
+ module = nso_config
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_config_invalid_version_short(self, open_url_mock):
+ self._test_invalid_version(open_url_mock, '3.3')
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_config_invalid_version_long(self, open_url_mock):
+ self._test_invalid_version(open_url_mock, '3.3.2')
+
+ def _test_invalid_version(self, open_url_mock, version):
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "%s"}' % (version, )),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ data = nso_module.load_fixture('config_config.json')
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc', 'data': data,
+ 'validate_certs': False
+ })
+ self.execute_module(failed=True)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_config_valid_version_short(self, open_url_mock):
+ self._test_valid_version(open_url_mock, '4.5')
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_config_valid_version_long(self, open_url_mock):
+ self._test_valid_version(open_url_mock, '4.4.3')
+
+ def _test_valid_version(self, open_url_mock, version):
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "%s"}' % (version, )),
+ MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_trans_changes', {}, 200, '{"result": {"changes": []}}'),
+ MockResponse('delete_trans', {}, 200, '{"result": {}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ data = nso_module.load_fixture('config_empty_data.json')
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc', 'data': data,
+ 'validate_certs': False
+ })
+ self.execute_module(changed=False, changes=[], diffs=[])
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_config_changed(self, open_url_mock):
+ vpn_schema = nso_module.load_fixture('l3vpn_schema.json')
+ l3vpn_schema = nso_module.load_fixture('l3vpn_l3vpn_schema.json')
+ endpoint_schema = nso_module.load_fixture('l3vpn_l3vpn_endpoint_schema.json')
+ changes = nso_module.load_fixture('config_config_changes.json')
+
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.1"}'),
+ MockResponse('get_module_prefix_map', {}, 200, '{"result": {"l3vpn": "l3vpn"}}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': '/l3vpn:vpn'}, 200, '{"result": %s}' % (json.dumps(vpn_schema, ))),
+ MockResponse('get_schema', {'path': '/l3vpn:vpn/l3vpn'}, 200, '{"result": %s}' % (json.dumps(l3vpn_schema, ))),
+ MockResponse('exists', {'path': '/l3vpn:vpn/l3vpn{company}'}, 200, '{"result": {"exists": true}}'),
+ MockResponse('get_schema', {'path': '/l3vpn:vpn/l3vpn/endpoint'}, 200, '{"result": %s}' % (json.dumps(endpoint_schema, ))),
+ MockResponse('exists', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}'}, 200, '{"result": {"exists": false}}'),
+ MockResponse('new_trans', {'mode': 'read_write'}, 200, '{"result": {"th": 2}}'),
+ MockResponse('create', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}'}, 200, '{"result": {}}'),
+ MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/route-distinguisher', 'value': 999}, 200, '{"result": {}}'),
+ MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/as-number', 'value': 65101}, 200, '{"result": {}}'),
+ MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/bandwidth', 'value': 12000000}, 200, '{"result": {}}'),
+ MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-device', 'value': 'ce6'}, 200, '{"result": {}}'),
+ MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-interface',
+ 'value': 'GigabitEthernet0/12'}, 200, '{"result": {}}'),
+ MockResponse('set_value', {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ip-network',
+ 'value': '10.10.1.0/24'}, 200, '{"result": {}}'),
+ MockResponse('get_trans_changes', {}, 200, '{"result": %s}' % (json.dumps(changes), )),
+ MockResponse('validate_commit', {}, 200, '{"result": {}}'),
+ MockResponse('commit', {}, 200, '{"result": {}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ data = nso_module.load_fixture('config_config.json')
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc', 'data': data,
+ 'validate_certs': False
+ })
+ self.execute_module(changed=True, changes=[
+ {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-device', 'type': 'set', 'from': None, 'to': 'ce6'},
+ {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ip-network', 'type': 'set', 'from': None, 'to': '10.10.1.0/24'},
+ {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/as-number', 'type': 'set', 'from': None, 'to': '65101'},
+ {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/ce-interface', 'type': 'set', 'from': None, 'to': 'GigabitEthernet0/12'},
+ {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}/bandwidth', 'type': 'set', 'from': None, 'to': '12000000'},
+ {'path': '/l3vpn:vpn/l3vpn{company}/endpoint{branch-office1}', 'type': 'create'},
+ ], diffs=[])
+
+ self.assertEqual(0, len(calls))
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_query.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_query.py
new file mode 100644
index 00000000..204478fb
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_query.py
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible_collections.cisco.nso.plugins.modules import nso_query
+from . import nso_module
+from .nso_module import MockResponse
+
+from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args
+
+
+class TestNsoQuery(nso_module.TestNsoModule):
+ module = nso_query
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_query(self, open_url_mock):
+ xpath = '/packages/package'
+ fields = ['name', 'package-version']
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('query',
+ {'xpath_expr': xpath, 'selection': fields}, 200,
+ '{"result": {"results": [["test", "1.0"]]}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'xpath': xpath,
+ 'fields': fields,
+ 'validate_certs': False
+ })
+ self.execute_module(changed=False, output=[["test", "1.0"]])
+
+ self.assertEqual(0, len(calls))
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_show.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_show.py
new file mode 100644
index 00000000..2b4e28f5
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_show.py
@@ -0,0 +1,98 @@
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible_collections.cisco.nso.plugins.modules import nso_show
+from . import nso_module
+from .nso_module import MockResponse
+
+from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args
+
+
+class TestNsoShow(nso_module.TestNsoModule):
+ module = nso_show
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_show_missing(self, open_url_mock):
+ path = '/ncs:devices/device{ce0}/missing'
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('show_config',
+ {'path': path, 'result_as': 'json'}, 200,
+ '{"error": {"data": {"param": "path"}, "type": "rpc.method.invalid_params"}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path
+ })
+ self.execute_module(failed=True, msg='NSO show_config invalid params. path = /ncs:devices/device{ce0}/missing')
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_show_config(self, open_url_mock):
+ path = '/ncs:devices/device{ce0}'
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('show_config', {'path': path, 'result_as': 'json'}, 200, '{"result": {"data": {}}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path,
+ 'operational': False
+ })
+ self.execute_module(changed=False, output={"data": {}})
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_show_config_and_oper(self, open_url_mock):
+ path = '/ncs:devices/device{ce0}/sync-from'
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5"}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('show_config', {'path': path, 'result_as': 'json'}, 200, '{"result": {"data": {}}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc',
+ 'path': path,
+ 'operational': True,
+ 'validate_certs': False
+ })
+ self.execute_module(changed=False, output={"data": {}})
+
+ self.assertEqual(0, len(calls))
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_verify.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_verify.py
new file mode 100644
index 00000000..1e485d75
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/test_nso_verify.py
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible_collections.cisco.nso.plugins.modules import nso_verify
+from . import nso_module
+from .nso_module import MockResponse
+
+from ansible_collections.cisco.nso.tests.unit.plugins.modules.utils import set_module_args
+
+
+class TestNsoVerify(nso_module.TestNsoModule):
+ module = nso_verify
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_verify_empty_data(self, open_url_mock):
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.4.3"}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ data = {}
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc', 'data': data
+ })
+ self.execute_module(changed=False)
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_verify_violation(self, open_url_mock):
+ devices_schema = nso_module.load_fixture('devices_schema.json')
+ device_schema = nso_module.load_fixture('device_schema.json')
+ description_schema = nso_module.load_fixture('description_schema.json')
+
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'),
+ MockResponse('get_module_prefix_map', {}, 200, '{"result": {"tailf-ncs": "ncs"}}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': '/ncs:devices'}, 200, '{"result": %s}' % (json.dumps(devices_schema, ))),
+ MockResponse('get_schema', {'path': '/ncs:devices/device'}, 200, '{"result": %s}' % (json.dumps(device_schema, ))),
+ MockResponse('exists', {'path': '/ncs:devices/device{ce0}'}, 200, '{"result": {"exists": true}}'),
+ MockResponse('get_value', {'path': '/ncs:devices/device{ce0}/description'}, 200, '{"result": {"value": "In Violation"}}'),
+ MockResponse('get_schema', {'path': '/ncs:devices/device/description'}, 200, '{"result": %s}' % (json.dumps(description_schema, ))),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ data = nso_module.load_fixture('verify_violation_data.json')
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc', 'data': data
+ })
+ self.execute_module(failed=True, violations=[
+ {'path': '/ncs:devices/device{ce0}/description', 'expected-value': 'Example Device', 'value': 'In Violation'},
+ ])
+
+ self.assertEqual(0, len(calls))
+
+ @patch('ansible_collections.cisco.nso.plugins.module_utils.nso.open_url')
+ def test_nso_verify_ok(self, open_url_mock):
+ devices_schema = nso_module.load_fixture('devices_schema.json')
+ device_schema = nso_module.load_fixture('device_schema.json')
+
+ calls = [
+ MockResponse('login', {}, 200, '{}', {'set-cookie': 'id'}),
+ MockResponse('get_system_setting', {'operation': 'version'}, 200, '{"result": "4.5.0"}'),
+ MockResponse('get_module_prefix_map', {}, 200, '{"result": {"tailf-ncs": "ncs"}}'),
+ MockResponse('new_trans', {'mode': 'read'}, 200, '{"result": {"th": 1}}'),
+ MockResponse('get_schema', {'path': '/ncs:devices'}, 200, '{"result": %s}' % (json.dumps(devices_schema, ))),
+ MockResponse('get_schema', {'path': '/ncs:devices/device'}, 200, '{"result": %s}' % (json.dumps(device_schema, ))),
+ MockResponse('exists', {'path': '/ncs:devices/device{ce0}'}, 200, '{"result": {"exists": true}}'),
+ MockResponse('get_value', {'path': '/ncs:devices/device{ce0}/description'}, 200, '{"result": {"value": "Example Device"}}'),
+ MockResponse('logout', {}, 200, '{"result": {}}'),
+ ]
+ open_url_mock.side_effect = lambda *args, **kwargs: nso_module.mock_call(calls, *args, **kwargs)
+
+ data = nso_module.load_fixture('verify_violation_data.json')
+ set_module_args({
+ 'username': 'user', 'password': 'password',
+ 'url': 'http://localhost:8080/jsonrpc', 'data': data,
+ 'validate_certs': False
+ })
+ self.execute_module(changed=False)
+
+ self.assertEqual(0, len(calls))
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/utils.py b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/utils.py
new file mode 100644
index 00000000..b14efe26
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/plugins/modules/utils.py
@@ -0,0 +1,50 @@
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+import json
+
+from ansible_collections.cisco.nso.tests.unit.compat import unittest
+from ansible_collections.cisco.nso.tests.unit.compat.mock import patch
+from ansible.module_utils import basic
+from ansible.module_utils._text import to_bytes
+
+
+def set_module_args(args):
+ if '_ansible_remote_tmp' not in args:
+ args['_ansible_remote_tmp'] = '/tmp'
+ if '_ansible_keep_remote_files' not in args:
+ args['_ansible_keep_remote_files'] = False
+
+ args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
+ basic._ANSIBLE_ARGS = to_bytes(args)
+
+
+class AnsibleExitJson(Exception):
+ pass
+
+
+class AnsibleFailJson(Exception):
+ pass
+
+
+def exit_json(*args, **kwargs):
+ if 'changed' not in kwargs:
+ kwargs['changed'] = False
+ raise AnsibleExitJson(kwargs)
+
+
+def fail_json(*args, **kwargs):
+ kwargs['failed'] = True
+ raise AnsibleFailJson(kwargs)
+
+
+class ModuleTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json)
+ self.mock_module.start()
+ self.mock_sleep = patch('time.sleep')
+ self.mock_sleep.start()
+ set_module_args({})
+ self.addCleanup(self.mock_module.stop)
+ self.addCleanup(self.mock_sleep.stop)
diff --git a/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/requirements.txt b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/requirements.txt
new file mode 100644
index 00000000..46fbfa46
--- /dev/null
+++ b/collections-debian-merged/ansible_collections/cisco/nso/tests/unit/requirements.txt
@@ -0,0 +1 @@
+unittest2 ; python_version < '2.7'