Skip to content

Commit

Permalink
fix genie structured result, bump to post1 version
Browse files Browse the repository at this point in the history
  • Loading branch information
carlmontanari committed Sep 17, 2020
1 parent 67bf732 commit 49daed3
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ int-import-graph=
known-standard-library=

# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
known-third-party=nornir,nornir_utils

# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
Expand Down
2 changes: 1 addition & 1 deletion nornir_scrapli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""scrapli's plugin for nornir"""

__version__ = "2020.09.16"
__version__ = "2020.09.16.post1"
14 changes: 10 additions & 4 deletions nornir_scrapli/functions/print_structured_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
import logging
import threading

from nornir_utils.plugins.functions.print_result import _print_result
from scrapli.response import Response

from nornir.core.task import AggregatedResult, MultiResult, Result
from nornir_utils.plugins.functions.print_result import _print_result
from nornir_scrapli.result import ScrapliResult

LOCK = threading.Lock()


def print_structured_result(
result: Result,
result: ScrapliResult,
failed: bool = False,
severity_level: int = logging.INFO,
parser: str = "textfsm",
Expand All @@ -27,7 +28,7 @@ def print_structured_result(
severity_level: Print only errors with this severity level or higher
parser: textfsm|genie -- parser to parse output with
to_dict: output structured data in dict form instead -- basically put k:v instead of just
lists of lists of values for textfsm output
lists of lists of values for textfsm output; ignored if parser == "genie"
fail_to_string: fallback to printing unstructured output or have tasks skipped (because
print_result won't print empty lists which scrapli returns if parsing fails)
Expand Down Expand Up @@ -55,7 +56,12 @@ def print_structured_result(
stderr=individual_result.stderr,
stdout=individual_result.stdout,
)
structured_result = parser_method(to_dict=to_dict)

if parser == "textfsm":
structured_result = parser_method(to_dict=to_dict)
else:
structured_result = parser_method()

if not structured_result and fail_to_string:
updated_result.result = scrapli_response.result
else:
Expand Down
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ scrapli>=2020.07.04
nornir>=3.0.0,<4.0.0
nornir-utils>=0.1.0
textfsm>=1.1.0,<2.0.0
ntc_templates>=1.4.0,<2.0.0
ntc_templates>=1.1.0,<2.0.0
genie>=20.2 ; sys_platform != "win32"
pyats>=20.2 ; sys_platform != "win32"
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ match-dir = ^nornir_scrapli/*
line_length = 100
multi_line_output = 3
include_trailing_comma = True
known_first_party = nornir,nornir_utils
known_third_party = scrapli,pytest
known_first_party = nornir
known_third_party = scrapli,pytest,nornir_utils

[darglint]
docstring_style = google
Expand Down
7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
long_description_content_type="text/markdown",
url="https://github.com/scrapli/nornir_scrapli",
packages=setuptools.find_packages(),
install_requires=["scrapli>=2020.06.06", "nornir>=3.0.0a0"],
extras_require={},
install_requires=["scrapli>=2020.06.06", "nornir>=3.0.0"],
extras_require={
"textfsm": ["textfsm>=1.1.0", "ntc-templates>=1.1.0"],
"genie": ["genie>=20.2", "pyats>=20.2"],
},
classifiers=[
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
Expand Down
58 changes: 52 additions & 6 deletions tests/unit/functions/test_print_structured_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,17 @@
RAW_RESULT = "\n".join([IOSXE_SHOW_VERSION, IOSXE_SHOW_IP_ROUTE])

TEST_SCRAPLI_RESPONSE_ONE = Response(
host="sea-ios-1", channel_input="show version", textfsm_platform="cisco_iosxe"
host="sea-ios-1",
channel_input="show version",
textfsm_platform="cisco_iosxe",
genie_platform="iosxe",
)
TEST_SCRAPLI_RESPONSE_ONE._record_response(result=IOSXE_SHOW_VERSION.encode())
TEST_SCRAPLI_RESPONSE_TWO = Response(
host="sea-ios-1", channel_input="show ip route", textfsm_platform="cisco_iosxe"
host="sea-ios-1",
channel_input="show ip route",
textfsm_platform="cisco_iosxe",
genie_platform="iosxe",
)
TEST_SCRAPLI_RESPONSE_TWO._record_response(result=IOSXE_SHOW_IP_ROUTE.encode())
TEST_SCRAPLI_RESPONSE = [TEST_SCRAPLI_RESPONSE_ONE, TEST_SCRAPLI_RESPONSE_TWO]
Expand All @@ -104,7 +110,7 @@


@pytest.mark.parametrize(
"to_dict",
"structured_result",
[
(
True,
Expand All @@ -117,10 +123,50 @@
],
ids=["True", "False"],
)
def test_print_structured_result(capsys, to_dict):
print_structured_result(TEST_AGG_RESULT, to_dict=to_dict[0])
def test_print_structured_result(capsys, structured_result):
print_structured_result(TEST_AGG_RESULT, to_dict=structured_result[0])
captured = capsys.readouterr()
assert captured.out == to_dict[1]
assert captured.out == structured_result[1]


@pytest.mark.parametrize(
"structured_result",
[
(
True,
"\x1b[1m\x1b[36msend_commands*******************************************************************\n\x1b[1m\x1b[34m* sea-ios-1 ** changed : False *************************************************\n\x1b[1m\x1b[32mvvvv send_commands ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\n{ 'version': { 'chassis': 'CSR1000V',\n 'chassis_sn': '9FKLJWM5EB0',\n 'compiled_by': 'mcpre',\n 'compiled_date': 'Sun 27-Nov-16 13:02',\n 'curr_config_register': '0x2102',\n 'disks': { 'bootflash:.': { 'disk_size': '7774207',\n 'type_of_disk': 'virtual hard disk'},\n 'webui:.': {'disk_size': '0', 'type_of_disk': ''}},\n 'hostname': 'csr1000v',\n 'image_id': 'X86_64_LINUX_IOSD-UNIVERSALK9-M',\n 'image_type': 'production image',\n 'last_reload_reason': 'reload',\n 'license_level': 'ax',\n 'license_type': 'Default. No valid license found.',\n 'main_mem': '2052375',\n 'mem_size': { 'non-volatile configuration': '32768',\n 'physical': '3985132'},\n 'next_reload_license_level': 'ax',\n 'number_of_intfs': {'Gigabit Ethernet': '10'},\n 'os': 'IOS-XE',\n 'platform': 'CSR1000V',\n 'processor_type': 'VXE',\n 'returned_to_rom_by': 'reload',\n 'rom': 'IOS-XE ROMMON',\n 'rtr_type': 'CSR1000V',\n 'system_image': 'bootflash:packages.conf',\n 'uptime': '2 hours, 43 minutes',\n 'uptime_this_cp': '2 hours, 45 minutes',\n 'version': '16.4.1',\n 'version_short': '16.4'}}\n\x1b[1m\x1b[32m---- send_commands ** changed : False ------------------------------------------ INFO\n{ 'vrf': { 'default': { 'address_family': { 'ipv4': { 'routes': { '10.0.0.0/24': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.0/24',\n 'source_protocol': 'connected',\n 'source_protocol_codes': 'C'},\n '10.0.0.15/32': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.15/32',\n 'source_protocol': 'local',\n 'source_protocol_codes': 'L'}}}}}}}\n\x1b[1m\x1b[32m^^^^ END send_commands ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
),
(
False,
"\x1b[1m\x1b[36msend_commands*******************************************************************\n\x1b[1m\x1b[34m* sea-ios-1 ** changed : False *************************************************\n\x1b[1m\x1b[32mvvvv send_commands ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\n{ 'version': { 'chassis': 'CSR1000V',\n 'chassis_sn': '9FKLJWM5EB0',\n 'compiled_by': 'mcpre',\n 'compiled_date': 'Sun 27-Nov-16 13:02',\n 'curr_config_register': '0x2102',\n 'disks': { 'bootflash:.': { 'disk_size': '7774207',\n 'type_of_disk': 'virtual hard disk'},\n 'webui:.': {'disk_size': '0', 'type_of_disk': ''}},\n 'hostname': 'csr1000v',\n 'image_id': 'X86_64_LINUX_IOSD-UNIVERSALK9-M',\n 'image_type': 'production image',\n 'last_reload_reason': 'reload',\n 'license_level': 'ax',\n 'license_type': 'Default. No valid license found.',\n 'main_mem': '2052375',\n 'mem_size': { 'non-volatile configuration': '32768',\n 'physical': '3985132'},\n 'next_reload_license_level': 'ax',\n 'number_of_intfs': {'Gigabit Ethernet': '10'},\n 'os': 'IOS-XE',\n 'platform': 'CSR1000V',\n 'processor_type': 'VXE',\n 'returned_to_rom_by': 'reload',\n 'rom': 'IOS-XE ROMMON',\n 'rtr_type': 'CSR1000V',\n 'system_image': 'bootflash:packages.conf',\n 'uptime': '2 hours, 43 minutes',\n 'uptime_this_cp': '2 hours, 45 minutes',\n 'version': '16.4.1',\n 'version_short': '16.4'}}\n\x1b[1m\x1b[32m---- send_commands ** changed : False ------------------------------------------ INFO\n{ 'vrf': { 'default': { 'address_family': { 'ipv4': { 'routes': { '10.0.0.0/24': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.0/24',\n 'source_protocol': 'connected',\n 'source_protocol_codes': 'C'},\n '10.0.0.15/32': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.15/32',\n 'source_protocol': 'local',\n 'source_protocol_codes': 'L'}}}}}}}\n\x1b[1m\x1b[32m^^^^ END send_commands ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
),
],
ids=["True", "False"],
)
def test_print_structured_result_genie(capsys, structured_result):
print_structured_result(TEST_AGG_RESULT, parser="genie")
captured = capsys.readouterr()
assert captured.out == structured_result[1]


@pytest.mark.parametrize(
"structured_result",
[
(
True,
"\x1b[1m\x1b[36msend_commands*******************************************************************\n\x1b[1m\x1b[34m* sea-ios-1 ** changed : False *************************************************\n\x1b[1m\x1b[32mvvvv send_commands ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\n{ 'version': { 'chassis': 'CSR1000V',\n 'chassis_sn': '9FKLJWM5EB0',\n 'compiled_by': 'mcpre',\n 'compiled_date': 'Sun 27-Nov-16 13:02',\n 'curr_config_register': '0x2102',\n 'disks': { 'bootflash:.': { 'disk_size': '7774207',\n 'type_of_disk': 'virtual hard disk'},\n 'webui:.': {'disk_size': '0', 'type_of_disk': ''}},\n 'hostname': 'csr1000v',\n 'image_id': 'X86_64_LINUX_IOSD-UNIVERSALK9-M',\n 'image_type': 'production image',\n 'last_reload_reason': 'reload',\n 'license_level': 'ax',\n 'license_type': 'Default. No valid license found.',\n 'main_mem': '2052375',\n 'mem_size': { 'non-volatile configuration': '32768',\n 'physical': '3985132'},\n 'next_reload_license_level': 'ax',\n 'number_of_intfs': {'Gigabit Ethernet': '10'},\n 'os': 'IOS-XE',\n 'platform': 'CSR1000V',\n 'processor_type': 'VXE',\n 'returned_to_rom_by': 'reload',\n 'rom': 'IOS-XE ROMMON',\n 'rtr_type': 'CSR1000V',\n 'system_image': 'bootflash:packages.conf',\n 'uptime': '2 hours, 43 minutes',\n 'uptime_this_cp': '2 hours, 45 minutes',\n 'version': '16.4.1',\n 'version_short': '16.4'}}\n\x1b[1m\x1b[32m---- send_commands ** changed : False ------------------------------------------ INFO\n{ 'vrf': { 'default': { 'address_family': { 'ipv4': { 'routes': { '10.0.0.0/24': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.0/24',\n 'source_protocol': 'connected',\n 'source_protocol_codes': 'C'},\n '10.0.0.15/32': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.15/32',\n 'source_protocol': 'local',\n 'source_protocol_codes': 'L'}}}}}}}\n\x1b[1m\x1b[32m^^^^ END send_commands ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
),
(
False,
"\x1b[1m\x1b[36msend_commands*******************************************************************\n\x1b[1m\x1b[34m* sea-ios-1 ** changed : False *************************************************\n\x1b[1m\x1b[32mvvvv send_commands ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO\n{ 'version': { 'chassis': 'CSR1000V',\n 'chassis_sn': '9FKLJWM5EB0',\n 'compiled_by': 'mcpre',\n 'compiled_date': 'Sun 27-Nov-16 13:02',\n 'curr_config_register': '0x2102',\n 'disks': { 'bootflash:.': { 'disk_size': '7774207',\n 'type_of_disk': 'virtual hard disk'},\n 'webui:.': {'disk_size': '0', 'type_of_disk': ''}},\n 'hostname': 'csr1000v',\n 'image_id': 'X86_64_LINUX_IOSD-UNIVERSALK9-M',\n 'image_type': 'production image',\n 'last_reload_reason': 'reload',\n 'license_level': 'ax',\n 'license_type': 'Default. No valid license found.',\n 'main_mem': '2052375',\n 'mem_size': { 'non-volatile configuration': '32768',\n 'physical': '3985132'},\n 'next_reload_license_level': 'ax',\n 'number_of_intfs': {'Gigabit Ethernet': '10'},\n 'os': 'IOS-XE',\n 'platform': 'CSR1000V',\n 'processor_type': 'VXE',\n 'returned_to_rom_by': 'reload',\n 'rom': 'IOS-XE ROMMON',\n 'rtr_type': 'CSR1000V',\n 'system_image': 'bootflash:packages.conf',\n 'uptime': '2 hours, 43 minutes',\n 'uptime_this_cp': '2 hours, 45 minutes',\n 'version': '16.4.1',\n 'version_short': '16.4'}}\n\x1b[1m\x1b[32m---- send_commands ** changed : False ------------------------------------------ INFO\n{ 'vrf': { 'default': { 'address_family': { 'ipv4': { 'routes': { '10.0.0.0/24': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.0/24',\n 'source_protocol': 'connected',\n 'source_protocol_codes': 'C'},\n '10.0.0.15/32': { 'active': True,\n 'next_hop': { 'outgoing_interface': { 'GigabitEthernet1': { 'outgoing_interface': 'GigabitEthernet1'}}},\n 'route': '10.0.0.15/32',\n 'source_protocol': 'local',\n 'source_protocol_codes': 'L'}}}}}}}\n\x1b[1m\x1b[32m^^^^ END send_commands ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
),
],
ids=["True", "False"],
)
def test_print_structured_result_genie_to_dict(capsys, structured_result):
print_structured_result(TEST_AGG_RESULT, parser="genie")
captured = capsys.readouterr()
assert captured.out == structured_result[1]


def test_print_structured_result_fallback(capsys):
Expand Down

0 comments on commit 49daed3

Please sign in to comment.