def genie_parse(platform: str, command: str, output: str) -> Union[List[Any], Dict[str, Any]]: """ Parse output with Cisco genie parsers, try to return structured output Args: platform: genie device type; i.e. iosxe, iosxr, etc. command: string of command that was executed (to find appropriate parser) output: unstructured output from device to parse Returns: output: structured data Raises: N/A """ try: Device = getattr( importlib.import_module(name=".conf.base", package="genie"), "Device") get_parser = getattr( importlib.import_module(name=".libs.parser.utils", package="genie"), "get_parser") except ModuleNotFoundError as exc: title = "Optional Extra Not Installed!" message = ( "Optional extra 'genie' is not installed!\n" f"To resolve this issue, install '{exc.name}'. You can do this in one of the following" " ways:\n" "1: 'pip install -r requirements-genie.txt'\n" "2: 'pip install scrapli[genie]'") user_warning(title=title, message=message) return [] genie_device = Device("scrapli_device", custom={"abstraction": { "order": ["os"] }}, os=platform) try: get_parser(command, genie_device) genie_parsed_result = genie_device.parse(command, output=output) if isinstance(genie_parsed_result, (list, dict)): return genie_parsed_result except Exception as exc: # pylint: disable=W0703 logger.warning( f"failed to parse data with genie, genie raised exception: `{exc}`" ) return []
def user_warning(title: str, message: str) -> None: """ Nicely raise warning messages for users Args: title: title of the warning message message: actual message body Returns: None Raises: N/A """ warning_message = format_user_warning(title=title, message=message) logger.warning(warning_message) warn(warning_message)
def _textfsm_get_template(platform: str, command: str) -> Optional[TextIO]: """ Find correct TextFSM template based on platform and command executed Args: platform: ntc-templates device type; i.e. cisco_ios, arista_eos, etc. command: string of command that was executed (to find appropriate template) Returns: None or TextIO of opened template Raises: N/A """ try: importlib.import_module(name=".templates", package="ntc_templates") CliTable = getattr( importlib.import_module(name=".clitable", package="textfsm"), "CliTable") except ModuleNotFoundError as exc: title = "Optional Extra Not Installed!" message = ( "Optional extra 'textfsm' is not installed!\n" f"To resolve this issue, install '{exc.name}'. You can do this in one of the following" " ways:\n" "1: 'pip install -r requirements-textfsm.txt'\n" "2: 'pip install scrapli[textfsm]'") user_warning(title=title, message=message) return None template_dir = pkg_resources.resource_filename("ntc_templates", "templates") cli_table = CliTable("index", template_dir) template_index = cli_table.index.GetRowMatch({ "Platform": platform, "Command": command }) if not template_index: logger.warning( f"No match in ntc_templates index for platform `{platform}` and command `{command}`" ) return None template_name = cli_table.index.index[template_index]["Template"] return open(f"{template_dir}/{template_name}", encoding="utf-8")
def textfsm_parse(template: Union[str, TextIOWrapper], output: str, to_dict: bool = True) -> Union[List[Any], Dict[str, Any]]: """ Parse output with TextFSM and ntc-templates, try to return structured output Args: template: TextIOWrapper or string of URL or filesystem path to template to use to parse data output: unstructured output from device to parse to_dict: convert textfsm output from list of lists to list of dicts -- basically create dict from header and row data so it is easier to read/parse the output Returns: output: structured data Raises: N/A """ import textfsm # pylint: disable=C0415 if not isinstance(template, TextIOWrapper): if template.startswith("http://") or template.startswith("https://"): with urllib.request.urlopen(template) as response: template_file = TextIOWrapper( BytesIO(response.read()), encoding=response.headers.get_content_charset(), ) else: template_file = TextIOWrapper(open(template, mode="rb")) # pylint: disable=R1732 else: template_file = template re_table = textfsm.TextFSM(template_file) try: structured_output: Union[List[Any], Dict[str, Any]] = re_table.ParseText(output) if to_dict: structured_output = _textfsm_to_dict( structured_output=structured_output, header=re_table.header) return structured_output except textfsm.parser.TextFSMError: logger.warning("failed to parse data with textfsm") return []
def user_warning(title: str, message: str) -> None: """ Nicely raise warning messages for users Args: title: title of the warning message message: actual message body Returns: None Raises: N/A """ warning_message = format_user_warning(title=title, message=message) logger.warning(warning_message) if Settings.SUPPRESS_USER_WARNINGS is False: warn(warning_message)
def textfsm_parse( template: Union[str, TextIOWrapper], output: str, to_dict: bool = True ) -> Union[List[Any], Dict[str, Any]]: """ Parse output with TextFSM and ntc-templates, try to return structured output Args: template: TextIOWrapper or string path to template to use to parse data output: unstructured output from device to parse to_dict: convert textfsm output from list of lists to list of dicts -- basically create dict from header and row data so it is easier to read/parse the output Returns: output: structured data Raises: N/A """ import textfsm # pylint: disable=C0415 if not isinstance(template, TextIOWrapper): template_file = open(template) else: template_file = template re_table = textfsm.TextFSM(template_file) try: structured_output: Union[List[Any], Dict[str, Any]] = re_table.ParseText(output) if to_dict: structured_output = _textfsm_to_dict( structured_output=structured_output, header=re_table.header ) return structured_output except textfsm.parser.TextFSMError: logger.warning("failed to parse data with textfsm") return []