diff options
Diffstat (limited to 'ansible_collections/cisco/iosxr/tests/unit')
85 files changed, 14865 insertions, 0 deletions
diff --git a/ansible_collections/cisco/iosxr/tests/unit/__init__.py b/ansible_collections/cisco/iosxr/tests/unit/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/__init__.py diff --git a/ansible_collections/cisco/iosxr/tests/unit/compat/__init__.py b/ansible_collections/cisco/iosxr/tests/unit/compat/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/compat/__init__.py diff --git a/ansible_collections/cisco/iosxr/tests/unit/compat/builtins.py b/ansible_collections/cisco/iosxr/tests/unit/compat/builtins.py new file mode 100644 index 00000000..e898a081 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/compat/builtins.py @@ -0,0 +1,35 @@ +# (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/ansible_collections/cisco/iosxr/tests/unit/compat/mock.py b/ansible_collections/cisco/iosxr/tests/unit/compat/mock.py new file mode 100644 index 00000000..e4ce72b3 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/compat/mock.py @@ -0,0 +1,129 @@ +# (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 + +import _io + + +# 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: + 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/ansible_collections/cisco/iosxr/tests/unit/compat/unittest.py b/ansible_collections/cisco/iosxr/tests/unit/compat/unittest.py new file mode 100644 index 00000000..df4266ec --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/compat/unittest.py @@ -0,0 +1,41 @@ +# (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/ansible_collections/cisco/iosxr/tests/unit/mock/__init__.py b/ansible_collections/cisco/iosxr/tests/unit/mock/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/mock/__init__.py diff --git a/ansible_collections/cisco/iosxr/tests/unit/mock/loader.py b/ansible_collections/cisco/iosxr/tests/unit/mock/loader.py new file mode 100644 index 00000000..2b5eb36a --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/mock/loader.py @@ -0,0 +1,117 @@ +# (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.module_utils._text import to_bytes, to_text +from ansible.parsing.dataloader import DataLoader + + +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/ansible_collections/cisco/iosxr/tests/unit/mock/path.py b/ansible_collections/cisco/iosxr/tests/unit/mock/path.py new file mode 100644 index 00000000..0c87896d --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/mock/path.py @@ -0,0 +1,13 @@ +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +from ansible.utils.path import unfrackpath + +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import MagicMock + + +mock_unfrackpath_noop = MagicMock( + spec_set=unfrackpath, + side_effect=lambda x, *args, **kwargs: x, +) diff --git a/ansible_collections/cisco/iosxr/tests/unit/mock/procenv.py b/ansible_collections/cisco/iosxr/tests/unit/mock/procenv.py new file mode 100644 index 00000000..3a4231bd --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/mock/procenv.py @@ -0,0 +1,97 @@ +# (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 json +import sys + +from contextlib import contextmanager +from io import BytesIO, StringIO + +from ansible.module_utils._text import to_bytes +from ansible.module_utils.six import PY3 + +from ansible_collections.cisco.iosxr.tests.unit.compat import unittest + + +@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/ansible_collections/cisco/iosxr/tests/unit/mock/vault_helper.py b/ansible_collections/cisco/iosxr/tests/unit/mock/vault_helper.py new file mode 100644 index 00000000..82d01f5c --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/mock/vault_helper.py @@ -0,0 +1,44 @@ +# 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/ansible_collections/cisco/iosxr/tests/unit/mock/yaml_helper.py b/ansible_collections/cisco/iosxr/tests/unit/mock/yaml_helper.py new file mode 100644 index 00000000..e46d3180 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/mock/yaml_helper.py @@ -0,0 +1,177 @@ +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.dumper import AnsibleDumper +from ansible.parsing.yaml.loader import AnsibleLoader + + +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/ansible_collections/cisco/iosxr/tests/unit/modules/__init__.py b/ansible_collections/cisco/iosxr/tests/unit/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/__init__.py diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/conftest.py b/ansible_collections/cisco/iosxr/tests/unit/modules/conftest.py new file mode 100644 index 00000000..349e71ad --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/conftest.py @@ -0,0 +1,34 @@ +# Copyright (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +import json + +import pytest + +from ansible.module_utils._text import to_bytes +from ansible.module_utils.common._collections_compat import MutableMapping +from ansible.module_utils.six import string_types + + +@pytest.fixture +def patch_ansible_module(request, mocker): + if isinstance(request.param, string_types): + args = request.param + elif isinstance(request.param, MutableMapping): + if "ANSIBLE_MODULE_ARGS" not in request.param: + request.param = {"ANSIBLE_MODULE_ARGS": request.param} + if "_ansible_remote_tmp" not in request.param["ANSIBLE_MODULE_ARGS"]: + request.param["ANSIBLE_MODULE_ARGS"]["_ansible_remote_tmp"] = "/tmp" + if "_ansible_keep_remote_files" not in request.param["ANSIBLE_MODULE_ARGS"]: + request.param["ANSIBLE_MODULE_ARGS"]["_ansible_keep_remote_files"] = False + args = json.dumps(request.param) + else: + raise Exception( + "Malformed data to the patch_ansible_module pytest fixture", + ) + + mocker.patch("ansible.module_utils.basic._ANSIBLE_ARGS", to_bytes(args)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/__init__.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/__init__.py diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/__init__.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/__init__.py diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/__init__.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/__init__.py diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf/iosxr/show_running-config_hostname b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf/iosxr/show_running-config_hostname new file mode 100644 index 00000000..ebc5bf85 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf/iosxr/show_running-config_hostname @@ -0,0 +1 @@ +hostname iosxr01 diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf/iosxr/show_version__utility_head_-n_20 b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf/iosxr/show_version__utility_head_-n_20 new file mode 100644 index 00000000..6922cbbf --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf/iosxr/show_version__utility_head_-n_20 @@ -0,0 +1,17 @@ +Cisco IOS XR Software, Version 6.0.0[Default] +Copyright (c) 2015 by Cisco Systems, Inc. + +ROM: GRUB, Version 1.99(0), DEV RELEASE + +iosxr01 uptime is 11 weeks, 2 days, 5 hours, 48 minutes +System image file is "bootflash:disk0/xrvr-os-mbi-6.0.0/mbixrvr-rp.vm" + +cisco IOS XRv Series (Pentium Celeron Stepping 3) processor with 3169911K bytes of memory. +Pentium Celeron Stepping 3 processor at 3836MHz, Revision 2.174 +IOS XRv Chassis + +1 Management Ethernet +6 GigabitEthernet +97070k bytes of non-volatile configuration memory. +866M bytes of hard disk. +2321392k bytes of disk0: (Sector size 512 bytes). diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf_ncs540/iosxr/show_running-config_hostname b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf_ncs540/iosxr/show_running-config_hostname new file mode 100644 index 00000000..ebc5bf85 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf_ncs540/iosxr/show_running-config_hostname @@ -0,0 +1 @@ +hostname iosxr01 diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf_ncs540/iosxr/show_version__utility_head_-n_20 b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf_ncs540/iosxr/show_version__utility_head_-n_20 new file mode 100644 index 00000000..5aa174c4 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/cliconf_ncs540/iosxr/show_version__utility_head_-n_20 @@ -0,0 +1,15 @@ +Cisco IOS XR Software, Version 7.5.2 LNT +Copyright (c) 2013-2022 by Cisco Systems, Inc. + +Build Information: + Built By : ingunawa + Built On : Tue Apr 26 23:47:22 UTC 2022 + Build Host : iox-lnx-023 + Workspace : /auto/srcarchive14/prod/7.5.2/ncs540l-aarch64/ws + Version : 7.5.2 + Label : 7.5.2 + +cisco NCS540L +cisco N540X-6Z18G-SYS-A processor with 8GB of memory +iosxr01 uptime is 5 days, 1 hour, 45 minutes +Cisco NCS 540 Series Fixed Router 18x1G, 6x1/10G, AC diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/dir_7all b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/dir_7all new file mode 100644 index 00000000..b992498c --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/dir_7all @@ -0,0 +1,6 @@ +Directory of disk0: +file1 +file2 + +Directory of flash0: +file3 diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_acl_interfaces_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_acl_interfaces_config.cfg new file mode 100644 index 00000000..6a05274a --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_acl_interfaces_config.cfg @@ -0,0 +1,11 @@ +interface GigabitEthernet0/0/0/0 + shutdown + ipv4 access-group acl_1 ingress + ipv4 access-group acl_2 egress + ipv6 access-group acl6_1 ingress + ipv6 access-group acl6_2 egress +! +interface GigabitEthernet0/0/0/1 + shutdown + ipv4 access-group acl_1 egress +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_acls_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_acls_config.cfg new file mode 100644 index 00000000..f5d1708c --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_acls_config.cfg @@ -0,0 +1,8 @@ +ipv4 access-list acl_2 + 10 deny ipv4 any any + 20 permit tcp host 192.168.1.100 any +ipv4 access-list acl_1 + 10 deny ipv4 10.233.0.0 0.0.255.255 net-group netgroup1 + 20 deny ipv4 10.233.0.0 0.0.255.255 port-group portgroup1 +ipv6 access-list acl6_1 + 10 deny icmpv6 any any diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_banner_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_banner_config.cfg new file mode 100644 index 00000000..ed8e6d6d --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_banner_config.cfg @@ -0,0 +1,2 @@ +banner motd this is my motd banner +banner login this is my login banner diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_config_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_config_config.cfg new file mode 100644 index 00000000..afad9d08 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_config_config.cfg @@ -0,0 +1,12 @@ +! +hostname router +! +interface GigabitEthernet0/0 + ip address 1.2.3.4 255.255.255.0 + description test string +! +interface GigabitEthernet0/1 + ip address 6.7.8.9 255.255.255.0 + description test string + shutdown +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_config_src.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_config_src.cfg new file mode 100644 index 00000000..b3d8961a --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_config_src.cfg @@ -0,0 +1,11 @@ +! +hostname foo +! +interface GigabitEthernet0/0 + no ip address +! +interface GigabitEthernet0/1 + ip address 6.7.8.9 255.255.255.0 + description test string + shutdown +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_interface_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_interface_config.cfg new file mode 100644 index 00000000..700dde0a --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_interface_config.cfg @@ -0,0 +1,9 @@ +interface GigabitEthernet0/0/0/0 + description Configured and Merged by Ansible-Network + mtu 110 + duplex half +interface GigabitEthernet0/0/0/1 + description Configured and Merged by Ansible-Network + no shutdown + mtu 2800 + speed 100 diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_l2_interface_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_l2_interface_config.cfg new file mode 100644 index 00000000..4192ee39 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_l2_interface_config.cfg @@ -0,0 +1,9 @@ +interface GigabitEthernet0/0/0/1 + l2transport + l2protocol cpsv tunnel + propagate remote-status + ! +! +interface GigabitEthernet0/0/0/3.900 + encapsulation dot1q 20 second-dot1q 40 +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_l3_interface_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_l3_interface_config.cfg new file mode 100644 index 00000000..d870f4e8 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_l3_interface_config.cfg @@ -0,0 +1,6 @@ +interface GigabitEthernet0/0/0/0 +ipv4 address 198.51.100.1 255.255.255.0 +ipv6 address 2001:db8::/32 +interface GigabitEthernet0/0/0/1 +ipv4 address 192.0.2.1 255.255.255.0 +ipv4 address 192.0.2.2 255.255.255.0 secondary diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lacp_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lacp_config.cfg new file mode 100644 index 00000000..01776dbe --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lacp_config.cfg @@ -0,0 +1,2 @@ +lacp system mac 00c1.4c00.bd15 +lacp system priority 12 diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lacp_interfaces_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lacp_interfaces_config.cfg new file mode 100644 index 00000000..b38bb39f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lacp_interfaces_config.cfg @@ -0,0 +1,11 @@ +interface Bundle-Ether10 + lacp churn logging actor + lacp switchover suppress-flaps 500 + lacp collector-max-delay 100 +! +interface Bundle-Ether11 + lacp system mac 00c2.4c00.bd15 +! +interface GigabitEthernet0/0/0/1 + lacp period 200 +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lag_interface_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lag_interface_config.cfg new file mode 100644 index 00000000..256d3f23 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lag_interface_config.cfg @@ -0,0 +1,24 @@ +interface Bundle-Ether10 + lacp mode active + bundle maximum-active links 10 + bundle minimum-active links 2 +! +interface Bundle-Ether11 +lacp mode active +! +interface GigabitEthernet0/0/0/0 + description "GigabitEthernet - 0" + bundle id 10 mode inherit +! +interface GigabitEthernet0/0/0/1 + description "GigabitEthernet - 2" + bundle id 10 mode passive +! +interface GigabitEthernet0/0/0/8 + description "GigabitEthernet - 8" + bundle id 11 mode passive +! +interface GigabitEthernet0/0/0/9 + description "GigabitEthernet - 9" + bundle id 11 mode passive +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lldp_global_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lldp_global_config.cfg new file mode 100644 index 00000000..4bd23847 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lldp_global_config.cfg @@ -0,0 +1,10 @@ +lldp + timer 3000 + reinit 2 + subinterfaces enable + holdtime 100 + tlv-select + management-address disable + system-description disable + ! +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lldp_interfaces_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lldp_interfaces_config.cfg new file mode 100644 index 00000000..b50b42e5 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_lldp_interfaces_config.cfg @@ -0,0 +1,16 @@ +interface TenGigE0/0/0/0 + ipv4 address 192.0.2.11 255.255.255.192 +! +interface preconfigure GigabitEthernet0/0/0/0 + lldp + transmit disable + destination mac-address + ieee-nearest-bridge + ! + ! +! +interface preconfigure GigabitEthernet0/0/0/1 + lldp + receive disable + destination mac-address + ieee-nearest-non-tmpr-bridge diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospf_interfaces.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospf_interfaces.cfg new file mode 100644 index 00000000..9ddb8d66 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospf_interfaces.cfg @@ -0,0 +1,8 @@ +router ospf LAB3 + area 0.0.0.3 + interface GigabitEthernet0/0/0/0 + cost 20 + authentication message-digest keychain cisco + ! + ! +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospfv2.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospfv2.cfg new file mode 100644 index 00000000..8645482e --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospfv2.cfg @@ -0,0 +1,8 @@ +Sun Jun 14 12:10:47.455 UTC +router ospf 30 + cost 2 + default-metric 10 + area 11 + default-cost 5 + ! +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospfv3.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospfv3.cfg new file mode 100644 index 00000000..b52c0ee0 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_ospfv3.cfg @@ -0,0 +1,8 @@ +Sun Jun 14 12:10:47.455 UTC +router ospfv3 30 + cost 2 + default-metric 10 + area 11 + default-cost 5 + ! +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_static_routes_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_static_routes_config.cfg new file mode 100644 index 00000000..35948336 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_static_routes_config.cfg @@ -0,0 +1,18 @@ +Fri Nov 29 21:10:41.896 UTC +router static + address-family ipv4 unicast + 192.0.2.16/28 FastEthernet0/0/0/1 192.0.2.10 tag 10 description LAB metric 120 + 192.0.2.16/28 FastEthernet0/0/0/5 track ip_sla_1 + 192.0.2.32/28 192.0.2.11 100 + ! + address-family ipv6 unicast + 2001:db8:1000::/36 FastEthernet0/0/0/7 description DC + 2001:db8:1000::/36 FastEthernet0/0/0/8 2001:db8:2000:2::1 + ! + vrf DEV_SITE + address-family ipv4 unicast + 192.0.2.48/28 vrf test_1 192.0.2.12 description DEV + 192.0.2.80/28 vrf test_1 FastEthernet0/0/0/2 192.0.2.14 vrflabel 124 track ip_sla_2 + ! + ! +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_system_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_system_config.cfg new file mode 100644 index 00000000..fc6fd2b7 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_system_config.cfg @@ -0,0 +1,8 @@ +hostname iosxr01 +domain name eng.ansible.com +domain lookup disable +domain lookup source-interface MgmtEth0/0/CPU0/0 +domain list redhat.com +domain list cisco.com +domain name-server 8.8.8.8 +domain name-server 8.8.4.4 diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_user_config.cfg b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_user_config.cfg new file mode 100644 index 00000000..0f0ab168 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/iosxr_user_config.cfg @@ -0,0 +1,8 @@ +username admin + secret 5 $1$mdQIUxjg$3t3lzBpfKfITKvFm1uEIY. + group sysadmin +! +username ansible + secret 5 $1$3yWSXiIi$VdzV59ChiurrNdGxlDeAW/ + group sysadmin +! diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_interfaces b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_interfaces new file mode 100644 index 00000000..edb3c6a0 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_interfaces @@ -0,0 +1,41 @@ +Loopback0 is up, line protocol is up + Interface state transitions: 1 + Hardware is Loopback interface(s) + Description: Loopback + Internet address is 192.168.0.3/32 + MTU 1500 bytes, BW 0 Kbit + reliability Unknown, txload Unknown, rxload Unknown + Encapsulation Loopback, loopback not set, + Last link flapped 12w1d + Last input Unknown, output Unknown + Last clearing of "show interface" counters Unknown + Input/output data rate is disabled. + +GigabitEthernet0/0/0/0 is up, line protocol is up + Interface state transitions: 1 + Hardware is GigabitEthernet, address is fa16.3e6c.20bd (bia fa16.3e6c.20bd) + Description: to nxos01 + Internet address is 10.0.0.5/30 + MTU 1514 bytes, BW 1000000 Kbit (Max: 1000000 Kbit) + reliability 255/255, txload 0/255, rxload 0/255 + Encapsulation ARPA, + Full-duplex, 1000Mb/s, unknown, link type is force-up + output flow control is off, input flow control is off + Carrier delay (up) is 10 msec + loopback not set, + Last link flapped 12w1d + ARP type ARPA, ARP timeout 04:00:00 + Last input 00:00:44, output 00:12:45 + Last clearing of "show interface" counters never + 5 minute input rate 0 bits/sec, 0 packets/sec + 5 minute output rate 0 bits/sec, 0 packets/sec + 150700 packets input, 36897055 bytes, 0 total input drops + 0 drops for unrecognized upper-level protocol + Received 1 broadcast packets, 150445 multicast packets + 0 runts, 0 giants, 0 throttles, 0 parity + 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort + 11691 packets output, 2904632 bytes, 0 total output drops + Output 1 broadcast packets, 11436 multicast packets + 0 output errors, 0 underruns, 0 applique, 0 resets + 0 output buffer failures, 0 output buffers swapped out + 1 carrier transitions diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_ipv6_interface b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_ipv6_interface new file mode 100644 index 00000000..971d1f65 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_ipv6_interface @@ -0,0 +1,5 @@ +Loopback0 is Up, ipv6 protocol is Up, Vrfid is default (0x60000000) + IPv6 is disabled, link-local address unassigned + No global unicast address is configured +GigabitEthernet0/0/0/0 is Up, ipv6 protocol is Up, Vrfid is default (0x60000000) + IPv6 is disabled, link-local address unassigned diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_lldp b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_lldp new file mode 100644 index 00000000..60ab287f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_lldp @@ -0,0 +1 @@ +% LLDP is not enabled diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_lldp_neighbors_detail b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_lldp_neighbors_detail new file mode 100644 index 00000000..60ab287f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_lldp_neighbors_detail @@ -0,0 +1 @@ +% LLDP is not enabled diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_memory_summary b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_memory_summary new file mode 100644 index 00000000..b26abeae --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_memory_summary @@ -0,0 +1,5 @@ +Physical Memory: 3095M total (1499M available) + Application Memory : 2893M (1499M available) + Image: 73M (bootram: 73M) + Reserved: 128M, IOMem: 0, flashfsys: 0 + Total shared window: 23M diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_running-config b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_running-config new file mode 100644 index 00000000..085baef4 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_running-config @@ -0,0 +1,43 @@ +hostname iosxr01 +service timestamps log datetime msec +service timestamps debug datetime msec +telnet vrf default ipv4 server max-servers 10 +telnet vrf Mgmt-intf ipv4 server max-servers 10 +domain name eng.ansible.com +domain lookup disable +vrf Mgmt-intf + address-family ipv4 unicast + ! + address-family ipv6 unicast + ! +! +line template vty + timestamp + exec-timeout 720 0 +! +line console + exec-timeout 0 0 +! +line default + exec-timeout 720 0 +! +vty-pool default 0 50 +control-plane + management-plane + inband + interface all + allow all + ! + ! + ! +! +interface Loopback0 + description Loopback + ipv4 address 192.168.0.1 255.255.255.255 +! +interface GigabitEthernet0/0/0/0 + description to nxos01 + cdp + ipv4 address 10.0.0.1 255.255.255.252 +! +end diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version new file mode 100644 index 00000000..faecfffd --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version @@ -0,0 +1,84 @@ +Cisco IOS XR Software, Version 6.0.0[Default] +Copyright (c) 2015 by Cisco Systems, Inc. + +ROM: GRUB, Version 1.99(0), DEV RELEASE + +iosxr01 uptime is 11 weeks, 2 days, 5 hours, 48 minutes +System image file is "bootflash:disk0/xrvr-os-mbi-6.0.0/mbixrvr-rp.vm" + +cisco IOS XRv Series (Pentium Celeron Stepping 3) processor with 3169911K bytes of memory. +Pentium Celeron Stepping 3 processor at 3836MHz, Revision 2.174 +IOS XRv Chassis + +1 Management Ethernet +6 GigabitEthernet +97070k bytes of non-volatile configuration memory. +866M bytes of hard disk. +2321392k bytes of disk0: (Sector size 512 bytes). + +Configuration register on node 0/0/CPU0 is 0x2102 +Boot device on node 0/0/CPU0 is disk0: +Package active on node 0/0/CPU0: +iosxr-infra, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-infra-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-fwding, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-fwding-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-routing, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-routing-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-ce, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-ce-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +xrvr-os-mbi, V 6.0.0[Default], Cisco Systems, at disk0:xrvr-os-mbi-6.0.0 + Built on Thu Dec 24 08:54:41 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +xrvr-base, V 6.0.0[Default], Cisco Systems, at disk0:xrvr-base-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +xrvr-fwding, V 6.0.0[Default], Cisco Systems, at disk0:xrvr-fwding-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +xrvr-mgbl-x, V 6.0.0[Default], Cisco Systems, at disk0:xrvr-mgbl-x-6.0.0 + Built on Thu Dec 24 08:53:57 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-mpls, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-mpls-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-mgbl, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-mgbl-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-mcast, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-mcast-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +xrvr-mcast-supp, V 6.0.0[Default], Cisco Systems, at disk0:xrvr-mcast-supp-6.0.0 + Built on Thu Dec 24 08:53:49 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-bng, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-bng-6.0.0 + Built on Thu Dec 24 08:53:47 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +xrvr-bng-supp, V 6.0.0[Default], Cisco Systems, at disk0:xrvr-bng-supp-6.0.0 + Built on Thu Dec 24 08:53:47 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +iosxr-security, V 6.0.0[Default], Cisco Systems, at disk0:iosxr-security-6.0.0 + Built on Thu Dec 24 08:53:41 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie + +xrvr-fullk9-x, V 6.0.0[Default], Cisco Systems, at disk0:xrvr-fullk9-x-6.0.0 + Built on Thu Dec 24 08:55:12 UTC 2015 + By iox-lnx-010 in /auto/srcarchive16/production/6.0.0/xrvr/workspace for pie diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version___utility_head_-n_20 b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version___utility_head_-n_20 new file mode 100644 index 00000000..7f82039f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version___utility_head_-n_20 @@ -0,0 +1,18 @@ +Cisco IOS XR Software, Version 6.0.0[Default] +Copyright (c) 2015 by Cisco Systems, Inc. + +ROM: GRUB, Version 1.99(0), DEV RELEASE + +iosxr01 uptime is 11 weeks, 6 days, 2 hours, 2 minutes +System image file is "bootflash:disk0/xrvr-os-mbi-6.0.0/mbixrvr-rp.vm" + +cisco IOS XRv Series (Pentium Celeron Stepping 3) processor with 3169911K bytes +of memory. +Pentium Celeron Stepping 3 processor at 3836MHz, Revision 2.174 +IOS XRv Chassis + +1 Management Ethernet +6 GigabitEthernet +97070k bytes of non-volatile configuration memory. +866M bytes of hard disk. +2321392k bytes of disk0: (Sector size 512 bytes). diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version_brief b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version_brief new file mode 100644 index 00000000..7f82039f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/fixtures/show_version_brief @@ -0,0 +1,18 @@ +Cisco IOS XR Software, Version 6.0.0[Default] +Copyright (c) 2015 by Cisco Systems, Inc. + +ROM: GRUB, Version 1.99(0), DEV RELEASE + +iosxr01 uptime is 11 weeks, 6 days, 2 hours, 2 minutes +System image file is "bootflash:disk0/xrvr-os-mbi-6.0.0/mbixrvr-rp.vm" + +cisco IOS XRv Series (Pentium Celeron Stepping 3) processor with 3169911K bytes +of memory. +Pentium Celeron Stepping 3 processor at 3836MHz, Revision 2.174 +IOS XRv Chassis + +1 Management Ethernet +6 GigabitEthernet +97070k bytes of non-volatile configuration memory. +866M bytes of hard disk. +2321392k bytes of disk0: (Sector size 512 bytes). diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/iosxr_module.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/iosxr_module.py new file mode 100644 index 00000000..1915b07e --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/iosxr_module.py @@ -0,0 +1,108 @@ +# (c) 2016 Red Hat Inc. +# +# 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 json +import os + +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import ( + AnsibleExitJson, + AnsibleFailJson, + ModuleTestCase, +) + + +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 in fixture_data: + return fixture_data[path] + + with open(path) as f: + data = f.read() + + try: + data = json.loads(data) + except Exception: + pass + + fixture_data[path] = data + return data + + +class TestIosxrModule(ModuleTestCase): + def execute_module( + self, + failed=False, + changed=False, + commands=None, + sort=True, + defaults=False, + ): + + self.load_fixtures(commands) + + if failed: + result = self.failed() + self.assertTrue(result["failed"], result) + else: + result = self.changed(changed) + self.assertEqual(result["changed"], changed, result) + + if commands is not None: + if sort: + self.assertEqual( + sorted(commands), + sorted(result["commands"]), + result["commands"], + ) + else: + self.assertEqual( + commands, + result["commands"], + result["commands"], + ) + + return result + + def failed(self): + 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): + with self.assertRaises(AnsibleExitJson) as exc: + self.module.main() + + result = exc.exception.args[0] + self.assertEqual(result["changed"], changed, result) + return result + + def load_fixtures(self, commands=None): + pass diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_hostname.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_hostname.py new file mode 100644 index 00000000..7c676530 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_hostname.py @@ -0,0 +1,114 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_hostname +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrHostnameModule(TestIosxrModule): + module = iosxr_hostname + + def setUp(self): + super(TestIosxrHostnameModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.hostname.hostname." + "HostnameFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrHostnameModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_hostname_merged_idempotent(self): + self.maxDiff = None + run_cfg = dedent( + """\ + hostname iosxr1 + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=dict(hostname="iosxr1"), state="merged")) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_hostname_merged(self): + self.maxDiff = None + set_module_args(dict(config=dict(hostname="iosxr1"), state="merged")) + commands = ["hostname iosxr1"] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_hostname_deleted(self): + self.maxDiff = None + run_cfg = dedent( + """\ + hostname iosxr1 + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(state="deleted")) + commands = ["no hostname iosxr1"] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_hostname_rendered(self): + self.maxDiff = None + set_module_args(dict(config=dict(hostname="iosxr1"), state="rendered")) + commands = ["hostname iosxr1"] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_hostname_gathered(self): + self.maxDiff = None + run_cfg = dedent( + """\ + hostname iosxr1 + """, + ) + self.get_config.return_value = run_cfg + print(self.get_config.return_value) + set_module_args(dict(state="gathered")) + gathered = {"hostname": "iosxr1"} + result = self.execute_module(changed=False) + self.assertEqual(gathered, result["gathered"]) + + def test_iosxr_hostname_parsed(self): + self.maxDiff = None + set_module_args(dict(running_config="hostname iosxr1", state="parsed")) + result = self.execute_module(changed=False) + parsed_list = {"hostname": "iosxr1"} + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr.py new file mode 100644 index 00000000..af2fd3a5 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr.py @@ -0,0 +1,97 @@ +# +# (c) 2020 Red Hat Inc. +# +# 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 os import path + +from ansible.module_utils._text import to_bytes, to_text +from mock import MagicMock + +from ansible_collections.cisco.iosxr.plugins.cliconf import iosxr +from ansible_collections.cisco.iosxr.tests.unit.compat import unittest + + +class TestPluginCLIConfIOSXR(unittest.TestCase): + """Test class for IOSXR CLI Conf Methods""" + + def setUp(self): + self._mock_connection = MagicMock() + self._prepare() + self._cliconf = iosxr.Cliconf(self._mock_connection) + self.maxDiff = None + + def _prepare(self, platform="iosxr"): + b_FIXTURE_DIR = b"%s/fixtures/cliconf/%s" % ( + to_bytes( + path.dirname(path.abspath(__file__)), + errors="surrogate_or_strict", + ), + to_bytes(platform), + ) + + def _connection_side_effect(*args, **kwargs): + try: + if args: + value = args[0] + else: + value = kwargs.get("command") + if b"|" in value: + value = value.replace(b"|", b"") + fixture_path = path.abspath( + b"%s/%s" % (b_FIXTURE_DIR, b"_".join(value.split(b" "))), + ) + with open(fixture_path, "rb") as file_desc: + return to_text(file_desc.read()) + except (OSError, IOError): + if args: + value = args[0] + return value + elif kwargs.get("command"): + value = kwargs.get("command") + return value + return "NO-OP" + + self._mock_connection.send.side_effect = _connection_side_effect + + def tearDown(self): + pass + + def test_get_device_info_iosxr(self): + """Test get_device_info for nxos""" + device_info = self._cliconf.get_device_info() + + mock_device_info = { + "network_os_image": "bootflash:disk0/xrvr-os-mbi-6.0.0/mbixrvr-rp.vm", + "network_os_version": "6.0.0[Default]", + "network_os": "iosxr", + "network_os_hostname": "iosxr01", + "network_os_model": "IOS XRv", + } + + self.assertEqual(device_info, mock_device_info) + + def test_get_command_output_iosxr(self): + """Test _get_command_with_output for iosxr""" + self._prepare() + cmd = self._cliconf.get_command_output("show running-config hostname") + + self.assertEqual(cmd, "hostname iosxr01") diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_acl_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_acl_interfaces.py new file mode 100644 index 00000000..8500c073 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_acl_interfaces.py @@ -0,0 +1,329 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_acl_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrAclInterfacesModule(TestIosxrModule): + module = iosxr_acl_interfaces + + def setUp(self): + super(TestIosxrAclInterfacesModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base.get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.acl_interfaces.acl_interfaces.Acl_interfacesFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrAclInterfacesModule, self).tearDown() + self.get_resource_connection.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_acl_interfaces_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_acl_interfaces_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + access_groups=[ + dict( + afi="ipv4", + acls=[ + dict(name="acl_1", direction="in"), + dict(name="acl_2", direction="out"), + ], + ), + dict( + afi="ipv6", + acls=[ + dict(name="acl6_1", direction="in"), + dict(name="acl6_2", direction="out"), + ], + ), + ], + ), + dict( + name="GigabitEthernet0/0/0/1", + access_groups=[ + dict( + afi="ipv4", + acls=[dict(name="acl_1", direction="out")], + ), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_acl_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + access_groups=[ + dict( + afi="ipv4", + acls=[ + dict(name="acl_1", direction="in"), + dict(name="acl_2", direction="out"), + ], + ), + dict( + afi="ipv6", + acls=[ + dict(name="acl6_1", direction="in"), + dict(name="acl6_2", direction="out"), + ], + ), + ], + ), + dict( + name="GigabitEthernet0/0/0/1", + access_groups=[ + dict( + afi="ipv4", + acls=[dict(name="acl_1", direction="in")], + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "ipv4 access-group acl_1 ingress", + "ipv4 access-group acl_2 egress", + "ipv6 access-group acl6_1 ingress", + "ipv6 access-group acl6_2 egress", + "interface GigabitEthernet0/0/0/1", + "ipv4 access-group acl_1 ingress", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_acl_interfaces_replaced(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + access_groups=[ + dict( + afi="ipv6", + acls=[dict(name="acl6_3", direction="in")], + ), + ], + ), + ], + state="replaced", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "no ipv4 access-group acl_1 ingress", + "no ipv4 access-group acl_2 egress", + "no ipv6 access-group acl6_2 egress", + "ipv6 access-group acl6_3 ingress", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_acl_interfaces_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "no ipv4 access-group acl_1 ingress", + "no ipv4 access-group acl_2 egress", + "no ipv6 access-group acl6_1 ingress", + "no ipv6 access-group acl6_2 egress", + "interface GigabitEthernet0/0/0/1", + "no ipv4 access-group acl_1 egress", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_acl_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + access_groups=[ + dict( + afi="ipv4", + acls=[ + dict(name="acl_1", direction="in"), + dict(name="acl_2", direction="out"), + ], + ), + dict( + afi="ipv6", + acls=[ + dict(name="acl6_1", direction="in"), + dict(name="acl6_2", direction="out"), + ], + ), + ], + ), + dict( + name="GigabitEthernet0/0/0/1", + access_groups=[ + dict( + afi="ipv4", + acls=[dict(name="acl_1", direction="in")], + ), + ], + ), + ], + state="rendered", + ), + ) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "ipv4 access-group acl_1 ingress", + "ipv4 access-group acl_2 egress", + "ipv6 access-group acl6_1 ingress", + "ipv6 access-group acl6_2 egress", + "interface GigabitEthernet0/0/0/1", + "ipv4 access-group acl_1 ingress", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_acl_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="interface GigabitEthernet0/0/0/0\r\n shutdown\r\n ipv4 access-group acl_1 ingress\r\n" + " ipv4 access-group acl_2 egress\r\n ipv6 access-group acl6_1 ingress\r\n ipv6 " + "access-group acl6_2 egress\r\n!\r\ninterface GigabitEthernet0/0/0/1\r\n " + "shutdown\r\n ipv4 access-group acl_1 egress\r\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + print(result["parsed"]) + parsed_list = [ + { + "name": "GigabitEthernet0/0/0/0", + "access_groups": [ + { + "afi": "ipv4", + "acls": [ + {"name": "acl_1", "direction": "in"}, + {"name": "acl_2", "direction": "out"}, + ], + }, + { + "afi": "ipv6", + "acls": [ + {"name": "acl6_1", "direction": "in"}, + {"name": "acl6_2", "direction": "out"}, + ], + }, + ], + }, + { + "name": "GigabitEthernet0/0/0/1", + "access_groups": [ + { + "afi": "ipv4", + "acls": [{"name": "acl_1", "direction": "out"}], + }, + ], + }, + ] + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_acl_interfaces_overridden(self): + self.maxDiff = None + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + access_groups=[ + dict( + afi="ipv6", + acls=[dict(name="acl6_3", direction="in")], + ), + ], + ), + dict( + name="GigabitEthernet0/0/0/1", + access_groups=[ + dict( + afi="ipv4", + acls=[dict(name="acl_2", direction="in")], + ), + dict( + afi="ipv6", + acls=[dict(name="acl6_3", direction="out")], + ), + ], + ), + ], + state="overridden", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "no ipv4 access-group acl_1 ingress", + "no ipv4 access-group acl_2 egress", + "no ipv6 access-group acl6_2 egress", + "ipv6 access-group acl6_3 ingress", + "interface GigabitEthernet0/0/0/1", + "no ipv4 access-group acl_1 egress", + "ipv4 access-group acl_2 ingress", + "ipv6 access-group acl6_3 egress", + ] + + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_acls.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_acls.py new file mode 100644 index 00000000..ed826b93 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_acls.py @@ -0,0 +1,496 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_acls +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrAclsModule(TestIosxrModule): + module = iosxr_acls + + def setUp(self): + super(TestIosxrAclsModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.acls.acls.AclsFacts.get_device_data", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrAclsModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_acls_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_acls_merged(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_1", + aces=[ + dict( + sequence="30", + grant="permit", + protocol="ospf", + source=dict(prefix="192.168.1.0/24"), + destination=dict(any="true"), + log="true", + ), + dict( + sequence="40", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + net_group="netgroup1", + ), + ), + dict( + sequence="50", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + port_group="portgroup1", + ), + ), + ], + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "ipv4 access-list acl_1", + "30 permit ospf 192.168.1.0 0.0.0.255 any log", + "40 deny ipv4 10.233.0.0 0.0.255.255 net-group netgroup1", + "50 deny ipv4 10.233.0.0 0.0.255.255 port-group portgroup1", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_acls_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_2", + aces=[ + dict( + sequence="10", + grant="deny", + protocol="ipv4", + destination=dict(any="true"), + source=dict(any="true"), + ), + ], + ), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_acls_replaced(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_2", + aces=[ + dict( + sequence="30", + grant="permit", + protocol="ospf", + source=dict(prefix="10.0.0.0/8"), + destination=dict(any="true"), + log="true", + ), + dict( + sequence="40", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + net_group="netgroup1", + ), + ), + dict( + sequence="50", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + port_group="portgroup1", + ), + ), + ], + ), + ], + ), + ], + state="replaced", + ), + ) + commands = [ + "ipv4 access-list acl_2", + "no 10", + "no 20", + "30 permit ospf 10.0.0.0 0.255.255.255 any log", + "40 deny ipv4 10.233.0.0 0.0.255.255 net-group netgroup1", + "50 deny ipv4 10.233.0.0 0.0.255.255 port-group portgroup1", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_acls_replaced_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_2", + aces=[ + dict( + sequence="10", + grant="deny", + protocol="ipv4", + destination=dict(any="true"), + source=dict(any="true"), + ), + dict( + sequence="20", + grant="permit", + protocol="tcp", + destination=dict(any="true"), + source=dict(host="192.168.1.100"), + ), + ], + ), + ], + ), + ], + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_acls_overridden(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_2", + aces=[ + dict( + sequence="40", + grant="permit", + protocol="ospf", + source=dict(any="true"), + destination=dict(any="true"), + log="true", + ), + dict( + sequence="50", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + net_group="netgroup1", + ), + ), + dict( + sequence="60", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + port_group="portgroup1", + ), + ), + ], + ), + ], + ), + ], + state="overridden", + ), + ) + commands = [ + "no ipv6 access-list acl6_1", + "no ipv4 access-list acl_1", + "ipv4 access-list acl_2", + "no 10", + "no 20", + "40 permit ospf any any log", + "50 deny ipv4 10.233.0.0 0.0.255.255 net-group netgroup1", + "60 deny ipv4 10.233.0.0 0.0.255.255 port-group portgroup1", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_acls_overridden_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_1", + aces=[ + dict( + sequence="10", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + net_group="netgroup1", + ), + ), + dict( + sequence="20", + grant="deny", + protocol="ipv4", + source=dict( + address="10.233.0.0", + wildcard_bits="0.0.255.255", + ), + destination=dict( + port_group="portgroup1", + ), + ), + ], + ), + dict( + name="acl_2", + aces=[ + dict( + sequence="10", + grant="deny", + protocol="ipv4", + destination=dict(any="true"), + source=dict(any="true"), + ), + dict( + sequence="20", + grant="permit", + protocol="tcp", + destination=dict(any="true"), + source=dict(host="192.168.1.100"), + ), + ], + ), + ], + ), + dict( + afi="ipv6", + acls=[ + dict( + name="acl6_1", + aces=[ + dict( + sequence="10", + grant="deny", + protocol="icmpv6", + destination=dict(any="true"), + source=dict(any="true"), + ), + ], + ), + ], + ), + ], + state="overridden", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_acls_deletedacls(self): + self._prepare() + set_module_args( + dict( + config=[dict(afi="ipv6", acls=[dict(name="acl6_1")])], + state="deleted", + ), + ) + commands = ["no ipv6 access-list acl6_1"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_acls_deletedafis(self): + self._prepare() + set_module_args(dict(config=[dict(afi="ipv4")], state="deleted")) + commands = ["no ipv4 access-list acl_2", "no ipv4 access-list acl_1"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_acls_rendered(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_2", + aces=[ + dict( + grant="permit", + source=dict(any="true"), + destination=dict(any="true"), + protocol="igmp", + ), + ], + ), + ], + ), + ], + state="rendered", + ), + ) + commands = ["ipv4 access-list acl_2", "permit igmp any any"] + result = self.execute_module(changed=False) + self.assertEqual( + sorted(result["rendered"]), + sorted(commands), + result["rendered"], + ) + + def test_iosxr_acls_overridden_on_empty_config(self): + self.execute_show_command.return_value = "" + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + acls=[ + dict( + name="acl_1", + aces=[ + dict( + sequence="10", + grant="deny", + source=dict(any=True), + destination=dict(any=True), + protocol="ip", + ), + ], + ), + ], + ), + ], + state="overridden", + ), + ) + cmds = ["ipv4 access-list acl_1", "10 deny ip any any"] + self.execute_module(changed=True, commands=cmds) + + def test_iosxr_acls_parsed_matches(self): + set_module_args( + dict( + running_config="""ipv4 access-list ACL_NAME\n5 permit ipv4 host x.x.x.x any (409 matches)""", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = [ + { + "acls": [ + { + "name": "ACL_NAME", + "aces": [ + { + "sequence": 5, + "grant": "permit", + "protocol": "ipv4", + "source": {"host": "x.x.x.x"}, + "destination": {"any": True}, + }, + ], + }, + ], + "afi": "ipv4", + }, + ] + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_banner.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_banner.py new file mode 100644 index 00000000..8c426f83 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_banner.py @@ -0,0 +1,117 @@ +# (c) 2021 Red Hat Inc. +# +# 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 +# (c) 2016 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_banner +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrBannerModule(TestIosxrModule): + + module = iosxr_banner + + def setUp(self): + super(TestIosxrBannerModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_banner.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_banner.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_is_cliconf = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_banner.is_cliconf", + ) + self.is_cliconf = self.mock_is_cliconf.start() + + def tearDown(self): + super(TestIosxrBannerModule, self).tearDown() + + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_is_cliconf.stop() + + def load_fixtures(self, commands=None): + self.get_config.return_value = load_fixture("iosxr_banner_config.cfg") + self.load_config.return_value = dict(diff=None, session="session") + self.is_cliconf.return_value = True + + def test_iosxr_banner_login_create(self): + set_module_args(dict(banner="login", text="test\nbanner\nstring")) + commands = ["banner login test\nbanner\nstring"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_banner_login_remove(self): + set_module_args(dict(banner="login", state="absent")) + commands = ["no banner login"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_banner_fail_create(self): + set_module_args(dict(banner="exec1", text="test\nbanner\nstring")) + result = self.execute_module(failed=True, changed=True) + self.assertEqual( + result["msg"], + "value of banner must be one of: login, motd, got: exec1", + ) + + def test_iosxr_banner_exec1_fail_remove(self): + set_module_args(dict(banner="exec1", state="absent")) + result = self.execute_module(failed=True, changed=True) + self.assertIn( + result["msg"], + "value of banner must be one of: login, motd, got: exec1", + ) + + def test_iosxr_banner_motd_create(self): + set_module_args(dict(banner="motd", text="test\nbanner\nstring")) + commands = ["banner motd test\nbanner\nstring"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_banner_motd_remove(self): + set_module_args(dict(banner="motd", state="absent")) + commands = ["no banner motd"] + self.execute_module(changed=True, commands=commands) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_address_family.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_address_family.py new file mode 100644 index 00000000..57770b59 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_address_family.py @@ -0,0 +1,384 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_bgp_address_family +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrBgpGlobalModule(TestIosxrModule): + module = iosxr_bgp_address_family + + def setUp(self): + super(TestIosxrBgpGlobalModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base.get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.bgp_address_family.bgp_address_family.Bgp_address_familyFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrBgpGlobalModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_bgp_address_family_merged_idempotent(self): + run_cfg = dedent( + """\ + router bgp 65536 + address-family ipv4 unicast + bgp attribute-download + advertise best-external + dynamic-med interval 10 + bgp scan-time 20 + redistribute connected metric 10 + redistribute isis test3 metric 4 + redistribute application test1 metric 10 + allocate-label all + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="65536", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + dynamic_med=10, + redistribute=[ + dict( + protocol="application", + id="test1", + metric=10, + ), + dict(protocol="connected", metric=10), + dict(protocol="isis", id="test3", metric=4), + ], + bgp=dict(scan_time=20, attribute_download=True), + advertise_best_external=True, + allocate_label=dict(all=True), + ), + ], + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_bgp_address_family_merged(self): + set_module_args( + dict( + config=dict( + as_number="65536", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + dynamic_med=10, + redistribute=[ + dict( + protocol="application", + id="test1", + metric=10, + ), + dict(protocol="connected", metric=10), + dict(protocol="isis", id="test3", metric=4), + ], + bgp=dict(scan_time=20, attribute_download=True), + advertise_best_external=True, + allocate_label=dict(all=True), + ), + ], + ), + state="merged", + ), + ) + commands = [ + "router bgp 65536", + "address-family ipv4 unicast", + "advertise best-external", + "allocate-label all", + "bgp attribute-download", + "bgp scan-time 20", + "dynamic-med interval 10", + "redistribute application test1 metric 10", + "redistribute connected metric 10", + "redistribute isis test3 metric 4", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_address_family_replaced(self): + run_cfg = dedent( + """\ + router bgp 65536 + address-family ipv4 unicast + bgp attribute-download + advertise best-external + dynamic-med interval 10 + bgp scan-time 20 + redistribute connected metric 10 + redistribute isis test3 metric 4 + redistribute application test1 metric 10 + allocate-label all + address-family ipv4 mvpn + """, + ) + self.get_config.return_value = run_cfg + + set_module_args( + dict( + config=dict( + as_number="65536", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + dynamic_med=4, + redistribute=[ + dict( + protocol="application", + id="test1", + metric=10, + ), + dict(protocol="connected", metric=10), + dict(protocol="isis", id="test3", metric=4), + ], + ), + ], + ), + state="replaced", + ), + ) + commands = [ + "router bgp 65536", + "address-family ipv4 unicast", + "no advertise best-external", + "no allocate-label all", + "no bgp attribute-download", + "no bgp scan-time 20", + "dynamic-med interval 4", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_address_family_replaced_idempotent(self): + run_cfg = dedent( + """\ + router bgp 65536 + address-family ipv4 unicast + dynamic-med interval 4 + redistribute connected metric 10 + redistribute isis test3 metric 4 + redistribute application test1 metric 10 + address-family ipv4 mvpn + """, + ) + self.get_config.return_value = run_cfg + + set_module_args( + dict( + config=dict( + as_number="65536", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + dynamic_med=4, + redistribute=[ + dict( + protocol="application", + id="test1", + metric=10, + ), + dict(protocol="connected", metric=10), + dict(protocol="isis", id="test3", metric=4), + ], + ), + ], + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_bgp_address_family_deleted(self): + run_cfg = dedent( + """\ + router bgp 65536 + address-family ipv4 unicast + bgp attribute-download + advertise best-external + dynamic-med interval 10 + bgp scan-time 20 + redistribute connected metric 10 + redistribute isis test3 metric 4 + redistribute application test1 metric 10 + allocate-label all + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=dict(), state="deleted")) + + commands = ["router bgp 65536", "no address-family ipv4 unicast"] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_address_family_deleted1(self): + run_cfg = dedent( + """\ + router bgp 65536 + address-family ipv6 unicast + dynamic-med interval 4 + address-family ipv4 unicast + bgp attribute-download + advertise best-external + dynamic-med interval 10 + bgp scan-time 20 + redistribute connected metric 10 + redistribute isis test3 metric 4 + redistribute application test1 metric 10 + allocate-label all + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number=65536, + address_family=[ + dict(afi="ipv6", safi="unicast", dynamic_med=4), + ], + ), + state="deleted", + ), + ) + commands = ["router bgp 65536", "no address-family ipv6 unicast"] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_address_family_deleted_idempotent(self): + run_cfg = dedent( + """\ + "router bgp 65536" + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=dict(as_number="65536"), state="deleted")) + + result = self.execute_module(changed=False) + self.assertEqual(result["commands"], []) + + def test_iosxr_bgp_address_family_rendered(self): + set_module_args( + dict( + config=dict( + as_number="65536", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + dynamic_med=10, + redistribute=[ + dict( + protocol="application", + id="test1", + metric=10, + ), + dict(protocol="connected", metric=10), + dict(protocol="isis", id="test3", metric=4), + ], + bgp=dict(scan_time=20, attribute_download=True), + advertise_best_external=True, + allocate_label=dict(all=True), + ), + ], + ), + state="rendered", + ), + ) + commands = [ + "router bgp 65536", + "address-family ipv4 unicast", + "advertise best-external", + "allocate-label all", + "bgp attribute-download", + "bgp scan-time 20", + "dynamic-med interval 10", + "redistribute application test1 metric 10", + "redistribute connected metric 10", + "redistribute isis test3 metric 4", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_bgp_address_family_parsed(self): + self.maxDiff = None + run_cfg = dedent( + """\ + router bgp 65536 + address-family ipv4 unicast + bgp attribute-download + advertise best-external + dynamic-med interval 10 + bgp scan-time 20 + redistribute application test1 metric 10 + allocate-label all + """, + ) + set_module_args(dict(running_config=run_cfg, state="parsed")) + result = self.execute_module(changed=False) + parsed_list = { + "address_family": [ + { + "advertise_best_external": True, + "safi": "unicast", + "afi": "ipv4", + "allocate_label": {"all": True}, + "bgp": {"attribute_download": True, "scan_time": 20}, + "dynamic_med": 10, + "redistribute": [ + { + "protocol": "application", + "metric": 10, + "id": "test1", + }, + ], + }, + ], + "as_number": "65536", + } + + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_global.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_global.py new file mode 100644 index 00000000..05480d09 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_global.py @@ -0,0 +1,493 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_bgp_global +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrBgpGlobalModule(TestIosxrModule): + module = iosxr_bgp_global + + def setUp(self): + super(TestIosxrBgpGlobalModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.bgp_global.bgp_global." + "Bgp_globalFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrBgpGlobalModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_bgp_global_merged_idempotent(self): + run_cfg = dedent( + """\ + router bgp 65536 + bgp confederation identifier 4 + bgp router-id 192.0.2.10 + bgp cluster-id 5 + default-metric 4 + socket send-buffer-size 4098 + bgp bestpath med confed + socket receive-buffer-size 514 + neighbor 192.0.2.11 + remote-as 65537 + cluster-id 3 + neighbor 192.0.2.14 + remote-as 65538 + bfd fast-detect strict-mode + bfd multiplier 6 + bfd minimum-interval 20 + vrf vrf1 + default-metric 5 + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="65536", + default_metric=4, + socket=dict( + receive_buffer_size=514, + send_buffer_size=4098, + ), + bgp=dict( + confederation=dict(identifier=4), + bestpath=dict(med=dict(confed=True)), + cluster_id=5, + router_id="192.0.2.10", + ), + neighbors=[ + dict( + neighbor="192.0.2.11", + cluster_id=3, + remote_as="65537", + ), + dict( + neighbor="192.0.2.14", + remote_as="65538", + bfd=dict( + multiplier=6, + minimum_interval=20, + fast_detect=dict(strict_mode=True), + ), + ), + ], + vrfs=[dict(vrf="vrf1", default_metric=5)], + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_bgp_global_merged(self): + set_module_args( + dict( + config=dict( + as_number="65536", + default_metric=4, + socket=dict( + receive_buffer_size=514, + send_buffer_size=4098, + ), + bgp=dict( + confederation=dict(identifier=4), + bestpath=dict(med=dict(confed=True)), + cluster_id=5, + router_id="192.0.2.10", + ), + neighbors=[ + dict( + neighbor="192.0.2.11", + cluster_id=3, + remote_as="65537", + ), + dict( + neighbor="192.0.2.14", + remote_as="65538", + bfd=dict( + multiplier=6, + minimum_interval=20, + fast_detect=dict(strict_mode=True), + ), + ), + ], + vrfs=[dict(vrf="vrf1", default_metric=5)], + ), + state="merged", + ), + ) + commands = [ + "router bgp 65536", + "bgp cluster-id 5", + "bgp router-id 192.0.2.10", + "bgp bestpath med confed", + "bgp confederation identifier 4", + "default-metric 4", + "socket receive-buffer-size 514", + "socket send-buffer-size 4098", + "neighbor 192.0.2.11", + "cluster-id 3", + "remote-as 65537", + "neighbor 192.0.2.14", + "bfd fast-detect strict-mode", + "bfd minimum-interval 20", + "bfd multiplier 6", + "remote-as 65538", + "vrf vrf1", + "default-metric 5", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_global_replaced(self): + run_cfg = dedent( + """\ + router bgp 65536 + bgp confederation identifier 4 + bgp router-id 192.0.2.10 + bgp cluster-id 5 + default-metric 4 + socket send-buffer-size 4098 + bgp bestpath med confed + socket receive-buffer-size 514 + neighbor 192.0.2.11 + remote-as 65537 + cluster-id 3 + neighbor 192.0.2.14 + remote-as 65538 + bfd fast-detect strict-mode + bfd multiplier 6 + bfd minimum-interval 20 + vrf vrf1 + default-metric 5 + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="65536", + default_metric=5, + socket=dict( + receive_buffer_size=514, + send_buffer_size=4098, + ), + bgp=dict( + confederation=dict(identifier=4), + bestpath=dict(med=dict(confed=True)), + cluster_id=5, + router_id="192.0.2.10", + ), + neighbors=[ + dict( + neighbor="192.0.2.13", + remote_as="65538", + bfd=dict( + multiplier=6, + minimum_interval=20, + fast_detect=dict(strict_mode=True), + ), + ), + ], + vrfs=[dict(vrf="vrf1", default_metric=5)], + ), + state="replaced", + ), + ) + commands = [ + "router bgp 65536", + "no neighbor 192.0.2.11", + "no neighbor 192.0.2.14", + "default-metric 5", + "neighbor 192.0.2.13", + "bfd fast-detect strict-mode", + "bfd minimum-interval 20", + "bfd multiplier 6", + "remote-as 65538", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_global_replaced_idempotent(self): + run_cfg = dedent( + """\ + router bgp 65536 + bgp confederation identifier 4 + bgp router-id 192.0.2.10 + bgp cluster-id 5 + default-metric 4 + socket send-buffer-size 4098 + bgp bestpath med confed + socket receive-buffer-size 514 + neighbor 192.0.2.11 + remote-as 65537 + cluster-id 3 + neighbor 192.0.2.14 + remote-as 65538 + bfd fast-detect strict-mode + bfd multiplier 6 + bfd minimum-interval 20 + vrf vrf1 + default-metric 5 + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="65536", + default_metric=4, + socket=dict( + receive_buffer_size=514, + send_buffer_size=4098, + ), + bgp=dict( + confederation=dict(identifier=4), + bestpath=dict(med=dict(confed=True)), + cluster_id=5, + router_id="192.0.2.10", + ), + neighbors=[ + dict( + neighbor="192.0.2.11", + cluster_id=3, + remote_as="65537", + ), + dict( + neighbor="192.0.2.14", + remote_as="65538", + bfd=dict( + multiplier=6, + minimum_interval=20, + fast_detect=dict(strict_mode=True), + ), + ), + ], + vrfs=[dict(vrf="vrf1", default_metric=5)], + ), + state="replaced", + ), + ) + + self.execute_module(changed=False, commands=[]) + + def test_iosxr_bgp_global_deleted(self): + run_cfg = dedent( + """\ + router bgp 65536 + bgp confederation identifier 4 + bgp router-id 192.0.2.10 + bgp cluster-id 5 + default-metric 4 + socket send-buffer-size 4098 + bgp bestpath med confed + socket receive-buffer-size 514 + neighbor 192.0.2.11 + remote-as 65537 + cluster-id 3 + neighbor 192.0.2.14 + remote-as 65538 + bfd fast-detect strict-mode + bfd multiplier 6 + bfd minimum-interval 20 + vrf vrf1 + default-metric 5 + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=dict(as_number="65536"), state="deleted")) + + commands = [ + "router bgp 65536", + "no bgp cluster-id 5", + "no bgp router-id 192.0.2.10", + "no bgp bestpath med confed", + "no bgp confederation identifier 4", + "no default-metric 4", + "no socket receive-buffer-size 514", + "no socket send-buffer-size 4098", + "no neighbor 192.0.2.11", + "no neighbor 192.0.2.14", + "no vrf vrf1", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_global_deleted_idempotent(self): + run_cfg = dedent( + """\ + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=dict(as_number="65536"), state="deleted")) + + result = self.execute_module(changed=False) + self.assertEqual(result["commands"], []) + + def test_iosxr_bgp_global_rendered(self): + set_module_args( + dict( + config=dict( + as_number="65536", + default_metric=4, + socket=dict( + receive_buffer_size=514, + send_buffer_size=4098, + ), + bgp=dict( + confederation=dict(identifier=4), + bestpath=dict(med=dict(confed=True)), + cluster_id=5, + router_id="192.0.2.10", + ), + neighbors=[ + dict( + neighbor="192.0.2.11", + cluster_id=3, + remote_as="65537", + ), + dict( + neighbor="192.0.2.14", + remote_as="65538", + bfd=dict( + multiplier=6, + minimum_interval=20, + fast_detect=dict(set=True), + ), + ), + ], + vrfs=[dict(vrf="vrf1", default_metric=5)], + ), + state="rendered", + ), + ) + + commands = [ + "router bgp 65536", + "bgp cluster-id 5", + "bgp router-id 192.0.2.10", + "bgp bestpath med confed", + "bgp confederation identifier 4", + "default-metric 4", + "socket receive-buffer-size 514", + "socket send-buffer-size 4098", + "neighbor 192.0.2.11", + "cluster-id 3", + "remote-as 65537", + "neighbor 192.0.2.14", + "bfd fast-detect", + "bfd minimum-interval 20", + "bfd multiplier 6", + "remote-as 65538", + "vrf vrf1", + "default-metric 5", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_bgp_global_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="router bgp 65536\n bgp confederation identifier 4\n " + "bgp router-id 192.0.2.10\n bgp cluster-id 5\n default-metric 4\n " + "socket send-buffer-size 4098\n bgp bestpath med confed\n " + "socket receive-buffer-size 514\n neighbor 192.0.2.11\n remote-as 65537\n " + "cluster-id 3\n !\n neighbor 192.0.2.14\n remote-as 65538\n description test nbr description\n" + " bfd fast-detect strict-mode\n " + " bfd multiplier 6\n bfd minimum-interval 20\n !\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "as_number": "65536", + "bgp": { + "confederation": {"identifier": 4}, + "cluster_id": "5", + "router_id": "192.0.2.10", + "bestpath": {"med": {"confed": True}}, + }, + "default_metric": 4, + "socket": {"send_buffer_size": 4098, "receive_buffer_size": 514}, + "neighbors": [ + {"neighbor_address": "192.0.2.11", "remote_as": 65537, "cluster_id": "3"}, + { + "neighbor_address": "192.0.2.14", + "remote_as": 65538, + "description": "test nbr description", + }, + ], + "bfd": {"multiplier": 6, "minimum_interval": 20}, + } + + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_bgp_global_purged(self): + run_cfg = dedent( + """\ + router bgp 65536 + bgp confederation identifier 4 + bgp router-id 192.0.2.10 + bgp cluster-id 5 + default-metric 4 + socket send-buffer-size 4098 + bgp bestpath med confed + socket receive-buffer-size 514 + neighbor 192.0.2.11 + remote-as 65537 + cluster-id 3 + neighbor 192.0.2.14 + remote-as 65538 + bfd fast-detect strict-mode + bfd multiplier 6 + bfd minimum-interval 20 + vrf vrf1 + default-metric 5 + """, + ) + + self.get_config.return_value = run_cfg + + set_module_args(dict(state="purged")) + commands = ["no router bgp 65536"] + + result = self.execute_module(changed=True) + self.assertEqual(set(result["commands"]), set(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_neighbor_address_family.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_neighbor_address_family.py new file mode 100644 index 00000000..d6fd0610 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_bgp_neighbor_address_family.py @@ -0,0 +1,826 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_bgp_neighbor_address_family +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrBgpNeighborAddressFamilyModule(TestIosxrModule): + module = iosxr_bgp_neighbor_address_family + + def setUp(self): + super(TestIosxrBgpNeighborAddressFamilyModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.bgp_neighbor_address_family.bgp_neighbor_address_family." + "Bgp_neighbor_address_familyFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrBgpNeighborAddressFamilyModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_bgp_nbr_af_merged_idempotent(self): + run_cfg = dedent( + """\ + router bgp 1 + bgp router-id 1.2.3.4 + neighbor 1.1.1.1 + remote-as 5 + address-family ipv4 unicast + origin-as validation disable + bestpath origin-as allow invalid + aigp + aigp send med + send-community-ebgp + multipath + allowas-in 4 + maximum-prefix 10 20 restart 10 + as-override + capability orf prefix both + send-extended-community-ebgp + default-originate + next-hop-self + send-community-gshut-ebgp + soft-reconfiguration inbound + send-multicast-attributes + remove-private-AS inbound entire-aspath + route-policy test1 in + route-policy test1 out + next-hop-unchanged multipath + vrf vrf1 + rd auto + address-family ipv4 unicast + neighbor 1.2.1.2 + remote-as 5 + address-family ipv4 unicast + multipath + capability orf prefix both + default-originate + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="1", + vrfs=[ + dict( + vrf="vrf1", + neighbors=[ + dict( + neighbor_address="1.2.1.2", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + ), + ], + ), + ], + ), + ], + neighbors=[ + dict( + neighbor_address="1.1.1.1", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + send_multicast_attributes=dict(set=True), + soft_reconfiguration=dict(inbound=dict(set=True)), + send_community_gshut_ebgp=dict(set=True), + send_extended_community_ebgp=dict(set=True), + send_community_ebgp=dict(set=True), + origin_as=dict(validation=dict(disable=True)), + remove_private_AS=dict( + set=True, + inbound=True, + entire_aspath=True, + ), + route_policy=dict(inbound="test1", outbound="test1"), + maximum_prefix=dict( + max_limit=10, + threshold_value=20, + restart=10, + ), + next_hop_self=dict(set=True), + next_hop_unchanged=dict(multipath=True), + aigp=dict(set=True, send_med=dict(set=True)), + as_override=dict(set=True), + allowas_in=dict(value=4), + bestpath_origin_as_allow_invalid=True, + long_lived_graceful_restart=dict( + stale_time=dict(send=20, accept=30), + ), + ), + ], + ), + ], + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_bgp_nbr_af_merged(self): + self.maxDiff = None + set_module_args( + dict( + config=dict( + as_number="1", + vrfs=[ + dict( + vrf="vrf1", + neighbors=[ + dict( + neighbor_address="1.2.1.2", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + ), + ], + ), + ], + ), + ], + neighbors=[ + dict( + neighbor_address="1.1.1.1", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + send_multicast_attributes=dict(set=True), + soft_reconfiguration=dict(inbound=dict(set=True)), + send_community_gshut_ebgp=dict(set=True), + send_extended_community_ebgp=dict(set=True), + send_community_ebgp=dict(set=True), + origin_as=dict(validation=dict(disable=True)), + remove_private_AS=dict( + set=True, + inbound=True, + entire_aspath=True, + ), + route_policy=dict(inbound="test1", outbound="test1"), + maximum_prefix=dict( + max_limit=10, + threshold_value=20, + restart=10, + ), + next_hop_self=dict(set=True), + next_hop_unchanged=dict(multipath=True), + aigp=dict(set=True, send_med=dict(set=True)), + as_override=dict(set=True), + bestpath_origin_as_allow_invalid=True, + long_lived_graceful_restart=dict( + stale_time=dict(send=20, accept=30), + ), + ), + ], + ), + ], + ), + state="merged", + ), + ) + commands = [ + "router bgp 1", + "neighbor 1.1.1.1", + "address-family ipv4 unicast", + "aigp", + "aigp send med", + "as-override", + "bestpath origin-as allow invalid", + "capability orf prefix both", + "default-originate", + "maximum-prefix 10 20 restart 10", + "multipath", + "next-hop-self", + "next-hop-unchanged multipath", + "origin-as validation disable", + "remove-private-AS inbound entire-aspath", + "route-policy test1 in", + "route-policy test1 out", + "send-community-ebgp", + "send-community-gshut-ebgp", + "send-extended-community-ebgp", + "send-multicast-attributes", + "soft-reconfiguration inbound", + "vrf vrf1", + "neighbor 1.2.1.2", + "address-family ipv4 unicast", + "capability orf prefix both", + "default-originate", + "multipath", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_nbr_af_replaced(self): + run_cfg = dedent( + """\ + router bgp 1 + bgp router-id 1.2.3.4 + neighbor 1.1.1.1 + remote-as 5 + address-family ipv4 unicast + origin-as validation disable + bestpath origin-as allow invalid + aigp + aigp send med + send-community-ebgp + multipath + allowas-in 4 + maximum-prefix 10 20 restart 10 + as-override + capability orf prefix both + send-extended-community-ebgp + default-originate + next-hop-self + send-community-gshut-ebgp + soft-reconfiguration inbound + send-multicast-attributes + remove-private-AS inbound entire-aspath + next-hop-unchanged multipath + vrf vrf1 + rd auto + address-family ipv4 unicast + neighbor 1.2.1.2 + remote-as 5 + address-family ipv4 unicast + multipath + capability orf prefix both + default-originate + route-policy test2 in + route-policy test2 out + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="1", + vrfs=[ + dict( + vrf="vrf1", + neighbors=[ + dict( + neighbor_address="1.2.1.2", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + route_policy=dict(inbound="test1", outbound="test1"), + ), + ], + ), + ], + ), + ], + ), + state="replaced", + ), + ) + commands = [ + "router bgp 1", + "vrf vrf1", + "neighbor 1.2.1.2", + "address-family ipv4 unicast", + "no capability orf prefix both", + "route-policy test1 in", + "route-policy test1 out", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_nbr_af_replaced_idempotent(self): + run_cfg = dedent( + """\ + router bgp 1 + bgp router-id 1.2.3.4 + neighbor 1.1.1.1 + remote-as 5 + address-family ipv4 unicast + origin-as validation disable + bestpath origin-as allow invalid + aigp + aigp send med + send-community-ebgp + multipath + allowas-in 4 + maximum-prefix 10 20 restart 10 + as-override + capability orf prefix both + send-extended-community-ebgp + default-originate + next-hop-self + send-community-gshut-ebgp + soft-reconfiguration inbound + send-multicast-attributes + remove-private-AS inbound entire-aspath + next-hop-unchanged multipath + vrf vrf1 + rd auto + address-family ipv4 unicast + neighbor 1.2.1.2 + remote-as 5 + address-family ipv4 unicast + multipath + capability orf prefix both + default-originate + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="1", + vrfs=[ + dict( + vrf="vrf1", + neighbors=[ + dict( + neighbor_address="1.2.1.2", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + ), + ], + ), + ], + ), + ], + ), + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_bgp_nbr_af_deleted(self): + self.maxDiff = None + run_cfg = dedent( + """\ + router bgp 1 + bgp router-id 1.2.3.4 + neighbor 1.1.1.1 + remote-as 5 + address-family ipv4 unicast + origin-as validation disable + bestpath origin-as allow invalid + aigp + aigp send med + send-community-ebgp + multipath + allowas-in 4 + maximum-prefix 10 20 restart 10 + as-override + capability orf prefix both + send-extended-community-ebgp + default-originate + next-hop-self + send-community-gshut-ebgp + soft-reconfiguration inbound + send-multicast-attributes + remove-private-AS inbound entire-aspath + next-hop-unchanged multipath + vrf vrf1 + rd auto + address-family ipv4 unicast + neighbor 1.2.1.2 + remote-as 5 + address-family ipv4 unicast + multipath + capability orf prefix both + default-originate + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=dict(), state="deleted")) + commands = [ + "router bgp 1", + "neighbor 1.1.1.1", + "no address-family ipv4 unicast", + "vrf vrf1", + "neighbor 1.2.1.2", + "no address-family ipv4 unicast", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_nbr_af_deleted_idempotent(self): + run_cfg = dedent( + """\ + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=dict(as_number="1"), state="deleted")) + + result = self.execute_module(changed=False) + self.assertEqual(result["commands"], []) + + def test_iosxr_bgp_nbr_af_rendered(self): + set_module_args( + dict( + config=dict( + as_number="1", + vrfs=[ + dict( + vrf="vrf1", + neighbors=[ + dict( + neighbor_address="1.2.1.2", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + as_override=dict(set=True), + ), + ], + ), + ], + ), + ], + neighbors=[ + dict( + neighbor_address="1.1.1.1", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + send_multicast_attributes=dict(set=True), + soft_reconfiguration=dict(inbound=dict(set=True)), + send_community_gshut_ebgp=dict(set=True), + send_extended_community_ebgp=dict(set=True), + send_community_ebgp=dict(set=True), + origin_as=dict(validation=dict(disable=True)), + remove_private_AS=dict( + set=True, + inbound=True, + entire_aspath=True, + ), + maximum_prefix=dict( + max_limit=10, + threshold_value=20, + restart=10, + ), + next_hop_self=dict(set=True), + next_hop_unchanged=dict(multipath=True), + aigp=dict(set=True, send_med=dict(set=True)), + as_override=dict(set=True), + allowas_in=dict(value=4), + bestpath_origin_as_allow_invalid=True, + long_lived_graceful_restart=dict( + stale_time=dict(send=20, accept=30), + ), + ), + ], + ), + ], + ), + state="rendered", + ), + ) + commands = [ + "router bgp 1", + "neighbor 1.1.1.1", + "address-family ipv4 unicast", + "aigp", + "aigp send med", + "allowas-in 4", + "as-override", + "bestpath origin-as allow invalid", + "capability orf prefix both", + "default-originate", + "maximum-prefix 10 20 restart 10", + "multipath", + "next-hop-self", + "next-hop-unchanged multipath", + "origin-as validation disable", + "remove-private-AS inbound entire-aspath", + "send-community-ebgp", + "send-community-gshut-ebgp", + "send-extended-community-ebgp", + "send-multicast-attributes", + "soft-reconfiguration inbound", + "vrf vrf1", + "neighbor 1.2.1.2", + "address-family ipv4 unicast", + "as-override", + "capability orf prefix both", + "default-originate", + "multipath", + ] + + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_bgp_global_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="router bgp 1\n bgp router-id 1.2.1.3\n neighbor 1.1.1.1\n " + "remote-as 6\n address-family ipv4 unicast\n origin-as validation disable\n " + "bestpath origin-as allow invalid\n weight 0\n send-community-ebgp\n " + " multipath\n allowas-in 3\n maximum-prefix 1 1 discard-extra-paths\n" + " capability orf prefix both\n " + "send-extended-community-ebgp\n long-lived-graceful-restart capable\n" + " next-hop-self\n " + "remove-private-AS\n send-community-gshut-ebgp inheritance-disable\n " + " send-multicast-attributes\n " + "remove-private-AS inbound entire-aspath\n " + "next-hop-unchanged multipath\n !\n " + "!\n !", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "as_number": "1", + "neighbors": [ + { + "address_family": [ + { + "afi": "ipv4", + "allowas_in": {"value": 3}, + "bestpath_origin_as_allow_invalid": True, + "capability_orf_prefix": "both", + "long_lived_graceful_restart": {"capable": True}, + "multipath": True, + "next_hop_self": {"set": True}, + "next_hop_unchanged": {"multipath": True}, + "origin_as": {"validation": {"disable": True}}, + "remove_private_AS": { + "entire_aspath": True, + "inbound": True, + "set": True, + }, + "safi": "unicast", + "send_community_ebgp": {"set": True}, + "send_community_gshut_ebgp": {"inheritance_disable": True}, + "send_extended_community_ebgp": {"set": True}, + "send_multicast_attributes": {"set": True}, + "weight": 0, + }, + ], + "neighbor_address": "1.1.1.1", + }, + ], + } + + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_bgp_add_fam_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="router bgp 1\n bgp router-id 1.2.1.3\n neighbor 1.1.1.1\n " + "remote-as 6\n address-family vpnv4 unicast\n origin-as validation disable\n " + "bestpath origin-as allow invalid\n weight 0\n send-community-ebgp\n " + " multipath\n allowas-in 3\n maximum-prefix 1 1 discard-extra-paths\n" + " capability orf prefix both\n " + "next-hop-unchanged multipath\n !\n " + "!\n !", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "as_number": "1", + "neighbors": [ + { + "neighbor_address": "1.1.1.1", + "address_family": [ + { + "afi": "vpnv4", + "safi": "unicast", + "origin_as": {"validation": {"disable": True}}, + "bestpath_origin_as_allow_invalid": True, + "weight": 0, + "send_community_ebgp": {"set": True}, + "multipath": True, + "allowas_in": {"value": 3}, + "capability_orf_prefix": "both", + "next_hop_unchanged": {"multipath": True}, + }, + ], + }, + ], + } + + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_bgp_nbr_af_afi_replaced(self): + self.maxDiff = None + set_module_args( + dict( + config=dict( + as_number="1", + neighbors=[ + dict( + neighbor_address="1.1.1.1", + address_family=[ + dict( + afi="vpnv4", + safi="flowspec", + multipath=True, + default_originate=dict(set=True), + capability_orf_prefix="both", + send_multicast_attributes=dict(set=True), + soft_reconfiguration=dict(inbound=dict(set=True)), + send_community_gshut_ebgp=dict(set=True), + send_extended_community_ebgp=dict(set=True), + send_community_ebgp=dict(set=True), + origin_as=dict(validation=dict(disable=True)), + remove_private_AS=dict( + set=True, + inbound=True, + entire_aspath=True, + ), + route_policy=dict(inbound="test1", outbound="test1"), + maximum_prefix=dict( + max_limit=10, + threshold_value=20, + restart=10, + ), + next_hop_self=dict(set=True), + next_hop_unchanged=dict(multipath=True), + aigp=dict(set=True, send_med=dict(set=True)), + as_override=dict(set=True), + bestpath_origin_as_allow_invalid=True, + long_lived_graceful_restart=dict( + stale_time=dict(send=20, accept=30), + ), + ), + ], + ), + ], + ), + state="replaced", + ), + ) + commands = [ + "address-family vpnv4 flowspec", + "aigp", + "aigp send med", + "as-override", + "bestpath origin-as allow invalid", + "capability orf prefix both", + "default-originate", + "maximum-prefix 10 20 restart 10", + "multipath", + "neighbor 1.1.1.1", + "next-hop-self", + "next-hop-unchanged multipath", + "origin-as validation disable", + "remove-private-AS inbound entire-aspath", + "route-policy test1 in", + "route-policy test1 out", + "router bgp 1", + "send-community-ebgp", + "send-community-gshut-ebgp", + "send-extended-community-ebgp", + "send-multicast-attributes", + "soft-reconfiguration inbound", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_bgp_nbr_af_overridden(self): + run_cfg = dedent( + """\ + router bgp 1 + bgp router-id 1.2.3.4 + neighbor 1.1.1.1 + remote-as 5 + address-family ipv4 unicast + origin-as validation disable + bestpath origin-as allow invalid + aigp + aigp send med + send-community-ebgp + multipath + allowas-in 4 + maximum-prefix 10 20 restart 10 + as-override + capability orf prefix both + send-extended-community-ebgp + default-originate + next-hop-self + send-community-gshut-ebgp + soft-reconfiguration inbound + send-multicast-attributes + remove-private-AS inbound entire-aspath + next-hop-unchanged multipath + vrf vrf1 + rd auto + address-family ipv4 unicast + neighbor 1.2.1.2 + remote-as 5 + address-family ipv4 unicast + multipath + capability orf prefix both + default-originate + route-policy test2 in + route-policy test2 out + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + as_number="1", + vrfs=[ + dict( + vrf="vrf1", + neighbors=[ + dict( + neighbor_address="1.2.1.2", + address_family=[ + dict( + afi="ipv4", + safi="unicast", + multipath=True, + default_originate=dict(set=True), + ), + ], + ), + ], + ), + ], + ), + state="overridden", + ), + ) + commands = [ + "router bgp 1", + "vrf vrf1", + "neighbor 1.2.1.2", + "address-family ipv4 unicast", + "no capability orf prefix both", + "no route-policy test2 in", + "no route-policy test2 out", + "neighbor 1.1.1.1", + "no address-family ipv4 unicast", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_command.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_command.py new file mode 100644 index 00000000..feb70876 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_command.py @@ -0,0 +1,128 @@ +# (c) 2016 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_command +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrCommandModule(TestIosxrModule): + + module = iosxr_command + + def setUp(self): + super(TestIosxrCommandModule, self).setUp() + + self.mock_run_commands = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_command.run_commands", + ) + self.run_commands = self.mock_run_commands.start() + + def tearDown(self): + super(TestIosxrCommandModule, self).tearDown() + + self.mock_run_commands.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + module, commands = args + output = list() + + for item in commands: + try: + command = item["command"] + except Exception: + command = item + filename = str(command).replace(" ", "_") + output.append(load_fixture(filename)) + return output + + self.run_commands.side_effect = load_from_file + + def test_iosxr_command_simple(self): + set_module_args(dict(commands=["show version"])) + result = self.execute_module() + self.assertEqual(len(result["stdout"]), 1) + self.assertTrue( + result["stdout"][0].startswith("Cisco IOS XR Software"), + ) + + def test_iosxr_command_multiple(self): + set_module_args(dict(commands=["show version", "show version"])) + result = self.execute_module() + self.assertEqual(len(result["stdout"]), 2) + self.assertTrue( + result["stdout"][0].startswith("Cisco IOS XR Software"), + ) + + def test_iosxr_command_wait_for(self): + wait_for = 'result[0] contains "Cisco IOS"' + set_module_args(dict(commands=["show version"], wait_for=wait_for)) + self.execute_module() + + def test_iosxr_command_wait_for_fails(self): + wait_for = 'result[0] contains "test string"' + set_module_args(dict(commands=["show version"], wait_for=wait_for)) + self.execute_module(failed=True) + self.assertEqual(self.run_commands.call_count, 10) + + def test_iosxr_command_retries(self): + wait_for = 'result[0] contains "test string"' + set_module_args( + dict(commands=["show version"], wait_for=wait_for, retries=2), + ) + self.execute_module(failed=True) + self.assertEqual(self.run_commands.call_count, 2) + + def test_iosxr_command_match_any(self): + wait_for = [ + 'result[0] contains "Cisco IOS"', + 'result[0] contains "test string"', + ] + set_module_args( + dict(commands=["show version"], wait_for=wait_for, match="any"), + ) + self.execute_module() + + def test_iosxr_command_match_all(self): + wait_for = [ + 'result[0] contains "Cisco IOS"', + 'result[0] contains "XR Software"', + ] + set_module_args( + dict(commands=["show version"], wait_for=wait_for, match="all"), + ) + self.execute_module() + + def test_iosxr_command_match_all_failure(self): + wait_for = [ + 'result[0] contains "Cisco IOS"', + 'result[0] contains "test string"', + ] + commands = ["show version", "show version"] + set_module_args( + dict(commands=commands, wait_for=wait_for, match="all"), + ) + self.execute_module(failed=True) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_config.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_config.py new file mode 100644 index 00000000..bbfdcb3e --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_config.py @@ -0,0 +1,313 @@ +# +# (c) 2016 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.cliconf.iosxr import Cliconf +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_config +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import MagicMock, patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrConfigModule(TestIosxrModule): + + module = iosxr_config + + def setUp(self): + super(TestIosxrConfigModule, self).setUp() + + self.patcher_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_config.get_config", + ) + self.mock_get_config = self.patcher_get_config.start() + + self.patcher_exec_command = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_config.load_config", + ) + self.mock_exec_command = self.patcher_exec_command.start() + + self.mock_get_connection = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_config.get_connection", + ) + self.get_connection = self.mock_get_connection.start() + + self.conn = self.get_connection() + self.conn.edit_config = MagicMock() + + self.cliconf_obj = Cliconf(MagicMock()) + self.running_config = load_fixture("iosxr_config_config.cfg") + + def tearDown(self): + super(TestIosxrConfigModule, self).tearDown() + + self.patcher_get_config.stop() + self.patcher_exec_command.stop() + self.mock_get_connection.stop() + + def load_fixtures(self, commands=None): + config_file = "iosxr_config_config.cfg" + self.mock_get_config.return_value = load_fixture(config_file) + self.mock_exec_command.return_value = "dummy diff" + + def test_iosxr_config_unchanged(self): + src = load_fixture("iosxr_config_config.cfg") + set_module_args(dict(src=src)) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff(src, src), + ) + self.execute_module() + + def test_iosxr_config_src(self): + src = load_fixture("iosxr_config_src.cfg") + set_module_args(dict(src=src)) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff(src, self.running_config), + ) + commands = [ + "hostname foo", + "interface GigabitEthernet0/0", + "no ip address", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_config_backup(self): + set_module_args(dict(backup=True)) + result = self.execute_module() + self.assertIn("__backup__", result) + + def test_iosxr_config_lines_wo_parents(self): + lines = ["hostname foo"] + set_module_args(dict(lines=lines)) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + "\n".join(lines), + self.running_config, + ), + ) + commands = ["hostname foo"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_config_lines_w_parents(self): + lines = ["shutdown"] + parents = ["interface GigabitEthernet0/0"] + set_module_args(dict(lines=lines, parents=parents)) + module = MagicMock() + module.params = {"lines": lines, "parents": parents, "src": None} + candidate_config = iosxr_config.get_candidate(module) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + candidate_config, + self.running_config, + ), + ) + commands = ["interface GigabitEthernet0/0", "shutdown"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_config_before(self): + lines = ["hostname foo"] + set_module_args(dict(lines=lines, before=["test1", "test2"])) + commands = ["test1", "test2", "hostname foo"] + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + "\n".join(lines), + self.running_config, + ), + ) + self.execute_module(changed=True, commands=commands, sort=False) + + def test_iosxr_config_after(self): + lines = ["hostname foo"] + set_module_args(dict(lines=lines, after=["test1", "test2"])) + commands = ["hostname foo", "test1", "test2"] + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + "\n".join(lines), + self.running_config, + ), + ) + self.execute_module(changed=True, commands=commands, sort=False) + + def test_iosxr_config_before_after_no_change(self): + lines = ["hostname router"] + set_module_args( + dict( + lines=lines, + before=["test1", "test2"], + after=["test3", "test4"], + ), + ) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + "\n".join(lines), + self.running_config, + ), + ) + self.execute_module() + + def test_iosxr_config_config(self): + config = "hostname localhost" + lines = ["hostname router"] + set_module_args(dict(lines=["hostname router"], config=config)) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff("\n".join(lines), config), + ) + commands = ["hostname router"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_config_replace_block(self): + lines = ["description test string", "test string"] + parents = ["interface GigabitEthernet0/0"] + set_module_args(dict(lines=lines, replace="block", parents=parents)) + commands = parents + lines + + module = MagicMock() + module.params = {"lines": lines, "parents": parents, "src": None} + candidate_config = iosxr_config.get_candidate(module) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + candidate_config, + self.running_config, + diff_replace="block", + path=parents, + ), + ) + self.execute_module(changed=True, commands=commands) + + def test_iosxr_config_force(self): + lines = ["hostname router"] + set_module_args(dict(lines=lines, force=True)) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + "\n".join(lines), + self.running_config, + diff_match="none", + ), + ) + self.execute_module(changed=True, commands=lines) + + def test_iosxr_config_admin(self): + lines = ["username admin", "group root-system", "secret P@ssw0rd"] + set_module_args(dict(lines=lines, admin=True)) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + "\n".join(lines), + self.running_config, + ), + ) + self.execute_module(changed=True, commands=lines) + + def test_iosxr_config_match_none(self): + lines = ["ip address 1.2.3.4 255.255.255.0", "description test string"] + parents = ["interface GigabitEthernet0/0"] + set_module_args(dict(lines=lines, parents=parents, match="none")) + commands = parents + lines + module = MagicMock() + module.params = {"lines": lines, "parents": parents, "src": None} + candidate_config = iosxr_config.get_candidate(module) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + candidate_config, + self.running_config, + diff_match="none", + path=parents, + ), + ) + + self.execute_module(changed=True, commands=commands, sort=False) + + def test_iosxr_config_match_strict(self): + lines = [ + "ip address 1.2.3.4 255.255.255.0", + "description test string", + "shutdown", + ] + parents = ["interface GigabitEthernet0/0"] + set_module_args(dict(lines=lines, parents=parents, match="strict")) + commands = parents + ["shutdown"] + module = MagicMock() + module.params = {"lines": lines, "parents": parents, "src": None} + candidate_config = iosxr_config.get_candidate(module) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + candidate_config, + self.running_config, + diff_match="strict", + path=parents, + ), + ) + + self.execute_module(changed=True, commands=commands, sort=False) + + def test_iosxr_config_match_exact(self): + lines = [ + "ip address 1.2.3.4 255.255.255.0", + "description test string", + "shutdown", + ] + parents = ["interface GigabitEthernet0/0"] + set_module_args(dict(lines=lines, parents=parents, match="exact")) + commands = parents + lines + module = MagicMock() + module.params = {"lines": lines, "parents": parents, "src": None} + candidate_config = iosxr_config.get_candidate(module) + self.conn.get_diff = MagicMock( + return_value=self.cliconf_obj.get_diff( + candidate_config, + self.running_config, + diff_match="exact", + path=parents, + ), + ) + + self.execute_module(changed=True, commands=commands, sort=False) + + def test_iosxr_config_src_and_lines_fails(self): + args = dict(src="foo", lines="foo") + set_module_args(args) + self.execute_module(failed=True) + + def test_iosxr_config_src_and_parents_fails(self): + args = dict(src="foo", parents="foo") + set_module_args(args) + self.execute_module(failed=True) + + def test_iosxr_config_match_exact_requires_lines(self): + args = dict(match="exact") + set_module_args(args) + self.execute_module(failed=True) + + def test_iosxr_config_match_strict_requires_lines(self): + args = dict(match="strict") + set_module_args(args) + self.execute_module(failed=True) + + def test_iosxr_config_replace_block_requires_lines(self): + args = dict(replace="block") + set_module_args(args) + self.execute_module(failed=True) + + def test_iosxr_config_replace_config_requires_src(self): + args = dict(replace="config") + set_module_args(args) + self.execute_module(failed=True) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_facts.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_facts.py new file mode 100644 index 00000000..7848f798 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_facts.py @@ -0,0 +1,120 @@ +# (c) 2016 Red Hat Inc. +# +# 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 json + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_facts +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrFacts(TestIosxrModule): + + module = iosxr_facts + + def setUp(self): + super(TestIosxrFacts, self).setUp() + + self.mock_run_commands = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.legacy.base.run_commands", + ) + self.run_commands = self.mock_run_commands.start() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_capabilities = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.legacy.base.get_capabilities", + ) + self.get_capabilities = self.mock_get_capabilities.start() + self.get_capabilities.return_value = { + "device_info": { + "network_os": "iosxr", + "network_os_hostname": "iosxr01", + "network_os_image": "bootflash:disk0/xrvr-os-mbi-6.1.3/mbixrvr-rp.vm", + "network_os_version": "6.1.3[Default]", + }, + "network_api": "cliconf", + } + + def tearDown(self): + super(TestIosxrFacts, self).tearDown() + + self.mock_run_commands.stop() + self.mock_get_capabilities.stop() + self.mock_get_resource_connection.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + module, commands = args + output = list() + + for item in commands: + try: + obj = json.loads(item) + command = obj["command"] + except ValueError: + command = item + filename = str(command).replace(" ", "_") + filename = filename.replace("/", "7") + filename = filename.replace("|", "_") + output.append(load_fixture(filename)) + return output + + self.run_commands.side_effect = load_from_file + + def test_iosxr_facts_gather_subset_default(self): + set_module_args(dict()) + result = self.execute_module() + ansible_facts = result["ansible_facts"] + self.assertIn("default", ansible_facts["ansible_net_gather_subset"][0]) + self.assertEqual( + [], + ansible_facts["ansible_net_gather_network_resources"], + ) + self.assertEqual("iosxr", ansible_facts["ansible_net_system"]) + self.assertEqual( + True, + True if ansible_facts.get("ansible_net_version") else False, + ) + self.assertEqual( + True, + True if ansible_facts.get("ansible_net_python_version") else False, + ) + self.assertEqual( + True, + True if ansible_facts.get("ansible_net_api") else False, + ) + + def test_iosxr_facts_gather_subset_config(self): + set_module_args({"gather_subset": "config"}) + result = self.execute_module() + ansible_facts = result["ansible_facts"] + self.assertIn("default", ansible_facts["ansible_net_gather_subset"]) + self.assertIn("config", ansible_facts["ansible_net_gather_subset"]) + self.assertEqual("iosxr01", ansible_facts["ansible_net_hostname"]) + self.assertIn("ansible_net_config", ansible_facts) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_interfaces.py new file mode 100644 index 00000000..4b7a0bcd --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_interfaces.py @@ -0,0 +1,288 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrInterfacesModule(TestIosxrModule): + module = iosxr_interfaces + + def setUp(self): + super(TestIosxrInterfacesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.interfaces.interfaces.InterfacesFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrInterfacesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_interface_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_interfaces_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + description="Configured and Merged by Ansible-Network", + mtu=110, + enabled=True, + duplex="half", + ), + dict( + name="GigabitEthernet0/0/0/1", + description="Configured and Merged by Ansible-Network", + mtu=2800, + speed=100, + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + description="Configured and Merged by Ansible-Network", + mtu=110, + enabled=True, + duplex="half", + ), + dict( + name="GigabitEthernet0/0/0/1", + description="Configured and Merged by Ansible-Network", + mtu=2800, + enabled=False, + duplex="full", + speed=100, + ), + ], + state="merged", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "description Configured and Merged by Ansible-Network", + "mtu 110", + "duplex half", + "no shutdown", + "interface GigabitEthernet0/0/0/1", + "description Configured and Merged by Ansible-Network", + "mtu 2800", + "speed 100", + "duplex full", + "shutdown", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_interfaces_replaced(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + description="Configured and Replaced by Ansible-Network", + mtu=110, + ), + dict( + name="GigabitEthernet0/0/0/1", + description="Configured and Replaced by Ansible-Network", + speed=100, + ), + ], + state="replaced", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "description Configured and Replaced by Ansible-Network", + "no duplex", + "interface GigabitEthernet0/0/0/1", + "description Configured and Replaced by Ansible-Network", + "no mtu", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_interfaces_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "no description", + "no mtu", + "no duplex", + "interface GigabitEthernet0/0/0/1", + "no description", + "no speed", + "no mtu", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + description="Configured and Merged by Ansible-Network", + mtu=110, + enabled=True, + duplex="half", + ), + dict( + name="GigabitEthernet0/0/0/1", + description="Configured and Merged by Ansible-Network", + mtu=2800, + enabled=False, + duplex="full", + speed=100, + ), + ], + state="rendered", + ), + ) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "description Configured and Merged by Ansible-Network", + "mtu 110", + "duplex half", + "no shutdown", + "interface GigabitEthernet0/0/0/1", + "description Configured and Merged by Ansible-Network", + "mtu 2800", + "speed 100", + "duplex full", + "shutdown", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="interface GigabitEthernet0/0/0/0\n description Configured and Merged by Ansible-Network\n " + "mtu 110\n duplex half\ninterface GigabitEthernet0/0/0/1\n " + "description Configured and Merged by Ansible-Network\n no shutdown\n mtu 2800\n speed 100", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = [ + { + "description": "Configured and Merged by Ansible-Network", + "duplex": "half", + "enabled": True, + "mtu": 110, + "name": "GigabitEthernet0/0/0/0", + }, + { + "description": "Configured and Merged by Ansible-Network", + "enabled": True, + "mtu": 2800, + "name": "GigabitEthernet0/0/0/1", + "speed": 100, + }, + ] + + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_interfaces_overridden(self): + self.maxDiff = None + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + description="Configured and Overridden by Ansible-Network", + mtu=2000, + enabled=False, + duplex="full", + speed=100, + ), + ], + state="overridden", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "no description", + "no mtu", + "no duplex", + "interface GigabitEthernet0/0/0/1", + "description Configured and Overridden by Ansible-Network", + "mtu 2000", + "duplex full", + "shutdown", + ] + + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_l2_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_l2_interfaces.py new file mode 100644 index 00000000..10053878 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_l2_interfaces.py @@ -0,0 +1,246 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_l2_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrL2InterfacesModule(TestIosxrModule): + module = iosxr_l2_interfaces + + def setUp(self): + super(TestIosxrL2InterfacesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + self.mock_get_os_version = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.l2_interfaces.l2_interfaces.get_os_version", + ) + self.get_os_version = self.mock_get_os_version.start() + self.get_os_version.return_value = "7.0.2" + self.mock_get_os_version1 = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.l2_interfaces.l2_interfaces.get_os_version", + ) + self.get_os_version1 = self.mock_get_os_version1.start() + self.get_os_version1.return_value = "7.0.2" + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.l2_interfaces.l2_interfaces.L2_InterfacesFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrL2InterfacesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_get_os_version.stop() + self.get_os_version1.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_l2_interface_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_l2_interfaces_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + l2transport=True, + l2protocol=[dict(cpsv="tunnel")], + ), + dict( + name="GigabitEthernet0/0/0/3.900", + encapsulation=dict(dot1q=20, second_dot1q=40), + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_l2_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + l2transport=True, + l2protocol=[dict(cpsv="tunnel")], + ), + dict( + name="GigabitEthernet0/0/0/3.900", + encapsulation=dict(dot1q=20, second_dot1q=40), + ), + ], + state="merged", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/1", + "l2transport l2protocol cpsv tunnel", + "interface GigabitEthernet0/0/0/3.900", + "encapsulation dot1q 20 second-dot1q 40", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_l2_interfaces_replaced(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + l2transport=True, + l2protocol=[dict(cpsv="drop")], + ), + ], + state="replaced", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/1", + "l2transport l2protocol cpsv drop", + "no l2transport", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_l2_interfaces_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "interface GigabitEthernet0/0/0/1", + "no l2transport", + "interface GigabitEthernet0/0/0/3.900", + "no encapsulation dot1q", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_l2_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + l2transport=True, + l2protocol=[dict(cpsv="tunnel")], + ), + dict( + name="GigabitEthernet0/0/0/3.900", + encapsulation=dict(dot1q=20, second_dot1q=40), + ), + ], + state="rendered", + ), + ) + + commands = [ + "interface GigabitEthernet0/0/0/1", + "l2transport l2protocol cpsv tunnel", + "interface GigabitEthernet0/0/0/3.900", + "encapsulation dot1q 20 second-dot1q 40", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_l2_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="interface GigabitEthernet0/0/0/1\n l2transport\n l2protocol cpsv tunnel\n " + "propagate remote-status\n !", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + print(result["parsed"]) + parsed_list = [ + { + "name": "GigabitEthernet0/0/0/1", + "l2transport": True, + "l2protocol": [{"cpsv": "tunnel"}], + "propagate": True, + }, + ] + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_l2_interfaces_overridden(self): + self.maxDiff = None + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/4", + l2transport=True, + l2protocol=[dict(cpsv="tunnel")], + ), + dict( + name="GigabitEthernet0/0/0/3.900", + encapsulation=dict(dot1q=40, second_dot1q=60), + ), + ], + state="overridden", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/4", + "l2transport l2protocol cpsv tunnel", + "interface GigabitEthernet0/0/0/3.900", + "encapsulation dot1q 40 second-dot1q 60", + "interface GigabitEthernet0/0/0/1", + "no l2transport", + ] + + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_l3_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_l3_interfaces.py new file mode 100644 index 00000000..5fab9f7e --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_l3_interfaces.py @@ -0,0 +1,255 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_l3_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrL3InterfacesModule(TestIosxrModule): + module = iosxr_l3_interfaces + + def setUp(self): + super(TestIosxrL3InterfacesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.l3_interfaces.l3_interfaces.L3_InterfacesFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrL3InterfacesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_l3_interface_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_l3_interfaces_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + ipv4=[dict(address="198.51.100.1/24")], + ipv6=[dict(address="2001:db8::/32")], + ), + dict( + name="GigabitEthernet0/0/0/1", + ipv4=[ + dict(address="192.0.2.1/24"), + dict(address="192.0.2.2/24", secondary=True), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_l3_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + ipv4=[dict(address="198.51.100.1/24")], + ), + dict( + name="GigabitEthernet0/0/0/1", + ipv4=[ + dict(address="192.0.2.1/24"), + dict(address="192.0.2.2/24", secondary=True), + ], + ipv6=[dict(address="2001:db8:0:3::/64")], + ), + ], + state="merged", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "ipv4 address 198.51.100.1 255.255.255.0", + "interface GigabitEthernet0/0/0/1", + "ipv4 address 192.0.2.2 255.255.255.0 secondary", + "ipv4 address 192.0.2.1 255.255.255.0", + "ipv6 address 2001:db8:0:3::/64", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_l3_interfaces_replaced(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + ipv4=[ + dict(address="203.0.113.27/24"), + dict(address="203.0.114.1/24", secondary=True), + ], + ), + ], + state="replaced", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "no ipv6 address", + "ipv4 address 203.0.113.27 255.255.255.0", + "ipv4 address 203.0.114.1 255.255.255.0 secondary", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_l3_interfaces_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "no ipv4 address", + "no ipv6 address", + "interface GigabitEthernet0/0/0/1", + "no ipv4 address", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_l3_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + ipv4=[dict(address="198.51.100.1/24")], + ), + dict( + name="GigabitEthernet0/0/0/1", + ipv4=[ + dict(address="192.0.2.1/24"), + dict(address="192.0.2.2/24", secondary=True), + ], + ipv6=[dict(address="2001:db8:0:3::/64")], + ), + ], + state="rendered", + ), + ) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "ipv4 address 198.51.100.1 255.255.255.0", + "interface GigabitEthernet0/0/0/1", + "ipv4 address 192.0.2.2 255.255.255.0 secondary", + "ipv4 address 192.0.2.1 255.255.255.0", + "ipv6 address 2001:db8:0:3::/64", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_l3_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="interface GigabitEthernet0/0/0/0\nipv4 address 198.51.100.1 255.255.255.0\n" + "ipv6 address 2001:db8::/32\ninterface GigabitEthernet0/0/0/1\nipv4 address" + " 192.0.2.1 255.255.255.0\nipv4 address 192.0.2.2 255.255.255.0 secondary\n", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + print(result["parsed"]) + parsed_list = [ + { + "name": "GigabitEthernet0/0/0/0", + "ipv4": [{"address": "198.51.100.1 255.255.255.0"}], + "ipv6": [{"address": "2001:db8::/32"}], + }, + { + "name": "GigabitEthernet0/0/0/1", + "ipv4": [ + {"address": "192.0.2.1 255.255.255.0"}, + {"address": "192.0.2.2 255.255.255.0", "secondary": True}, + ], + }, + ] + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_l3_interfaces_overridden(self): + self.maxDiff = None + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + ipv4=[dict(address="198.51.102.1/24")], + ipv6=[dict(address="2001:db8:1::/64")], + ), + ], + state="overridden", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "no ipv4 address", + "no ipv6 address", + "interface GigabitEthernet0/0/0/1", + "no ipv4 address", + "ipv4 address 198.51.102.1 255.255.255.0", + "ipv6 address 2001:db8:1::/64", + ] + + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lacp.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lacp.py new file mode 100644 index 00000000..e4c9c467 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lacp.py @@ -0,0 +1,93 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_lacp +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrLacpModule(TestIosxrModule): + module = iosxr_lacp + + def setUp(self): + super(TestIosxrLacpModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lacp.lacp.LacpFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrLacpModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_lacp_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_lacp_merged(self): + set_module_args( + dict( + config=dict( + system=dict( + priority=12, + mac=dict(address="00c1.4c00.bd15"), + ), + ), + state="merged", + ), + ) + commands = [ + "lacp system mac 00c1.4c00.bd15", + "lacp system priority 12", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lacp_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lacp_interfaces.py new file mode 100644 index 00000000..55358a06 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lacp_interfaces.py @@ -0,0 +1,263 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_lacp_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrLacpInterfacesModule(TestIosxrModule): + module = iosxr_lacp_interfaces + + def setUp(self): + super(TestIosxrLacpInterfacesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lacp_interfaces.lacp_interfaces.Lacp_interfacesFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrLacpInterfacesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_lacp_interfaces_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_lacp_interfaces_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether10", + churn_logging="actor", + collector_max_delay=100, + switchover_suppress_flaps=500, + ), + dict( + name="Bundle-Ether11", + system=dict(mac="00c2.4c00.bd15"), + ), + dict(name="GigabitEthernet0/0/0/1", period=200), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_lacp_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether10", + churn_logging="actor", + collector_max_delay=100, + switchover_suppress_flaps=500, + ), + dict( + name="Bundle-Ether11", + system=dict(mac="00c2.4c00.bd15"), + ), + dict(name="GigabitEthernet0/0/0/1", period=100), + ], + state="merged", + ), + ) + commands = [ + "interface Bundle-Ether10", + "lacp churn logging actor", + "lacp switchover suppress-flaps 500", + "lacp collector-max-delay 100", + "interface Bundle-Ether11", + "lacp system mac 00c2.4c00.bd15", + "interface GigabitEthernet0/0/0/1", + "lacp period 100", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lacp_interfaces_replaced(self): + self._prepare() + set_module_args( + dict( + config=[ + dict(name="Bundle-Ether10", churn_logging="partner"), + dict(name="GigabitEthernet0/0/0/1", period=300), + ], + state="replaced", + ), + ) + commands = [ + "interface Bundle-Ether10", + "no lacp switchover suppress-flaps 500", + "no lacp collector-max-delay 100", + "lacp churn logging partner", + "interface GigabitEthernet0/0/0/1", + "lacp period 300", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lacp_interfaces_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "interface Bundle-Ether10", + "no lacp switchover suppress-flaps 500", + "no lacp collector-max-delay 100", + "no lacp churn logging actor", + "interface Bundle-Ether11", + "no lacp system mac 00c2.4c00.bd15", + "interface GigabitEthernet0/0/0/1", + "no lacp period 200", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lag_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether10", + churn_logging="actor", + collector_max_delay=100, + switchover_suppress_flaps=500, + ), + dict( + name="Bundle-Ether11", + system=dict(mac="00c2.4c00.bd15"), + ), + dict(name="GigabitEthernet0/0/0/1", period=100), + ], + state="rendered", + ), + ) + + commands = [ + "interface Bundle-Ether10", + "lacp churn logging actor", + "lacp switchover suppress-flaps 500", + "lacp collector-max-delay 100", + "interface Bundle-Ether11", + "lacp system mac 00c2.4c00.bd15", + "interface GigabitEthernet0/0/0/1", + "lacp period 100", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_lacp_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="interface Bundle-Ether10\r\n lacp churn logging actor\r\n lacp" + " switchover suppress-flaps 500\r\n " + "lacp collector-max-delay 100\r\n!\r\ninterface " + "Bundle-Ether11\r\n lacp system mac 00c2.4c00.bd15\r" + "\n!\r\ninterface MgmtEth0/RP0/CPU0/0\r\n ipv4 address" + " 192.0.2.11 255.255.255.0\r\n!\r\ninterface " + "GigabitEthernet0/0/0/1\r\n lacp period 200\r\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + print(result["parsed"]) + parsed_list = [ + { + "churn_logging": "actor", + "collector_max_delay": 100, + "name": "Bundle-Ether10", + "switchover_suppress_flaps": 500, + }, + {"name": "Bundle-Ether11", "system": {"mac": "00c2.4c00.bd15"}}, + {"name": "GigabitEthernet0/0/0/1", "period": 200}, + ] + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_lag_interfaces_overridden(self): + self.maxDiff = None + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether12", + churn_logging="both", + collector_max_delay=100, + switchover_suppress_flaps=500, + ), + dict(name="GigabitEthernet0/0/0/1", period=300), + ], + state="overridden", + ), + ) + commands = [ + "interface Bundle-Ether10", + "no lacp switchover suppress-flaps 500", + "no lacp collector-max-delay 100", + "no lacp churn logging actor", + "interface Bundle-Ether11", + "no lacp system mac 00c2.4c00.bd15", + "interface Bundle-Ether12", + "lacp churn logging both", + "lacp collector-max-delay 100", + "lacp switchover suppress-flaps 500", + "interface GigabitEthernet0/0/0/1", + "lacp period 300", + ] + + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lag_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lag_interfaces.py new file mode 100644 index 00000000..b0d68fc6 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lag_interfaces.py @@ -0,0 +1,375 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_lag_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrLagInterfacesModule(TestIosxrModule): + module = iosxr_lag_interfaces + + def setUp(self): + super(TestIosxrLagInterfacesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lag_interfaces.lag_interfaces.Lag_interfacesFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrLagInterfacesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_lag_interface_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_lag_interfaces_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether10", + mode="active", + members=[ + dict( + member="GigabitEthernet0/0/0/0", + mode="inherit", + ), + dict( + member="GigabitEthernet0/0/0/1", + mode="passive", + ), + ], + links=dict(max_active=10, min_active=2), + ), + dict( + name="Bundle-Ether11", + mode="active", + members=[ + dict( + member="GigabitEthernet0/0/0/8", + mode="passive", + ), + dict( + member="GigabitEthernet0/0/0/9", + mode="passive", + ), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_lag_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether10", + mode="active", + members=[ + dict( + member="GigabitEthernet0/0/0/0", + mode="inherit", + ), + dict( + member="GigabitEthernet0/0/0/1", + mode="passive", + ), + ], + links=dict(max_active=10, min_active=2), + ), + dict( + name="Bundle-Ether11", + mode="active", + members=[ + dict( + member="GigabitEthernet0/0/0/8", + mode="passive", + ), + dict( + member="GigabitEthernet0/0/0/9", + mode="passive", + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "interface Bundle-Ether10", + "bundle minimum-active links 2", + "bundle maximum-active links 10", + "lacp mode active", + "interface GigabitEthernet0/0/0/1", + "bundle id 10 mode passive", + "interface GigabitEthernet0/0/0/0", + "bundle id 10 mode inherit", + "interface Bundle-Ether11", + "lacp mode active", + "interface GigabitEthernet0/0/0/8", + "bundle id 11 mode passive", + "interface GigabitEthernet0/0/0/9", + "bundle id 11 mode passive", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lag_interfaces_replaced(self): + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether10", + mode="passive", + members=[ + dict( + member="GigabitEthernet0/0/0/0", + mode="passive", + ), + ], + ), + dict(name="Bundle-Ether12", mode="active"), + ], + state="replaced", + ), + ) + commands = [ + "interface Bundle-Ether10", + "no bundle maximum-active links 10", + "no bundle minimum-active links 2", + "lacp mode passive", + "interface GigabitEthernet0/0/0/1", + "no bundle id", + "interface GigabitEthernet0/0/0/0", + "bundle id 10 mode passive", + "interface Bundle-Ether12", + "lacp mode active", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lag_interfaces_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "interface Bundle-Ether10", + "no bundle maximum-active links 10", + "no bundle minimum-active links 2", + "no lacp mode active", + "interface GigabitEthernet0/0/0/0", + "no bundle id", + "interface GigabitEthernet0/0/0/1", + "no bundle id", + "interface Bundle-Ether11", + "no lacp mode active", + "interface GigabitEthernet0/0/0/8", + "no bundle id", + "interface GigabitEthernet0/0/0/9", + "no bundle id", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lag_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether10", + mode="active", + members=[ + dict( + member="GigabitEthernet0/0/0/0", + mode="passive", + ), + dict( + member="GigabitEthernet0/0/0/1", + mode="passive", + ), + ], + links=dict(max_active=10, min_active=2), + ), + dict( + name="Bundle-Ether11", + mode="active", + members=[ + dict( + member="GigabitEthernet0/0/0/8", + mode="passive", + ), + dict( + member="GigabitEthernet0/0/0/9", + mode="passive", + ), + ], + ), + ], + state="rendered", + ), + ) + + commands = [ + "interface Bundle-Ether10", + "bundle minimum-active links 2", + "bundle maximum-active links 10", + "lacp mode active", + "interface GigabitEthernet0/0/0/1", + "bundle id 10 mode passive", + "interface GigabitEthernet0/0/0/0", + "bundle id 10 mode passive", + "interface Bundle-Ether11", + "lacp mode active", + "interface GigabitEthernet0/0/0/8", + "bundle id 11 mode passive", + "interface GigabitEthernet0/0/0/9", + "bundle id 11 mode passive", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_lag_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="interface Bundle-Ether10\r\n lacp mode active\r\n bundle maximum-active " + "links 10\r\n bundle minimum-active links 2\r\n!\r\ninterface Bundle-Ether11" + "\r\nlacp mode active\r\n!\r\ninterface GigabitEthernet0/0/0/0\r\n description " + '"GigabitEthernet - 0"\r\n bundle id 10 mode inherit\r\n!\r\ninterface ' + "GigabitEthernet0/0/0/1" + '\r\n description "GigabitEthernet - 2"\r\n bundle id 10 mode passive\r\n!\r\n' + 'interface GigabitEthernet0/0/0/8\r\n description "GigabitEthernet - 8"' + "\r\n bundle id 11 mode passive" + "\r\n!\r\ninterface GigabitEthernet0/0/0/9\r\n description " + '"GigabitEthernet - 9"\r\n bundle id 11 mode passive\r\n!', + state="parsed", + ), + ) + result = self.execute_module(changed=False) + print(result["parsed"]) + parsed_list = [ + { + "links": {"max_active": 10, "min_active": 2}, + "members": [ + {"member": "GigabitEthernet0/0/0/0", "mode": "inherit"}, + {"member": "GigabitEthernet0/0/0/1", "mode": "passive"}, + ], + "mode": "active", + "name": "Bundle-Ether10", + }, + { + "members": [ + {"member": "GigabitEthernet0/0/0/8", "mode": "passive"}, + {"member": "GigabitEthernet0/0/0/9", "mode": "passive"}, + ], + "mode": "active", + "name": "Bundle-Ether11", + }, + ] + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_lag_interfaces_overridden(self): + self.maxDiff = None + self._prepare() + set_module_args( + dict( + config=[ + dict( + name="Bundle-Ether11", + mode="active", + members=[ + dict( + member="GigabitEthernet0/0/0/0", + mode="active", + ), + dict( + member="GigabitEthernet0/0/0/1", + mode="active", + ), + ], + links=dict(max_active=10, min_active=5), + ), + ], + state="overridden", + ), + ) + commands = [ + "interface Bundle-Ether10", + "no bundle maximum-active links 10", + "no bundle minimum-active links 2", + "no lacp mode active", + "interface GigabitEthernet0/0/0/0", + "no bundle id", + "interface GigabitEthernet0/0/0/1", + "no bundle id", + "interface Bundle-Ether11", + "bundle minimum-active links 5", + "bundle maximum-active links 10", + "interface GigabitEthernet0/0/0/8", + "no bundle id", + "interface GigabitEthernet0/0/0/9", + "no bundle id", + "interface GigabitEthernet0/0/0/0", + "bundle id 11 mode active", + "interface GigabitEthernet0/0/0/1", + "bundle id 11 mode active", + ] + + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lldp_global.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lldp_global.py new file mode 100644 index 00000000..65f749ec --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lldp_global.py @@ -0,0 +1,206 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_lldp_global +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrLldpModule(TestIosxrModule): + module = iosxr_lldp_global + + def setUp(self): + super(TestIosxrLldpModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lldp_global.lldp_global.Lldp_globalFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrLldpModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_lldp_global_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_lldp_global_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=dict( + holdtime=100, + reinit=2, + timer=3000, + subinterfaces=True, + tlv_select=dict( + management_address=False, + system_description=False, + ), + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_lldp_global_merged(self): + set_module_args( + dict( + config=dict( + holdtime=100, + reinit=2, + timer=3000, + subinterfaces=True, + tlv_select=dict( + management_address=False, + system_description=False, + ), + ), + state="merged", + ), + ) + commands = [ + "lldp reinit 2", + "lldp holdtime 100", + "lldp timer 3000", + "lldp subinterfaces enable", + "lldp tlv-select system-description disable", + "lldp tlv-select management-address disable", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lldp_global_replaced(self): + self._prepare() + set_module_args( + dict( + config=dict( + holdtime=100, + tlv_select=dict( + management_address=False, + system_description=False, + port_description=False, + ), + ), + state="replaced", + ), + ) + commands = [ + "no lldp reinit 2", + "no lldp subinterfaces enable", + "no lldp timer 3000", + "lldp tlv-select port-description disable", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lldp_global_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "no lldp holdtime 100", + "no lldp reinit 2", + "no lldp subinterfaces enable", + "no lldp timer 3000", + "no lldp tlv-select management-address disable", + "no lldp tlv-select system-description disable", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lldp_global_rendered(self): + set_module_args( + dict( + config=dict( + holdtime=100, + reinit=2, + timer=3000, + subinterfaces=True, + tlv_select=dict( + management_address=False, + system_description=False, + ), + ), + state="rendered", + ), + ) + + commands = [ + "lldp reinit 2", + "lldp holdtime 100", + "lldp timer 3000", + "lldp subinterfaces enable", + "lldp tlv-select system-description disable", + "lldp tlv-select management-address disable", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_lag_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="lldp reinit 2\nlldp holdtime 100\nlldp timer 3000\nlldp subinterfaces\ + enable\nlldp tlv-select system-description disable\nlldp tlv-select management-address\ + disable\n", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "holdtime": 100, + "reinit": 2, + "timer": 3000, + "tlv_select": {"system_description": False}, + } + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lldp_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lldp_interfaces.py new file mode 100644 index 00000000..78b6d79f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_lldp_interfaces.py @@ -0,0 +1,206 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_lldp_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrLldpInterfacesModule(TestIosxrModule): + module = iosxr_lldp_interfaces + + def setUp(self): + super(TestIosxrLldpInterfacesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.lldp_interfaces.lldp_interfaces.Lldp_interfacesFacts.get_config", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrLldpInterfacesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def _prepare(self): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_lldp_interfaces_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_lldp_interfaces_merged_idempotent(self): + self._prepare() + set_module_args( + dict( + config=[ + dict(name="GigabitEthernet0/0/0/0", transmit=False), + dict(name="GigabitEthernet0/0/0/1", receive=False), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_lldp_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict(name="GigabitEthernet0/0/0/0", transmit=False), + dict(name="GigabitEthernet0/0/0/1", receive=False), + ], + state="merged", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/0", + "lldp transmit disable", + "interface GigabitEthernet0/0/0/1", + "lldp receive disable", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lldp_interfaces_replaced(self): + self._prepare() + set_module_args( + dict( + config=[dict(name="GigabitEthernet0/0/0/1", transmit=False)], + state="replaced", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/1", + "no lldp receive disable", + "no lldp destination mac-address ieee-nearest-non-tmpr-bridge", + "lldp transmit disable", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lldp_interfaces_deleted(self): + self._prepare() + set_module_args(dict(state="deleted")) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "no lldp transmit disable", + "no lldp destination mac-address ieee-nearest-bridge", + "interface GigabitEthernet0/0/0/1", + "no lldp destination mac-address ieee-nearest-non-tmpr-bridge", + "no lldp receive disable", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_lldp_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict(name="GigabitEthernet0/0/0/0", transmit=False), + dict(name="GigabitEthernet0/0/0/1", receive=False), + ], + state="rendered", + ), + ) + + commands = [ + "interface GigabitEthernet0/0/0/0", + "lldp transmit disable", + "interface GigabitEthernet0/0/0/1", + "lldp receive disable", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_lldp_interfaces_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="interface TenGigE0/0/0/0\r\n ipv4 address 192.0.2.11 255.255.255.192\r\n!\r\ninterface preconfigure " + "GigabitEthernet0/0/0/0\r\n lldp\r\n transmit disable\r\n destination mac-address\r\n " + "ieee-nearest-bridge\r\n !\r\n !\r\n!\r\ninterface preconfigure GigabitEthernet0/0/0/1\r\n lldp\r\n " + "receive disable\r\n destination mac-address\r\n ieee-nearest-non-tmpr-bridge\r\n", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + print(result["parsed"]) + parsed_list = [ + {"name": "TenGigE0/0/0/0"}, + { + "destination": {"mac_address": "ieee-nearest-bridge"}, + "name": "GigabitEthernet0/0/0/0", + "transmit": False, + }, + { + "destination": {"mac_address": "ieee-nearest-non-tmpr-bridge"}, + "name": "GigabitEthernet0/0/0/1", + "receive": False, + }, + ] + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_lldp_interfaces_overridden(self): + self.maxDiff = None + self._prepare() + set_module_args( + dict( + config=[dict(name="GigabitEthernet0/0/0/0", transmit=False)], + state="overridden", + ), + ) + commands = [ + "interface GigabitEthernet0/0/0/1", + "no lldp destination mac-address ieee-nearest-non-tmpr-bridge", + "no lldp receive disable", + "interface GigabitEthernet0/0/0/0", + "no lldp destination mac-address ieee-nearest-bridge", + ] + + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_logging_global.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_logging_global.py new file mode 100644 index 00000000..bffee2b1 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_logging_global.py @@ -0,0 +1,1263 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_logging_global +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrLoggingGlobalModule(TestIosxrModule): + module = iosxr_logging_global + + def setUp(self): + super(TestIosxrLoggingGlobalModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.logging_global.logging_global." + "Logging_globalFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrLoggingGlobalModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_logging_global_merged_idempotent(self): + run_cfg = dedent( + """\ + logging tls-server test + vrf test + trustpoint test2 + tls-hostname test2 + ! + logging file test path test maxfilesize 1024 severity info + logging file test2 path test1 maxfilesize 1024 severity debugging + logging ipv4 dscp af11 + logging ipv6 precedence routine + logging trap informational + logging events filter + match test + match test1 + ! + logging events threshold 10 + logging events buffer-size 1024 + logging events display-location + logging events level warnings + logging format rfc5424 + logging archive + device disk0 + severity alerts + file-size 1 + frequency daily + archive-size 1 + archive-length 1 + ! + logging console warning + logging console discriminator + match1 test + nomatch1 test3 + ! + logging history size 10 + logging monitor errors + logging monitor discriminator + match1 test1 + ! + logging buffered 2097152 + logging buffered warnings + logging buffered discriminator + match2 test + ! + logging 1.1.1.1 vrf default severity critical port default + logging correlator rule test type stateful + reissue-nonbistate + timeout 5 + reparent + context-correlation + ! + logging correlator rule test1 type nonstateful + timeout 6 + context-correlation + ! + logging correlator ruleset test + rulename test + rulename test1 + ! + logging correlator buffer-size 1024 + logging localfilesize 1024 + logging source-interface GigabitEthernet0/0/0/0 vrf test + logging hostnameprefix test + logging suppress duplicates + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + archive=dict( + archive_length=1, + archive_size=1, + device="disk0", + file_size=1, + frequency="daily", + severity="alerts", + ), + buffered=dict( + size=2097152, + severity="warnings", + discriminator=[ + dict(match_params="match2", name="test"), + ], + ), + console=dict( + severity="warning", + discriminator=[ + dict(match_params="match1", name="test"), + dict(match_params="nomatch1", name="test3"), + ], + ), + correlator=dict( + buffer_size=1024, + rule_sets=[ + dict(name="test", rulename=["test1", "test"]), + ], + rules=[ + dict( + rule_name="test", + rule_type="stateful", + timeout=5, + context_correlation=True, + reissue_nonbistate=True, + reparent=True, + ), + dict( + rule_name="test1", + rule_type="nonstateful", + timeout=6, + context_correlation=True, + ), + ], + ), + events=dict( + severity="warnings", + display_location=True, + buffer_size=1024, + filter_match=["test1", "test"], + threshold=10, + ), + format=True, + files=[ + dict( + maxfilesize=1024, + name="test", + path="test", + severity="info", + ), + dict( + maxfilesize=1024, + name="test2", + path="test1", + severity="debugging", + ), + ], + history=dict(size=10), + hostnameprefix="test", + hosts=[ + dict( + host="1.1.1.1", + port="default", + severity="critical", + vrf="default", + ), + ], + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + localfilesize=1024, + monitor=dict( + severity="errors", + discriminator=[ + dict(match_params="match1", name="test1"), + ], + ), + source_interfaces=[ + dict(interface="GigabitEthernet0/0/0/0", vrf="test"), + ], + suppress=dict(duplicates=True), + tls_servers=[ + dict( + name="test", + tls_hostname="test2", + trustpoint="test2", + vrf="test", + ), + ], + trap=dict(severity="informational"), + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_logging_global_merged(self): + set_module_args( + dict( + config=dict( + archive=dict( + archive_length=1, + archive_size=1, + device="disk0", + file_size=1, + frequency="daily", + severity="alerts", + ), + buffered=dict( + size=2097152, + severity="warnings", + discriminator=[ + dict(match_params="match2", name="test"), + ], + ), + console=dict( + severity="warning", + discriminator=[ + dict(match_params="match1", name="test"), + dict(match_params="nomatch1", name="test3"), + ], + ), + correlator=dict( + buffer_size=1024, + rule_sets=[ + dict(name="test", rulename=["test1", "test"]), + ], + rules=[ + dict( + rule_name="test", + rule_type="stateful", + timeout=5, + context_correlation=True, + reissue_nonbistate=True, + reparent=True, + ), + dict( + rule_name="test1", + rule_type="nonstateful", + timeout=6, + context_correlation=True, + ), + ], + ), + events=dict( + severity="warnings", + display_location=True, + buffer_size=1024, + filter_match=["test1", "test"], + threshold=10, + ), + format=True, + files=[ + dict( + maxfilesize=1024, + name="test", + path="test", + severity="info", + ), + dict( + maxfilesize=1024, + name="test2", + path="test1", + severity="debugging", + ), + ], + history=dict(state="disabled", size=10), + hostnameprefix="test", + hosts=[ + dict( + host="1.1.1.1", + port="default", + severity="critical", + vrf="default", + ), + ], + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + localfilesize=1024, + monitor=dict( + severity="errors", + discriminator=[ + dict(match_params="match1", name="test1"), + ], + ), + source_interfaces=[ + dict(interface="GigabitEthernet0/0/0/0", vrf="test"), + ], + suppress=dict(duplicates=True), + tls_servers=[ + dict( + name="test", + tls_hostname="test2", + trustpoint="test2", + vrf="test", + ), + ], + trap=dict(severity="informational"), + ), + state="merged", + ), + ) + commands = [ + "logging archive device disk0", + "logging archive frequency daily", + "logging archive severity alerts", + "logging archive archive-size 1", + "logging archive archive-length 1", + "logging archive file-size 1", + "logging buffered 2097152", + "logging buffered warnings", + "logging console warning", + "logging correlator buffer-size 1024", + "logging events threshold 10", + "logging events buffer-size 1024", + "logging events display-location", + "logging events level warnings", + "logging hostnameprefix test", + "logging format rfc5424", + "logging ipv4 dscp af11", + "logging ipv6 precedence routine", + "logging localfilesize 1024", + "logging suppress duplicates", + "logging monitor errors", + "logging history size 10", + "logging history disable", + "logging trap informational", + "logging 1.1.1.1 vrf default severity critical port default", + "logging file test path test maxfilesize 1024 severity info", + "logging file test2 path test1 maxfilesize 1024 severity debugging", + "logging source-interface GigabitEthernet0/0/0/0 vrf test", + "logging tls-server test tls-hostname test2", + "logging tls-server test trustpoint test2", + "logging tls-server test vrf test", + "logging correlator ruleset test rulename test1", + "logging correlator ruleset test rulename test", + "logging correlator rule test type stateful timeout 5", + "logging correlator rule test type stateful reissue-nonbistate", + "logging correlator rule test type stateful reparent", + "logging correlator rule test type stateful context-correlation", + "logging correlator rule test1 type nonstateful timeout 6", + "logging correlator rule test1 type nonstateful context-correlation", + "logging events filter match test1", + "logging events filter match test", + "logging buffered discriminator match2 test", + "logging monitor discriminator match1 test1", + "logging console discriminator match1 test", + "logging console discriminator nomatch1 test3", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_logging_global_deleted(self): + self.maxDiff = None + run_cfg = dedent( + """\ + logging tls-server test + vrf test + trustpoint test2 + tls-hostname test2 + ! + logging file test path test maxfilesize 1024 severity info + logging file test2 path test1 maxfilesize 1024 severity debugging + logging ipv4 dscp af11 + logging ipv6 precedence routine + logging trap informational + logging events filter + match test + match test1 + ! + logging events threshold 10 + logging events buffer-size 1024 + logging events display-location + logging events level warnings + logging format rfc5424 + logging archive + device disk0 + severity alerts + file-size 1 + frequency daily + archive-size 1 + archive-length 1 + ! + logging console warning + logging console discriminator + match1 test + nomatch1 test3 + ! + logging history size 10 + logging history disable + logging monitor errors + logging monitor discriminator + match1 test1 + ! + logging buffered 2097152 + logging buffered warnings + logging buffered discriminator + match2 test + ! + logging 1.1.1.1 vrf default severity critical port default + logging correlator rule test type stateful + reissue-nonbistate + timeout 5 + reparent + context-correlation + ! + logging correlator rule test1 type nonstateful + timeout 6 + context-correlation + ! + logging correlator ruleset test + rulename test + rulename test1 + ! + logging correlator buffer-size 1024 + logging localfilesize 1024 + logging source-interface GigabitEthernet0/0/0/0 vrf test + logging hostnameprefix test + logging suppress duplicates + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(state="deleted")) + commands = [ + "no logging archive device disk0", + "no logging archive frequency daily", + "no logging archive severity alerts", + "no logging archive archive-size 1", + "no logging archive archive-length 1", + "no logging archive file-size 1", + "no logging buffered 2097152", + "no logging buffered warnings", + "no logging console warning", + "no logging correlator buffer-size 1024", + "no logging events threshold 10", + "no logging events buffer-size 1024", + "no logging events display-location", + "no logging events level warnings", + "no logging hostnameprefix test", + "no logging format rfc5424", + "no logging ipv4 dscp af11", + "no logging ipv6 precedence routine", + "no logging localfilesize 1024", + "no logging suppress duplicates", + "no logging monitor errors", + "no logging history size 10", + "no logging history disable", + "no logging trap informational", + "no logging 1.1.1.1 vrf default severity critical port default", + "no logging file test path test maxfilesize 1024 severity info", + "no logging file test2 path test1 maxfilesize 1024 severity debugging", + "no logging source-interface GigabitEthernet0/0/0/0 vrf test", + "no logging tls-server test", + "no logging correlator ruleset test rulename test", + "no logging correlator ruleset test rulename test1", + "no logging correlator rule test type stateful timeout 5", + "no logging correlator rule test type stateful reissue-nonbistate", + "no logging correlator rule test type stateful reparent", + "no logging correlator rule test type stateful context-correlation", + "no logging correlator rule test1 type nonstateful timeout 6", + "no logging correlator rule test1 type nonstateful context-correlation", + "no logging events filter match test", + "no logging events filter match test1", + "no logging buffered discriminator match2 test", + "no logging monitor discriminator match1 test1", + "no logging console discriminator match1 test", + "no logging console discriminator nomatch1 test3", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_logging_global_replaced(self): + self.maxDiff = None + run_cfg = dedent( + """\ + logging tls-server test + vrf test + trustpoint test2 + tls-hostname test2 + ! + logging file test path test maxfilesize 1024 severity info + logging file test2 path test1 maxfilesize 1024 severity debugging + logging ipv4 dscp af11 + logging ipv6 precedence routine + logging trap informational + logging events filter + match test + match test1 + ! + logging events threshold 10 + logging events buffer-size 1024 + logging events display-location + logging events level warnings + logging format rfc5424 + logging archive + device disk0 + severity alerts + file-size 1 + frequency daily + archive-size 1 + archive-length 1 + ! + logging console warning + logging console discriminator + match1 test + nomatch1 test3 + ! + logging history size 10 + logging history disable + logging monitor errors + logging monitor discriminator + match1 test1 + ! + logging buffered 2097152 + logging buffered warnings + logging buffered discriminator + match2 test + ! + logging 1.1.1.1 vrf default severity critical port default + logging correlator rule test type stateful + reissue-nonbistate + timeout 5 + reparent + context-correlation + ! + logging correlator rule test1 type nonstateful + timeout 6 + context-correlation + ! + logging correlator ruleset test + rulename test + rulename test1 + ! + logging correlator buffer-size 1024 + logging localfilesize 1024 + logging source-interface GigabitEthernet0/0/0/0 vrf test + logging hostnameprefix test + logging suppress duplicates + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + archive=dict( + archive_length=1, + archive_size=1, + device="disk0", + file_size=1, + severity="alerts", + ), + buffered=dict(size=2097152, severity="warnings"), + console=dict( + severity="warning", + discriminator=[ + dict(match_params="match1", name="test1"), + ], + ), + correlator=dict( + buffer_size=1024, + rules=[ + dict( + rule_name="test", + rule_type="stateful", + timeout=6, + context_correlation=True, + reissue_nonbistate=True, + reparent=True, + ), + ], + ), + events=dict( + severity="warnings", + display_location=True, + buffer_size=1024, + filter_match=["test1"], + threshold=12, + ), + format=True, + files=[ + dict( + maxfilesize=1024, + name="test", + path="test1", + severity="info", + ), + ], + history=dict(state="disabled", size=10), + hostnameprefix="test", + hosts=[ + dict( + host="1.1.1.2", + port="default", + severity="critical", + vrf="default", + ), + ], + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + localfilesize=1024, + source_interfaces=[ + dict(interface="GigabitEthernet0/0/0/0", vrf="test"), + ], + tls_servers=[ + dict( + name="test", + tls_hostname="test2", + trustpoint="test3", + vrf="test", + ), + ], + ), + state="replaced", + ), + ) + commands = [ + "logging console discriminator match1 test1", + "logging correlator rule test type stateful timeout 6", + "logging events threshold 12", + "logging 1.1.1.2 vrf default severity critical port default", + "logging file test path test1 maxfilesize 1024 severity info", + "logging tls-server test trustpoint test3", + "no logging 1.1.1.1 vrf default severity critical port default", + "no logging archive frequency daily", + "no logging buffered discriminator match2 test", + "no logging console discriminator match1 test", + "no logging console discriminator nomatch1 test3", + "no logging correlator rule test1 type nonstateful context-correlation", + "no logging correlator rule test1 type nonstateful timeout 6", + "no logging correlator ruleset test rulename test", + "no logging correlator ruleset test rulename test1", + "no logging events filter match test", + "no logging file test2 path test1 maxfilesize 1024 severity debugging", + "no logging monitor discriminator match1 test1", + "no logging monitor errors", + "no logging suppress duplicates", + "no logging trap informational", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_logging_global_rendered(self): + self.maxDiff = None + set_module_args( + dict( + config=dict( + archive=dict( + archive_length=1, + archive_size=1, + device="disk0", + file_size=1, + frequency="daily", + severity="alerts", + ), + buffered=dict( + size=2097152, + severity="warnings", + discriminator=[ + dict(match_params="match2", name="test"), + ], + ), + console=dict( + severity="warning", + discriminator=[ + dict(match_params="match1", name="test"), + dict(match_params="nomatch1", name="test3"), + ], + ), + correlator=dict( + buffer_size=1024, + rule_sets=[ + dict(name="test", rulename=["test1", "test"]), + ], + rules=[ + dict( + rule_name="test", + rule_type="stateful", + timeout=5, + context_correlation=True, + reissue_nonbistate=True, + reparent=True, + ), + dict( + rule_name="test1", + rule_type="nonstateful", + timeout=6, + context_correlation=True, + ), + ], + ), + events=dict( + severity="warnings", + display_location=True, + buffer_size=1024, + filter_match=["test1", "test"], + threshold=10, + ), + format=True, + files=[ + dict( + maxfilesize=1024, + name="test", + path="test", + severity="info", + ), + dict( + maxfilesize=1024, + name="test2", + path="test1", + severity="debugging", + ), + ], + history=dict(state="disabled", size=10), + hostnameprefix="test", + hosts=[ + dict( + host="1.1.1.1", + port="default", + severity="critical", + vrf="default", + ), + ], + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + localfilesize=1024, + monitor=dict( + severity="errors", + discriminator=[ + dict(match_params="match1", name="test1"), + ], + ), + source_interfaces=[ + dict(interface="GigabitEthernet0/0/0/0", vrf="test"), + ], + suppress=dict(duplicates=True), + tls_servers=[ + dict( + name="test", + tls_hostname="test2", + trustpoint="test2", + vrf="test", + ), + ], + trap=dict(severity="informational"), + ), + state="rendered", + ), + ) + commands = [ + "logging archive device disk0", + "logging archive frequency daily", + "logging archive severity alerts", + "logging archive archive-size 1", + "logging archive archive-length 1", + "logging archive file-size 1", + "logging buffered 2097152", + "logging buffered warnings", + "logging console warning", + "logging correlator buffer-size 1024", + "logging events threshold 10", + "logging events buffer-size 1024", + "logging events display-location", + "logging events level warnings", + "logging hostnameprefix test", + "logging format rfc5424", + "logging ipv4 dscp af11", + "logging ipv6 precedence routine", + "logging localfilesize 1024", + "logging suppress duplicates", + "logging monitor errors", + "logging history size 10", + "logging history disable", + "logging trap informational", + "logging 1.1.1.1 vrf default severity critical port default", + "logging file test path test maxfilesize 1024 severity info", + "logging file test2 path test1 maxfilesize 1024 severity debugging", + "logging source-interface GigabitEthernet0/0/0/0 vrf test", + "logging tls-server test tls-hostname test2", + "logging tls-server test trustpoint test2", + "logging tls-server test vrf test", + "logging correlator ruleset test rulename test1", + "logging correlator ruleset test rulename test", + "logging correlator rule test type stateful timeout 5", + "logging correlator rule test type stateful reissue-nonbistate", + "logging correlator rule test type stateful reparent", + "logging correlator rule test type stateful context-correlation", + "logging correlator rule test1 type nonstateful timeout 6", + "logging correlator rule test1 type nonstateful context-correlation", + "logging events filter match test1", + "logging events filter match test", + "logging buffered discriminator match2 test", + "logging monitor discriminator match1 test1", + "logging console discriminator match1 test", + "logging console discriminator nomatch1 test3", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_logging_global_overridden(self): + self.maxDiff = None + run_cfg = dedent( + """\ + logging tls-server test + vrf test + trustpoint test2 + tls-hostname test2 + ! + logging file test path test maxfilesize 1024 severity info + logging file test2 path test1 maxfilesize 1024 severity debugging + logging ipv4 dscp af11 + logging ipv6 precedence routine + logging trap informational + logging events filter + match test + match test1 + ! + logging events threshold 10 + logging events buffer-size 1024 + logging events display-location + logging events level warnings + logging format rfc5424 + logging archive + device disk0 + severity alerts + file-size 1 + frequency daily + archive-size 1 + archive-length 1 + ! + logging console warning + logging console discriminator + match1 test + nomatch1 test3 + ! + logging history size 10 + logging history disable + logging monitor errors + logging monitor discriminator + match1 test1 + ! + logging buffered 2097152 + logging buffered warnings + logging buffered discriminator + match2 test + ! + logging 1.1.1.1 vrf default severity critical port default + logging correlator rule test type stateful + reissue-nonbistate + timeout 5 + reparent + context-correlation + ! + logging correlator rule test1 type nonstateful + timeout 6 + context-correlation + ! + logging correlator ruleset test + rulename test + rulename test1 + ! + logging correlator buffer-size 1024 + logging localfilesize 1024 + logging source-interface GigabitEthernet0/0/0/0 vrf test + logging hostnameprefix test + logging suppress duplicates + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + archive=dict( + archive_length=1, + archive_size=1, + device="disk0", + file_size=1, + severity="alerts", + ), + buffered=dict(size=2097152, severity="warnings"), + console=dict( + severity="warning", + discriminator=[ + dict(match_params="match1", name="test1"), + ], + ), + correlator=dict( + buffer_size=1024, + rules=[ + dict( + rule_name="test", + rule_type="stateful", + timeout=6, + context_correlation=True, + reissue_nonbistate=True, + reparent=True, + ), + ], + ), + events=dict( + severity="warnings", + display_location=True, + buffer_size=1024, + filter_match=["test1"], + threshold=12, + ), + format=True, + files=[ + dict( + maxfilesize=1024, + name="test", + path="test1", + severity="info", + ), + ], + history=dict(state="disabled", size=10), + hostnameprefix="test", + hosts=[ + dict( + host="1.1.1.2", + port="default", + severity="critical", + vrf="default", + ), + ], + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + localfilesize=1024, + source_interfaces=[ + dict(interface="GigabitEthernet0/0/0/0", vrf="test"), + ], + tls_servers=[ + dict( + name="test", + tls_hostname="test2", + trustpoint="test3", + vrf="test", + ), + ], + ), + state="overridden", + ), + ) + commands = [ + "logging console discriminator match1 test1", + "logging correlator rule test type stateful timeout 6", + "logging events threshold 12", + "logging 1.1.1.2 vrf default severity critical port default", + "logging file test path test1 maxfilesize 1024 severity info", + "logging tls-server test trustpoint test3", + "no logging 1.1.1.1 vrf default severity critical port default", + "no logging archive frequency daily", + "no logging buffered discriminator match2 test", + "no logging console discriminator match1 test", + "no logging console discriminator nomatch1 test3", + "no logging correlator rule test1 type nonstateful context-correlation", + "no logging correlator rule test1 type nonstateful timeout 6", + "no logging correlator ruleset test rulename test", + "no logging correlator ruleset test rulename test1", + "no logging events filter match test", + "no logging file test2 path test1 maxfilesize 1024 severity debugging", + "no logging monitor discriminator match1 test1", + "no logging monitor errors", + "no logging suppress duplicates", + "no logging trap informational", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_logging_global_gathered(self): + run_cfg = dedent( + """\ + logging tls-server test + vrf test + trustpoint test2 + tls-hostname test2 + ! + logging file test path test maxfilesize 1024 severity info + logging ipv4 dscp af11 + logging ipv6 precedence routine + logging trap informational + logging events filter + match test + ! + logging events threshold 10 + logging events buffer-size 1024 + logging events display-location + logging events level warnings + logging format rfc5424 + logging archive + device disk0 + severity alerts + file-size 1 + frequency daily + archive-size 1 + archive-length 1 + ! + logging console warning + logging console discriminator + match1 test + ! + logging history size 10 + logging history disable + logging monitor errors + logging monitor discriminator + match1 test1 + ! + logging buffered 2097152 + logging buffered warnings + logging buffered discriminator + match2 test + ! + logging 1.1.1.1 vrf default severity critical port default + logging correlator rule test type stateful + reissue-nonbistate + timeout 5 + reparent + context-correlation + ! + logging correlator ruleset test + rulename test + ! + logging correlator buffer-size 1024 + logging localfilesize 1024 + logging source-interface GigabitEthernet0/0/0/0 vrf test + logging hostnameprefix test + logging suppress duplicates + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(state="gathered")) + gathered = { + "archive": { + "archive_length": 1, + "archive_size": 1, + "device": "disk0", + "file_size": 1, + "frequency": "daily", + "severity": "alerts", + }, + "buffered": { + "discriminator": [{"match_params": "match2", "name": "test"}], + "severity": "warnings", + "size": 2097152, + }, + "console": { + "discriminator": [{"match_params": "match1", "name": "test"}], + "severity": "warning", + }, + "correlator": { + "buffer_size": 1024, + "rule_sets": [{"name": "test", "rulename": ["test"]}], + "rules": [ + { + "context_correlation": True, + "reissue_nonbistate": True, + "reparent": True, + "rule_name": "test", + "rule_type": "stateful", + "timeout": 5, + }, + ], + }, + "events": { + "buffer_size": 1024, + "display_location": True, + "filter_match": ["test"], + "severity": "warnings", + "threshold": 10, + }, + "files": [ + { + "maxfilesize": 1024, + "name": "test", + "path": "test", + "severity": "info", + }, + ], + "format": True, + "history": {"state": "disabled", "size": 10}, + "hostnameprefix": "test", + "hosts": [ + { + "host": "1.1.1.1", + "port": "default", + "severity": "critical", + "vrf": "default", + }, + ], + "ipv4": {"dscp": "af11"}, + "ipv6": {"precedence": "routine"}, + "localfilesize": 1024, + "monitor": { + "discriminator": [{"match_params": "match1", "name": "test1"}], + "severity": "errors", + }, + "source_interfaces": [ + {"interface": "GigabitEthernet0/0/0/0", "vrf": "test"}, + ], + "suppress": {"duplicates": True}, + "tls_servers": [ + { + "name": "test", + "tls_hostname": "test2", + "trustpoint": "test2", + "vrf": "test", + }, + ], + "trap": {"severity": "informational"}, + } + result = self.execute_module(changed=False) + self.assertEqual(gathered, result["gathered"]) + + def test_iosxr_logging_global_parsed(self): + set_module_args( + dict( + running_config="logging tls-server test\n vrf test\n trustpoint test2\n tls-hostname test2" + "\n!\nlogging file test path test maxfilesize 1024 severity info\nlogging ipv4 dscp" + " af11\nlogging ipv6 precedence routine\nlogging trap informational\nlogging events" + " filter\n match test1\n!\nlogging events threshold " + "10\nlogging events buffer-size 1024\nlogging events display-location" + "\nlogging events level warnings" + "\nlogging format rfc5424\nlogging archive\n device disk0" + "\n severity alerts\n file-size 1\n frequency " + "daily\n archive-size 1\n archive-length 1\n!\nlogging console " + "warning\nlogging console discriminator\n " + "match1 test\n!\nlogging history size " + "10\nlogging history disable\nlogging monitor errors" + "\nlogging monitor discriminator\n match1 test1\n!" + "\nlogging buffered 2097152\nlogging buffered warnings\n" + "logging buffered discriminator\n match2 test\n!\nlogging " + "1.1.1.1 vrf default severity critical port default" + "\nlogging correlator rule test type stateful\n reissue-nonbistate\n " + "timeout 5\n reparent\n context-correlation\n!" + "\n!\nlogging correlator ruleset test\n rulename test1" + "\n!\nlogging correlator buffer-size 1024\nlogging " + "localfilesize 1024\nlogging source-interface" + " GigabitEthernet0/0/0/0 vrf test\nlogging hostnameprefix " + "test\nlogging suppress duplicates", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "archive": { + "archive_length": 1, + "archive_size": 1, + "device": "disk0", + "file_size": 1, + "frequency": "daily", + "severity": "alerts", + }, + "buffered": { + "discriminator": [{"match_params": "match2", "name": "test"}], + "severity": "warnings", + "size": 2097152, + }, + "console": { + "discriminator": [{"match_params": "match1", "name": "test"}], + "severity": "warning", + }, + "correlator": { + "buffer_size": 1024, + "rule_sets": [{"name": "test", "rulename": ["test1"]}], + "rules": [ + { + "context_correlation": True, + "reissue_nonbistate": True, + "reparent": True, + "rule_name": "test", + "rule_type": "stateful", + "timeout": 5, + }, + ], + }, + "events": { + "buffer_size": 1024, + "display_location": True, + "filter_match": ["test1"], + "severity": "warnings", + "threshold": 10, + }, + "files": [ + { + "maxfilesize": 1024, + "name": "test", + "path": "test", + "severity": "info", + }, + ], + "format": True, + "history": {"state": "disabled", "size": 10}, + "hostnameprefix": "test", + "hosts": [ + { + "host": "1.1.1.1", + "port": "default", + "severity": "critical", + "vrf": "default", + }, + ], + "ipv4": {"dscp": "af11"}, + "ipv6": {"precedence": "routine"}, + "localfilesize": 1024, + "monitor": { + "discriminator": [{"match_params": "match1", "name": "test1"}], + "severity": "errors", + }, + "source_interfaces": [ + {"interface": "GigabitEthernet0/0/0/0", "vrf": "test"}, + ], + "suppress": {"duplicates": True}, + "tls_servers": [ + { + "name": "test", + "tls_hostname": "test2", + "trustpoint": "test2", + "vrf": "test", + }, + ], + "trap": {"severity": "informational"}, + } + + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_n540.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_n540.py new file mode 100644 index 00000000..d2820cfa --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_n540.py @@ -0,0 +1,96 @@ +# +# (c) 2022 Red Hat Inc. +# +# 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 os import path + +from ansible.module_utils._text import to_bytes, to_text +from mock import MagicMock + +from ansible_collections.cisco.iosxr.plugins.cliconf import iosxr +from ansible_collections.cisco.iosxr.tests.unit.compat import unittest + + +class TestPluginCLIConfIOSXR(unittest.TestCase): + """Test class for IOSXR CLI Conf Methods""" + + def setUp(self): + self._mock_connection = MagicMock() + self._prepare() + self._cliconf = iosxr.Cliconf(self._mock_connection) + self.maxDiff = None + + def _prepare(self, platform="iosxr"): + b_FIXTURE_DIR = b"%s/fixtures/cliconf_ncs540/%s" % ( + to_bytes( + path.dirname(path.abspath(__file__)), + errors="surrogate_or_strict", + ), + to_bytes(platform), + ) + + def _connection_side_effect(*args, **kwargs): + try: + if args: + value = args[0] + else: + value = kwargs.get("command") + if b"|" in value: + value = value.replace(b"|", b"") + fixture_path = path.abspath( + b"%s/%s" % (b_FIXTURE_DIR, b"_".join(value.split(b" "))), + ) + with open(fixture_path, "rb") as file_desc: + return to_text(file_desc.read()) + except (OSError, IOError): + if args: + value = args[0] + return value + elif kwargs.get("command"): + value = kwargs.get("command") + return value + return "NO-OP" + + self._mock_connection.send.side_effect = _connection_side_effect + + def tearDown(self): + pass + + def test_get_device_info_iosxr(self): + """Test get_device_info for nxos""" + device_info = self._cliconf.get_device_info() + + mock_device_info = { + "network_os_version": "7.5.2 LNT", + "network_os": "iosxr", + "network_os_hostname": "iosxr01", + "network_os_model": "N540X-6Z18G-SYS-A", + } + + self.assertEqual(device_info, mock_device_info) + + def test_get_command_output_iosxr(self): + """Test _get_command_with_output for iosxr""" + self._prepare() + cmd = self._cliconf.get_command_output("show running-config hostname") + + self.assertEqual(cmd, "hostname iosxr01") diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_netconf.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_netconf.py new file mode 100644 index 00000000..bbd61050 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_netconf.py @@ -0,0 +1,115 @@ +# (c) 2017 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_netconf +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrNetconfModule(TestIosxrModule): + + module = iosxr_netconf + + def setUp(self): + super(TestIosxrNetconfModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_netconf.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_netconf.load_config", + ) + self.load_config = self.mock_load_config.start() + + def tearDown(self): + super(TestIosxrNetconfModule, self).tearDown() + self.mock_get_config.stop() + self.mock_load_config.stop() + + def test_iosxr_disable_netconf_service(self): + self.get_config.return_value = """ + netconf-yang agent + ssh + ! + ssh server netconf vrf default + """ + self.load_config.return_value = "dummy diff" + set_module_args( + dict(netconf_port=830, netconf_vrf="default", state="absent"), + ) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + [ + "no netconf-yang agent ssh", + "no ssh server netconf port 830", + "no ssh server netconf vrf default", + ], + ) + + def test_iosxr_enable_netconf_service(self): + self.get_config.return_value = "" + self.load_config.return_value = "dummy diff" + set_module_args( + dict(netconf_port=830, netconf_vrf="default", state="present"), + ) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + [ + "netconf-yang agent ssh", + "ssh server netconf port 830", + "ssh server netconf vrf default", + ], + ) + + def test_iosxr_change_netconf_port(self): + self.get_config.return_value = """ + netconf-yang agent + ssh + ! + ssh server netconf vrf default + """ + self.load_config.return_value = "dummy diff" + set_module_args(dict(netconf_port=9000, state="present")) + result = self.execute_module(changed=True) + self.assertEqual(result["commands"], ["ssh server netconf port 9000"]) + + def test_iosxr_change_netconf_vrf(self): + self.get_config.return_value = """ + netconf-yang agent + ssh + ! + ssh server netconf vrf default + """ + self.load_config.return_value = "dummy diff" + set_module_args(dict(netconf_vrf="new_default", state="present")) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + ["ssh server netconf vrf new_default"], + ) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ntp_global.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ntp_global.py new file mode 100644 index 00000000..702e2a00 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ntp_global.py @@ -0,0 +1,902 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_ntp_global +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrNtpGlobalModule(TestIosxrModule): + module = iosxr_ntp_global + + def setUp(self): + super(TestIosxrNtpGlobalModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ntp_global.ntp_global." + "Ntp_globalFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrNtpGlobalModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_ntp_global_merged_idempotent(self): + self.maxDiff = None + run_cfg = dedent( + """\ + ntp + max-associations 10 + interface GigabitEthernet0/0/0/0 vrf siteB + multicast key 1 + ! + interface GigabitEthernet0/0/0/0 + broadcast client + multicast client 224.0.0.8 + multicast destination 224.0.0.8 + ! + authentication-key 1 md5 encrypted testkey + authentication-key 2 md5 encrypted 071B245F5A5B + authenticate + trusted-key 1 + trusted-key 2 + ipv4 dscp af11 + ipv6 precedence routine + peer vrf siteC 192.0.2.1 iburst + server vrf siteD 192.0.2.2 burst + server 192.0.2.2 version 2 key 1 minpoll 4 maxpoll 5 prefer burst iburst source GigabitEthernet0/0/0/0 + drift file apphost + drift aging time 0 + master 1 + access-group vrf siteA ipv4 peer PeerAcl2 + access-group vrf siteA ipv4 serve ServeAcl2 + access-group ipv4 peer PeerAcl1 + access-group ipv4 serve ServeAcl1 + access-group ipv4 serve-only ServeOnlyAcl1 + access-group ipv4 query-only QueryOnlyAcl1 + access-group ipv6 peer PeerAcl2 + source vrf siteE GigabitEthernet0/0/0/0 + source GigabitEthernet0/0/0/0 + passive + broadcastdelay 1 + update-calendar + log-internal-sync + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + access_group=dict( + ipv4=dict( + peer="PeerAcl1", + query_only="QueryOnlyAcl1", + serve="ServeAcl1", + serve_only="ServeOnlyAcl1", + ), + ipv6=dict(peer="PeerAcl2"), + vrfs=[ + dict( + ipv4=dict(peer="PeerAcl2", serve="ServeAcl2"), + name="siteA", + ), + ], + ), + authenticate=True, + authentication_keys=[ + dict(id=1, key="testkey", encryption=True), + dict(id=2, key="071B245F5A5B", encryption=True), + ], + broadcastdelay=1, + drift=dict(aging_time=0, file="apphost"), + interfaces=[ + dict( + name="GigabitEthernet0/0/0/0", + multicast_client="224.0.0.8", + multicast_destination="224.0.0.8", + broadcast_client=True, + ), + dict( + name="GigabitEthernet0/0/0/0", + multicast_key=1, + vrf="siteB", + ), + ], + ipv4=dict(dscp="af11"), + ipv6=dict(precedence="routine"), + log_internal_sync=True, + master=dict(stratum=1), + max_associations=10, + passive=True, + peers=[dict(iburst=True, peer="192.0.2.1", vrf="siteC")], + servers=[ + dict(burst=True, server="192.0.2.2", vrf="siteD"), + dict( + iburst=True, + burst=True, + server="192.0.2.2", + key_id=1, + maxpoll=5, + minpoll=4, + prefer=True, + source="GigabitEthernet0/0/0/0", + version=2, + ), + ], + source_interface="GigabitEthernet0/0/0/0", + source_vrfs=[ + dict(name="GigabitEthernet0/0/0/0", vrf="siteE"), + ], + trusted_keys=[dict(key_id=1), dict(key_id=2)], + update_calendar=True, + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ntp_global_merged(self): + self.maxDiff = None + set_module_args( + dict( + config=dict( + access_group=dict( + ipv4=dict( + peer="PeerAcl1", + query_only="QueryOnlyAcl1", + serve="ServeAcl1", + serve_only="ServeOnlyAcl1", + ), + ipv6=dict(peer="PeerAcl2"), + vrfs=[ + dict( + ipv4=dict(peer="PeerAcl2", serve="ServeAcl2"), + name="siteA", + ), + ], + ), + authenticate=True, + authentication_keys=[ + dict(id=1, key="testkey", encryption=True), + dict(id=2, key="071B245F5A5B", encryption=True), + ], + broadcastdelay=1, + drift=dict(aging_time=0, file="apphost"), + interfaces=[ + dict( + name="GigabitEthernet0/0/0/0", + multicast_client="224.0.0.8", + multicast_destination="224.0.0.8", + broadcast_client=True, + ), + dict( + name="GigabitEthernet0/0/0/0", + multicast_key=1, + vrf="siteB", + ), + ], + ipv4=dict(dscp="af11"), + ipv6=dict(precedence="routine"), + log_internal_sync=True, + master=dict(stratum=1), + max_associations=10, + passive=True, + peers=[dict(iburst=True, peer="192.0.2.1", vrf="siteC")], + servers=[ + dict(burst=True, server="192.0.2.2", vrf="siteD"), + dict( + iburst=True, + burst=True, + server="192.0.2.2", + key_id=1, + maxpoll=5, + minpoll=4, + prefer=True, + source="GigabitEthernet0/0/0/0", + version=2, + ), + ], + source_interface="GigabitEthernet0/0/0/0", + source_vrfs=[ + dict(name="GigabitEthernet0/0/0/0", vrf="siteE"), + ], + trusted_keys=[dict(key_id=1), dict(key_id=2)], + update_calendar=True, + ), + state="merged", + ), + ) + commands = [ + "ntp authentication-key 1 md5 encrypted testkey", + "ntp authentication-key 2 md5 encrypted 071B245F5A5B", + "ntp peer vrf siteC 192.0.2.1 iburst", + "ntp server vrf siteD 192.0.2.2 burst", + "ntp server 192.0.2.2 burst iburst key 1 minpoll 4 maxpoll 5 prefer version 2 source GigabitEthernet0/0/0/0", + "ntp trusted-key 1", + "ntp trusted-key 2", + "ntp interface GigabitEthernet0/0/0/0 broadcast client", + "ntp interface GigabitEthernet0/0/0/0 multicast destination 224.0.0.8", + "ntp interface GigabitEthernet0/0/0/0 multicast client 224.0.0.8", + "ntp interface GigabitEthernet0/0/0/0 vrf siteB multicast key 1", + "ntp vrf siteE source GigabitEthernet0/0/0/0", + "ntp access-group vrf siteA ipv4 serve ServeAcl2", + "ntp access-group vrf siteA ipv4 peer PeerAcl2", + "ntp access-group ipv4 peer PeerAcl1", + "ntp access-group ipv4 serve ServeAcl1", + "ntp access-group ipv4 serve-only ServeOnlyAcl1", + "ntp access-group ipv4 query-only QueryOnlyAcl1", + "ntp access-group ipv6 peer PeerAcl2", + "ntp authenticate", + "ntp log-internal-sync", + "ntp broadcastdelay 1", + "ntp drift aging time 0", + "ntp drift file apphost", + "ntp ipv4 dscp af11", + "ntp ipv6 precedence routine", + "ntp max-associations 10", + "ntp master 1", + "ntp passive", + "ntp update-calendar", + "ntp source GigabitEthernet0/0/0/0", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ntp_global_deleted(self): + self.maxDiff = None + run_cfg = dedent( + """\ + ntp + max-associations 10 + interface GigabitEthernet0/0/0/0 vrf siteB + multicast key 1 + ! + interface GigabitEthernet0/0/0/0 + broadcast client + multicast client 224.0.0.8 + multicast destination 224.0.0.8 + ! + authentication-key 1 md5 encrypted testkey + authentication-key 2 md5 encrypted 071B245F5A5B + authenticate + trusted-key 1 + trusted-key 2 + ipv4 dscp af11 + ipv6 precedence routine + peer vrf siteC 192.0.2.1 iburst + server vrf siteD 192.0.2.2 burst + server 192.0.2.2 version 2 key 1 minpoll 4 maxpoll 5 prefer burst iburst source GigabitEthernet0/0/0/0 + drift file apphost + drift aging time 0 + master 1 + access-group vrf siteA ipv4 peer PeerAcl3 + access-group vrf siteA ipv4 serve ServeAcl2 + access-group ipv4 peer PeerAcl1 + access-group ipv4 serve ServeAcl1 + access-group ipv4 serve-only ServeOnlyAcl1 + access-group ipv4 query-only QueryOnlyAcl1 + access-group ipv6 peer PeerAcl2 + source vrf siteE GigabitEthernet0/0/0/0 + source GigabitEthernet0/0/0/0 + passive + broadcastdelay 1 + update-calendar + log-internal-sync + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(state="deleted")) + commands = [ + "no ntp authentication-key 1 md5 encrypted testkey", + "no ntp authentication-key 2 md5 encrypted 071B245F5A5B", + "no ntp peer vrf siteC 192.0.2.1 iburst", + "no ntp server vrf siteD 192.0.2.2 burst", + "no ntp server 192.0.2.2 burst iburst key 1 minpoll 4 maxpoll 5 prefer version 2 source GigabitEthernet0/0/0/0", + "no ntp trusted-key 1", + "no ntp trusted-key 2", + "no ntp interface GigabitEthernet0/0/0/0 vrf siteB", + "no ntp interface GigabitEthernet0/0/0/0", + "no ntp vrf siteE source GigabitEthernet0/0/0/0", + "no ntp access-group vrf siteA ipv4 serve ServeAcl2", + "no ntp access-group vrf siteA ipv4 peer PeerAcl3", + "no ntp access-group ipv4 peer PeerAcl1", + "no ntp access-group ipv4 serve ServeAcl1", + "no ntp access-group ipv4 serve-only ServeOnlyAcl1", + "no ntp access-group ipv4 query-only QueryOnlyAcl1", + "no ntp access-group ipv6 peer PeerAcl2", + "no ntp authenticate", + "no ntp log-internal-sync", + "no ntp broadcastdelay 1", + "no ntp drift aging time 0", + "no ntp drift file apphost", + "no ntp ipv4 dscp af11", + "no ntp ipv6 precedence routine", + "no ntp max-associations 10", + "no ntp master 1", + "no ntp passive", + "no ntp update-calendar", + "no ntp source GigabitEthernet0/0/0/0", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ntp_global_replaced(self): + self.maxDiff = None + run_cfg = dedent( + """\ + ntp + max-associations 10 + interface GigabitEthernet0/0/0/0 vrf siteB + multicast key 1 + ! + interface GigabitEthernet0/0/0/0 + broadcast client + multicast client 224.0.0.8 + multicast destination 224.0.0.8 + ! + authentication-key 1 md5 encrypted testkey + authentication-key 2 md5 encrypted 071B245F5A5B + authenticate + trusted-key 1 + trusted-key 2 + ipv4 dscp af11 + ipv6 precedence routine + peer vrf siteC 192.0.2.1 iburst + server vrf siteD 192.0.2.2 burst + server 192.0.2.2 version 2 key 1 minpoll 4 maxpoll 5 prefer burst iburst source GigabitEthernet0/0/0/0 + drift file apphost + drift aging time 0 + master 1 + access-group vrf siteA ipv4 peer PeerAcl3 + access-group vrf siteA ipv4 serve ServeAcl2 + access-group ipv4 peer PeerAcl1 + access-group ipv4 serve ServeAcl1 + access-group ipv4 serve-only ServeOnlyAcl1 + access-group ipv4 query-only QueryOnlyAcl1 + access-group ipv6 peer PeerAcl2 + source vrf siteE GigabitEthernet0/0/0/0 + source GigabitEthernet0/0/0/0 + passive + broadcastdelay 1 + update-calendar + log-internal-sync + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + access_group=dict( + ipv4=dict( + peer="PeerAcl1", + query_only="QueryOnlyAcl2", + serve="ServeAcl1", + serve_only="ServeOnlyAcl1", + ), + ipv6=dict(peer="PeerAcl2"), + vrfs=[ + dict( + ipv4=dict(peer="PeerAcl2", serve="ServeAcl2"), + name="siteA", + ), + ], + ), + authenticate=True, + authentication_keys=[ + dict(id=1, key="testkey1", encryption=True), + dict(id=2, key="071B245F5A5B", encryption=True), + ], + broadcastdelay=1, + drift=dict(aging_time=0, file="apphost"), + interfaces=[ + dict( + name="GigabitEthernet0/0/0/1", + multicast_client="224.0.0.8", + multicast_destination="224.0.0.8", + broadcast_client=True, + ), + dict( + name="GigabitEthernet0/0/0/0", + multicast_key=1, + vrf="siteB", + ), + ], + ipv4=dict(dscp="af12"), + ipv6=dict(precedence="routine"), + log_internal_sync=True, + master=dict(stratum=1), + max_associations=10, + passive=True, + peers=[dict(iburst=True, peer="192.0.2.1", vrf="siteC")], + servers=[ + dict(burst=True, server="192.0.2.3", vrf="siteD"), + dict( + iburst=True, + burst=True, + server="192.0.2.2", + key_id=1, + maxpoll=5, + minpoll=4, + prefer=True, + source="GigabitEthernet0/0/0/1", + version=2, + ), + ], + source_interface="GigabitEthernet0/0/0/0", + source_vrfs=[ + dict(name="GigabitEthernet0/0/0/0", vrf="siteE"), + ], + trusted_keys=[dict(key_id=1), dict(key_id=2)], + update_calendar=True, + ), + state="replaced", + ), + ) + commands = [ + "no ntp server vrf siteD 192.0.2.2 burst", + "no ntp interface GigabitEthernet0/0/0/0", + "ntp authentication-key 1 md5 encrypted testkey1", + "ntp server vrf siteD 192.0.2.3 burst", + "ntp server 192.0.2.2 burst iburst key 1 minpoll 4 maxpoll 5 prefer version 2 source GigabitEthernet0/0/0/1", + "ntp interface GigabitEthernet0/0/0/1 broadcast client", + "ntp interface GigabitEthernet0/0/0/1 multicast destination 224.0.0.8", + "ntp interface GigabitEthernet0/0/0/1 multicast client 224.0.0.8", + "ntp access-group ipv4 query-only QueryOnlyAcl2", + "ntp access-group vrf siteA ipv4 peer PeerAcl2", + "ntp access-group vrf siteA ipv4 serve ServeAcl2", + "ntp ipv4 dscp af12", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_logging_global_rendered(self): + self.maxDiff = None + set_module_args( + dict( + config=dict( + access_group=dict( + ipv4=dict( + peer="PeerAcl1", + query_only="QueryOnlyAcl1", + serve="ServeAcl1", + serve_only="ServeOnlyAcl1", + ), + ipv6=dict(peer="PeerAcl2"), + vrfs=[ + dict( + ipv4=dict(peer="PeerAcl2", serve="ServeAcl2"), + name="siteA", + ), + ], + ), + authenticate=True, + authentication_keys=[ + dict(id=1, key="testkey", encryption=True), + dict(id=2, key="071B245F5A5B", encryption=True), + ], + broadcastdelay=1, + drift=dict(aging_time=0, file="apphost"), + interfaces=[ + dict( + name="GigabitEthernet0/0/0/0", + multicast_client="224.0.0.8", + multicast_destination="224.0.0.8", + broadcast_client=True, + ), + dict( + name="GigabitEthernet0/0/0/0", + multicast_key=1, + vrf="siteB", + ), + ], + ipv4=dict(dscp="af11"), + ipv6=dict(precedence="routine"), + log_internal_sync=True, + master=dict(stratum=1), + max_associations=10, + passive=True, + peers=[dict(iburst=True, peer="192.0.2.1", vrf="siteC")], + servers=[ + dict(burst=True, server="192.0.2.2", vrf="siteD"), + dict( + iburst=True, + burst=True, + server="192.0.2.2", + key_id=1, + maxpoll=5, + minpoll=4, + prefer=True, + source="GigabitEthernet0/0/0/0", + version=2, + ), + ], + source_interface="GigabitEthernet0/0/0/0", + source_vrfs=[ + dict(name="GigabitEthernet0/0/0/0", vrf="siteE"), + ], + trusted_keys=[dict(key_id=1), dict(key_id=2)], + update_calendar=True, + ), + state="rendered", + ), + ) + commands = [ + "ntp authentication-key 1 md5 encrypted testkey", + "ntp authentication-key 2 md5 encrypted 071B245F5A5B", + "ntp peer vrf siteC 192.0.2.1 iburst", + "ntp server vrf siteD 192.0.2.2 burst", + "ntp server 192.0.2.2 burst iburst key 1 minpoll 4 maxpoll 5 prefer version 2 source GigabitEthernet0/0/0/0", + "ntp trusted-key 1", + "ntp trusted-key 2", + "ntp interface GigabitEthernet0/0/0/0 broadcast client", + "ntp interface GigabitEthernet0/0/0/0 multicast destination 224.0.0.8", + "ntp interface GigabitEthernet0/0/0/0 multicast client 224.0.0.8", + "ntp interface GigabitEthernet0/0/0/0 vrf siteB multicast key 1", + "ntp vrf siteE source GigabitEthernet0/0/0/0", + "ntp access-group vrf siteA ipv4 serve ServeAcl2", + "ntp access-group vrf siteA ipv4 peer PeerAcl2", + "ntp access-group ipv4 peer PeerAcl1", + "ntp access-group ipv4 serve ServeAcl1", + "ntp access-group ipv4 serve-only ServeOnlyAcl1", + "ntp access-group ipv4 query-only QueryOnlyAcl1", + "ntp access-group ipv6 peer PeerAcl2", + "ntp authenticate", + "ntp log-internal-sync", + "ntp broadcastdelay 1", + "ntp drift aging time 0", + "ntp drift file apphost", + "ntp ipv4 dscp af11", + "ntp ipv6 precedence routine", + "ntp max-associations 10", + "ntp master 1", + "ntp passive", + "ntp update-calendar", + "ntp source GigabitEthernet0/0/0/0", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_ntp_global_overridden(self): + run_cfg = dedent( + """\ + ntp + max-associations 10 + interface GigabitEthernet0/0/0/0 vrf siteB + multicast key 1 + ! + interface GigabitEthernet0/0/0/0 + broadcast client + multicast client 224.0.0.8 + multicast destination 224.0.0.8 + ! + authentication-key 1 md5 encrypted testkey + authentication-key 2 md5 encrypted 071B245F5A5B + authenticate + trusted-key 1 + trusted-key 2 + ipv4 dscp af11 + ipv6 precedence routine + peer vrf siteC 192.0.2.1 iburst + server vrf siteD 192.0.2.2 burst + server 192.0.2.2 version 2 key 1 minpoll 4 maxpoll 5 prefer burst iburst source GigabitEthernet0/0/0/0 + drift file apphost + drift aging time 0 + master 1 + access-group vrf siteA ipv4 peer PeerAcl3 + access-group vrf siteA ipv4 serve ServeAcl2 + access-group ipv4 peer PeerAcl1 + access-group ipv4 serve ServeAcl1 + access-group ipv4 serve-only ServeOnlyAcl1 + access-group ipv4 query-only QueryOnlyAcl1 + access-group ipv6 peer PeerAcl2 + source vrf siteE GigabitEthernet0/0/0/0 + source GigabitEthernet0/0/0/0 + passive + broadcastdelay 1 + update-calendar + log-internal-sync + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + access_group=dict( + ipv4=dict( + peer="PeerAcl1", + query_only="QueryOnlyAcl2", + serve="ServeAcl1", + serve_only="ServeOnlyAcl1", + ), + ipv6=dict(peer="PeerAcl2"), + vrfs=[ + dict( + ipv4=dict(peer="PeerAcl2", serve="ServeAcl2"), + name="siteA", + ), + ], + ), + authenticate=True, + authentication_keys=[ + dict(id=1, key="testkey1", encryption=True), + dict(id=2, key="071B245F5A5B", encryption=True), + ], + broadcastdelay=1, + drift=dict(aging_time=0, file="apphost"), + interfaces=[ + dict( + name="GigabitEthernet0/0/0/1", + multicast_client="224.0.0.8", + multicast_destination="224.0.0.8", + broadcast_client=True, + ), + dict( + name="GigabitEthernet0/0/0/0", + multicast_key=1, + vrf="siteB", + ), + ], + ipv4=dict(dscp="af12"), + ipv6=dict(precedence="routine"), + log_internal_sync=True, + master=dict(stratum=1), + max_associations=10, + passive=True, + peers=[dict(iburst=True, peer="192.0.2.1", vrf="siteC")], + servers=[ + dict(burst=True, server="192.0.2.3", vrf="siteD"), + dict( + iburst=True, + burst=True, + server="192.0.2.2", + key_id=1, + maxpoll=5, + minpoll=4, + prefer=True, + source="GigabitEthernet0/0/0/1", + version=2, + ), + ], + source_interface="GigabitEthernet0/0/0/0", + source_vrfs=[ + dict(name="GigabitEthernet0/0/0/0", vrf="siteE"), + ], + trusted_keys=[dict(key_id=1), dict(key_id=2)], + update_calendar=True, + ), + state="overridden", + ), + ) + commands = [ + "no ntp server vrf siteD 192.0.2.2 burst", + "no ntp interface GigabitEthernet0/0/0/0", + "ntp authentication-key 1 md5 encrypted testkey1", + "ntp server vrf siteD 192.0.2.3 burst", + "ntp server 192.0.2.2 burst iburst key 1 minpoll 4 maxpoll 5 prefer version 2 source GigabitEthernet0/0/0/1", + "ntp interface GigabitEthernet0/0/0/1 broadcast client", + "ntp interface GigabitEthernet0/0/0/1 multicast destination 224.0.0.8", + "ntp interface GigabitEthernet0/0/0/1 multicast client 224.0.0.8", + "ntp access-group ipv4 query-only QueryOnlyAcl2", + "ntp access-group vrf siteA ipv4 peer PeerAcl2", + "ntp access-group vrf siteA ipv4 serve ServeAcl2", + "ntp ipv4 dscp af12", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ntp_global_gathered(self): + self.maxDiff = None + run_cfg = dedent( + """\ + ntp + max-associations 10 + interface GigabitEthernet0/0/0/0 + broadcast client + multicast client 224.0.0.8 + multicast destination 224.0.0.8 + ! + authentication-key 1 md5 encrypted testkey + authentication-key 2 md5 encrypted 071B245F5A5B + authenticate + trusted-key 1 + trusted-key 2 + ipv4 dscp af11 + ipv6 precedence routine + peer vrf siteC 192.0.2.1 iburst + server 192.0.2.2 version 2 key 1 minpoll 4 maxpoll 5 prefer burst iburst source GigabitEthernet0/0/0/0 + drift file apphost + drift aging time 0 + master 1 + access-group vrf siteA ipv4 peer PeerAcl3 + access-group vrf siteA ipv4 serve ServeAcl2 + access-group ipv4 peer PeerAcl1 + access-group ipv4 serve ServeAcl1 + access-group ipv4 serve-only ServeOnlyAcl1 + access-group ipv4 query-only QueryOnlyAcl1 + access-group ipv6 peer PeerAcl2 + source vrf siteE GigabitEthernet0/0/0/0 + source GigabitEthernet0/0/0/0 + passive + broadcastdelay 1 + update-calendar + log-internal-sync + ! + """, + ) + self.get_config.return_value = run_cfg + print(self.get_config.return_value) + set_module_args(dict(state="gathered")) + gathered = { + "max_associations": 10, + "interfaces": [ + { + "name": "GigabitEthernet0/0/0/0", + "broadcast_client": True, + "multicast_client": "224.0.0.8", + "multicast_destination": "224.0.0.8", + }, + ], + "authentication_keys": [ + {"id": 1, "key": "testkey", "encryption": True}, + {"id": 2, "key": "071B245F5A5B", "encryption": True}, + ], + "authenticate": True, + "trusted_keys": [{"key_id": 1}, {"key_id": 2}], + "ipv4": {"dscp": "af11"}, + "ipv6": {"precedence": "routine"}, + "peers": [{"peer": "192.0.2.1", "vrf": "siteC", "iburst": True}], + "servers": [ + { + "server": "192.0.2.2", + "burst": True, + "iburst": True, + "key_id": 1, + "minpoll": 4, + "maxpoll": 5, + "prefer": True, + "version": 2, + "source": "GigabitEthernet0/0/0/0", + }, + ], + "drift": {"file": "apphost", "aging_time": 0}, + "master": {"stratum": 1}, + "access_group": { + "vrfs": [ + { + "name": "siteA", + "ipv4": {"peer": "PeerAcl3", "serve": "ServeAcl2"}, + }, + ], + "ipv4": { + "peer": "PeerAcl1", + "serve": "ServeAcl1", + "serve_only": "ServeOnlyAcl1", + "query_only": "QueryOnlyAcl1", + }, + "ipv6": {"peer": "PeerAcl2"}, + }, + "source_vrfs": [ + {"name": "GigabitEthernet0/0/0/0", "vrf": "siteE"}, + ], + "source_interface": "GigabitEthernet0/0/0/0", + "passive": True, + "broadcastdelay": 1, + "update_calendar": True, + "log_internal_sync": True, + } + result = self.execute_module(changed=False) + self.assertEqual(gathered, result["gathered"]) + + def test_iosxr_ntp_global_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="ntp\n max-associations 10\n interface GigabitEthernet0/0/0/0\n broadcast client\n" + " multicast client 224.0.0.8\n multicast destination 224.0.0.8\n !\n " + "authentication-key 1 md5 encrypted testkey\n authentication-key 2 md5 " + "encrypted 071B245F5A5B\n authenticate\n trusted-key 1\n trusted-key 2\n ipv4 dscp " + "af11\n ipv6 precedence routine\n peer vrf siteC 192.0.2.1 iburst\n" + " server 192.0.2.2 version 2 key 1 minpoll 4 maxpoll 5 prefer " + "burst iburst source GigabitEthernet0/0/0/0\n drift file apphost\n drift aging time 0\n" + " master 1\n access-group vrf siteA ipv4 peer PeerAcl3\n access-group vrf siteA " + "ipv4 serve ServeAcl2\n access-group ipv4 peer PeerAcl1\n access-group ipv4 serve " + "ServeAcl1\n access-group ipv4 serve-only ServeOnlyAcl1\n access-group ipv4 " + "query-only QueryOnlyAcl1\n access-group ipv6 peer PeerAcl2\n source vrf siteE " + "GigabitEthernet0/0/0/0\n source GigabitEthernet0/0/0/0\n" + " passive\n broadcastdelay " + "1\n update-calendar\n log-internal-sync\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "max_associations": 10, + "interfaces": [ + { + "name": "GigabitEthernet0/0/0/0", + "broadcast_client": True, + "multicast_client": "224.0.0.8", + "multicast_destination": "224.0.0.8", + }, + ], + "authentication_keys": [ + {"id": 1, "key": "testkey", "encryption": True}, + {"id": 2, "key": "071B245F5A5B", "encryption": True}, + ], + "authenticate": True, + "trusted_keys": [{"key_id": 1}, {"key_id": 2}], + "ipv4": {"dscp": "af11"}, + "ipv6": {"precedence": "routine"}, + "peers": [{"peer": "192.0.2.1", "vrf": "siteC", "iburst": True}], + "servers": [ + { + "server": "192.0.2.2", + "burst": True, + "iburst": True, + "key_id": 1, + "minpoll": 4, + "maxpoll": 5, + "prefer": True, + "version": 2, + "source": "GigabitEthernet0/0/0/0", + }, + ], + "drift": {"file": "apphost", "aging_time": 0}, + "master": {"stratum": 1}, + "access_group": { + "vrfs": [{"name": "siteA", "ipv4": {"peer": "PeerAcl3"}}], + "ipv4": { + "peer": "PeerAcl1", + "serve": "ServeAcl1", + "serve_only": "ServeOnlyAcl1", + "query_only": "QueryOnlyAcl1", + }, + "ipv6": {"peer": "PeerAcl2"}, + }, + "source_vrfs": [ + {"name": "GigabitEthernet0/0/0/0", "vrf": "siteE"}, + ], + "source_interface": "GigabitEthernet0/0/0/0", + "passive": True, + "broadcastdelay": 1, + "update_calendar": True, + "log_internal_sync": True, + } + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospf_interfaces.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospf_interfaces.py new file mode 100644 index 00000000..8c976944 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospf_interfaces.py @@ -0,0 +1,359 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_ospf_interfaces +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrOspf_InterfacesModule(TestIosxrModule): + module = iosxr_ospf_interfaces + + def setUp(self): + super(TestIosxrOspf_InterfacesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base." + "get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + + self.mock_edit_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.providers.CliProvider.edit_config", + ) + self.edit_config = self.mock_edit_config.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ospf_interfaces.ospf_interfaces." + "Ospf_interfacesFacts.get_ospf_interfaces", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrOspf_InterfacesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_edit_config.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_ospf_interfaces.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_ospf_interfaces_merged(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB1", + area=dict(area_id="0.0.0.3"), + ), + ], + cost=10, + authentication=dict( + message_digest=dict(keychain="iosxr"), + ), + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 cost 10", + "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 authentication message-digest", + "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 authentication message-digest keychain iosxr", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospf_interfaces_merged_idempotent(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB3", + area=dict(area_id="0.0.0.3"), + ), + ], + cost=20, + authentication=dict( + message_digest=dict(keychain="cisco"), + ), + ), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospf_interfaces_replaced(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB3", + area=dict(area_id="0.0.0.3"), + ), + ], + cost=40, + authentication=dict( + message_digest=dict(keychain="ciscoiosxr"), + ), + ), + ], + ), + ], + state="replaced", + ), + ) + commands = [ + "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 cost 40", + "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest", + "router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0 authentication message-digest keychain ciscoiosxr", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospf_interfaces_replaced_idempotent(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB3", + area=dict(area_id="0.0.0.3"), + ), + ], + cost=20, + authentication=dict( + message_digest=dict(keychain="cisco"), + ), + ), + ], + ), + ], + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospf_interfaces_overridden(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/4", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB4", + area=dict(area_id="0.0.0.4"), + ), + ], + cost=40, + authentication=dict( + message_digest=dict(keychain="iosxr"), + ), + ), + ], + ), + ], + state="overridden", + ), + ) + + commands = [ + "no router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0", + "router ospf LAB4 area 0.0.0.4 interface GigabitEthernet 0/0/0/4 cost 40", + "router ospf LAB4 area 0.0.0.4 interface GigabitEthernet 0/0/0/4 authentication message-digest", + "router ospf LAB4 area 0.0.0.4 interface GigabitEthernet 0/0/0/4 authentication message-digest keychain iosxr", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospf_interfaces_overridden_idempotent(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB3", + area=dict(area_id="0.0.0.3"), + ), + ], + cost=20, + authentication=dict( + message_digest=dict(keychain="cisco"), + ), + ), + ], + ), + ], + state="overridden", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospf_interfaces_deleted(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/0", + type="gigabitethernet", + ), + ], + state="deleted", + ), + ) + commands = [ + "no router ospf LAB3 area 0.0.0.3 interface GigabitEthernet 0/0/0/0", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospf_interfaces_deleted_idempotent(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + type="gigabitethernet", + ), + ], + state="deleted", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospf_interfaces_parsed(self): + set_module_args( + dict( + running_config="router ospf LAB3\n area 0.0.0.3\n interface GigabitEthernet0/0/0/0\n cost 20\n !\n !\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = [ + dict( + name="GigabitEthernet0/0/0/0", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB3", + area=dict(area_id="0.0.0.3"), + ), + ], + cost=20, + ), + ], + ), + ] + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_ospf_interfaces_rendered(self): + set_module_args( + dict( + config=[ + dict( + name="GigabitEthernet0/0/0/1", + type="gigabitethernet", + address_family=[ + dict( + afi="ipv4", + processes=[ + dict( + process_id="LAB1", + area=dict(area_id="0.0.0.3"), + ), + ], + cost=10, + authentication=dict( + message_digest=dict(keychain="iosxr"), + ), + ), + ], + ), + ], + state="rendered", + ), + ) + commands = [ + "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 cost 10", + "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 authentication message-digest", + "router ospf LAB1 area 0.0.0.3 interface GigabitEthernet 0/0/0/1 authentication message-digest keychain iosxr", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospfv2.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospfv2.py new file mode 100644 index 00000000..6d00a825 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospfv2.py @@ -0,0 +1,277 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_ospfv2 +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrOspfV2Module(TestIosxrModule): + module = iosxr_ospfv2 + + def setUp(self): + super(TestIosxrOspfV2Module, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base." + "get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + + self.mock_edit_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.providers.CliProvider.edit_config", + ) + self.edit_config = self.mock_edit_config.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ospfv2.ospfv2." + "Ospfv2Facts.get_ospfv2_data", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrOspfV2Module, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_edit_config.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_ospfv2.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_ospfv2_merged(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="300", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + log_adjacency_changes=dict(set=True), + ), + ], + ), + state="merged", + ), + ) + commands = [ + "router ospf 300", + "cost 2", + "default-metric 10", + "area 11 default-cost 5", + "log adjacency changes", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv2_merged_idempotent(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospfv2_replaced(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + dict( + process_id="40", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="replaced", + ), + ) + commands = [ + "router ospf 30", + "no default-metric 10", + "router ospf 40", + "cost 2", + "default-metric 10", + "area 11 default-cost 5", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv2_replaced_idempotent(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospfv2_overridden(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="40", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + log_adjacency_changes=dict(set=True), + ), + ], + ), + state="overridden", + ), + ) + + commands = [ + "router ospf 30", + "no cost 2", + "no default-metric 10", + "no area 11 default-cost 5", + "router ospf 40", + "cost 2", + "default-metric 10", + "area 11 default-cost 5", + "log adjacency changes", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv2_overridden_idempotent(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="overridden", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospfv2_deleted(self): + set_module_args( + dict( + config=dict(processes=[dict(process_id="30", cost=2)]), + state="deleted", + ), + ) + commands = [ + "router ospf 30", + "no cost 2", + "no default-metric 10", + "no area 11 default-cost 5", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv2_parsed(self): + set_module_args( + dict( + running_config="router ospf 50\n cost 2\n area 11\n default-cost 5\n !\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "processes": [ + dict( + process_id="50", + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + } + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_ospfv2_rendered(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="60", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + log_adjacency_changes=dict(set=True), + ), + ], + ), + state="rendered", + ), + ) + commands = [ + "area 11 default-cost 5", + "cost 2", + "log adjacency changes", + "default-metric 10", + "router ospf 60", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospfv3.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospfv3.py new file mode 100644 index 00000000..1b8e491f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ospfv3.py @@ -0,0 +1,271 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_ospfv3 +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrOspfV3Module(TestIosxrModule): + module = iosxr_ospfv3 + + def setUp(self): + super(TestIosxrOspfV3Module, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base." + "get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + + self.mock_edit_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.providers.providers.CliProvider.edit_config", + ) + self.edit_config = self.mock_edit_config.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.ospfv3.ospfv3." + "Ospfv3Facts.get_ospfv3_data", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrOspfV3Module, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_edit_config.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_ospfv3.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_ospfv3_merged(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="300", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="merged", + ), + ) + commands = [ + "router ospfv3 300", + "cost 2", + "default-metric 10", + "area 11 default-cost 5", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv3_merged_idempotent(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospfv3_replaced(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + dict( + process_id="40", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="replaced", + ), + ) + commands = [ + "router ospfv3 30", + "no default-metric 10", + "router ospfv3 40", + "cost 2", + "default-metric 10", + "area 11 default-cost 5", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv3_replaced_idempotent(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospfv3_overridden(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="40", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="overridden", + ), + ) + + commands = [ + "router ospfv3 30", + "no cost 2", + "no default-metric 10", + "no area 11 default-cost 5", + "router ospfv3 40", + "cost 2", + "default-metric 10", + "area 11 default-cost 5", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv3_overridden_idempotent(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="30", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="overridden", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_ospfv3_deleted(self): + set_module_args( + dict( + config=dict(processes=[dict(process_id="30", cost=2)]), + state="deleted", + ), + ) + commands = [ + "router ospfv3 30", + "no cost 2", + "no default-metric 10", + "no area 11 default-cost 5", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_ospfv3_parsed(self): + set_module_args( + dict( + running_config="router ospfv3 50\n cost 2\n area 11\n default-cost 5\n !\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "processes": [ + dict( + process_id="50", + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + } + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_ospfv3_rendered(self): + set_module_args( + dict( + config=dict( + processes=[ + dict( + process_id="60", + default_metric=10, + cost=2, + areas=[dict(area_id="11", default_cost=5)], + ), + ], + ), + state="rendered", + ), + ) + commands = [ + "area 11 default-cost 5", + "cost 2", + "default-metric 10", + "router ospfv3 60", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), commands) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ping.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ping.py new file mode 100644 index 00000000..d0ceda0f --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_ping.py @@ -0,0 +1,180 @@ +# +# (c) 2022, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_ping +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrPingModule(TestIosxrModule): + module = iosxr_ping + + def setUp(self): + super(TestIosxrPingModule, self).setUp() + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.config.ping.ping.Ping.run_command", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrPingModule, self).tearDown() + self.mock_execute_show_command.stop() + + def test_iosxr_ping_count(self): + self.execute_show_command.return_value = dedent( + """\ + Type escape sequence to abort. + ending 2, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds: + ! + Success rate is 100 percent (2/2), round-trip min/avg/max = 25/25/25 ms + """, + ) + set_module_args(dict(count=2, dest="8.8.8.8")) + result = self.execute_module() + mock_res = { + "commands": "ping ipv4 8.8.8.8 count 2", + "packet_loss": "0%", + "packets_rx": 2, + "packets_tx": 2, + "rtt": {"min": 25, "avg": 25, "max": 25}, + "changed": False, + } + self.assertEqual(result, mock_res) + + def test_iosxr_ping_v6(self): + self.execute_show_command.return_value = dedent( + """\ + Type escape sequence to abort. + ending 2, 100-byte ICMP Echos to 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff, timeout is 2 seconds: + ! + Success rate is 100 percent (2/2), round-trip min/avg/max = 25/25/25 ms + """, + ) + set_module_args( + dict( + count=2, + dest="2001:db8:ffff:ffff:ffff:ffff:ffff:ffff", + afi="ipv6", + ), + ) + result = self.execute_module() + mock_res = { + "commands": "ping ipv6 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff count 2", + "packet_loss": "0%", + "packets_rx": 2, + "packets_tx": 2, + "rtt": {"min": 25, "avg": 25, "max": 25}, + "changed": False, + } + self.assertEqual(result, mock_res) + + def test_iosxr_ping_options_all(self): + self.execute_show_command.return_value = dedent( + """\ + Type escape sequence to abort. + ending 2, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds: + ! + Success rate is 100 percent (2/2), round-trip min/avg/max = 25/25/25 ms + """, + ) + set_module_args( + { + "afi": "ipv4", + "count": 4, + "dest": "8.8.8.8", + "df_bit": True, + "size": "10", + "source": "Loopback88", + "state": "present", + "sweep": True, + "validate": True, + "vrf": "DummyVrf", + }, + ) + result = self.execute_module() + mock_res = { + "commands": "ping vrf DummyVrf ipv4 8.8.8.8 count 4 df-bit sweep validate size 10 source Loopback88", + "packet_loss": "0%", + "packets_rx": 2, + "packets_tx": 2, + "rtt": {"min": 25, "avg": 25, "max": 25}, + "changed": False, + } + self.assertEqual(result, mock_res) + + def test_iosxr_ping_state_absent_pass(self): + self.execute_show_command.return_value = dedent( + """\ + Type escape sequence to abort. + ending 2, 100-byte ICMP Echos to 8.8.8.8, timeout is 2 seconds: + ! + Success rate is 90 percent (2/2), round-trip min/avg/max = 25/25/25 ms + """, + ) + set_module_args(dict(count=2, dest="8.8.8.8", state="absent")) + result = self.execute_module(failed=True) + mock_res = { + "msg": "Ping succeeded unexpectedly", + "commands": "ping ipv4 8.8.8.8 count 2", + "packet_loss": "10%", + "packets_rx": 2, + "packets_tx": 2, + "rtt": {"min": 25, "avg": 25, "max": 25}, + "failed": True, + } + self.assertEqual(result, mock_res) + + def test_iosxr_ping_state_absent_pass(self): + self.execute_show_command.return_value = dedent( + """\ + Type escape sequence to abort. + Sending 5, 100-byte ICMP Echos to 192.0.2.1, timeout is 2 seconds: + ..... + Success rate is 0 percent (0/5) + """, + ) + set_module_args(dict(count=2, dest="192.0.2.1", state="absent")) + result = self.execute_module(failed=False) + print(result) + mock_res = { + "commands": "ping ipv4 192.0.2.1 count 2", + "packet_loss": "100%", + "packets_rx": 0, + "packets_tx": 5, + "rtt": {}, + "changed": False, + } + self.assertEqual(result, mock_res) + + def test_iosxr_ping_state_absent_present_fail(self): + self.execute_show_command.return_value = dedent( + """\ + Type escape sequence to abort. + ending 2, 100-byte ICMP Echos to 8.8.8.8, timeout is 12 seconds: + ! + Success rate is 0 percent (0/2), round-trip min/avg/max = 25/25/25 ms + """, + ) + set_module_args(dict(count=2, dest="8.8.8.8", state="present")) + result = self.execute_module(failed=True) + mock_res = { + "msg": "Ping failed unexpectedly", + "commands": "ping ipv4 8.8.8.8 count 2", + "packet_loss": "100%", + "packets_rx": 0, + "packets_tx": 2, + "rtt": {"min": 25, "avg": 25, "max": 25}, + "failed": True, + } + self.assertEqual(result, mock_res) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_prefix_lists.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_prefix_lists.py new file mode 100644 index 00000000..6dca5d92 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_prefix_lists.py @@ -0,0 +1,442 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_prefix_lists +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrPrefixListsModule(TestIosxrModule): + module = iosxr_prefix_lists + + def setUp(self): + super(TestIosxrPrefixListsModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.prefix_lists.prefix_lists." + "Prefix_listsFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrPrefixListsModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_prefix_lists_merged_idempotent(self): + run_cfg = dedent( + """ipv6 prefix-list test2\n 4 remark test\n! + \nipv4 prefix-list test1\n 3 remark test1\n 2 permit 10.0.0.0/24\n! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=[ + dict( + afi="ipv6", + prefix_lists=[ + dict( + name="test2", + entries=[ + dict( + sequence=4, + action="remark", + description="test", + ), + ], + ), + ], + ), + dict( + afi="ipv4", + prefix_lists=[ + dict( + name="test1", + entries=[ + dict( + sequence=3, + action="remark", + description="test1", + ), + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_prefix_lists_merged(self): + set_module_args( + dict( + config=[ + dict( + afi="ipv6", + prefix_lists=[ + dict( + name="test2", + entries=[ + dict( + sequence=4, + action="remark", + description="test", + ), + ], + ), + ], + ), + dict( + afi="ipv4", + prefix_lists=[ + dict( + name="test1", + entries=[ + dict( + sequence=3, + action="remark", + description="test1", + ), + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + dict( + name="test3", + entries=[ + dict( + sequence=5, + action="permit", + eq="3", + prefix="32.0.0.0/8", + ), + ], + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "ipv6 prefix-list test2 4 remark test", + "ipv4 prefix-list test1 2 permit 10.0.0.0/24", + "ipv4 prefix-list test1 3 remark test1", + "ipv4 prefix-list test3 5 permit 32.0.0.0/8 eq 3", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_prefix_lists_replaced(self): + run_cfg = dedent( + """ipv6 prefix-list test2\n 4 remark test\n! + \nipv4 prefix-list test1\n 3 remark test1\n 2 permit 10.0.0.0/24\n!""", + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + prefix_lists=[ + dict( + name="test2", + entries=[ + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + dict( + name="test1", + entries=[ + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + dict( + name="test3", + entries=[ + dict( + sequence=5, + action="permit", + eq="3", + prefix="32.0.0.0/8", + ), + ], + ), + ], + ), + ], + state="replaced", + ), + ) + commands = [ + "no ipv4 prefix-list test1 3 remark test1", + "ipv4 prefix-list test2 2 permit 10.0.0.0/24", + "ipv4 prefix-list test3 5 permit 32.0.0.0/8 eq 3", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_prefix_lists_replaced_idempotent(self): + run_cfg = dedent( + """ipv6 prefix-list test2\n 4 remark test\n! + \nipv4 prefix-list test1\n 3 remark test1\n 2 permit 10.0.0.0/24\n!""", + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=[ + dict( + afi="ipv6", + prefix_lists=[ + dict( + name="test2", + entries=[ + dict( + sequence=4, + action="remark", + description="test", + ), + ], + ), + ], + ), + dict( + afi="ipv4", + prefix_lists=[ + dict( + name="test1", + entries=[ + dict( + sequence=3, + action="remark", + description="test1", + ), + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + ], + ), + ], + state="replaced", + ), + ) + + self.execute_module(changed=False, commands=[]) + + def test_iosxr_prefix_list_deleted(self): + run_cfg = dedent( + """ipv6 prefix-list test2\n 4 remark test\n! + \nipv4 prefix-list test1\n 3 remark test1\n 2 permit 10.0.0.0/24\n!""", + ) + self.get_config.return_value = run_cfg + set_module_args(dict(state="deleted")) + + commands = ["no ipv4 prefix-list test1", "no ipv6 prefix-list test2"] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_prefix_list_deleted_idempotent(self): + run_cfg = dedent( + """\ + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(config=[], state="deleted")) + + result = self.execute_module(changed=False) + self.assertEqual(result["commands"], []) + + def test_iosxr_prefix_list_rendered(self): + set_module_args( + dict( + config=[ + dict( + afi="ipv6", + prefix_lists=[ + dict( + name="test2", + entries=[ + dict( + sequence=4, + action="remark", + description="test", + ), + ], + ), + ], + ), + dict( + afi="ipv4", + prefix_lists=[ + dict( + name="test1", + entries=[ + dict( + sequence=3, + action="remark", + description="test1", + ), + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + dict( + name="test3", + entries=[ + dict( + sequence=5, + action="permit", + eq="3", + prefix="32.0.0.0/8", + ), + ], + ), + ], + ), + ], + state="rendered", + ), + ) + + commands = [ + "ipv6 prefix-list test2 4 remark test", + "ipv4 prefix-list test1 2 permit 10.0.0.0/24", + "ipv4 prefix-list test1 3 remark test1", + "ipv4 prefix-list test3 5 permit 32.0.0.0/8 eq 3", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_prefix_list_parsed(self): + set_module_args( + dict( + running_config="ipv4 prefix-list test1\n 3 remark test1\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = [ + { + "afi": "ipv4", + "prefix_lists": [ + { + "name": "test1", + "entries": [ + { + "sequence": 3, + "action": "remark", + "description": "test1", + }, + ], + }, + ], + }, + ] + + self.assertEqual(parsed_list, result["parsed"]) + + def test_iosxr_prefix_list_overridden(self): + run_cfg = dedent( + """ipv6 prefix-list test2\n 4 remark test\n! + \nipv4 prefix-list test1\n 3 remark test1\n 2 permit 10.0.0.0/24\n! + """, + ) + + self.get_config.return_value = run_cfg + + set_module_args( + dict( + config=[ + dict( + afi="ipv4", + prefix_lists=[ + dict( + name="test2", + entries=[ + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + dict( + name="test1", + entries=[ + dict( + sequence=2, + action="permit", + prefix="10.0.0.0/24", + ), + ], + ), + ], + ), + ], + state="overridden", + ), + ) + commands = [ + "no ipv4 prefix-list test1 3 remark test1", + "ipv4 prefix-list test2 2 permit 10.0.0.0/24", + "no ipv6 prefix-list test2", + ] + + result = self.execute_module(changed=True) + self.assertEqual(set(result["commands"]), set(commands)) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_snmp_server.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_snmp_server.py new file mode 100644 index 00000000..14862519 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_snmp_server.py @@ -0,0 +1,3612 @@ +# (c) 2021 Red Hat Inc. +# +# 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 + +from textwrap import dedent + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_snmp_server +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule + + +class TestIosxrSnmpServerModule(TestIosxrModule): + module = iosxr_snmp_server + + def setUp(self): + super(TestIosxrSnmpServerModule, self).setUp() + + self.mock_get_resource_connection = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base." + "get_resource_connection", + ) + self.get_resource_connection = self.mock_get_resource_connection.start() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.snmp_server.snmp_server." + "Snmp_serverFacts.get_config", + ) + self.get_config = self.mock_get_config.start() + + def tearDown(self): + super(TestIosxrSnmpServerModule, self).tearDown() + self.get_resource_connection.stop() + self.get_config.stop() + + def test_iosxr_snmp_server_merged_idempotent(self): + self.maxDiff = None + run_cfg = dedent( + """\ + snmp-server vrf vrf1 + host 1.1.1.1 traps test1 + ! + snmp-server drop report acl IPv4 test1 + snmp-server drop unknown-user + snmp-server ipv4 dscp af11 + snmp-server ipv6 precedence routine + snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl + snmp-server community test2 RW SystemOwner IPv4 test IPv6 test1 + snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1 + snmp-server queue-length 2 + snmp-server trap-timeout 3 + snmp-server trap throttle-time 12 + snmp-server traps rf + snmp-server traps bfd + snmp-server traps bgp cbgp2 + snmp-server traps pim neighbor-change + snmp-server traps pim invalid-message-received + snmp-server traps pim rp-mapping-change + snmp-server traps pim interface-state-change + snmp-server traps copy-complete + snmp-server traps hsrp + snmp-server traps ipsla + snmp-server traps msdp peer-state-change + snmp-server traps snmp linkup + snmp-server traps snmp linkdown + snmp-server traps snmp coldstart + snmp-server traps snmp warmstart + snmp-server traps snmp authentication + snmp-server traps vrrp events + snmp-server traps flash removal + snmp-server traps flash insertion + snmp-server traps ipsec tunnel stop + snmp-server traps ipsec tunnel start + snmp-server traps power + snmp-server traps config + snmp-server traps entity + snmp-server traps sensor + snmp-server traps selective-vrf-download role-change + snmp-server traps syslog + snmp-server traps system + snmp-server traps ospf lsa lsa-maxage + snmp-server traps ospf lsa lsa-originate + snmp-server traps ospf errors bad-packet + snmp-server traps ospf errors authentication-failure + snmp-server traps ospf errors config-error + snmp-server traps ospf errors virt-bad-packet + snmp-server traps ospf errors virt-authentication-failure + snmp-server traps ospf errors virt-config-error + snmp-server traps ospf retransmit packets + snmp-server traps ospf retransmit virt-packets + snmp-server traps ospf state-change if-state-change + snmp-server traps ospf state-change neighbor-state-change + snmp-server traps ospf state-change virtif-state-change + snmp-server traps ospf state-change virtneighbor-state-change + snmp-server traps rsvp all + snmp-server traps rsvp new-flow + snmp-server traps rsvp lost-flow + snmp-server traps l2tun sessions + snmp-server traps l2tun tunnel-up + snmp-server traps l2tun tunnel-down + snmp-server traps vpls all + snmp-server traps vpls status + snmp-server traps vpls full-clear + snmp-server traps vpls full-raise + snmp-server traps bulkstat collection + snmp-server traps diameter peerup + snmp-server traps diameter peerdown + snmp-server traps diameter protocolerror + snmp-server traps diameter permanentfail + snmp-server traps diameter transientfail + snmp-server traps l2vpn all + snmp-server traps l2vpn vc-up + snmp-server traps l2vpn vc-down + snmp-server traps bridgemib + snmp-server traps ospfv3 errors bad-packet + snmp-server traps ospfv3 errors config-error + snmp-server traps ospfv3 errors virt-config-error + snmp-server traps ospfv3 state-change neighbor-state-change + snmp-server traps ospfv3 state-change virtif-state-change + snmp-server traps ospfv3 state-change virtneighbor-state-change + snmp-server traps ospfv3 state-change restart-status-change + snmp-server traps ospfv3 state-change restart-helper-status-change + snmp-server traps ospfv3 state-change restart-virtual-helper-status-change + snmp-server traps subscriber session-agg node + snmp-server traps subscriber session-agg access-interface + snmp-server traps addrpool low + snmp-server traps addrpool high + snmp-server traps cisco-entity-ext + snmp-server traps entity-state operstatus + snmp-server traps entity-state switchover + snmp-server traps entity-redundancy all + snmp-server traps entity-redundancy status + snmp-server traps entity-redundancy switchover + snmp-server chassis-id test2 + snmp-server contact t1 + snmp-server location test1 + snmp-server target list test host 1.1.1.2 + snmp-server target list test2 vrf vrf2 + snmp-server context c1 + snmp-server context c2 + snmp-server logging threshold oid-processing 1 + snmp-server logging threshold pdu-processing 1 + snmp-server mib bulkstat max-procmem-size 101 + snmp-server mib bulkstat object-list test1 + ! + snmp-server mib bulkstat schema mib1 + object-list test1 + poll-interval 1 + ! + snmp-server mib bulkstat transfer-id test2 + retry 1 + buffer-size 1024 + enable + format schemaASCII + retain 1 + schema test2 + ! + snmp-server timeouts duplicate 0 + snmp-server timeouts inQdrop 0 + snmp-server timeouts subagent 1 + snmp-server timeouts pdu stats 1 + snmp-server timeouts threshold 0 + snmp-server packetsize 490 + snmp-server correlator rule rule1 + timeout 5 + ! + snmp-server correlator ruleset rule1 + ! + snmp-server correlator buffer-size 1024 + snmp-server trap-source GigabitEthernet0/0/0/2 + snmp-server throttle-time 60 + snmp-server community-map cm1 context c1 security-name s1 target-list t1 + snmp-server inform retries 7 + snmp-server overload-control 4 6 + snmp-server ifmib internal cache max-duration 4 + snmp-server mroutemib send-all-vrf + snmp-server notification-log-mib size 5 + snmp-server notification-log-mib GlobalSize 5 + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + vrfs=[ + dict( + vrf="vrf1", + hosts=[ + dict( + community="test1", + host="1.1.1.1", + traps=True, + ), + ], + ), + ], + users=[ + dict( + Ipv4_acl="test1", + Ipv6_acl="test2", + group="test2", + user="u1", + v4_acl="v4acl", + ), + ], + timeouts=dict( + duplicate=0, + inQdrop=0, + pdu_stats=1, + subagent=1, + threshold=0, + ), + trap=dict(throttle_time=12), + targets=[ + dict(name="test2", vrf="vrf2"), + dict(host="1.1.1.2", name="test"), + ], + ifmib=dict(internal_cache_max_duration=4), + inform=dict(retries=7), + chassis_id="test2", + packetsize=490, + queue_length=2, + throttle_time=60, + trap_source="GigabitEthernet0/0/0/2", + trap_timeout=3, + context=["c1", "c2"], + correlator=dict( + buffer_size=1024, + rule_sets=[dict(name="rule1")], + rules=[dict(rule_name="rule1", timeout=5)], + ), + communities=[ + dict( + name="test2", + rw=True, + systemowner=True, + acl_v4="test", + acl_v6="test1", + ), + ], + community_maps=[ + dict( + name="cm1", + context="c1", + target_list="t1", + security_name="s1", + ), + ], + drop=dict(report_IPv4="test1", unknown_user=True), + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + groups=[ + dict( + Ipv4_acl="test", + Ipv6_acl="test1", + context="test3", + group="g2", + read="test1", + version="v1", + write="test2", + ), + ], + location="test1", + logging_threshold_oid_processing=1, + logging_threshold_pdu_processing=1, + mib_bulkstat_max_procmem_size=101, + mroutemib_send_all_vrf=True, + mib_object_lists=["test1"], + overload_control=dict( + overload_drop_time=4, + overload_throttle_rate=6, + ), + mib_schema=[ + dict( + name="mib1", + object_list="test1", + poll_interval=1, + ), + ], + notification_log_mib=dict(GlobalSize=5, size=5), + mib_bulkstat_transfer_ids=[ + dict( + buffer_size=1024, + enable=True, + format_schemaASCI=True, + name="test2", + retain=1, + retry=1, + schema="test2", + ), + ], + traps=dict( + diameter=dict( + peerdown=True, + peerup=True, + permanentfail=True, + protocolerror=True, + transientfail=True, + ), + entity=True, + entity_redundancy=dict( + all=True, + status=True, + switchover=True, + ), + entity_state=dict(operstatus=True, switchover=True), + flash=dict(insertion=True, removal=True), + hsrp=True, + ipsla=True, + ipsec=dict(start=True, stop=True), + bridgemib=True, + bulkstat_collection=True, + cisco_entity_ext=True, + config=True, + copy_complete=True, + addrpool=dict(high=True, low=True), + bfd=True, + bgp=dict(cbgp2=True), + l2tun=dict( + sessions=True, + tunnel_down=True, + tunnel_up=True, + ), + l2vpn=dict(all=True, vc_down=True, vc_up=True), + msdp_peer_state_change=True, + ospf=dict( + errors=dict( + authentication_failure=True, + bad_packet=True, + config_error=True, + virt_authentication_failure=True, + virt_bad_packet=True, + virt_config_error=True, + ), + lsa=dict(lsa_maxage=True, lsa_originate=True), + retransmit=dict(packets=True, virt_packets=True), + state_change=dict( + if_state_change=True, + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + ), + ), + ospfv3=dict( + errors=dict( + bad_packet=True, + config_error=True, + virt_config_error=True, + ), + state_change=dict( + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + restart_helper_status_change=True, + restart_status_change=True, + restart_virtual_helper_status_change=True, + ), + ), + pim=dict( + interface_state_change=True, + invalid_message_received=True, + neighbor_change=True, + rp_mapping_change=True, + ), + power=True, + rf=True, + rsvp=dict(all=True, lost_flow=True, new_flow=True), + selective_vrf_download_role_change=True, + sensor=True, + snmp=dict( + authentication=True, + coldstart=True, + linkdown=True, + linkup=True, + warmstart=True, + ), + subscriber=dict( + session_agg_access_interface=True, + session_agg_node=True, + ), + syslog=True, + system=True, + vpls=dict( + all=True, + full_clear=True, + full_raise=True, + status=True, + ), + vrrp_events=True, + ), + ), + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_snmp_server_merged(self): + self.maxDiff = None + + set_module_args( + dict( + config=dict( + vrfs=[ + dict( + vrf="vrf1", + hosts=[ + dict( + community="test1", + host="1.1.1.1", + traps=True, + ), + ], + ), + ], + users=[ + dict( + Ipv4_acl="test1", + Ipv6_acl="test2", + group="test2", + user="u1", + v4_acl="v4acl", + SystemOwner=True, + ), + ], + timeouts=dict( + duplicate=0, + inQdrop=0, + pdu_stats=1, + subagent=1, + threshold=0, + ), + trap=dict(throttle_time=12, link_ietf=True), + targets=[ + dict(name="test2", vrf="vrf2"), + dict(host="1.1.1.2", name="test"), + ], + ifmib=dict(internal_cache_max_duration=4), + inform=dict(retries=7), + chassis_id="test2", + packetsize=490, + queue_length=2, + throttle_time=60, + trap_source="GigabitEthernet0/0/0/2", + trap_timeout=3, + context=["c1", "c2"], + correlator=dict( + buffer_size=1024, + rule_sets=[dict(name="rule1")], + rules=[dict(rule_name="rule1", timeout=5)], + ), + communities=[ + dict( + name="test2", + ro=True, + sdrowner=True, + acl_v4="test", + acl_v6="test1", + ), + ], + community_maps=[ + dict( + name="cm1", + context="c1", + target_list="t1", + security_name="s1", + ), + ], + drop=dict(report_IPv4="test1", unknown_user=True), + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + groups=[ + dict( + Ipv4_acl="test", + Ipv6_acl="test1", + context="test3", + group="g2", + read="test1", + version="v1", + write="test2", + ), + ], + interfaces=[dict(name=" GigabitEthernet0/0/0/2")], + location="test1", + logging_threshold_oid_processing=1, + logging_threshold_pdu_processing=1, + mib_bulkstat_max_procmem_size=101, + mroutemib_send_all_vrf=True, + mib_object_lists=["test1"], + overload_control=dict( + overload_drop_time=4, + overload_throttle_rate=6, + ), + mib_schema=[ + dict( + name="mib1", + object_list="test1", + poll_interval=1, + ), + ], + notification_log_mib=dict(GlobalSize=5, size=5), + mib_bulkstat_transfer_ids=[ + dict( + buffer_size=1024, + enable=True, + format_schemaASCI=True, + name="test2", + retain=1, + retry=1, + schema="test2", + ), + ], + traps=dict( + diameter=dict( + peerdown=True, + peerup=True, + permanentfail=True, + protocolerror=True, + transientfail=True, + ), + entity=True, + entity_redundancy=dict( + all=True, + status=True, + switchover=True, + ), + entity_state=dict(operstatus=True, switchover=True), + flash=dict(insertion=True, removal=True), + hsrp=True, + ipsla=True, + ipsec=dict(start=True, stop=True), + bridgemib=True, + bulkstat_collection=True, + cisco_entity_ext=True, + config=True, + copy_complete=True, + addrpool=dict(high=True, low=True), + bfd=True, + bgp=dict(cbgp2=True), + l2tun=dict( + sessions=True, + tunnel_down=True, + tunnel_up=True, + ), + l2vpn=dict(all=True, vc_down=True, vc_up=True), + msdp_peer_state_change=True, + ospf=dict( + errors=dict( + authentication_failure=True, + bad_packet=True, + config_error=True, + virt_authentication_failure=True, + virt_bad_packet=True, + virt_config_error=True, + ), + lsa=dict(lsa_maxage=True, lsa_originate=True), + retransmit=dict(packets=True, virt_packets=True), + state_change=dict( + if_state_change=True, + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + ), + ), + ospfv3=dict( + errors=dict( + bad_packet=True, + config_error=True, + virt_config_error=True, + ), + state_change=dict( + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + restart_helper_status_change=True, + restart_status_change=True, + restart_virtual_helper_status_change=True, + ), + ), + pim=dict( + interface_state_change=True, + invalid_message_received=True, + neighbor_change=True, + rp_mapping_change=True, + ), + power=True, + rf=True, + rsvp=dict(all=True, lost_flow=True, new_flow=True), + selective_vrf_download_role_change=True, + sensor=True, + snmp=dict( + authentication=True, + coldstart=True, + linkdown=True, + linkup=True, + warmstart=True, + ), + subscriber=dict( + session_agg_access_interface=True, + session_agg_node=True, + ), + syslog=True, + system=True, + vpls=dict( + all=True, + full_clear=True, + full_raise=True, + status=True, + ), + vrrp_events=True, + isis=dict( + adjacency_change=True, + area_mismatch=True, + attempt_to_exceed_max_sequence=True, + authentication_failure=True, + authentication_type_failure=True, + corrupted_lsp_detected=True, + database_overload=True, + id_len_mismatch=True, + lsp_error_detected=True, + lsp_too_large_to_propagate=True, + manual_address_drops=True, + max_area_addresses_mismatch=True, + orig_lsp_buff_size_mismatch=True, + own_lsp_purge=True, + protocols_supported_mismatch=True, + rejected_adjacency=True, + sequence_number_skip=True, + version_skew=True, + ), + ), + ), + state="merged", + ), + ) + commands = [ + "snmp-server chassis-id test2", + "snmp-server correlator buffer-size 1024", + "snmp-server ipv4 dscp af11", + "snmp-server ipv6 precedence routine", + "snmp-server location test1", + "snmp-server logging threshold oid-processing 1", + "snmp-server logging threshold pdu-processing 1", + "snmp-server mib bulkstat max-procmem-size 101", + "snmp-server mroutemib send-all-vrf", + "snmp-server overload-control 4 6", + "snmp-server packetsize 490", + "snmp-server queue-length 2", + "snmp-server throttle-time 60", + "snmp-server trap-source GigabitEthernet0/0/0/2", + "snmp-server trap-timeout 3", + "snmp-server drop report acl IPv4 test1", + "snmp-server drop unknown-user", + "snmp-server ifmib internal cache max-duration 4", + "snmp-server inform retries 7", + "snmp-server notification-log-mib size 5", + "snmp-server notification-log-mib GlobalSize 5", + "snmp-server trap link ietf", + "snmp-server trap throttle-time 12", + "snmp-server timeouts threshold 0", + "snmp-server timeouts pdu stats 1", + "snmp-server timeouts subagent 1", + "snmp-server timeouts inQdrop 0", + "snmp-server timeouts duplicate 0", + "snmp-server traps addrpool low", + "snmp-server traps addrpool high", + "snmp-server traps bfd", + "snmp-server traps bgp cbgp2", + "snmp-server traps bulkstat collection", + "snmp-server traps bridgemib", + "snmp-server traps copy-complete", + "snmp-server traps cisco-entity-ext", + "snmp-server traps config", + "snmp-server traps diameter peerdown", + "snmp-server traps diameter peerup", + "snmp-server traps diameter protocolerror", + "snmp-server traps diameter permanentfail", + "snmp-server traps diameter transientfail", + "snmp-server traps entity", + "snmp-server traps entity-redundancy all", + "snmp-server traps entity-redundancy status", + "snmp-server traps entity-redundancy switchover", + "snmp-server traps entity-state operstatus", + "snmp-server traps entity-state switchover", + "snmp-server traps flash removal", + "snmp-server traps flash insertion", + "snmp-server traps hsrp", + "snmp-server traps ipsla", + "snmp-server traps ipsec tunnel start", + "snmp-server traps ipsec tunnel stop", + "snmp-server traps isis adjacency-change area-mismatch attempt-to-exceed-max-sequence " + "authentication-failure authentication-type-failure corrupted-lsp-detected database-overload " + "id-len-mismatch lsp-error-detected lsp-too-large-to-propagate manual-address-drops" + " max-area-addresses-mismatch orig-lsp-buff-size-mismatch version-skew own-lsp-purge" + " rejected-adjacency protocols-supported-mismatch sequence-number-skip", + "snmp-server traps l2tun sessions", + "snmp-server traps l2tun tunnel-up", + "snmp-server traps l2tun tunnel-down", + "snmp-server traps l2vpn all", + "snmp-server traps l2vpn vc-up", + "snmp-server traps l2vpn vc-down", + "snmp-server traps msdp peer-state-change", + "snmp-server traps ospf retransmit virt-packets", + "snmp-server traps ospf retransmit packets", + "snmp-server traps ospf lsa lsa-originate", + "snmp-server traps ospf lsa lsa-maxage", + "snmp-server traps ospf errors bad-packet", + "snmp-server traps ospf errors authentication-failure", + "snmp-server traps ospf errors config-error", + "snmp-server traps ospf errors virt-bad-packet", + "snmp-server traps ospf errors virt-authentication-failure", + "snmp-server traps ospf errors virt-config-error", + "snmp-server traps ospf state-change if-state-change", + "snmp-server traps ospf state-change neighbor-state-change", + "snmp-server traps ospf state-change virtif-state-change", + "snmp-server traps ospf state-change virtneighbor-state-change", + "snmp-server traps ospfv3 errors bad-packet", + "snmp-server traps ospfv3 errors config-error", + "snmp-server traps ospfv3 errors virt-config-error", + "snmp-server traps ospfv3 state-change neighbor-state-change", + "snmp-server traps ospfv3 state-change virtif-state-change", + "snmp-server traps ospfv3 state-change virtneighbor-state-change", + "snmp-server traps ospfv3 state-change restart-status-change", + "snmp-server traps ospfv3 state-change restart-helper-status-change", + "snmp-server traps ospfv3 state-change restart-virtual-helper-status-change", + "snmp-server traps power", + "snmp-server traps rf", + "snmp-server traps pim neighbor-change", + "snmp-server traps pim invalid-message-received", + "snmp-server traps pim rp-mapping-change", + "snmp-server traps pim interface-state-change", + "snmp-server traps rsvp lost-flow", + "snmp-server traps rsvp new-flow", + "snmp-server traps rsvp all", + "snmp-server traps selective-vrf-download role-change", + "snmp-server traps sensor", + "snmp-server traps vrrp events", + "snmp-server traps syslog", + "snmp-server traps system", + "snmp-server traps subscriber session-agg access-interface", + "snmp-server traps subscriber session-agg node", + "snmp-server traps vpls all", + "snmp-server traps vpls full-clear", + "snmp-server traps vpls full-raise", + "snmp-server traps vpls status", + "snmp-server traps snmp linkup", + "snmp-server traps snmp linkdown", + "snmp-server traps snmp coldstart", + "snmp-server traps snmp warmstart", + "snmp-server traps snmp authentication", + "snmp-server community test2 RO SDROwner IPv4 test IPv6 test1", + "snmp-server community-map cm1 context c1 security-name s1 target-list t1", + "snmp-server correlator ruleset rule1", + "snmp-server correlator rule rule1 timeout 5", + "snmp-server context c1", + "snmp-server context c2", + "snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1", + "snmp-server interface GigabitEthernet0/0/0/2", + "snmp-server mib bulkstat object-list test1", + "snmp-server mib bulkstat schema mib1 object-list test1", + "snmp-server mib bulkstat schema mib1 poll-interval 1", + "snmp-server mib bulkstat transfer-id test2 buffer-size 1024", + "snmp-server mib bulkstat transfer-id test2 enable", + "snmp-server mib bulkstat transfer-id test2 format schemaASCII", + "snmp-server mib bulkstat transfer-id test2 retain 1", + "snmp-server mib bulkstat transfer-id test2 retry 1", + "snmp-server mib bulkstat transfer-id test2 schema test2", + "snmp-server user u1 test2 IPv4 test1 IPv6 test2 v4acl SystemOwner", + "snmp-server target list test2 vrf vrf2", + "snmp-server target list test host 1.1.1.2", + "snmp-server vrf vrf1", + "host 1.1.1.1 traps test1", + ] + result = self.execute_module(changed=True) + print(result["commands"]) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_snmp_server_deleted(self): + self.maxDiff = None + run_cfg = dedent( + """\ + snmp-server vrf vrf1 + host 1.1.1.1 traps test1 + ! + snmp-server drop report acl IPv4 test1 + snmp-server drop unknown-user + snmp-server ipv4 dscp af11 + snmp-server ipv6 precedence routine + snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl + snmp-server community test2 RW SystemOwner IPv4 test IPv6 test1 + snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1 + snmp-server queue-length 2 + snmp-server trap-timeout 3 + snmp-server trap throttle-time 12 + snmp-server traps rf + snmp-server traps bfd + snmp-server traps bgp cbgp2 + snmp-server traps pim neighbor-change + snmp-server traps pim invalid-message-received + snmp-server traps pim rp-mapping-change + snmp-server traps pim interface-state-change + snmp-server traps copy-complete + snmp-server traps hsrp + snmp-server traps ipsla + snmp-server traps msdp peer-state-change + snmp-server traps snmp linkup + snmp-server traps snmp linkdown + snmp-server traps snmp coldstart + snmp-server traps snmp warmstart + snmp-server traps snmp authentication + snmp-server traps vrrp events + snmp-server traps flash removal + snmp-server traps flash insertion + snmp-server traps ipsec tunnel stop + snmp-server traps ipsec tunnel start + snmp-server traps power + snmp-server traps config + snmp-server traps entity + snmp-server traps sensor + snmp-server traps selective-vrf-download role-change + snmp-server traps syslog + snmp-server traps system + snmp-server traps ospf lsa lsa-maxage + snmp-server traps ospf lsa lsa-originate + snmp-server traps ospf errors bad-packet + snmp-server traps ospf errors authentication-failure + snmp-server traps ospf errors config-error + snmp-server traps ospf errors virt-bad-packet + snmp-server traps ospf errors virt-authentication-failure + snmp-server traps ospf errors virt-config-error + snmp-server traps ospf retransmit packets + snmp-server traps ospf retransmit virt-packets + snmp-server traps ospf state-change if-state-change + snmp-server traps ospf state-change neighbor-state-change + snmp-server traps ospf state-change virtif-state-change + snmp-server traps ospf state-change virtneighbor-state-change + snmp-server traps rsvp all + snmp-server traps rsvp new-flow + snmp-server traps rsvp lost-flow + snmp-server traps l2tun sessions + snmp-server traps l2tun tunnel-up + snmp-server traps l2tun tunnel-down + snmp-server traps vpls all + snmp-server traps vpls status + snmp-server traps vpls full-clear + snmp-server traps vpls full-raise + snmp-server traps bulkstat collection + snmp-server traps diameter peerup + snmp-server traps diameter peerdown + snmp-server traps diameter protocolerror + snmp-server traps diameter permanentfail + snmp-server traps diameter transientfail + snmp-server traps l2vpn all + snmp-server traps l2vpn vc-up + snmp-server traps l2vpn vc-down + snmp-server traps bridgemib + snmp-server traps ospfv3 errors bad-packet + snmp-server traps ospfv3 errors config-error + snmp-server traps ospfv3 errors virt-config-error + snmp-server traps ospfv3 state-change neighbor-state-change + snmp-server traps ospfv3 state-change virtif-state-change + snmp-server traps ospfv3 state-change virtneighbor-state-change + snmp-server traps ospfv3 state-change restart-status-change + snmp-server traps ospfv3 state-change restart-helper-status-change + snmp-server traps ospfv3 state-change restart-virtual-helper-status-change + snmp-server traps subscriber session-agg node + snmp-server traps subscriber session-agg access-interface + snmp-server traps addrpool low + snmp-server traps addrpool high + snmp-server traps cisco-entity-ext + snmp-server traps entity-state operstatus + snmp-server traps entity-state switchover + snmp-server traps entity-redundancy all + snmp-server traps entity-redundancy status + snmp-server traps entity-redundancy switchover + snmp-server chassis-id test2 + snmp-server contact t1 + snmp-server location test1 + snmp-server target list test host 1.1.1.2 + snmp-server target list test2 vrf vrf2 + snmp-server context c1 + snmp-server context c2 + snmp-server logging threshold oid-processing 1 + snmp-server logging threshold pdu-processing 1 + snmp-server mib bulkstat max-procmem-size 101 + snmp-server mib bulkstat object-list test1 + ! + snmp-server timeouts duplicate 0 + snmp-server timeouts inQdrop 0 + snmp-server timeouts subagent 1 + snmp-server timeouts pdu stats 1 + snmp-server timeouts threshold 0 + snmp-server packetsize 490 + snmp-server correlator buffer-size 1024 + snmp-server trap-source GigabitEthernet0/0/0/2 + snmp-server throttle-time 60 + snmp-server community-map cm1 context c1 security-name s1 target-list t1 + snmp-server inform retries 7 + snmp-server overload-control 4 6 + snmp-server interface GigabitEthernet0/0/0/2 + ! + snmp-server ifmib internal cache max-duration 4 + snmp-server mroutemib send-all-vrf + snmp-server notification-log-mib size 5 + snmp-server notification-log-mib GlobalSize 5 + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(state="deleted")) + commands = [ + "no snmp-server chassis-id test2", + "no snmp-server correlator buffer-size 1024", + "no snmp-server contact t1", + "no snmp-server ipv4 dscp af11", + "no snmp-server ipv6 precedence routine", + "no snmp-server location test1", + "no snmp-server logging threshold oid-processing 1", + "no snmp-server logging threshold pdu-processing 1", + "no snmp-server mib bulkstat max-procmem-size 101", + "no snmp-server mroutemib send-all-vrf", + "no snmp-server overload-control 4 6", + "no snmp-server packetsize 490", + "no snmp-server queue-length 2", + "no snmp-server throttle-time 60", + "no snmp-server trap-source GigabitEthernet0/0/0/2", + "no snmp-server trap-timeout 3", + "no snmp-server drop report acl IPv4 test1", + "no snmp-server drop unknown-user", + "no snmp-server ifmib internal cache max-duration 4", + "no snmp-server inform retries 7", + "no snmp-server notification-log-mib size 5", + "no snmp-server notification-log-mib GlobalSize 5", + "no snmp-server trap throttle-time 12", + "no snmp-server timeouts threshold 0", + "no snmp-server timeouts pdu stats 1", + "no snmp-server timeouts subagent 1", + "no snmp-server timeouts inQdrop 0", + "no snmp-server timeouts duplicate 0", + "no snmp-server traps addrpool low", + "no snmp-server traps addrpool high", + "no snmp-server traps bfd", + "no snmp-server traps bgp cbgp2", + "no snmp-server traps bulkstat collection", + "no snmp-server traps bridgemib", + "no snmp-server traps copy-complete", + "no snmp-server traps cisco-entity-ext", + "no snmp-server traps config", + "no snmp-server traps diameter peerdown", + "no snmp-server traps diameter peerup", + "no snmp-server traps diameter protocolerror", + "no snmp-server traps diameter permanentfail", + "no snmp-server traps diameter transientfail", + "no snmp-server traps entity", + "no snmp-server traps entity-redundancy all", + "no snmp-server traps entity-redundancy status", + "no snmp-server traps entity-redundancy switchover", + "no snmp-server traps entity-state operstatus", + "no snmp-server traps entity-state switchover", + "no snmp-server traps flash removal", + "no snmp-server traps flash insertion", + "no snmp-server traps hsrp", + "no snmp-server traps ipsla", + "no snmp-server traps ipsec tunnel start", + "no snmp-server traps ipsec tunnel stop", + "no snmp-server traps l2tun sessions", + "no snmp-server traps l2tun tunnel-up", + "no snmp-server traps l2tun tunnel-down", + "no snmp-server traps l2vpn all", + "no snmp-server traps l2vpn vc-up", + "no snmp-server traps l2vpn vc-down", + "no snmp-server traps msdp peer-state-change", + "no snmp-server traps ospf retransmit virt-packets", + "no snmp-server traps ospf retransmit packets", + "no snmp-server traps ospf lsa lsa-originate", + "no snmp-server traps ospf lsa lsa-maxage", + "no snmp-server traps ospf errors bad-packet", + "no snmp-server traps ospf errors authentication-failure", + "no snmp-server traps ospf errors config-error", + "no snmp-server traps ospf errors virt-bad-packet", + "no snmp-server traps ospf errors virt-authentication-failure", + "no snmp-server traps ospf errors virt-config-error", + "no snmp-server traps ospf state-change if-state-change", + "no snmp-server traps ospf state-change neighbor-state-change", + "no snmp-server traps ospf state-change virtif-state-change", + "no snmp-server traps ospf state-change virtneighbor-state-change", + "no snmp-server traps ospfv3 errors bad-packet", + "no snmp-server traps ospfv3 errors config-error", + "no snmp-server traps ospfv3 errors virt-config-error", + "no snmp-server traps ospfv3 state-change neighbor-state-change", + "no snmp-server traps ospfv3 state-change virtif-state-change", + "no snmp-server traps ospfv3 state-change virtneighbor-state-change", + "no snmp-server traps ospfv3 state-change restart-status-change", + "no snmp-server traps ospfv3 state-change restart-helper-status-change", + "no snmp-server traps ospfv3 state-change restart-virtual-helper-status-change", + "no snmp-server traps power", + "no snmp-server traps rf", + "no snmp-server traps pim neighbor-change", + "no snmp-server traps pim invalid-message-received", + "no snmp-server traps pim rp-mapping-change", + "no snmp-server traps pim interface-state-change", + "no snmp-server traps rsvp lost-flow", + "no snmp-server traps rsvp new-flow", + "no snmp-server traps rsvp all", + "no snmp-server traps selective-vrf-download role-change", + "no snmp-server traps sensor", + "no snmp-server traps vrrp events", + "no snmp-server traps syslog", + "no snmp-server traps system", + "no snmp-server traps subscriber session-agg access-interface", + "no snmp-server traps subscriber session-agg node", + "no snmp-server traps vpls all", + "no snmp-server traps vpls full-clear", + "no snmp-server traps vpls full-raise", + "no snmp-server traps vpls status", + "no snmp-server traps snmp linkup", + "no snmp-server traps snmp linkdown", + "no snmp-server traps snmp coldstart", + "no snmp-server traps snmp warmstart", + "no snmp-server traps snmp authentication", + "no snmp-server community test2 RW SystemOwner IPv4 test IPv6 test1", + "no snmp-server community-map cm1 context c1 security-name s1 target-list t1", + "no snmp-server context c1", + "no snmp-server context c2", + "no snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1", + "no snmp-server interface GigabitEthernet0/0/0/2", + "no snmp-server mib bulkstat object-list test1", + "no snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl", + "no snmp-server target list test host 1.1.1.2", + "no snmp-server target list test2 vrf vrf2", + "no snmp-server vrf vrf1", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_snmp_server_replaced(self): + self.maxDiff = None + run_cfg = dedent( + """\ + snmp-server vrf vrf1 + host 1.1.1.1 traps test1 + ! + snmp-server drop report acl IPv4 test1 + snmp-server drop unknown-user + snmp-server ipv4 dscp af11 + snmp-server ipv6 precedence routine + snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl + snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 + snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1 + snmp-server queue-length 2 + snmp-server trap-timeout 3 + snmp-server trap throttle-time 12 + snmp-server traps rf + snmp-server traps bfd + snmp-server traps bgp cbgp2 + snmp-server traps pim neighbor-change + snmp-server traps pim invalid-message-received + snmp-server traps pim rp-mapping-change + snmp-server traps pim interface-state-change + snmp-server traps copy-complete + snmp-server traps hsrp + snmp-server traps ipsla + snmp-server traps msdp peer-state-change + snmp-server traps snmp linkup + snmp-server traps snmp linkdown + snmp-server traps snmp coldstart + snmp-server traps snmp warmstart + snmp-server traps snmp authentication + snmp-server traps vrrp events + snmp-server traps flash removal + snmp-server traps flash insertion + snmp-server traps ipsec tunnel stop + snmp-server traps ipsec tunnel start + snmp-server traps power + snmp-server traps config + snmp-server traps entity + snmp-server traps sensor + snmp-server traps selective-vrf-download role-change + snmp-server traps syslog + snmp-server traps system + snmp-server traps ospf lsa lsa-maxage + snmp-server traps ospf lsa lsa-originate + snmp-server traps ospf errors bad-packet + snmp-server traps ospf errors authentication-failure + snmp-server traps ospf errors config-error + snmp-server traps ospf errors virt-bad-packet + snmp-server traps ospf errors virt-authentication-failure + snmp-server traps ospf errors virt-config-error + snmp-server traps ospf retransmit packets + snmp-server traps ospf retransmit virt-packets + snmp-server traps ospf state-change if-state-change + snmp-server traps ospf state-change neighbor-state-change + snmp-server traps ospf state-change virtif-state-change + snmp-server traps ospf state-change virtneighbor-state-change + snmp-server traps rsvp all + snmp-server traps rsvp new-flow + snmp-server traps rsvp lost-flow + snmp-server traps l2tun sessions + snmp-server traps l2tun tunnel-up + snmp-server traps l2tun tunnel-down + snmp-server traps vpls all + snmp-server traps vpls status + snmp-server traps vpls full-clear + snmp-server traps vpls full-raise + snmp-server traps bulkstat collection + snmp-server traps diameter peerup + snmp-server traps diameter peerdown + snmp-server traps diameter protocolerror + snmp-server traps diameter permanentfail + snmp-server traps diameter transientfail + snmp-server traps l2vpn all + snmp-server traps l2vpn vc-up + snmp-server traps l2vpn vc-down + snmp-server traps bridgemib + snmp-server traps ospfv3 errors bad-packet + snmp-server traps ospfv3 errors config-error + snmp-server traps ospfv3 errors virt-config-error + snmp-server traps ospfv3 state-change neighbor-state-change + snmp-server traps ospfv3 state-change virtif-state-change + snmp-server traps ospfv3 state-change virtneighbor-state-change + snmp-server traps ospfv3 state-change restart-status-change + snmp-server traps ospfv3 state-change restart-helper-status-change + snmp-server traps ospfv3 state-change restart-virtual-helper-status-change + snmp-server traps subscriber session-agg node + snmp-server traps subscriber session-agg access-interface + snmp-server traps addrpool low + snmp-server traps addrpool high + snmp-server traps cisco-entity-ext + snmp-server traps entity-state operstatus + snmp-server traps entity-state switchover + snmp-server traps entity-redundancy all + snmp-server traps entity-redundancy status + snmp-server traps entity-redundancy switchover + snmp-server chassis-id test2 + snmp-server contact t1 + snmp-server location test1 + snmp-server target list test host 1.1.1.2 + snmp-server target list test2 vrf vrf2 + snmp-server context c1 + snmp-server context c2 + snmp-server logging threshold oid-processing 1 + snmp-server logging threshold pdu-processing 1 + snmp-server mib bulkstat max-procmem-size 101 + snmp-server mib bulkstat object-list test1 + ! + snmp-server mib bulkstat schema mib1 + object-list test1 + poll-interval 1 + ! + snmp-server mib bulkstat transfer-id test2 + retry 1 + buffer-size 1024 + enable + format schemaASCII + retain 1 + schema test2 + ! + snmp-server timeouts duplicate 0 + snmp-server timeouts inQdrop 0 + snmp-server timeouts subagent 1 + snmp-server timeouts pdu stats 1 + snmp-server timeouts threshold 0 + snmp-server packetsize 490 + snmp-server correlator rule rule1 + timeout 5 + ! + snmp-server correlator ruleset rule1 + ! + snmp-server correlator buffer-size 1024 + snmp-server trap-source GigabitEthernet0/0/0/2 + snmp-server throttle-time 60 + snmp-server community-map cm1 context c1 security-name s1 target-list t1 + snmp-server inform retries 7 + snmp-server overload-control 4 6 + snmp-server ifmib internal cache max-duration 4 + snmp-server mroutemib send-all-vrf + snmp-server notification-log-mib size 5 + snmp-server notification-log-mib GlobalSize 5 + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + vrfs=[ + dict( + vrf="vrf2", + hosts=[ + dict( + community="test1", + host="1.1.1.1", + traps=True, + ), + ], + ), + ], + users=[ + dict( + Ipv4_acl="test1", + Ipv6_acl="test2", + group="test2", + user="u1", + v4_acl="v4acl", + ), + ], + timeouts=dict( + duplicate=0, + inQdrop=0, + pdu_stats=1, + subagent=1, + threshold=0, + ), + trap=dict(throttle_time=12), + targets=[ + dict(name="test2", vrf="vrf2"), + dict(host="1.1.1.2", name="test"), + ], + ifmib=dict(internal_cache_max_duration=4), + inform=dict(retries=7), + chassis_id="test2", + packetsize=490, + queue_length=2, + throttle_time=60, + trap_source="GigabitEthernet0/0/0/2", + trap_timeout=3, + context=["c1", "c2"], + correlator=dict( + buffer_size=1024, + rule_sets=[dict(name="rule1")], + rules=[dict(rule_name="rule1", timeout=5)], + ), + communities=[ + dict( + name="test2", + ro=True, + sdrowner=True, + acl_v4="test", + acl_v6="test1", + ), + ], + community_maps=[ + dict( + name="cm1", + context="c1", + target_list="t1", + security_name="s1", + ), + ], + drop=dict(report_IPv4="test1", unknown_user=True), + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + groups=[ + dict( + Ipv4_acl="test", + Ipv6_acl="test1", + context="test3", + group="g2", + read="test1", + version="v1", + write="test2", + ), + ], + location="test", + logging_threshold_oid_processing=2, + logging_threshold_pdu_processing=1, + mib_bulkstat_max_procmem_size=101, + mroutemib_send_all_vrf=True, + mib_object_lists=["test1"], + overload_control=dict( + overload_drop_time=4, + overload_throttle_rate=6, + ), + mib_schema=[ + dict( + name="mib1", + object_list="test1", + poll_interval=1, + ), + ], + notification_log_mib=dict(GlobalSize=5, size=5), + mib_bulkstat_transfer_ids=[ + dict( + buffer_size=1024, + enable=True, + format_schemaASCI=True, + name="test2", + retain=1, + retry=1, + schema="test2", + ), + ], + traps=dict( + diameter=dict( + peerdown=True, + peerup=True, + permanentfail=True, + protocolerror=True, + transientfail=True, + ), + entity=True, + entity_redundancy=dict( + all=True, + status=True, + switchover=True, + ), + entity_state=dict(operstatus=True, switchover=True), + flash=dict(insertion=True, removal=True), + ipsec=dict(start=True, stop=True), + bridgemib=True, + bulkstat_collection=True, + cisco_entity_ext=True, + config=True, + copy_complete=True, + addrpool=dict(high=True, low=True), + bfd=True, + bgp=dict(cbgp2=True), + l2tun=dict( + sessions=True, + tunnel_down=True, + tunnel_up=True, + ), + l2vpn=dict(all=True, vc_down=True, vc_up=True), + msdp_peer_state_change=True, + ospf=dict( + errors=dict( + authentication_failure=True, + bad_packet=True, + config_error=True, + virt_authentication_failure=True, + virt_bad_packet=True, + virt_config_error=True, + ), + lsa=dict(lsa_maxage=True, lsa_originate=True), + retransmit=dict(packets=True, virt_packets=True), + state_change=dict( + if_state_change=True, + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + ), + ), + ospfv3=dict( + errors=dict( + bad_packet=True, + config_error=True, + virt_config_error=True, + ), + ), + pim=dict( + interface_state_change=True, + invalid_message_received=True, + neighbor_change=True, + rp_mapping_change=True, + ), + power=True, + rf=True, + rsvp=dict(all=True, lost_flow=True, new_flow=True), + selective_vrf_download_role_change=True, + sensor=True, + snmp=dict( + authentication=True, + coldstart=True, + linkdown=True, + linkup=True, + warmstart=True, + ), + subscriber=dict( + session_agg_access_interface=True, + session_agg_node=True, + ), + syslog=True, + system=True, + vpls=dict( + all=True, + full_clear=True, + full_raise=True, + status=True, + ), + vrrp_events=True, + ), + ), + state="replaced", + ), + ) + commands = [ + "no snmp-server contact t1", + "no snmp-server traps hsrp", + "no snmp-server traps ipsla", + "no snmp-server traps ospfv3 state-change neighbor-state-change", + "no snmp-server traps ospfv3 state-change virtif-state-change", + "no snmp-server traps ospfv3 state-change virtneighbor-state-change", + "no snmp-server traps ospfv3 state-change restart-status-change", + "no snmp-server traps ospfv3 state-change restart-helper-status-change", + "no snmp-server traps ospfv3 state-change restart-virtual-helper-status-change", + "no snmp-server vrf vrf1", + "snmp-server location test", + "snmp-server logging threshold oid-processing 2", + "snmp-server user u1 test2 IPv4 test1 IPv6 test2 v4acl", + "snmp-server vrf vrf2", + "host 1.1.1.1 traps test1", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_snmp_server_replaced_idempotent(self): + self.maxDiff = None + run_cfg = dedent( + """\ + snmp-server vrf vrf1 + host 1.1.1.1 traps test1 + ! + snmp-server drop report acl IPv4 test1 + snmp-server drop unknown-user + snmp-server ipv4 dscp af11 + snmp-server ipv6 precedence routine + snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl + snmp-server community test2 RW SystemOwner IPv4 test IPv6 test1 + snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1 + snmp-server queue-length 2 + snmp-server trap-timeout 3 + snmp-server trap throttle-time 12 + snmp-server traps rf + snmp-server traps bfd + snmp-server traps bgp cbgp2 + snmp-server traps pim neighbor-change + snmp-server traps pim invalid-message-received + snmp-server traps pim rp-mapping-change + snmp-server traps pim interface-state-change + snmp-server traps copy-complete + snmp-server traps hsrp + snmp-server traps ipsla + snmp-server traps msdp peer-state-change + snmp-server traps snmp linkup + snmp-server traps snmp linkdown + snmp-server traps snmp coldstart + snmp-server traps snmp warmstart + snmp-server traps snmp authentication + snmp-server traps vrrp events + snmp-server traps flash removal + snmp-server traps flash insertion + snmp-server traps ipsec tunnel stop + snmp-server traps ipsec tunnel start + snmp-server traps power + snmp-server traps config + snmp-server traps entity + snmp-server traps sensor + snmp-server traps selective-vrf-download role-change + snmp-server traps syslog + snmp-server traps system + snmp-server traps ospf lsa lsa-maxage + snmp-server traps ospf lsa lsa-originate + snmp-server traps ospf errors bad-packet + snmp-server traps ospf errors authentication-failure + snmp-server traps ospf errors config-error + snmp-server traps ospf errors virt-bad-packet + snmp-server traps ospf errors virt-authentication-failure + snmp-server traps ospf errors virt-config-error + snmp-server traps ospf retransmit packets + snmp-server traps ospf retransmit virt-packets + snmp-server traps ospf state-change if-state-change + snmp-server traps ospf state-change neighbor-state-change + snmp-server traps ospf state-change virtif-state-change + snmp-server traps ospf state-change virtneighbor-state-change + snmp-server traps rsvp all + snmp-server traps rsvp new-flow + snmp-server traps rsvp lost-flow + snmp-server traps l2tun sessions + snmp-server traps l2tun tunnel-up + snmp-server traps l2tun tunnel-down + snmp-server traps vpls all + snmp-server traps vpls status + snmp-server traps vpls full-clear + snmp-server traps vpls full-raise + snmp-server traps bulkstat collection + snmp-server traps diameter peerup + snmp-server traps diameter peerdown + snmp-server traps diameter protocolerror + snmp-server traps diameter permanentfail + snmp-server traps diameter transientfail + snmp-server traps l2vpn all + snmp-server traps l2vpn vc-up + snmp-server traps l2vpn vc-down + snmp-server traps bridgemib + snmp-server traps ospfv3 errors bad-packet + snmp-server traps ospfv3 errors config-error + snmp-server traps ospfv3 errors virt-config-error + snmp-server traps ospfv3 state-change neighbor-state-change + snmp-server traps ospfv3 state-change virtif-state-change + snmp-server traps ospfv3 state-change virtneighbor-state-change + snmp-server traps ospfv3 state-change restart-status-change + snmp-server traps ospfv3 state-change restart-helper-status-change + snmp-server traps ospfv3 state-change restart-virtual-helper-status-change + snmp-server traps subscriber session-agg node + snmp-server traps subscriber session-agg access-interface + snmp-server traps addrpool low + snmp-server traps addrpool high + snmp-server traps cisco-entity-ext + snmp-server traps entity-state operstatus + snmp-server traps entity-state switchover + snmp-server traps entity-redundancy all + snmp-server traps entity-redundancy status + snmp-server traps entity-redundancy switchover + snmp-server chassis-id test2 + snmp-server location test1 + snmp-server target list test host 1.1.1.2 + snmp-server target list test2 vrf vrf2 + snmp-server context c1 + snmp-server context c2 + snmp-server logging threshold oid-processing 1 + snmp-server logging threshold pdu-processing 1 + snmp-server mib bulkstat max-procmem-size 101 + snmp-server mib bulkstat object-list test1 + ! + snmp-server mib bulkstat schema mib1 + object-list test1 + poll-interval 1 + ! + snmp-server mib bulkstat transfer-id test2 + retry 1 + buffer-size 1024 + enable + format schemaASCII + retain 1 + schema test2 + ! + snmp-server timeouts duplicate 0 + snmp-server timeouts inQdrop 0 + snmp-server timeouts subagent 1 + snmp-server timeouts pdu stats 1 + snmp-server timeouts threshold 0 + snmp-server packetsize 490 + snmp-server correlator rule rule1 + timeout 5 + ! + snmp-server correlator ruleset rule1 + ! + snmp-server correlator buffer-size 1024 + snmp-server trap-source GigabitEthernet0/0/0/2 + snmp-server throttle-time 60 + snmp-server community-map cm1 context c1 security-name s1 target-list t1 + snmp-server inform retries 7 + snmp-server overload-control 4 6 + snmp-server ifmib internal cache max-duration 4 + snmp-server mroutemib send-all-vrf + snmp-server notification-log-mib size 5 + snmp-server notification-log-mib GlobalSize 5 + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + vrfs=[ + dict( + vrf="vrf1", + hosts=[ + dict( + community="test1", + host="1.1.1.1", + traps=True, + ), + ], + ), + ], + users=[ + dict( + Ipv4_acl="test1", + Ipv6_acl="test2", + group="test2", + user="u1", + v4_acl="v4acl", + version="v1", + ), + ], + timeouts=dict( + duplicate=0, + inQdrop=0, + pdu_stats=1, + subagent=1, + threshold=0, + ), + trap=dict(throttle_time=12), + targets=[ + dict(name="test2", vrf="vrf2"), + dict(host="1.1.1.2", name="test"), + ], + ifmib=dict(internal_cache_max_duration=4), + inform=dict(retries=7), + chassis_id="test2", + packetsize=490, + queue_length=2, + throttle_time=60, + trap_source="GigabitEthernet0/0/0/2", + trap_timeout=3, + context=["c1", "c2"], + correlator=dict( + buffer_size=1024, + rule_sets=[dict(name="rule1")], + rules=[dict(rule_name="rule1", timeout=5)], + ), + communities=[ + dict( + name="test2", + rw=True, + systemowner=True, + acl_v4="test", + acl_v6="test1", + ), + ], + community_maps=[ + dict( + name="cm1", + context="c1", + target_list="t1", + security_name="s1", + ), + ], + drop=dict(report_IPv4="test1", unknown_user=True), + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + groups=[ + dict( + Ipv4_acl="test", + Ipv6_acl="test1", + context="test3", + group="g2", + read="test1", + version="v1", + write="test2", + ), + ], + location="test1", + logging_threshold_oid_processing=1, + logging_threshold_pdu_processing=1, + mib_bulkstat_max_procmem_size=101, + mroutemib_send_all_vrf=True, + mib_object_lists=["test1"], + overload_control=dict( + overload_drop_time=4, + overload_throttle_rate=6, + ), + mib_schema=[ + dict( + name="mib1", + object_list="test1", + poll_interval=1, + ), + ], + notification_log_mib=dict(GlobalSize=5, size=5), + mib_bulkstat_transfer_ids=[ + dict( + buffer_size=1024, + enable=True, + format_schemaASCI=True, + name="test2", + retain=1, + retry=1, + schema="test2", + ), + ], + traps=dict( + diameter=dict( + peerdown=True, + peerup=True, + permanentfail=True, + protocolerror=True, + transientfail=True, + ), + entity=True, + entity_redundancy=dict( + all=True, + status=True, + switchover=True, + ), + entity_state=dict(operstatus=True, switchover=True), + flash=dict(insertion=True, removal=True), + hsrp=True, + ipsla=True, + ipsec=dict(start=True, stop=True), + bridgemib=True, + bulkstat_collection=True, + cisco_entity_ext=True, + config=True, + copy_complete=True, + addrpool=dict(high=True, low=True), + bfd=True, + bgp=dict(cbgp2=True), + l2tun=dict( + sessions=True, + tunnel_down=True, + tunnel_up=True, + ), + l2vpn=dict(all=True, vc_down=True, vc_up=True), + msdp_peer_state_change=True, + ospf=dict( + errors=dict( + authentication_failure=True, + bad_packet=True, + config_error=True, + virt_authentication_failure=True, + virt_bad_packet=True, + virt_config_error=True, + ), + lsa=dict(lsa_maxage=True, lsa_originate=True), + retransmit=dict(packets=True, virt_packets=True), + state_change=dict( + if_state_change=True, + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + ), + ), + ospfv3=dict( + errors=dict( + bad_packet=True, + config_error=True, + virt_config_error=True, + ), + state_change=dict( + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + restart_helper_status_change=True, + restart_status_change=True, + restart_virtual_helper_status_change=True, + ), + ), + pim=dict( + interface_state_change=True, + invalid_message_received=True, + neighbor_change=True, + rp_mapping_change=True, + ), + power=True, + rf=True, + rsvp=dict(all=True, lost_flow=True, new_flow=True), + selective_vrf_download_role_change=True, + sensor=True, + snmp=dict( + authentication=True, + coldstart=True, + linkdown=True, + linkup=True, + warmstart=True, + ), + subscriber=dict( + session_agg_access_interface=True, + session_agg_node=True, + ), + syslog=True, + system=True, + vpls=dict( + all=True, + full_clear=True, + full_raise=True, + status=True, + ), + vrrp_events=True, + ), + ), + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_snmp_server_overridden(self): + self.maxDiff = None + run_cfg = dedent( + """\ + snmp-server vrf vrf1 + host 1.1.1.1 traps test1 + ! + snmp-server drop report acl IPv4 test1 + snmp-server drop unknown-user + snmp-server ipv4 dscp af11 + snmp-server ipv6 precedence routine + snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl + snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 + snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1 + snmp-server queue-length 2 + snmp-server trap-timeout 3 + snmp-server trap throttle-time 12 + snmp-server traps rf + snmp-server traps bfd + snmp-server traps bgp cbgp2 + snmp-server traps pim neighbor-change + snmp-server traps pim invalid-message-received + snmp-server traps pim rp-mapping-change + snmp-server traps pim interface-state-change + snmp-server traps copy-complete + snmp-server traps hsrp + snmp-server traps ipsla + snmp-server traps msdp peer-state-change + snmp-server traps snmp linkup + snmp-server traps snmp linkdown + snmp-server traps snmp coldstart + snmp-server traps snmp warmstart + snmp-server traps snmp authentication + snmp-server traps vrrp events + snmp-server traps flash removal + snmp-server traps flash insertion + snmp-server traps ipsec tunnel stop + snmp-server traps ipsec tunnel start + snmp-server traps power + snmp-server traps config + snmp-server traps entity + snmp-server traps sensor + snmp-server traps selective-vrf-download role-change + snmp-server traps syslog + snmp-server traps system + snmp-server traps ospf lsa lsa-maxage + snmp-server traps ospf lsa lsa-originate + snmp-server traps ospf errors bad-packet + snmp-server traps ospf errors authentication-failure + snmp-server traps ospf errors config-error + snmp-server traps ospf errors virt-bad-packet + snmp-server traps ospf errors virt-authentication-failure + snmp-server traps ospf errors virt-config-error + snmp-server traps ospf retransmit packets + snmp-server traps ospf retransmit virt-packets + snmp-server traps ospf state-change if-state-change + snmp-server traps ospf state-change neighbor-state-change + snmp-server traps ospf state-change virtif-state-change + snmp-server traps ospf state-change virtneighbor-state-change + snmp-server traps rsvp all + snmp-server traps rsvp new-flow + snmp-server traps rsvp lost-flow + snmp-server traps l2tun sessions + snmp-server traps l2tun tunnel-up + snmp-server traps l2tun tunnel-down + snmp-server traps vpls all + snmp-server traps vpls status + snmp-server traps vpls full-clear + snmp-server traps vpls full-raise + snmp-server traps bulkstat collection + snmp-server traps diameter peerup + snmp-server traps diameter peerdown + snmp-server traps diameter protocolerror + snmp-server traps diameter permanentfail + snmp-server traps diameter transientfail + snmp-server traps l2vpn all + snmp-server traps l2vpn vc-up + snmp-server traps l2vpn vc-down + snmp-server traps bridgemib + snmp-server traps ospfv3 errors bad-packet + snmp-server traps ospfv3 errors config-error + snmp-server traps ospfv3 errors virt-config-error + snmp-server traps ospfv3 state-change neighbor-state-change + snmp-server traps ospfv3 state-change virtif-state-change + snmp-server traps ospfv3 state-change virtneighbor-state-change + snmp-server traps ospfv3 state-change restart-status-change + snmp-server traps ospfv3 state-change restart-helper-status-change + snmp-server traps ospfv3 state-change restart-virtual-helper-status-change + snmp-server traps subscriber session-agg node + snmp-server traps subscriber session-agg access-interface + snmp-server traps addrpool low + snmp-server traps addrpool high + snmp-server traps cisco-entity-ext + snmp-server traps entity-state operstatus + snmp-server traps entity-state switchover + snmp-server traps entity-redundancy all + snmp-server traps entity-redundancy status + snmp-server traps entity-redundancy switchover + snmp-server chassis-id test2 + snmp-server contact t1 + snmp-server location test1 + snmp-server target list test host 1.1.1.2 + snmp-server target list test2 vrf vrf2 + snmp-server context c1 + snmp-server context c2 + snmp-server logging threshold oid-processing 1 + snmp-server logging threshold pdu-processing 1 + snmp-server mib bulkstat max-procmem-size 101 + snmp-server mib bulkstat object-list test1 + ! + snmp-server mib bulkstat schema mib1 + object-list test1 + poll-interval 1 + ! + snmp-server mib bulkstat transfer-id test2 + retry 1 + buffer-size 1024 + enable + format schemaASCII + retain 1 + schema test2 + ! + snmp-server timeouts duplicate 0 + snmp-server timeouts inQdrop 0 + snmp-server timeouts subagent 1 + snmp-server timeouts pdu stats 1 + snmp-server timeouts threshold 0 + snmp-server packetsize 490 + snmp-server correlator rule rule1 + timeout 5 + ! + snmp-server correlator ruleset rule1 + ! + snmp-server correlator buffer-size 1024 + snmp-server trap-source GigabitEthernet0/0/0/2 + snmp-server throttle-time 60 + snmp-server community-map cm1 context c1 security-name s1 target-list t1 + snmp-server inform retries 7 + snmp-server overload-control 4 6 + snmp-server ifmib internal cache max-duration 4 + snmp-server mroutemib send-all-vrf + snmp-server notification-log-mib size 5 + snmp-server notification-log-mib GlobalSize 5 + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + vrfs=[ + dict( + vrf="vrf2", + hosts=[ + dict( + community="test1", + host="1.1.1.1", + traps=True, + ), + ], + ), + ], + users=[ + dict( + Ipv4_acl="test1", + Ipv6_acl="test2", + group="test2", + user="u1", + v4_acl="v4acl", + ), + ], + timeouts=dict( + duplicate=0, + inQdrop=0, + pdu_stats=1, + subagent=1, + threshold=0, + ), + trap=dict(throttle_time=12), + targets=[ + dict(name="test2", vrf="vrf2"), + dict(host="1.1.1.2", name="test"), + ], + ifmib=dict(internal_cache_max_duration=4), + inform=dict(retries=7), + chassis_id="test2", + packetsize=490, + queue_length=2, + throttle_time=60, + trap_source="GigabitEthernet0/0/0/2", + trap_timeout=3, + context=["c1", "c2"], + correlator=dict( + buffer_size=1024, + rule_sets=[dict(name="rule1")], + rules=[dict(rule_name="rule1", timeout=5)], + ), + communities=[ + dict( + name="test2", + ro=True, + sdrowner=True, + acl_v4="test", + acl_v6="test1", + ), + ], + community_maps=[ + dict( + name="cm1", + context="c1", + target_list="t1", + security_name="s1", + ), + ], + drop=dict(report_IPv4="test1", unknown_user=True), + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + groups=[ + dict( + Ipv4_acl="test", + Ipv6_acl="test1", + context="test3", + group="g2", + read="test1", + version="v1", + write="test2", + ), + ], + location="test", + logging_threshold_oid_processing=2, + logging_threshold_pdu_processing=1, + mib_bulkstat_max_procmem_size=101, + mroutemib_send_all_vrf=True, + mib_object_lists=["test1"], + overload_control=dict( + overload_drop_time=4, + overload_throttle_rate=6, + ), + mib_schema=[ + dict( + name="mib1", + object_list="test1", + poll_interval=1, + ), + ], + notification_log_mib=dict(GlobalSize=5, size=5), + mib_bulkstat_transfer_ids=[ + dict( + buffer_size=1024, + enable=True, + format_schemaASCI=True, + name="test2", + retain=1, + retry=1, + schema="test2", + ), + ], + traps=dict( + diameter=dict( + peerdown=True, + peerup=True, + permanentfail=True, + protocolerror=True, + transientfail=True, + ), + entity=True, + entity_redundancy=dict( + all=True, + status=True, + switchover=True, + ), + entity_state=dict(operstatus=True, switchover=True), + flash=dict(insertion=True, removal=True), + ipsec=dict(start=True, stop=True), + bridgemib=True, + bulkstat_collection=True, + cisco_entity_ext=True, + config=True, + copy_complete=True, + addrpool=dict(high=True, low=True), + bfd=True, + bgp=dict(cbgp2=True), + l2tun=dict( + sessions=True, + tunnel_down=True, + tunnel_up=True, + ), + l2vpn=dict(all=True, vc_down=True, vc_up=True), + msdp_peer_state_change=True, + ospf=dict( + errors=dict( + authentication_failure=True, + bad_packet=True, + config_error=True, + virt_authentication_failure=True, + virt_bad_packet=True, + virt_config_error=True, + ), + lsa=dict(lsa_maxage=True, lsa_originate=True), + retransmit=dict(packets=True, virt_packets=True), + state_change=dict( + if_state_change=True, + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + ), + ), + ospfv3=dict( + errors=dict( + bad_packet=True, + config_error=True, + virt_config_error=True, + ), + ), + pim=dict( + interface_state_change=True, + invalid_message_received=True, + neighbor_change=True, + rp_mapping_change=True, + ), + power=True, + rf=True, + rsvp=dict(all=True, lost_flow=True, new_flow=True), + selective_vrf_download_role_change=True, + sensor=True, + snmp=dict( + authentication=True, + coldstart=True, + linkdown=True, + linkup=True, + warmstart=True, + ), + subscriber=dict( + session_agg_access_interface=True, + session_agg_node=True, + ), + syslog=True, + system=True, + vpls=dict( + all=True, + full_clear=True, + full_raise=True, + status=True, + ), + vrrp_events=True, + ), + ), + state="overridden", + ), + ) + commands = [ + "no snmp-server contact t1", + "no snmp-server traps hsrp", + "no snmp-server traps ipsla", + "no snmp-server traps ospfv3 state-change neighbor-state-change", + "no snmp-server traps ospfv3 state-change virtif-state-change", + "no snmp-server traps ospfv3 state-change virtneighbor-state-change", + "no snmp-server traps ospfv3 state-change restart-status-change", + "no snmp-server traps ospfv3 state-change restart-helper-status-change", + "no snmp-server traps ospfv3 state-change restart-virtual-helper-status-change", + "no snmp-server vrf vrf1", + "snmp-server location test", + "snmp-server logging threshold oid-processing 2", + "snmp-server user u1 test2 IPv4 test1 IPv6 test2 v4acl", + "snmp-server vrf vrf2", + "host 1.1.1.1 traps test1", + ] + result = self.execute_module(changed=True) + self.assertEqual(sorted(result["commands"]), sorted(commands)) + + def test_iosxr_snmp_server_overridden_idempotent(self): + self.maxDiff = None + run_cfg = dedent( + """\ + snmp-server vrf vrf1 + host 1.1.1.1 traps test1 + ! + snmp-server drop report acl IPv4 test1 + snmp-server drop unknown-user + snmp-server ipv4 dscp af11 + snmp-server ipv6 precedence routine + snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl + snmp-server community test2 RW SystemOwner IPv4 test IPv6 test1 + snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1 + snmp-server queue-length 2 + snmp-server trap-timeout 3 + snmp-server trap throttle-time 12 + snmp-server traps rf + snmp-server traps bfd + snmp-server traps bgp cbgp2 + snmp-server traps pim neighbor-change + snmp-server traps pim invalid-message-received + snmp-server traps pim rp-mapping-change + snmp-server traps pim interface-state-change + snmp-server traps copy-complete + snmp-server traps hsrp + snmp-server traps ipsla + snmp-server traps msdp peer-state-change + snmp-server traps snmp linkup + snmp-server traps snmp linkdown + snmp-server traps snmp coldstart + snmp-server traps snmp warmstart + snmp-server traps snmp authentication + snmp-server traps vrrp events + snmp-server traps flash removal + snmp-server traps flash insertion + snmp-server traps ipsec tunnel stop + snmp-server traps ipsec tunnel start + snmp-server traps power + snmp-server traps config + snmp-server traps entity + snmp-server traps sensor + snmp-server traps selective-vrf-download role-change + snmp-server traps syslog + snmp-server traps system + snmp-server traps ospf lsa lsa-maxage + snmp-server traps ospf lsa lsa-originate + snmp-server traps ospf errors bad-packet + snmp-server traps ospf errors authentication-failure + snmp-server traps ospf errors config-error + snmp-server traps ospf errors virt-bad-packet + snmp-server traps ospf errors virt-authentication-failure + snmp-server traps ospf errors virt-config-error + snmp-server traps ospf retransmit packets + snmp-server traps ospf retransmit virt-packets + snmp-server traps ospf state-change if-state-change + snmp-server traps ospf state-change neighbor-state-change + snmp-server traps ospf state-change virtif-state-change + snmp-server traps ospf state-change virtneighbor-state-change + snmp-server traps rsvp all + snmp-server traps rsvp new-flow + snmp-server traps rsvp lost-flow + snmp-server traps l2tun sessions + snmp-server traps l2tun tunnel-up + snmp-server traps l2tun tunnel-down + snmp-server traps vpls all + snmp-server traps vpls status + snmp-server traps vpls full-clear + snmp-server traps vpls full-raise + snmp-server traps bulkstat collection + snmp-server traps diameter peerup + snmp-server traps diameter peerdown + snmp-server traps diameter protocolerror + snmp-server traps diameter permanentfail + snmp-server traps diameter transientfail + snmp-server traps l2vpn all + snmp-server traps l2vpn vc-up + snmp-server traps l2vpn vc-down + snmp-server traps bridgemib + snmp-server traps ospfv3 errors bad-packet + snmp-server traps ospfv3 errors config-error + snmp-server traps ospfv3 errors virt-config-error + snmp-server traps ospfv3 state-change neighbor-state-change + snmp-server traps ospfv3 state-change virtif-state-change + snmp-server traps ospfv3 state-change virtneighbor-state-change + snmp-server traps ospfv3 state-change restart-status-change + snmp-server traps ospfv3 state-change restart-helper-status-change + snmp-server traps ospfv3 state-change restart-virtual-helper-status-change + snmp-server traps subscriber session-agg node + snmp-server traps subscriber session-agg access-interface + snmp-server traps addrpool low + snmp-server traps addrpool high + snmp-server traps cisco-entity-ext + snmp-server traps entity-state operstatus + snmp-server traps entity-state switchover + snmp-server traps entity-redundancy all + snmp-server traps entity-redundancy status + snmp-server traps entity-redundancy switchover + snmp-server chassis-id test2 + snmp-server location test1 + snmp-server target list test host 1.1.1.2 + snmp-server target list test2 vrf vrf2 + snmp-server context c1 + snmp-server context c2 + snmp-server logging threshold oid-processing 1 + snmp-server logging threshold pdu-processing 1 + snmp-server mib bulkstat max-procmem-size 101 + snmp-server mib bulkstat object-list test1 + ! + snmp-server mib bulkstat schema mib1 + object-list test1 + poll-interval 1 + ! + snmp-server mib bulkstat transfer-id test2 + retry 1 + buffer-size 1024 + enable + format schemaASCII + retain 1 + schema test2 + ! + snmp-server timeouts duplicate 0 + snmp-server timeouts inQdrop 0 + snmp-server timeouts subagent 1 + snmp-server timeouts pdu stats 1 + snmp-server timeouts threshold 0 + snmp-server packetsize 490 + snmp-server correlator rule rule1 + timeout 5 + ! + snmp-server correlator ruleset rule1 + ! + snmp-server correlator buffer-size 1024 + snmp-server trap-source GigabitEthernet0/0/0/2 + snmp-server throttle-time 60 + snmp-server community-map cm1 context c1 security-name s1 target-list t1 + snmp-server inform retries 7 + snmp-server overload-control 4 6 + snmp-server ifmib internal cache max-duration 4 + snmp-server mroutemib send-all-vrf + snmp-server notification-log-mib size 5 + snmp-server notification-log-mib GlobalSize 5 + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args( + dict( + config=dict( + vrfs=[ + dict( + vrf="vrf1", + hosts=[ + dict( + community="test1", + host="1.1.1.1", + traps=True, + ), + ], + ), + ], + users=[ + dict( + Ipv4_acl="test1", + Ipv6_acl="test2", + group="test2", + user="u1", + v4_acl="v4acl", + version="v1", + ), + ], + timeouts=dict( + duplicate=0, + inQdrop=0, + pdu_stats=1, + subagent=1, + threshold=0, + ), + trap=dict(throttle_time=12), + targets=[ + dict(name="test2", vrf="vrf2"), + dict(host="1.1.1.2", name="test"), + ], + ifmib=dict(internal_cache_max_duration=4), + inform=dict(retries=7), + chassis_id="test2", + packetsize=490, + queue_length=2, + throttle_time=60, + trap_source="GigabitEthernet0/0/0/2", + trap_timeout=3, + context=["c1", "c2"], + correlator=dict( + buffer_size=1024, + rule_sets=[dict(name="rule1")], + rules=[dict(rule_name="rule1", timeout=5)], + ), + communities=[ + dict( + name="test2", + rw=True, + systemowner=True, + acl_v4="test", + acl_v6="test1", + ), + ], + community_maps=[ + dict( + name="cm1", + context="c1", + target_list="t1", + security_name="s1", + ), + ], + drop=dict(report_IPv4="test1", unknown_user=True), + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + groups=[ + dict( + Ipv4_acl="test", + Ipv6_acl="test1", + context="test3", + group="g2", + read="test1", + version="v1", + write="test2", + ), + ], + location="test1", + logging_threshold_oid_processing=1, + logging_threshold_pdu_processing=1, + mib_bulkstat_max_procmem_size=101, + mroutemib_send_all_vrf=True, + mib_object_lists=["test1"], + overload_control=dict( + overload_drop_time=4, + overload_throttle_rate=6, + ), + mib_schema=[ + dict( + name="mib1", + object_list="test1", + poll_interval=1, + ), + ], + notification_log_mib=dict(GlobalSize=5, size=5), + mib_bulkstat_transfer_ids=[ + dict( + buffer_size=1024, + enable=True, + format_schemaASCI=True, + name="test2", + retain=1, + retry=1, + schema="test2", + ), + ], + traps=dict( + diameter=dict( + peerdown=True, + peerup=True, + permanentfail=True, + protocolerror=True, + transientfail=True, + ), + entity=True, + entity_redundancy=dict( + all=True, + status=True, + switchover=True, + ), + entity_state=dict(operstatus=True, switchover=True), + flash=dict(insertion=True, removal=True), + hsrp=True, + ipsla=True, + ipsec=dict(start=True, stop=True), + bridgemib=True, + bulkstat_collection=True, + cisco_entity_ext=True, + config=True, + copy_complete=True, + addrpool=dict(high=True, low=True), + bfd=True, + bgp=dict(cbgp2=True), + l2tun=dict( + sessions=True, + tunnel_down=True, + tunnel_up=True, + ), + l2vpn=dict(all=True, vc_down=True, vc_up=True), + msdp_peer_state_change=True, + ospf=dict( + errors=dict( + authentication_failure=True, + bad_packet=True, + config_error=True, + virt_authentication_failure=True, + virt_bad_packet=True, + virt_config_error=True, + ), + lsa=dict(lsa_maxage=True, lsa_originate=True), + retransmit=dict(packets=True, virt_packets=True), + state_change=dict( + if_state_change=True, + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + ), + ), + ospfv3=dict( + errors=dict( + bad_packet=True, + config_error=True, + virt_config_error=True, + ), + state_change=dict( + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + restart_helper_status_change=True, + restart_status_change=True, + restart_virtual_helper_status_change=True, + ), + ), + pim=dict( + interface_state_change=True, + invalid_message_received=True, + neighbor_change=True, + rp_mapping_change=True, + ), + power=True, + rf=True, + rsvp=dict(all=True, lost_flow=True, new_flow=True), + selective_vrf_download_role_change=True, + sensor=True, + snmp=dict( + authentication=True, + coldstart=True, + linkdown=True, + linkup=True, + warmstart=True, + ), + subscriber=dict( + session_agg_access_interface=True, + session_agg_node=True, + ), + syslog=True, + system=True, + vpls=dict( + all=True, + full_clear=True, + full_raise=True, + status=True, + ), + vrrp_events=True, + ), + ), + state="overridden", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_snmp_server_rendered(self): + self.maxDiff = None + set_module_args( + dict( + config=dict( + vrfs=[ + dict( + vrf="vrf1", + hosts=[ + dict( + community="test1", + host="1.1.1.1", + traps=True, + ), + ], + ), + ], + users=[ + dict( + Ipv4_acl="test1", + Ipv6_acl="test2", + group="test2", + user="u1", + v4_acl="v4acl", + ), + ], + timeouts=dict( + duplicate=0, + inQdrop=0, + pdu_stats=1, + subagent=1, + threshold=0, + ), + trap=dict(throttle_time=12), + targets=[ + dict(name="test2", vrf="vrf2"), + dict(host="1.1.1.2", name="test"), + ], + ifmib=dict(internal_cache_max_duration=4), + inform=dict(retries=7), + chassis_id="test2", + packetsize=490, + queue_length=2, + throttle_time=60, + trap_source="GigabitEthernet0/0/0/2", + trap_timeout=3, + context=["c1", "c2"], + correlator=dict( + buffer_size=1024, + rule_sets=[dict(name="rule1")], + rules=[dict(rule_name="rule1", timeout=5)], + ), + communities=[ + dict( + name="test2", + ro=True, + sdrowner=True, + acl_v4="test", + acl_v6="test1", + ), + ], + community_maps=[ + dict( + name="cm1", + context="c1", + target_list="t1", + security_name="s1", + ), + ], + drop=dict(report_IPv4="test1", unknown_user=True), + ipv6=dict(precedence="routine"), + ipv4=dict(dscp="af11"), + groups=[ + dict( + Ipv4_acl="test", + Ipv6_acl="test1", + context="test3", + group="g2", + read="test1", + version="v1", + write="test2", + ), + ], + interfaces=[dict(name=" GigabitEthernet0/0/0/2")], + location="test1", + logging_threshold_oid_processing=1, + logging_threshold_pdu_processing=1, + mib_bulkstat_max_procmem_size=101, + mroutemib_send_all_vrf=True, + mib_object_lists=["test1"], + overload_control=dict( + overload_drop_time=4, + overload_throttle_rate=6, + ), + mib_schema=[ + dict( + name="mib1", + object_list="test1", + poll_interval=1, + ), + ], + notification_log_mib=dict(GlobalSize=5, size=5), + mib_bulkstat_transfer_ids=[ + dict( + buffer_size=1024, + enable=True, + format_schemaASCI=True, + name="test2", + retain=1, + retry=1, + schema="test2", + ), + ], + traps=dict( + diameter=dict( + peerdown=True, + peerup=True, + permanentfail=True, + protocolerror=True, + transientfail=True, + ), + entity=True, + entity_redundancy=dict( + all=True, + status=True, + switchover=True, + ), + entity_state=dict(operstatus=True, switchover=True), + flash=dict(insertion=True, removal=True), + hsrp=True, + ipsla=True, + ipsec=dict(start=True, stop=True), + bridgemib=True, + bulkstat_collection=True, + cisco_entity_ext=True, + config=True, + copy_complete=True, + addrpool=dict(high=True, low=True), + bfd=True, + bgp=dict(cbgp2=True), + l2tun=dict( + sessions=True, + tunnel_down=True, + tunnel_up=True, + ), + l2vpn=dict(all=True, vc_down=True, vc_up=True), + msdp_peer_state_change=True, + ospf=dict( + errors=dict( + authentication_failure=True, + bad_packet=True, + config_error=True, + virt_authentication_failure=True, + virt_bad_packet=True, + virt_config_error=True, + ), + lsa=dict(lsa_maxage=True, lsa_originate=True), + retransmit=dict(packets=True, virt_packets=True), + state_change=dict( + if_state_change=True, + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + ), + ), + ospfv3=dict( + errors=dict( + bad_packet=True, + config_error=True, + virt_config_error=True, + ), + state_change=dict( + neighbor_state_change=True, + virtif_state_change=True, + virtneighbor_state_change=True, + restart_helper_status_change=True, + restart_status_change=True, + restart_virtual_helper_status_change=True, + ), + ), + pim=dict( + interface_state_change=True, + invalid_message_received=True, + neighbor_change=True, + rp_mapping_change=True, + ), + power=True, + rf=True, + rsvp=dict(all=True, lost_flow=True, new_flow=True), + selective_vrf_download_role_change=True, + sensor=True, + snmp=dict( + authentication=True, + coldstart=True, + linkdown=True, + linkup=True, + warmstart=True, + ), + subscriber=dict( + session_agg_access_interface=True, + session_agg_node=True, + ), + syslog=True, + system=True, + vpls=dict( + all=True, + full_clear=True, + full_raise=True, + status=True, + ), + vrrp_events=True, + ), + ), + state="rendered", + ), + ) + commands = [ + "snmp-server chassis-id test2", + "snmp-server correlator buffer-size 1024", + "snmp-server ipv4 dscp af11", + "snmp-server ipv6 precedence routine", + "snmp-server location test1", + "snmp-server logging threshold oid-processing 1", + "snmp-server logging threshold pdu-processing 1", + "snmp-server mib bulkstat max-procmem-size 101", + "snmp-server mroutemib send-all-vrf", + "snmp-server overload-control 4 6", + "snmp-server packetsize 490", + "snmp-server queue-length 2", + "snmp-server throttle-time 60", + "snmp-server trap-source GigabitEthernet0/0/0/2", + "snmp-server trap-timeout 3", + "snmp-server drop report acl IPv4 test1", + "snmp-server drop unknown-user", + "snmp-server ifmib internal cache max-duration 4", + "snmp-server inform retries 7", + "snmp-server notification-log-mib size 5", + "snmp-server notification-log-mib GlobalSize 5", + "snmp-server trap throttle-time 12", + "snmp-server timeouts threshold 0", + "snmp-server timeouts pdu stats 1", + "snmp-server timeouts subagent 1", + "snmp-server timeouts inQdrop 0", + "snmp-server timeouts duplicate 0", + "snmp-server traps addrpool low", + "snmp-server traps addrpool high", + "snmp-server traps bfd", + "snmp-server traps bgp cbgp2", + "snmp-server traps bulkstat collection", + "snmp-server traps bridgemib", + "snmp-server traps copy-complete", + "snmp-server traps cisco-entity-ext", + "snmp-server traps config", + "snmp-server traps diameter peerdown", + "snmp-server traps diameter peerup", + "snmp-server traps diameter protocolerror", + "snmp-server traps diameter permanentfail", + "snmp-server traps diameter transientfail", + "snmp-server traps entity", + "snmp-server traps entity-redundancy all", + "snmp-server traps entity-redundancy status", + "snmp-server traps entity-redundancy switchover", + "snmp-server traps entity-state operstatus", + "snmp-server traps entity-state switchover", + "snmp-server traps flash removal", + "snmp-server traps flash insertion", + "snmp-server traps hsrp", + "snmp-server traps ipsla", + "snmp-server traps ipsec tunnel start", + "snmp-server traps ipsec tunnel stop", + "snmp-server traps l2tun sessions", + "snmp-server traps l2tun tunnel-up", + "snmp-server traps l2tun tunnel-down", + "snmp-server traps l2vpn all", + "snmp-server traps l2vpn vc-up", + "snmp-server traps l2vpn vc-down", + "snmp-server traps msdp peer-state-change", + "snmp-server traps ospf retransmit virt-packets", + "snmp-server traps ospf retransmit packets", + "snmp-server traps ospf lsa lsa-originate", + "snmp-server traps ospf lsa lsa-maxage", + "snmp-server traps ospf errors bad-packet", + "snmp-server traps ospf errors authentication-failure", + "snmp-server traps ospf errors config-error", + "snmp-server traps ospf errors virt-bad-packet", + "snmp-server traps ospf errors virt-authentication-failure", + "snmp-server traps ospf errors virt-config-error", + "snmp-server traps ospf state-change if-state-change", + "snmp-server traps ospf state-change neighbor-state-change", + "snmp-server traps ospf state-change virtif-state-change", + "snmp-server traps ospf state-change virtneighbor-state-change", + "snmp-server traps ospfv3 errors bad-packet", + "snmp-server traps ospfv3 errors config-error", + "snmp-server traps ospfv3 errors virt-config-error", + "snmp-server traps ospfv3 state-change neighbor-state-change", + "snmp-server traps ospfv3 state-change virtif-state-change", + "snmp-server traps ospfv3 state-change virtneighbor-state-change", + "snmp-server traps ospfv3 state-change restart-status-change", + "snmp-server traps ospfv3 state-change restart-helper-status-change", + "snmp-server traps ospfv3 state-change restart-virtual-helper-status-change", + "snmp-server traps power", + "snmp-server traps rf", + "snmp-server traps pim neighbor-change", + "snmp-server traps pim invalid-message-received", + "snmp-server traps pim rp-mapping-change", + "snmp-server traps pim interface-state-change", + "snmp-server traps rsvp lost-flow", + "snmp-server traps rsvp new-flow", + "snmp-server traps rsvp all", + "snmp-server traps selective-vrf-download role-change", + "snmp-server traps sensor", + "snmp-server traps vrrp events", + "snmp-server traps syslog", + "snmp-server traps system", + "snmp-server traps subscriber session-agg access-interface", + "snmp-server traps subscriber session-agg node", + "snmp-server traps vpls all", + "snmp-server traps vpls full-clear", + "snmp-server traps vpls full-raise", + "snmp-server traps vpls status", + "snmp-server traps snmp linkup", + "snmp-server traps snmp linkdown", + "snmp-server traps snmp coldstart", + "snmp-server traps snmp warmstart", + "snmp-server traps snmp authentication", + "snmp-server community test2 RO SDROwner IPv4 test IPv6 test1", + "snmp-server community-map cm1 context c1 security-name s1 target-list t1", + "snmp-server correlator ruleset rule1", + "snmp-server correlator rule rule1 timeout 5", + "snmp-server context c1", + "snmp-server context c2", + "snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1", + "snmp-server interface GigabitEthernet0/0/0/2", + "snmp-server mib bulkstat object-list test1", + "snmp-server mib bulkstat schema mib1 object-list test1", + "snmp-server mib bulkstat schema mib1 poll-interval 1", + "snmp-server mib bulkstat transfer-id test2 buffer-size 1024", + "snmp-server mib bulkstat transfer-id test2 enable", + "snmp-server mib bulkstat transfer-id test2 format schemaASCII", + "snmp-server mib bulkstat transfer-id test2 retain 1", + "snmp-server mib bulkstat transfer-id test2 retry 1", + "snmp-server mib bulkstat transfer-id test2 schema test2", + "snmp-server user u1 test2 IPv4 test1 IPv6 test2 v4acl", + "snmp-server target list test2 vrf vrf2", + "snmp-server target list test host 1.1.1.2", + "snmp-server vrf vrf1", + "host 1.1.1.1 traps test1", + ] + result = self.execute_module(changed=False) + self.assertEqual(sorted(result["rendered"]), sorted(commands)) + + def test_iosxr_snmp_server_gathered(self): + self.maxDiff = None + run_cfg = dedent( + """\ + snmp-server vrf vrf1 + host 1.1.1.1 traps test1 + ! + snmp-server drop report acl IPv4 test1 + snmp-server drop unknown-user + snmp-server ipv4 dscp af11 + snmp-server ipv6 precedence routine + snmp-server user u1 test2 v1 IPv4 test1 IPv6 test2 v4acl + snmp-server community test2 RO SDROwner IPv4 test IPv6 test1 + snmp-server group g2 v1 read test1 write test2 context test3 IPv4 test IPv6 test1 + snmp-server queue-length 2 + snmp-server trap-timeout 3 + snmp-server trap throttle-time 12 + snmp-server traps rf + snmp-server traps bfd + snmp-server traps bgp cbgp2 + snmp-server traps pim neighbor-change + snmp-server traps pim invalid-message-received + snmp-server traps pim rp-mapping-change + snmp-server traps pim interface-state-change + snmp-server traps copy-complete + snmp-server traps hsrp + snmp-server traps ipsla + snmp-server traps msdp peer-state-change + snmp-server traps snmp linkup + snmp-server traps snmp linkdown + snmp-server traps snmp coldstart + snmp-server traps snmp warmstart + snmp-server traps snmp authentication + snmp-server traps vrrp events + snmp-server traps flash removal + snmp-server traps flash insertion + snmp-server traps ipsec tunnel stop + snmp-server traps ipsec tunnel start + snmp-server traps power + snmp-server traps config + snmp-server traps entity + snmp-server traps sensor + snmp-server traps selective-vrf-download role-change + snmp-server traps syslog + snmp-server traps system + snmp-server traps ospf lsa lsa-maxage + snmp-server traps ospf lsa lsa-originate + snmp-server traps ospf errors bad-packet + snmp-server traps ospf errors authentication-failure + snmp-server traps ospf errors config-error + snmp-server traps ospf errors virt-bad-packet + snmp-server traps ospf errors virt-authentication-failure + snmp-server traps ospf errors virt-config-error + snmp-server traps ospf retransmit packets + snmp-server traps ospf retransmit virt-packets + snmp-server traps ospf state-change if-state-change + snmp-server traps ospf state-change neighbor-state-change + snmp-server traps ospf state-change virtif-state-change + snmp-server traps ospf state-change virtneighbor-state-change + snmp-server traps rsvp all + snmp-server traps rsvp new-flow + snmp-server traps rsvp lost-flow + snmp-server traps l2tun sessions + snmp-server traps l2tun tunnel-up + snmp-server traps l2tun tunnel-down + snmp-server traps vpls all + snmp-server traps vpls status + snmp-server traps vpls full-clear + snmp-server traps vpls full-raise + snmp-server traps bulkstat collection + snmp-server traps diameter peerup + snmp-server traps diameter peerdown + snmp-server traps diameter protocolerror + snmp-server traps diameter permanentfail + snmp-server traps diameter transientfail + snmp-server traps l2vpn all + snmp-server traps l2vpn vc-up + snmp-server traps l2vpn vc-down + snmp-server traps bridgemib + snmp-server traps ospfv3 errors bad-packet + snmp-server traps ospfv3 errors config-error + snmp-server traps ospfv3 errors virt-config-error + snmp-server traps ospfv3 state-change neighbor-state-change + snmp-server traps ospfv3 state-change virtif-state-change + snmp-server traps ospfv3 state-change virtneighbor-state-change + snmp-server traps ospfv3 state-change restart-status-change + snmp-server traps ospfv3 state-change restart-helper-status-change + snmp-server traps ospfv3 state-change restart-virtual-helper-status-change + snmp-server traps subscriber session-agg node + snmp-server traps subscriber session-agg access-interface + snmp-server traps addrpool low + snmp-server traps addrpool high + snmp-server traps cisco-entity-ext + snmp-server traps entity-state operstatus + snmp-server traps entity-state switchover + snmp-server traps entity-redundancy all + snmp-server traps entity-redundancy status + snmp-server traps entity-redundancy switchover + snmp-server chassis-id test2 + snmp-server contact t1 + snmp-server location test1 + snmp-server target list test host 1.1.1.2 + snmp-server target list test2 vrf vrf2 + snmp-server context c1 + snmp-server logging threshold oid-processing 1 + snmp-server logging threshold pdu-processing 1 + snmp-server mib bulkstat max-procmem-size 101 + snmp-server mib bulkstat object-list test1 + ! + snmp-server mib bulkstat schema mib1 + object-list test1 + poll-interval 1 + ! + snmp-server mib bulkstat transfer-id test2 + retry 1 + buffer-size 1024 + enable + format schemaASCII + retain 1 + schema test2 + ! + snmp-server timeouts duplicate 0 + snmp-server timeouts inQdrop 0 + snmp-server timeouts subagent 1 + snmp-server timeouts pdu stats 1 + snmp-server timeouts threshold 0 + snmp-server packetsize 490 + snmp-server correlator rule rule1 + timeout 5 + ! + snmp-server correlator ruleset rule1 + ! + snmp-server correlator buffer-size 1024 + snmp-server trap-source GigabitEthernet0/0/0/2 + snmp-server throttle-time 60 + snmp-server community-map cm1 context c1 security-name s1 target-list t1 + snmp-server inform retries 7 + snmp-server overload-control 4 6 + snmp-server ifmib internal cache max-duration 4 + snmp-server mroutemib send-all-vrf + snmp-server notification-log-mib size 5 + snmp-server notification-log-mib GlobalSize 5 + ! + """, + ) + self.get_config.return_value = run_cfg + set_module_args(dict(state="gathered")) + gathered = { + "vrfs": [ + { + "vrf": "vrf1", + "hosts": [ + { + "host": "1.1.1.1", + "traps": True, + "community": "test1", + }, + ], + }, + ], + "drop": {"report_IPv4": "test1", "unknown_user": True}, + "ipv4": {"dscp": "af11"}, + "ipv6": {"precedence": "routine"}, + "users": [ + { + "user": "u1", + "group": "test2", + "acl_v4": "test1", + "acl_v6": "test2", + "v4_acl": "v4acl", + "version": "v1", + }, + ], + "communities": [ + { + "name": "test2", + "ro": True, + "acl_v4": "test", + "acl_v6": "test1", + "sdrowner": True, + }, + ], + "groups": [ + { + "group": "g2", + "acl_v4": "test", + "acl_v6": "test1", + "context": "test3", + "read": "test1", + "write": "test2", + "version": "v1", + }, + ], + "queue_length": 2, + "trap_timeout": 3, + "trap": {"throttle_time": 12}, + "traps": { + "rf": True, + "bfd": True, + "bgp": {"cbgp2": True}, + "pim": { + "neighbor_change": True, + "invalid_message_received": True, + "rp_mapping_change": True, + "interface_state_change": True, + }, + "copy_complete": True, + "hsrp": True, + "ipsla": True, + "msdp_peer_state_change": True, + "snmp": { + "linkup": True, + "linkdown": True, + "coldstart": True, + "warmstart": True, + "authentication": True, + }, + "vrrp_events": True, + "flash": {"removal": True, "insertion": True}, + "ipsec": {"stop": True, "start": True}, + "power": True, + "config": True, + "entity": True, + "sensor": True, + "selective_vrf_download_role_change": True, + "syslog": True, + "system": True, + "ospf": { + "lsa": {"lsa_maxage": True, "lsa_originate": True}, + "errors": { + "bad_packet": True, + "authentication_failure": True, + "config_error": True, + "virt_bad_packet": True, + "virt_authentication_failure": True, + "virt_config_error": True, + }, + "retransmit": {"packets": True, "virt_packets": True}, + "state_change": { + "if_state_change": True, + "neighbor_state_change": True, + "virtif_state_change": True, + "virtneighbor_state_change": True, + }, + }, + "rsvp": {"all": True, "new_flow": True, "lost_flow": True}, + "l2tun": { + "sessions": True, + "tunnel_up": True, + "tunnel_down": True, + }, + "vpls": { + "all": True, + "status": True, + "full_clear": True, + "full_raise": True, + }, + "bulkstat_collection": True, + "diameter": { + "peerup": True, + "peerdown": True, + "protocolerror": True, + "permanentfail": True, + "transientfail": True, + }, + "l2vpn": {"all": True, "vc_up": True, "vc_down": True}, + "bridgemib": True, + "ospfv3": { + "errors": { + "bad_packet": True, + "config_error": True, + "virt_config_error": True, + }, + "state_change": { + "neighbor_state_change": True, + "virtif_state_change": True, + "virtneighbor_state_change": True, + "restart_status_change": True, + "restart_helper_status_change": True, + "restart_virtual_helper_status_change": True, + }, + }, + "subscriber": { + "session_agg_node": True, + "session_agg_access_interface": True, + }, + "addrpool": {"low": True, "high": True}, + "cisco_entity_ext": True, + "entity_state": {"operstatus": True, "switchover": True}, + "entity_redundancy": { + "all": True, + "status": True, + "switchover": True, + }, + }, + "chassis_id": "test2", + "contact": "t1", + "location": "test1", + "targets": [ + {"name": "test", "host": "1.1.1.2"}, + {"name": "test2", "vrf": "vrf2"}, + ], + "context": ["c1"], + "logging_threshold_oid_processing": 1, + "logging_threshold_pdu_processing": 1, + "mib_bulkstat_max_procmem_size": 101, + "mib_object_lists": ["test1"], + "mib_schema": [ + {"name": "mib1", "object_list": "test1", "poll_interval": 1}, + ], + "mib_bulkstat_transfer_ids": [ + { + "name": "test2", + "retry": 1, + "buffer_size": 1024, + "enable": True, + "format_schemaASCI": True, + "retain": 1, + "schema": "test2", + }, + ], + "timeouts": { + "duplicate": 0, + "inQdrop": 0, + "subagent": 1, + "pdu_stats": 1, + "threshold": 0, + }, + "packetsize": 490, + "correlator": { + "rules": [ + {"rule_name": "rule1"}, + {"rule_name": "rule1", "timeout": 5}, + ], + "rule_sets": [{"name": "rule1"}], + "buffer_size": 1024, + }, + "trap_source": "GigabitEthernet0/0/0/2", + "throttle_time": 60, + "community_maps": [ + { + "name": "cm1", + "context": "c1", + "security_name": "s1", + "target_list": "t1", + }, + ], + "inform": {"retries": 7}, + "overload_control": { + "overload_drop_time": 4, + "overload_throttle_rate": 6, + }, + "ifmib": {"internal_cache_max_duration": 4}, + "mroutemib_send_all_vrf": True, + "notification_log_mib": {"size": 5, "GlobalSize": 5}, + } + result = self.execute_module(changed=False) + self.assertEqual(gathered, result["gathered"]) + + def test_iosxr_snmp_server_parsed(self): + self.maxDiff = None + set_module_args( + dict( + running_config="snmp-server vrf test1\n host 1.1.1.1 traps test1\n host 1.1.1.2 traps test1\n " + "context test2\n!\nsnmp-server drop report acl IPv6 test\nsnmp-server drop unknown-user" + "\nsnmp-server host 1.1.1.1 traps test udp-port 1\nsnmp-server host 1.1.1.2 informs " + "version 2c test\nsnmp-server host 1.1.1.3 traps test\nsnmp-server user test1 test2 v1 " + "IPv4 test1 IPv6 test2 SDROwner\nsnmp-server " + "community test RO IPv4 test IPv6 test\nsnmp-" + "server community test1 RO\nsnmp-server group " + "test v1 notify test1\nsnmp-server group test1 " + "v1 read test1 write test2 context test3 IPv4 test" + " IPv6 test1\nsnmp-server group test2 v1 " + "notify test read test1\nsnmp-server group test4 " + "v1 notify t1 context test\nsnmp-server queue-length " + "1\nsnmp-server trap-timeout 1\nsnmp-server trap " + "throttle-time 10\nsnmp-server traps rf\nsnmp-server traps " + "bfd\nsnmp-server traps bgp cbgp2\nsnmp-server " + "traps bgp updown\nsnmp-server traps ntp\nsnmp-server " + "traps pim neighbor-change\nsnmp-server traps " + "pim invalid-message-received\nsnmp-server traps pim " + "rp-mapping-change\nsnmp-server traps pim interface-state-change" + "\nsnmp-server traps copy-complete\nsnmp-server " + "traps hsrp\nsnmp-server traps ipsla\nsnmp-server traps msdp " + "peer-state-change\nsnmp-server traps vrrp events\nsnmp-server " + "traps flash removal\nsnmp-server traps flash insertion\nsnmp-server " + "traps ipsec tunnel stop\nsnmp-server traps ipsec tunnel start\nsnmp-server " + "traps power\nsnmp-server traps config\nsnmp-server traps entity\nsnmp-server " + "traps isakmp tunnel stop\nsnmp-server traps isakmp tunnel start\nsnmp-server " + "traps isis database-overload manual-address-drops corrupted-lsp-detected " + "attempt-to-exceed-max-sequence id-len-mismatch max-area-addresses-mismatch" + " own-lsp-purge sequence-number-skip authentication-type-failure " + "authentication-failure version-skew area-mismatch rejected-adjacency " + "lsp-too-large-to-propagate orig-lsp-buff-size-mismatch protocols-supported-mismatch" + " adjacency-change lsp-error-detected\nsnmp-server traps sensor\nsnmp-server" + " traps selective-vrf-download role-change\nsnmp-server traps syslog" + "\nsnmp-server traps system\nsnmp-server traps ospf lsa lsa-maxage" + "\nsnmp-server traps ospf lsa lsa-originate\nsnmp-server traps ospf" + " errors bad-packet\nsnmp-server traps ospf errors authentication-failure" + "\nsnmp-server traps ospf errors config-error\nsnmp-server traps ospf" + " errors virt-bad-packet\nsnmp-server traps ospf errors " + "virt-authentication-failure\nsnmp-server traps ospf errors" + " virt-config-error\nsnmp-server traps ospf retransmit" + " packets\nsnmp-server traps ospf retransmit virt-packets" + "\nsnmp-server traps ospf state-change if-state-change" + "\nsnmp-server traps ospf state-change neighbor-state-change" + "\nsnmp-server traps ospf state-change virtif-state-change\n" + "snmp-server traps ospf state-change virtneighbor-state-change" + "\nsnmp-server traps rsvp all\nsnmp-server traps rsvp new-flow\n" + "snmp-server traps rsvp lost-flow\nsnmp-server traps l2tun sessions\n" + "snmp-server traps l2tun tunnel-up\nsnmp-server traps l2tun tunnel-down" + "\nsnmp-server traps l2tun pseudowire status\nsnmp-server traps vpls all\n" + "snmp-server traps vpls status\nsnmp-server traps vpls full-clear\nsnmp-server " + "traps vpls full-raise\nsnmp-server traps snmp linkup\nsnmp-server traps snmp " + "linkdown\nsnmp-server traps snmp coldstart\nsnmp-server traps snmp warmstart" + "\nsnmp-server traps snmp authentication\nsnmp-server traps bulkstat transfer" + "\nsnmp-server traps bulkstat collection\nsnmp-server traps diameter peerup\ + nsnmp-server traps diameter peerdown\nsnmp-server traps diameter protocolerror" + "\nsnmp-server traps diameter permanentfail\nsnmp-server traps diameter transientfail" + "\nsnmp-server traps l2vpn all\nsnmp-server traps l2vpn cisco\nsnmp-server traps " + "l2vpn vc-up\nsnmp-server traps l2vpn vc-down\nsnmp-server traps bridgemib\nsnmp-" + "server traps ospfv3 errors bad-packet\nsnmp-server traps ospfv3 errors config-error" + "\nsnmp-server traps ospfv3 errors virt-bad-packet\nsnmp-server traps ospfv3 errors " + "virt-config-error\nsnmp-server traps ospfv3 state-change if-state-change\nsnmp-" + "server traps ospfv3 state-change neighbor-state-change\nsnmp-server traps ospfv3 " + "state-change nssa-state-change\nsnmp-server traps ospfv3 state-change " + "virtif-state-change\nsnmp-server traps ospfv3 state-change " + "virtneighbor-state-change\nsnmp-server traps ospfv3 state-change " + "restart-status-change\nsnmp-server traps ospfv3 state-change " + "restart-helper-status-change\nsnmp-server traps ospfv3 state-change " + "restart-virtual-helper-status-change\nsnmp-server traps fru-ctrl" + "\nsnmp-server traps subscriber session-agg node\nsnmp-server traps " + "subscriber session-agg access-interface\nsnmp-server traps addrpool " + "low\nsnmp-server traps addrpool high\nsnmp-server traps cisco-entity-ext" + "\nsnmp-server traps entity-state operstatus\nsnmp-server traps entity-state " + "switchover\nsnmp-server traps entity-redundancy all" + "\nsnmp-server traps entity-redundancy " + "status\nsnmp-server traps entity-redundancy switchover\nsnmp-server chassis-id test2" + "\nsnmp-server contact test\nsnmp-server location test\nsnmp-server target list test1 " + "vrf vrf1\nsnmp-server target list test1 host 1.1.1.1\nsnmp-server context test\n" + "snmp-server context test2\nsnmp-server logging threshold oid-processing 0\n" + "snmp-server logging threshold pdu-processing 0\nsnmp-server mib bulkstat max-" + "procmem-size 100\nsnmp-server mib bulkstat object-list test\n!\nsnmp-server mib " + "bulkstat transfer-id test1\n retry 1\n buffer-size 1024\n enable\n format schemaASCII\n" + " retain 1\n schema test\n!\nsnmp-server timeouts duplicate 0\nsnmp-server timeouts" + " inQdrop 0\nsnmp-server timeouts subagent 1\nsnmp-server timeouts pdu stats" + " 1\nsnmp-server timeouts threshold 0\nsnmp-server packetsize 485\nsnmp-server" + " correlator buffer-size 1024\nsnmp-server trap-source GigabitEthernet0/0/0/1" + "\nsnmp-server throttle-time 50\nsnmp-server community-map test context test " + "security-name test2\nsnmp-server community-map test1 context test security-name " + "test2\nsnmp-server inform pending 1\nsnmp-server inform retries 1\nsnmp-server " + "inform timeout 1\nsnmp-server oid-poll-stats\nsnmp-server overload-control 0 0" + "\nsnmp-server trap authentication vrf disable\nsnmp-server " + "interface GigabitEthernet0/0/0/0\n notification linkupdown disable\n " + "index persistence\n!\nsnmp-server ifmib ifalias long\nsnmp-server " + "ifindex persist\nsnmp-server ifmib internal cache max-duration " + "0\nsnmp-server ifmib ipsubscriber\nsnmp-server ifmib stats cache" + "\nsnmp-server trap link ietf\nsnmp-server location test\nsnmp-server" + " mroutemib send-all-vrf\nsnmp-server notification-log-mib size 1\nsnmp-server " + "notification-log-mib default\nsnmp-server notification-log-mib disable\nsnmp-server" + " notification-log-mib GlobalSize 1", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = { + "vrfs": [ + { + "vrf": "test1", + "context": ["test2"], + "hosts": [ + { + "host": "1.1.1.1", + "traps": True, + "community": "test1", + }, + { + "host": "1.1.1.2", + "traps": True, + "community": "test1", + }, + ], + }, + ], + "drop": {"report_IPv6": "test", "unknown_user": True}, + "hosts": [ + { + "host": "1.1.1.1", + "traps": True, + "community": "test", + "udp_port": 1, + }, + { + "host": "1.1.1.2", + "informs": True, + "community": "test", + "version": "2c", + }, + {"host": "1.1.1.3", "traps": True, "community": "test"}, + ], + "users": [ + { + "user": "test1", + "group": "test2", + "acl_v4": "test1", + "acl_v6": "test2", + "v4_acl": "SDROwner", + "version": "v1", + }, + ], + "communities": [ + { + "name": "test", + "ro": True, + "acl_v4": "test", + "acl_v6": "test", + }, + {"name": "test1", "ro": True}, + ], + "groups": [ + {"group": "test", "notify": "test1", "version": "v1"}, + { + "group": "test1", + "acl_v4": "test", + "acl_v6": "test1", + "context": "test3", + "read": "test1", + "write": "test2", + "version": "v1", + }, + { + "group": "test2", + "notify": "test", + "read": "test1", + "version": "v1", + }, + { + "group": "test4", + "context": "test", + "notify": "t1", + "version": "v1", + }, + ], + "queue_length": 1, + "trap_timeout": 1, + "trap": { + "throttle_time": 10, + "authentication_vrf_disable": True, + "link_ietf": True, + }, + "traps": { + "rf": True, + "bfd": True, + "bgp": {"cbgp2": True}, + "pim": { + "neighbor_change": True, + "invalid_message_received": True, + "rp_mapping_change": True, + "interface_state_change": True, + }, + "copy_complete": True, + "hsrp": True, + "ipsla": True, + "msdp_peer_state_change": True, + "vrrp_events": True, + "flash": {"removal": True, "insertion": True}, + "ipsec": {"stop": True, "start": True}, + "power": True, + "config": True, + "entity": True, + "isakmp": {"stop": True, "start": True}, + "isis": { + "id_len_mismatch": True, + "database_overload": True, + "manual_address_drops": True, + "corrupted_lsp_detected": True, + "attempt_to_exceed_max_sequence": True, + "max_area_addresses_mismatch": True, + "own_lsp_purge": True, + "sequence_number_skip": True, + "authentication_type_failure": True, + "authentication_failure": True, + "version_skew": True, + "area_mismatch": True, + "rejected_adjacency": True, + "lsp_too_large_to_propagate": True, + "orig_lsp_buff_size_mismatch": True, + "protocols_supported_mismatch": True, + "adjacency_change": True, + "lsp_error_detected": True, + }, + "sensor": True, + "selective_vrf_download_role_change": True, + "syslog": True, + "system": True, + "ospf": { + "lsa": {"lsa_maxage": True, "lsa_originate": True}, + "errors": { + "bad_packet": True, + "authentication_failure": True, + "config_error": True, + "virt_bad_packet": True, + "virt_authentication_failure": True, + "virt_config_error": True, + }, + "retransmit": {"packets": True, "virt_packets": True}, + "state_change": { + "if_state_change": True, + "neighbor_state_change": True, + "virtif_state_change": True, + "virtneighbor_state_change": True, + }, + }, + "rsvp": {"all": True, "new_flow": True, "lost_flow": True}, + "l2tun": { + "sessions": True, + "tunnel_up": True, + "tunnel_down": True, + }, + "vpls": { + "all": True, + "status": True, + "full_clear": True, + "full_raise": True, + }, + "snmp": { + "linkup": True, + "linkdown": True, + "coldstart": True, + "warmstart": True, + "authentication": True, + }, + "bulkstat_transfer": True, + "bulkstat_collection": True, + "diameter": { + "protocolerror": True, + "permanentfail": True, + "transientfail": True, + }, + "l2vpn": { + "all": True, + "cisco": True, + "vc_up": True, + "vc_down": True, + }, + "bridgemib": True, + "ospfv3": { + "errors": { + "bad_packet": True, + "config_error": True, + "virt_bad_packet": True, + "virt_config_error": True, + }, + "state_change": { + "if_state_change": True, + "neighbor_state_change": True, + "nssa_state_change": True, + "virtif_state_change": True, + "virtneighbor_state_change": True, + "restart_status_change": True, + "restart_helper_status_change": True, + "restart_virtual_helper_status_change": True, + }, + }, + "fru_ctrl": True, + "subscriber": { + "session_agg_node": True, + "session_agg_access_interface": True, + }, + "addrpool": {"low": True, "high": True}, + "cisco_entity_ext": True, + "entity_state": {"operstatus": True, "switchover": True}, + "entity_redundancy": { + "all": True, + "status": True, + "switchover": True, + }, + }, + "chassis_id": "test2", + "contact": "test", + "location": "test", + "targets": [ + {"name": "test1", "vrf": "vrf1"}, + {"name": "test1", "host": "1.1.1.1"}, + ], + "context": ["test", "test2"], + "logging_threshold_oid_processing": 0, + "logging_threshold_pdu_processing": 0, + "mib_bulkstat_max_procmem_size": 100, + "mib_object_lists": ["test"], + "mib_bulkstat_transfer_ids": [ + { + "name": "test1", + "retry": 1, + "buffer_size": 1024, + "enable": True, + "format_schemaASCI": True, + "retain": 1, + "schema": "test", + }, + ], + "timeouts": { + "duplicate": 0, + "inQdrop": 0, + "subagent": 1, + "pdu_stats": 1, + "threshold": 0, + }, + "packetsize": 485, + "correlator": {"buffer_size": 1024}, + "trap_source": "GigabitEthernet0/0/0/1", + "throttle_time": 50, + "community_maps": [ + {"name": "test", "context": "test", "security_name": "test2"}, + {"name": "test1", "context": "test", "security_name": "test2"}, + ], + "inform": {"pending": 1, "retries": 1, "timeout": 1}, + "oid_poll_stats": True, + "overload_control": { + "overload_drop_time": 0, + "overload_throttle_rate": 0, + }, + "interfaces": [ + { + "name": "GigabitEthernet0/0/0/0", + "notification_linkupdown_disable": True, + }, + ], + "ifmib": { + "ifalias_long": True, + "internal_cache_max_duration": 0, + "ipsubscriber": True, + "stats": True, + }, + "ifindex": True, + "mroutemib_send_all_vrf": True, + "notification_log_mib": { + "size": 1, + "default": True, + "disable": True, + "GlobalSize": 1, + }, + } + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_static_routes.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_static_routes.py new file mode 100644 index 00000000..ba91d7f3 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_static_routes.py @@ -0,0 +1,380 @@ +# +# (c) 2019, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_static_routes +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrStaticRoutesModule(TestIosxrModule): + module = iosxr_static_routes + + def setUp(self): + super(TestIosxrStaticRoutesModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection", + ) + self.get_resource_connection_config = self.mock_get_resource_connection_config.start() + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection", + ) + self.get_resource_connection_facts = self.mock_get_resource_connection_facts.start() + + self.mock_execute_show_command = patch( + "ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.facts.static_routes.static_routes.Static_routesFacts.get_device_data", + ) + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestIosxrStaticRoutesModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_execute_show_command.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + return load_fixture("iosxr_static_routes_config.cfg") + + self.execute_show_command.side_effect = load_from_file + + def test_iosxr_static_routes_merged(self): + set_module_args( + dict( + config=[ + dict( + vrf="dev_site", + address_families=[ + dict( + afi="ipv6", + safi="unicast", + routes=[ + dict( + dest="1200:10::/64", + next_hops=[ + dict( + interface="GigabitEthernet0/0/0/1", + admin_distance=55, + ), + ], + ), + ], + ), + ], + ), + ], + state="merged", + ), + ) + commands = [ + "router static", + "vrf dev_site", + "address-family ipv6 unicast", + "1200:10::/64 GigabitEthernet0/0/0/1 55", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_static_routes_merged_idempotent(self): + set_module_args( + dict( + config=[ + dict( + vrf="DEV_SITE", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + routes=[ + dict( + dest="192.0.2.48/28", + next_hops=[ + dict( + interface="192.0.2.12", + description="DEV", + dest_vrf="test_1", + ), + ], + ), + ], + ), + ], + ), + ], + state="merged", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_static_routes_default(self): + set_module_args( + dict( + config=[ + dict( + address_families=[ + dict( + afi="ipv4", + safi="unicast", + routes=[ + dict( + dest="192.168.1.0/24", + next_hops=[ + dict( + interface="GigabitEthernet0/0/0/2", + track="ip_sla_2", + vrflabel=1200, + ), + ], + ), + ], + ), + ], + ), + ], + ), + ) + commands = [ + "router static", + "address-family ipv4 unicast", + "192.168.1.0/24 GigabitEthernet0/0/0/2 track ip_sla_2 vrflabel 1200", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_static_routes_default_idempotent(self): + set_module_args( + dict( + config=[ + dict( + address_families=[ + dict( + afi="ipv4", + safi="unicast", + routes=[ + dict( + dest="192.0.2.32/28", + next_hops=[ + dict( + forward_router_address="192.0.2.11", + admin_distance=100, + ), + ], + ), + ], + ), + ], + ), + ], + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_static_routes_replaced(self): + set_module_args( + dict( + config=[ + dict( + address_families=[ + dict( + afi="ipv4", + safi="unicast", + routes=[ + dict( + dest="192.0.2.16/28", + next_hops=[ + dict( + forward_router_address="192.0.2.11", + admin_distance=100, + ), + ], + ), + ], + ), + ], + ), + ], + state="replaced", + ), + ) + commands = [ + "router static", + "address-family ipv4 unicast", + "no 192.0.2.16/28 192.0.2.10 FastEthernet0/0/0/1", + "no 192.0.2.16/28 FastEthernet0/0/0/5", + "192.0.2.16/28 192.0.2.11 100", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_static_routes_replaced_idempotent(self): + set_module_args( + dict( + config=[ + dict( + address_families=[ + dict( + afi="ipv4", + safi="unicast", + routes=[ + dict( + dest="192.0.2.16/28", + next_hops=[ + dict( + interface="FastEthernet0/0/0/5", + track="ip_sla_1", + ), + dict( + interface="FastEthernet0/0/0/1", + forward_router_address="192.0.2.10", + tag=10, + description="LAB", + metric=120, + ), + ], + ), + ], + ), + ], + ), + ], + state="replaced", + ), + ) + self.execute_module(changed=False, commands=[]) + + def test_iosxr_static_routes_overridden(self): + set_module_args( + dict( + config=[ + dict( + vrf="DEV_SITE_NEW", + address_families=[ + dict( + afi="ipv4", + safi="unicast", + routes=[ + dict( + dest="192.0.4.16/28", + next_hops=[ + dict( + interface="FastEthernet0/0/0/5", + track="ip_sla_1", + ), + dict( + interface="FastEthernet0/0/0/1", + forward_router_address="192.0.2.10", + tag=10, + description="LAB", + metric=120, + ), + ], + ), + ], + ), + ], + ), + ], + state="overridden", + ), + ) + commands = [ + "router static", + "no address-family ipv4 unicast", + "no address-family ipv6 unicast", + "no vrf DEV_SITE", + "vrf DEV_SITE_NEW", + "address-family ipv4 unicast", + "192.0.4.16/28 192.0.2.10 FastEthernet0/0/0/1 description LAB metric 120 tag 10", + "192.0.4.16/28 FastEthernet0/0/0/5 track ip_sla_1", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_static_routes_deleted_afi(self): + set_module_args( + dict( + config=[ + dict(address_families=[dict(afi="ipv4", safi="unicast")]), + ], + state="deleted", + ), + ) + + commands = ["router static", "no address-family ipv4 unicast"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_static_routes_deleted_vrf(self): + set_module_args(dict(config=[dict(vrf="DEV_SITE")], state="deleted")) + + commands = ["router static", "no vrf DEV_SITE"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_static_routes_deleted_all(self): + set_module_args(dict(state="deleted")) + + commands = ["no router static"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_static_routes_parsed(self): + set_module_args( + dict( + running_config="router static\n address-family ipv4 unicast\n 0.0.0.0/0 172.31.32.1\n " + "10.0.0.0/8 Null0 200\n 11.0.0.0/8 Loopback888\n 203.0.113.0/24 TenGigE0/0/0/0\n !\n!", + state="parsed", + ), + ) + result = self.execute_module(changed=False) + parsed_list = [ + { + "address_families": [ + { + "afi": "ipv4", + "routes": [ + { + "dest": "0.0.0.0/0", + "next_hops": [ + {"forward_router_address": "172.31.32.1"}, + ], + }, + { + "dest": "10.0.0.0/8", + "next_hops": [ + { + "admin_distance": 200, + "interface": "Null0", + }, + ], + }, + { + "dest": "11.0.0.0/8", + "next_hops": [{"interface": "Loopback888"}], + }, + { + "dest": "203.0.113.0/24", + "next_hops": [{"interface": "TenGigE0/0/0/0"}], + }, + ], + "safi": "unicast", + }, + ], + }, + ] + self.assertEqual(parsed_list, result["parsed"]) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_system.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_system.py new file mode 100644 index 00000000..4e09671e --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_system.py @@ -0,0 +1,123 @@ +# (c) 2016 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_system +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrSystemModule(TestIosxrModule): + + module = iosxr_system + + def setUp(self): + super(TestIosxrSystemModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_system.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_system.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_is_cliconf = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_system.is_cliconf", + ) + self.is_cliconf = self.mock_is_cliconf.start() + + def tearDown(self): + super(TestIosxrSystemModule, self).tearDown() + + self.mock_get_config.stop() + self.mock_load_config.stop() + + def load_fixtures(self, commands=None): + self.get_config.return_value = load_fixture("iosxr_system_config.cfg") + self.load_config.return_value = dict(diff=None, session="session") + self.is_cliconf.return_value = True + + def test_iosxr_system_hostname_changed(self): + set_module_args(dict(hostname="foo")) + commands = ["hostname foo", "no domain lookup disable"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_system_domain_name(self): + set_module_args(dict(domain_name="test.com")) + commands = ["domain name test.com", "no domain lookup disable"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_system_domain_search(self): + set_module_args(dict(domain_search=["ansible.com", "redhat.com"])) + commands = [ + "domain list ansible.com", + "no domain list cisco.com", + "no domain lookup disable", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_system_lookup_source(self): + set_module_args(dict(lookup_source="Ethernet1")) + commands = [ + "domain lookup source-interface Ethernet1", + "no domain lookup disable", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_system_lookup_enabled(self): + set_module_args(dict(lookup_enabled=True)) + commands = ["no domain lookup disable"] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_system_name_servers(self): + name_servers = ["8.8.8.8", "8.8.4.4", "1.1.1.1"] + set_module_args(dict(name_servers=name_servers)) + self.execute_module(changed=True) + + def test_iosxr_system_state_absent(self): + set_module_args(dict(state="absent")) + commands = [ + "no hostname", + "no domain name", + "no domain lookup disable", + "no domain lookup source-interface MgmtEth0/0/CPU0/0", + "no domain list redhat.com", + "no domain list cisco.com", + "no domain name-server 8.8.8.8", + "no domain name-server 8.8.4.4", + ] + self.execute_module(changed=True, commands=commands) + + def test_iosxr_system_no_change(self): + set_module_args( + dict( + hostname="iosxr01", + domain_name="eng.ansible.com", + lookup_enabled=False, + ), + ) + self.execute_module() diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_user.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_user.py new file mode 100644 index 00000000..3bb6f504 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_user.py @@ -0,0 +1,131 @@ +# (c) 2016 Red Hat Inc. +# +# 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 + +from ansible_collections.cisco.iosxr.plugins.modules import iosxr_user +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch +from ansible_collections.cisco.iosxr.tests.unit.modules.utils import set_module_args + +from .iosxr_module import TestIosxrModule, load_fixture + + +class TestIosxrUserModule(TestIosxrModule): + + module = iosxr_user + + def setUp(self): + super(TestIosxrUserModule, self).setUp() + + self.mock_get_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_user.get_config", + ) + self.get_config = self.mock_get_config.start() + + self.mock_load_config = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_user.load_config", + ) + self.load_config = self.mock_load_config.start() + + self.mock_is_cliconf = patch( + "ansible_collections.cisco.iosxr.plugins.modules.iosxr_user.is_cliconf", + ) + self.is_cliconf = self.mock_is_cliconf.start() + + def tearDown(self): + super(TestIosxrUserModule, self).tearDown() + + self.mock_get_config.stop() + self.mock_load_config.stop() + self.mock_is_cliconf.stop() + + def load_fixtures(self, commands=None, transport="cli"): + self.get_config.return_value = load_fixture("iosxr_user_config.cfg") + self.load_config.return_value = dict(diff=None, session="session") + self.is_cliconf.return_value = True + + def test_iosxr_user_delete(self): + set_module_args(dict(name="ansible", state="absent")) + result = self.execute_module(changed=True) + self.assertEqual(result["commands"], ["no username ansible"]) + + def test_iosxr_user_password(self): + set_module_args(dict(name="ansible", configured_password="test")) + result = self.execute_module(changed=True) + self.assertEqual(result["commands"], ["username ansible secret test"]) + + def test_iosxr_user_purge(self): + set_module_args(dict(purge=True)) + result = self.execute_module(changed=True) + self.assertEqual(result["commands"], ["no username ansible"]) + + def test_iosxr_user_group(self): + set_module_args(dict(name="ansible", group="sysadmin")) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + ["username ansible group sysadmin"], + ) + + def test_iosxr_user_update_password_changed(self): + set_module_args( + dict( + name="test", + configured_password="test", + update_password="on_create", + ), + ) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + ["username test", "username test secret test"], + ) + + def test_iosxr_user_update_password_on_create_ok(self): + set_module_args( + dict( + name="ansible", + configured_password="test", + update_password="on_create", + ), + ) + self.execute_module() + + def test_iosxr_user_update_password_always(self): + set_module_args( + dict( + name="ansible", + configured_password="test", + update_password="always", + ), + ) + result = self.execute_module(changed=True) + self.assertEqual(result["commands"], ["username ansible secret test"]) + + def test_iosxr_user_admin_mode(self): + set_module_args( + dict(name="ansible-2", configured_password="test-2", admin=True), + ) + result = self.execute_module(changed=True) + self.assertEqual( + result["commands"], + ["username ansible-2", "username ansible-2 secret test-2"], + ) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_utils.py b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_utils.py new file mode 100644 index 00000000..7707adf4 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/network/iosxr/test_iosxr_utils.py @@ -0,0 +1,28 @@ +# +# (c) 2022, Ansible by Red Hat, inc +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# + +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import Version +from ansible_collections.cisco.iosxr.tests.unit.compat import unittest + + +class TestIosxrUtils(unittest.TestCase): + def setUp(self): + pass + + def tearDown(self): + pass + + def test_VersionOperation(self): + self.assertEqual(Version("3.0.1") < Version("3.1.0"), True) + self.assertEqual(Version("0.0.1") < Version("3.1.0"), True) + self.assertEqual(Version("3.0.1") < Version("3.0.1"), False) + self.assertEqual(Version("3.0.1") <= Version("3.0.1"), True) + self.assertEqual(Version("4.0.1") > Version("3.0.1"), True) + self.assertEqual(Version("4.1.1") > Version("4.1.0"), True) + self.assertEqual(Version("4.1.1") == Version("4.1.1"), True) diff --git a/ansible_collections/cisco/iosxr/tests/unit/modules/utils.py b/ansible_collections/cisco/iosxr/tests/unit/modules/utils.py new file mode 100644 index 00000000..d63a8692 --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/modules/utils.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import, division, print_function + + +__metaclass__ = type +import json + +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes + +from ansible_collections.cisco.iosxr.tests.unit.compat import unittest +from ansible_collections.cisco.iosxr.tests.unit.compat.mock import patch + + +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/ansible_collections/cisco/iosxr/tests/unit/requirements.txt b/ansible_collections/cisco/iosxr/tests/unit/requirements.txt new file mode 100644 index 00000000..a9772bea --- /dev/null +++ b/ansible_collections/cisco/iosxr/tests/unit/requirements.txt @@ -0,0 +1,42 @@ +boto3 +placebo +pycrypto +passlib +pypsrp +python-memcached +pytz +pyvmomi +redis +requests +setuptools > 0.6 # pytest-xdist installed via requirements does not work with very old setuptools (sanity_ok) +unittest2 ; python_version < '2.7' +importlib ; python_version < '2.7' +netaddr +ipaddress +netapp-lib +solidfire-sdk-python + +# requirements for F5 specific modules +f5-sdk ; python_version >= '2.7' +f5-icontrol-rest ; python_version >= '2.7' +deepdiff + +# requirement for Fortinet specific modules +pyFMG + +# requirement for aci_rest module +xmljson + +# requirement for winrm connection plugin tests +pexpect + +# requirement for the linode module +linode-python # APIv3 +linode_api4 ; python_version > '2.6' # APIv4 + +# requirement for the gitlab module +python-gitlab +httmock + +# requirment for kubevirt modules +openshift ; python_version >= '2.7' |