diff --git a/docs/dev/code_reference/nist.md b/docs/dev/code_reference/nist.md deleted file mode 100644 index 6fe7452e..00000000 --- a/docs/dev/code_reference/nist.md +++ /dev/null @@ -1,5 +0,0 @@ -# NIST URLs - -::: netutils.nist - options: - show_submodules: True \ No newline at end of file diff --git a/docs/dev/code_reference/platform_mapper.md b/docs/dev/code_reference/platform_mapper.md deleted file mode 100644 index 81cd38df..00000000 --- a/docs/dev/code_reference/platform_mapper.md +++ /dev/null @@ -1,5 +0,0 @@ -# Platform Mapper - -::: netutils.platform_mapper - options: - show_submodules: True \ No newline at end of file diff --git a/docs/user/include_jinja_list.md b/docs/user/include_jinja_list.md index 7c67d29a..362fae63 100644 --- a/docs/user/include_jinja_list.md +++ b/docs/user/include_jinja_list.md @@ -59,7 +59,6 @@ | mac_to_int | netutils.mac.mac_to_int | | mac_type | netutils.mac.mac_type | | get_upgrade_path | netutils.os_version.get_upgrade_path | -| juniper_junos_version_parser | netutils.os_version.juniper_junos_version_parser | | compare_cisco_type5 | netutils.password.compare_cisco_type5 | | compare_cisco_type7 | netutils.password.compare_cisco_type7 | | compare_cisco_type9 | netutils.password.compare_cisco_type9 | @@ -76,7 +75,6 @@ | encrypt_type7 | netutils.password.encrypt_type7 | | get_hash_salt | netutils.password.get_hash_salt | | tcp_ping | netutils.ping.tcp_ping | -| os_platform_object_builder | netutils.platform_mapper.os_platform_object_builder | | regex_findall | netutils.regex.regex_findall | | regex_match | netutils.regex.regex_match | | regex_search | netutils.regex.regex_search | diff --git a/mkdocs.yml b/mkdocs.yml index 01e71ca7..7c0a66ff 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -147,11 +147,9 @@ nav: - Library Helpers: "dev/code_reference/lib_helpers.md" - Library Mapping: "dev/code_reference/lib_mapping.md" - Mac Address: "dev/code_reference/mac.md" - - NIST: "dev/code_reference/nist.md" - OS Version: "dev/code_reference/os_version.md" - Password: "dev/code_reference/password.md" - Ping: "dev/code_reference/ping.md" - - Platform Mapper: "dev/code_reference/platform_mapper.md" - Protocol Mapper: "dev/code_reference/protocol_mapper.md" - Regex: "dev/code_reference/regex.md" - Route: "dev/code_reference/route.md" diff --git a/netutils/nist.py b/netutils/nist.py deleted file mode 100644 index 8bc1362b..00000000 --- a/netutils/nist.py +++ /dev/null @@ -1,141 +0,0 @@ -"""Functions building NIST URLs from the os platform values.""" -import re -import typing as t - - -def get_nist_urls_juniper_junos( # pylint: disable=R0911 - os_platform_data: t.Dict[str, t.Any], api_key: str -) -> t.List[str]: - """Create a list of possible NIST Url strings for JuniperPlatform. - - Args: - api_key: NIST-API-KEY - Request here https://nvd.nist.gov/developers/request-an-api-key - - Returns: - List of NIST CPE URLs that may contain platform data. - """ - nist_urls = [] - base_url = f"""https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey={api_key}&addOns=cves&cpeMatchString=cpe:2.3:o:juniper:junos""" - - # BASE - _main = os_platform_data.get("main") - _minor = os_platform_data.get("minor") - if os_platform_data["type"]: - _type = os_platform_data["type"].lower() - _build = os_platform_data.get("build") - - # SERVICE - if os_platform_data["service"]: - _service = os_platform_data["service"].lower() - _service_build = os_platform_data.get("service_build") - _service_respin = os_platform_data.get("service_respin") - - # EXTRAS - delim_six = ":*" * 6 - delim_seven = ":*" * 7 - - if os_platform_data["isspecial"]: - # e.g. base_ext = juniper:junos:12.1x47 - base_ext = f"{base_url}:{_main}.{_minor}{_type}{_build}" - else: - # e.g. base_ext = juniper:junos:12.1 - base_ext = f"{base_url}:{_main}.{_minor}" - - # X Series (Special) Examples: 12.1x47:d40, 12.2x50:d41.1 - if os_platform_data["isspecial"] and os_platform_data["service_respin"]: # pylint: disable=R1705 - # nist_urls.append(juniper:junos:12.2x50:d41.1:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}:{_service}{_service_build}.{_service_respin}{delim_six}") - - # nist_urls.append(juniper:junos:12.2x50-d41.1:*:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}-{_service}{_service_build}.{_service_respin}{delim_seven}") - - return nist_urls - - elif os_platform_data["isspecial"]: - # nist_urls.append(juniper:junos:12.1x47:d40:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}:{_service}{_service_build}{delim_six}") - - # nist_urls.append(juniper:junos:12.1x47-d40:*:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}-{_service}{_service_build}{delim_seven}") - - return nist_urls # - - if not os_platform_data.get("type"): - # nist_urls.append(juniper:junos:12.1:-:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}:-{delim_six}") - - return nist_urls - - if not os_platform_data.get("build"): - # nist_urls.append(juniper:junos:10.4s:*:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}{_type}{delim_seven}") - - return nist_urls - - if os_platform_data.get("build") and not os_platform_data.get("service"): - # nist_urls.append(juniper:junos:12.3r12:*:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}{_type}{_build}{delim_seven}") - - # nist_urls.append(juniper:junos:12.2:r1:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}:{_type}{_build}{delim_six}") - - return nist_urls - - if os_platform_data.get("service") and os_platform_data.get("service_respin"): - # nist_urls.append(juniper:junos:11.4r13:s2.1:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}{_type}{_build}:{_service}{_service_build}.{_service_respin}{delim_six}") - - # nist_urls.append(juniper:junos:12.2:r8-s2.1:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}{_type}{_build}-{_service}{_service_build}.{_service_respin}{delim_seven}") - - return nist_urls - - if os_platform_data.get("service"): - # nist_urls.append(juniper:junos:11.4r13:s2:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}{_type}{_build}:{_service}{_service_build}{delim_six}") - - # nist_urls.append(juniper:junos:12.2:r8-s2:*:*:*:*:*:*) - nist_urls.append(f"{base_ext}{_type}{_build}-{_service}{_service_build}{delim_seven}") - - return nist_urls - - raise ValueError("Failure creating Juniper JunOS Version. Format is unknown.") - - -def get_nist_urls_default(os_platform_data: t.Dict[str, t.Any], api_key: str) -> t.List[str]: - r"""Create a list of possible NIST Url strings. - - Child models with NIST URL customizations need their own "get_nist_urls" method. - - Args: - api_key: NIST-API-KEY - Request here https://nvd.nist.gov/developers/request-an-api-key - - Returns: - List of NIST CPE URLs that may contain platform data. - """ - nist_urls = [] - escape_list = [r"\(", r"\)"] - base_url = ( - f"""https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey={api_key}&addOns=cves&cpeMatchString=cpe:2.3:o:""" - ) - os_platform_data = {"base_url": base_url, **os_platform_data} - delim_seven = ":*" * 7 - os_platform_data["version_string"] = os_platform_data.get("version_string").replace("-", ":") # type: ignore - - version_string = os_platform_data.get("version_string", "") - for escape_char in escape_list: - version_string = re.sub(escape_char, "\\" + escape_char, version_string) - - os_platform_data["version_string"] = version_string - - nist_urls.append( - f"{base_url}{os_platform_data['vendor']}:{os_platform_data['os_type']}:{os_platform_data['version_string']}{delim_seven}" - ) - - return nist_urls - - -get_nist_url_funcs: t.Dict[str, t.Any] = { - "default": get_nist_urls_default, - "juniper": {"junos": get_nist_urls_juniper_junos}, -} diff --git a/netutils/os_version.py b/netutils/os_version.py index db277ccd..09268de9 100644 --- a/netutils/os_version.py +++ b/netutils/os_version.py @@ -1,5 +1,4 @@ """Functions for working with OS Versions.""" -import re import typing as t from distutils.version import LooseVersion # pylint: disable=deprecated-module @@ -48,90 +47,3 @@ def get_upgrade_path( upgrade_path.append(target_version) return upgrade_path - - -def juniper_junos_version_parser(version: str) -> t.Dict[str, t.Any]: - """Parses JunOS Version into usable bits matching JunOS Standards. - - Args: - version - - Returns: - A dictionary containing parsed version information - - Examples: - >>> parsed_version = juniper_junos_version_parser("12.3R4") - """ - # Use regex to group the main, minor, type and build into useable pieces - # re_main_minor_type_build = re.search(r"^(\d+)\.(\d+)([xXrRsS])?(\d+)?", split_version[0]) - re_main_minor_type_build: re.Pattern[str] = re.compile( - r""" - ^ - (?P
\d+) # main train - \. # dot separator - (?P\d+) # minor version - (?P[xXrRsS])? # version type (optional) - (?P\d+)? # build (optional) - """, - re.VERBOSE, - ) - re_service_build_respin: re.Pattern[str] = re.compile( - r""" - (?P[sSdD])? # service (optional) - (?P\d+)? # service build (optional) - \.? - (?P\d+)? # service respin (optional) - """, - re.VERBOSE, - ) - # Set empty params for service pieces and complete them if a second indice exists from the version split - # Define isservice, isfrs, isspecial, ismaintenance - parsed_version: t.Dict[str, t.Any] = { - "isservice": False, - "ismaintenance": False, - "isfrs": False, - "isspecial": False, - "service": None, - "service_build": None, - "service_respin": None, - } - - # Juniper junos marks the division between main, minor, type and build from the service build and respin with a - - version_core_part, *version_service_part = re.split("-|:", version) - - # Parse out junos into sections that can be used for logic - parsed_version.update(re_main_minor_type_build.search(version_core_part).groupdict()) # type:ignore - - if version_service_part: - parsed_version.update(re_service_build_respin.search(version_service_part[0]).groupdict()) # type:ignore - if parsed_version.get("service", "").lower() == "s": - parsed_version["isservice"] = True - # Juniper looks at the D in special releases like it's the R in normal releases; Use it as the frs identifier - elif parsed_version.get("service").lower() == "d" and ( # type:ignore - parsed_version.get("service_build") is None or int(parsed_version.get("service_build", 1)) <= 1 - ): - parsed_version["isfrs"] = True - - if parsed_version.get("type") is None: - return parsed_version - - if parsed_version["type"].lower() == "x": - parsed_version["isspecial"] = True - elif parsed_version["type"].lower() == "s": - parsed_version["isservice"] = True - - if parsed_version["type"].lower() == "r" and ( - parsed_version.get("build") is None or int(parsed_version.get("build")) <= 1 # type:ignore - ): - parsed_version["isfrs"] = True - elif parsed_version["type"].lower() == "r": - parsed_version["ismaintenance"] = True - - return parsed_version - - -os_version_parsers = { - "juniper": { - "junos": juniper_junos_version_parser, - } -} diff --git a/netutils/platform_mapper.py b/netutils/platform_mapper.py deleted file mode 100644 index 916fa25e..00000000 --- a/netutils/platform_mapper.py +++ /dev/null @@ -1,96 +0,0 @@ -"""Platform Mappers.""" -# The intent of this script is to take a given platform, determine the format, and reformat it for another purpose -# An example of this is a platform being formatted for NIST Database Query -import abc -import dataclasses -import typing as t - -from netutils.nist import get_nist_url_funcs -from netutils.os_version import os_version_parsers - -PLATFORM_FIELDS: t.Dict[str, t.Any] = { - "default": [ - ("vendor", str), - ("os_type", str), - ("version_string", str), - ], - "juniper": { - "junos": [ - ("main", str), - ("minor", str), - ("type", str), - ("build", str), - ("service", str), - ("service_build", int), - ("service_respin", str), - ("isservice", bool, dataclasses.field(default=False)), - ("ismaintenance", bool, dataclasses.field(default=False)), - ("isfrs", bool, dataclasses.field(default=False)), - ("isspecial", bool, dataclasses.field(default=False)), - ] - }, -} - - -class OsPlatform(metaclass=abc.ABCMeta): - """Base class for dynamically generated vendor specific platform data classes.""" - - def asdict(self) -> t.Dict[str, t.Any]: - """Returns dictionary representation of the class attributes.""" - return dataclasses.asdict(self) # type: ignore - - @abc.abstractmethod - def get_nist_urls(self, api_key: str) -> t.List[str]: - """Returns list of NIST URLs for the platform.""" - - def get(self, key: str) -> t.Any: - """Return value of the attribute matching provided name or None if no attribute is found.""" - return getattr(self, key, None) - - def keys(self) -> t.KeysView[t.Any]: - """Return attributes and their values as dict keys.""" - # Disabling pylint no-member due to BUG: https://github.com/pylint-dev/pylint/issues/7126 - return self.__annotations__.keys() # pylint: disable=no-member - - def __getitem__(self, key: str) -> t.Any: - """Allow retrieving attributes using subscript notation.""" - return getattr(self, key) - - -def os_platform_object_builder(vendor: str, platform: str, version: str) -> object: - """Creates a platform object relative to its need and definition. - - Args: - vendor - - Returns: - A platform object - - Examples: - >>> jp = os_platform_object_builder("juniper", "junos", "12.1R3-S4.1") - >>> jp.get_nist_urls("AAA-BBB-CCC-DDD") - ['https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:juniper:junos:12.1r3:s4.1:*:*:*:*:*:*', 'https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:juniper:junos:12.1r3-s4.1:*:*:*:*:*:*:*'] - """ - platform = platform.lower() - - class_fields = [*PLATFORM_FIELDS["default"]] - vendor_platform_fields = PLATFORM_FIELDS.get(vendor, {}).get(platform, []) - class_fields.extend(vendor_platform_fields) - - version_parser = os_version_parsers.get(vendor, {}).get(platform, None) - field_values = { - "vendor": vendor, - "os_type": platform, - "version_string": version, - } - if version_parser: - field_values.update(version_parser(version)) - - class_name = f"{vendor.capitalize()}{platform.capitalize()}" - get_nist_urls_func = get_nist_url_funcs.get(vendor, {}).get(platform) or get_nist_url_funcs["default"] - - platform_cls = dataclasses.make_dataclass( - cls_name=class_name, fields=class_fields, bases=(OsPlatform,), namespace={"get_nist_urls": get_nist_urls_func} - ) - - return platform_cls(**field_values) diff --git a/netutils/utils.py b/netutils/utils.py index 82677419..9c56dae2 100644 --- a/netutils/utils.py +++ b/netutils/utils.py @@ -88,8 +88,6 @@ "get_napalm_getters": "lib_helpers.get_napalm_getters", "paloalto_panos_brace_to_set": "config.conversion.paloalto_panos_brace_to_set", "get_upgrade_path": "os_version.get_upgrade_path", - "os_platform_object_builder": "platform_mapper.os_platform_object_builder", - "juniper_junos_version_parser": "os_version.juniper_junos_version_parser", "hash_data": "hash.hash_data", } diff --git a/tests/unit/test_platform_mapper.py b/tests/unit/test_platform_mapper.py deleted file mode 100644 index a9c20946..00000000 --- a/tests/unit/test_platform_mapper.py +++ /dev/null @@ -1,142 +0,0 @@ -"""Test functions for platform_mapper""" - -import pytest - -from netutils import platform_mapper - -platform_data = [ - # Cisco and Arista use the generic parsing - { - "sent": {"vendor": "cisco", "platform": "ios", "version": "15.7(2.0z)M"}, - "received": {"vendor": "cisco", "os_type": "ios", "version_string": "15.7(2.0z)M"}, - }, - { - "sent": {"vendor": "arista", "platform": "eos", "version": "4.15.3f"}, - "received": {"vendor": "arista", "os_type": "eos", "version_string": "4.15.3f"}, - }, - # Juniper Junos uses a custom parser - { - "sent": {"vendor": "juniper", "platform": "junos", "version": "12.4R"}, - "received": { - "vendor": "juniper", - "os_type": "junos", - "version_string": "12.4R", - "isservice": False, - "ismaintenance": False, - "isfrs": True, - "isspecial": False, - "main": "12", - "minor": "4", - "type": "R", - "build": None, - "service": None, - "service_build": None, - "service_respin": None, - }, - }, - { - "sent": {"vendor": "juniper", "platform": "junos", "version": "12.3x48-d80"}, - "received": { - "vendor": "juniper", - "os_type": "junos", - "version_string": "12.3x48-d80", - "isservice": False, - "ismaintenance": False, - "isfrs": False, - "isspecial": True, - "main": "12", - "minor": "3", - "type": "x", - "build": "48", - "service": "d", - "service_build": "80", - "service_respin": None, - }, - }, - { - "sent": {"vendor": "juniper", "platform": "junos", "version": "12.3x48:d80"}, - "received": { - "vendor": "juniper", - "os_type": "junos", - "version_string": "12.3x48:d80", - "isservice": False, - "ismaintenance": False, - "isfrs": False, - "isspecial": True, - "main": "12", - "minor": "3", - "type": "x", - "build": "48", - "service": "d", - "service_build": "80", - "service_respin": None, - }, - }, - { - "sent": {"vendor": "juniper", "platform": "junos", "version": "12.3R12-S15"}, - "received": { - "vendor": "juniper", - "os_type": "junos", - "version_string": "12.3R12-S15", - "isservice": True, - "ismaintenance": True, - "isfrs": False, - "isspecial": False, - "main": "12", - "minor": "3", - "type": "R", - "build": "12", - "service": "S", - "service_build": "15", - "service_respin": None, - }, - }, -] - -platform_nist_urls = [ - { - "sent": {"vendor": "cisco", "platform": "ios", "version": "15.5"}, - "received": [ - "https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:cisco:ios:15.5:*:*:*:*:*:*:*" - ], - }, - { - "sent": {"vendor": "arista", "platform": "eos", "version": "4.15.3f"}, - "received": [ - "https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:arista:eos:4.15.3f:*:*:*:*:*:*:*" - ], - }, - # Juniper platforms receive multiple URLs to try as they are not very standardized and some return info on both - { - "sent": {"vendor": "juniper", "platform": "junos", "version": "12.3R12-S15"}, - "received": [ - "https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:juniper:junos:12.3r12:s15:*:*:*:*:*:*", - "https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:juniper:junos:12.3r12-s15:*:*:*:*:*:*:*", - ], - }, - { - "sent": {"vendor": "juniper", "platform": "junos", "version": "12.3x48:d25"}, - "received": [ - "https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:juniper:junos:12.3x48:d25:*:*:*:*:*:*", - "https://services.nvd.nist.gov/rest/json/cpes/1.0?apiKey=AAA-BBB-CCC-DDD&addOns=cves&cpeMatchString=cpe:2.3:o:juniper:junos:12.3x48-d25:*:*:*:*:*:*:*", - ], - }, -] - - -# Testing the parsing of a Vendor, Platform, Version into vendor standardized sections -@pytest.mark.parametrize("data", platform_data) -def test_platform_parsing(data): - platform_obj = platform_mapper.os_platform_object_builder( - data["sent"]["vendor"], data["sent"]["platform"], data["sent"]["version"] - ) - assert platform_obj.asdict() == data["received"] - - -# Testing the composition of the nist url(s) created for a platform -@pytest.mark.parametrize("data", platform_nist_urls) -def test_platform_nist(data): - platform_obj = platform_mapper.os_platform_object_builder( - data["sent"]["vendor"], data["sent"]["platform"], data["sent"]["version"] - ) - assert platform_obj.get_nist_urls("AAA-BBB-CCC-DDD") == data["received"] diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 37e98ccc..c0e7028a 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -23,13 +23,7 @@ _EXCLUDED_DECORATOR_FUNCTIONS = ["wraps", "total_ordering", "abstractmethod"] -_EXCLUDED_FUNCTIONS = [ - "jinja2_convenience_function", - "import_module", - "get_network_driver", - "get_nist_urls_default", - "get_nist_urls_juniper_junos", -] +_EXCLUDED_FUNCTIONS = ["jinja2_convenience_function", "import_module", "get_network_driver"] @pytest.fixture