def _parse(raw_cli_output, cmd, nos): # Boilerplate code to get the parser functional # tb = Testbed() device = Device("new_device", os=nos) device.custom.setdefault("abstraction", {})["order"] = ["os"] device.cli = AttrDict({"execute": None}) # User input checking of the command provided. Does the command have a Genie parser? try: get_parser(cmd, device) except Exception as e: raise AnsibleFilterError( "genie_parse: {0} - Available parsers: {1}".format( to_native(e), "https://pubhub.devnetcloud.com/media/pyats-packages/docs/genie/genie_libs/#/parsers" )) try: parsed_output = device.parse(cmd, output=raw_cli_output) return parsed_output except Exception as e: raise AnsibleFilterError( "genie_parse: {0} - Failed to parse command output.".format( to_native(e)))
def genie_parser(self, cli_output, command, os): if not PY3: raise AnsibleFilterError("Genie requires Python 3") if not HAS_GENIE: raise AnsibleFilterError( "Genie not found. Run 'pip install genie'") if not HAS_PYATS: raise AnsibleFilterError( "pyATS not found. Run 'pip install pyats'") device = Device("new_device", os=os) device.custom.setdefault("abstraction", {})["order"] = ["os"] device.cli = AttrDict({"execute": None}) try: get_parser(command, device) except Exception as e: raise AnsibleFilterError( "Unable to find parser for command '{0}' ({1})".format( command, e)) try: parsed_output = device.parse(command, output=cli_output) except Exception as e: raise AnsibleFilterError( "Unable to parse output for command '{0}' ({1})".format( command, e)) if parsed_output: return parsed_output else: return None
def _check_commands_against_pyats(self): network_os = self._task.args.get('network_os') or self._network_os self._pyats_device = Device("uut", os=network_os) self._pyats_device.custom.setdefault("abstraction", {})["order"] = ["os"] self._pyats_device.cli = AttrDict({"execute": None}) for command in self._commands: try: get_parser(command['command'], self._pyats_device) except Exception: # pylint: disable=W0703 self._errors.append("PYATS: Unable to find parser for command " "'{}' for {}".format( command['command'], network_os)) self._check_for_errors()
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: from genie.conf.base import Device # pylint: disable=C0415 from genie.libs.parser.utils import get_parser # pylint: disable=C0415 except ModuleNotFoundError as exc: err = f"Module '{exc.name}' not installed!" msg = f"***** {err} {'*' * (80 - len(err))}" fix = ( 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]'") warning = "\n" + msg + "\n" + fix + "\n" + msg warnings.warn(warning) 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 not genie_parsed_result: return [] if isinstance(genie_parsed_result, (list, dict)): return genie_parsed_result # have to catch base exception because that is all genie raises for some reason :( except Exception: # pylint: disable=E0012,W0703 pass return []
def get_structured_data_genie(raw_output: str, platform: str, command: str) -> Union[str, Dict[str, Any]]: if not sys.version_info >= (3, 4): raise ValueError("Genie requires Python >= 3.4") if not GENIE_INSTALLED: msg = ( "\nGenie and PyATS are not installed. Please PIP install both Genie and PyATS:\n" "pip install genie\npip install pyats\n") raise ValueError(msg) if "cisco" not in platform: return raw_output genie_device_mapper = { "cisco_ios": "ios", "cisco_xe": "iosxe", "cisco_xr": "iosxr", "cisco_nxos": "nxos", "cisco_asa": "asa", } os = None # platform might be _ssh, _telnet, _serial strip that off if platform.count("_") > 1: base_list = platform.split("_")[:-1] base_platform = "_".join(base_list) else: base_platform = platform os = genie_device_mapper.get(base_platform) if os is None: return raw_output # Genie specific construct for doing parsing (based on Genie in Ansible) device = Device("new_device", os=os) device.custom.setdefault("abstraction", {}) device.custom["abstraction"]["order"] = ["os"] device.cli = AttrDict({"execute": None}) try: # Test whether there is a parser for given command (return Exception if fails) get_parser(command, device) parsed_output: Dict[str, Any] = device.parse(command, output=raw_output) return parsed_output except Exception: return raw_output
def pyats_parser(cli_output, command, os): if not PY3: raise AnsibleFilterError("Genie requires Python 3") if GENIE_IMPORT_ERROR: raise_from( AnsibleError('genie must be installed to use this plugin'), GENIE_IMPORT_ERROR) if PYATS_IMPORT_ERROR: raise_from( AnsibleError('pyats must be installed to use this plugin'), PYATS_IMPORT_ERROR) # Translate from ansible_network_os values to pyATS if os in ansible_os_map.keys(): os = ansible_os_map[os] device = Device("uut", os=os) device.custom.setdefault("abstraction", {})["order"] = ["os"] device.cli = AttrDict({"execute": None}) try: get_parser(command, device) except Exception as e: raise AnsibleFilterError("Unable to find parser for command '{0}' ({1})".format(command, e)) try: parsed_output = device.parse(command, output=cli_output) except Exception as e: raise AnsibleFilterError("Unable to parse output for command '{0}' ({1})".format(command, e)) if parsed_output: return parsed_output else: return None
def main(): argument_spec = dict(command=dict(type='str', required=True), prompt=dict(type='list', required=False), answer=dict(type='list', required=False), compare=dict(type='dict', required=False), sendonly=dict(type='bool', default=False, required=False), # newline=dict(type='bool', default=True, required=False), # check_all=dict(type='bool', default=False, required=False), ) required_together = [['prompt', 'answer']] module = AnsibleModule(argument_spec=argument_spec, required_together=required_together, supports_check_mode=True) if not PY3: module.fail_json(msg="pyATS/Genie requires Python 3") if not HAS_GENIE: module.fail_json(msg="Genie not found. Run 'pip install genie'") if not HAS_PYATS: module.fail_json(msg="pyATS not found. Run 'pip install pyats'") if module.check_mode and not module.params['command'].startswith('show'): module.fail_json( msg='Only show commands are supported when using check_mode, not ' 'executing %s' % module.params['command'] ) warnings = list() result = {'changed': False, 'warnings': warnings} connection = Connection(module._socket_path) capabilities = json.loads(connection.get_capabilities()) if capabilities['device_info']['network_os'] == 'ios': genie_os = 'iosxe' else: genie_os = capabilities['device_info']['network_os'] compare = module.params.pop('compare') response = '' try: response = connection.get(**module.params) except ConnectionError as exc: module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) device = Device("uut", os=genie_os) device.custom.setdefault("abstraction", {})["order"] = ["os"] device.cli = AttrDict({"execute": None}) try: get_parser(module.params['command'], device) except Exception as e: module.fail_json(msg="Unable to find parser for command '{0}' ({1})".format(module.params['command'], e)) try: parsed_output = device.parse(module.params['command'], output=response) except Exception as e: module.fail_json(msg="Unable to parse output for command '{0}' ({1})".format(module.params['command'], e)) # import sys; # sys.stdin = open('/dev/tty') # import pdb; # pdb.set_trace() if compare: diff = Diff(parsed_output, compare, exclude=get_parser_exclude(module.params['command'], device)) diff.findDiff() else: diff = None if not module.params['sendonly']: try: result['json'] = module.from_json(response) except ValueError: pass result.update({ 'stdout': response, 'structured': parsed_output, 'diff': "{0}".format(diff), 'exclude': get_parser_exclude(module.params['command'], device), }) module.exit_json(**result)