remove legacy parsers

This commit is contained in:
thatmattlove 2022-12-26 11:15:20 -05:00
parent 2c7456c317
commit e494db5337
5 changed files with 0 additions and 258 deletions

View file

@ -1 +0,0 @@
"""Parsing utilities for command output."""

View file

@ -1,57 +0,0 @@
"""Parse Arista JSON Response to Structured Data."""
# Standard Library
import json
from typing import Dict, Sequence
# Third Party
from pydantic import ValidationError
# Project
from hyperglass.log import log
from hyperglass.exceptions.private import ParsingError
from hyperglass.models.parsing.arista_eos import AristaRoute
def parse_arista(output: Sequence[str]) -> Dict: # noqa: C901
"""Parse a Arista BGP JSON response."""
data = {}
for i, response in enumerate(output):
try:
data: Dict = json.loads(response)
log.debug("Pre-parsed data: {}", data)
vrf = list(data["vrfs"].keys())[0]
routes = data["vrfs"][vrf]
log.debug("Pre-validated data: {}", routes)
validated = AristaRoute(**routes)
serialized = validated.serialize().export_dict()
if i == 0:
data.update(serialized)
else:
data["routes"].extend(serialized["routes"])
except json.JSONDecodeError as err:
log.critical("Error decoding JSON: {}", str(err))
raise ParsingError("Error parsing response data") from err
except KeyError as err:
log.critical("'{}' was not found in the response", str(err))
raise ParsingError("Error parsing response data") from err
except IndexError as err:
log.critical(str(err))
raise ParsingError("Error parsing response data") from err
except ValidationError as err:
log.critical(str(err))
raise ParsingError(err.errors()) from err
log.debug("Serialized: {}", data)
return data

View file

@ -1,103 +0,0 @@
"""Parse Juniper XML Response to Structured Data."""
# Standard Library
import re
from typing import Dict, List, Sequence, Generator
# Third Party
import xmltodict # type:ignore
from pydantic import ValidationError
# Project
from hyperglass.log import log
from hyperglass.exceptions.private import ParsingError
from hyperglass.models.parsing.juniper import JuniperRoute
REMOVE_PATTERNS = (
# The XML response can a CLI banner appended to the end of the XML
# string. For example:
# ```
# <rpc-reply>
# ...
# <cli>
# <banner>{master}</banner>
# </cli>
# </rpc-reply>
#
# {master} noqa: E800
# ```
#
# This pattern will remove anything inside braces, including the braces.
r"\{.+\}",
)
def clean_xml_output(output: str) -> str:
"""Remove Juniper-specific patterns from output."""
def scrub(lines: List[str]) -> Generator[str, None, None]:
"""Clean & remove each pattern from each line."""
for pattern in REMOVE_PATTERNS:
for line in lines:
# Remove the pattern & strip extra newlines
scrubbed = re.sub(pattern, "", line.strip())
# Only return non-empty and non-newline lines
if scrubbed and scrubbed != "\n":
yield scrubbed
lines = scrub(output.splitlines())
return "\n".join(lines)
def parse_juniper(output: Sequence) -> Dict: # noqa: C901
"""Parse a Juniper BGP XML response."""
data = {}
for i, response in enumerate(output):
cleaned = clean_xml_output(response)
try:
parsed = xmltodict.parse(cleaned, force_list=("rt", "rt-entry", "community"))
log.debug("Initially Parsed Response: \n{}", parsed)
if "rpc-reply" in parsed.keys():
if "xnm:error" in parsed["rpc-reply"]:
if "message" in parsed["rpc-reply"]["xnm:error"]:
err = parsed["rpc-reply"]["xnm:error"]["message"]
raise ParsingError('Error from device: "{}"', err)
parsed_base = parsed["rpc-reply"]["route-information"]
elif "route-information" in parsed.keys():
parsed_base = parsed["route-information"]
if "route-table" not in parsed_base:
return data
if "rt" not in parsed_base["route-table"]:
return data
parsed = parsed_base["route-table"]
validated = JuniperRoute(**parsed)
serialized = validated.serialize().export_dict()
if i == 0:
data.update(serialized)
else:
data["routes"].extend(serialized["routes"])
except xmltodict.expat.ExpatError as err:
log.critical(str(err))
raise ParsingError("Error parsing response data") from err
except KeyError as err:
log.critical("{} was not found in the response", str(err))
raise ParsingError("Error parsing response data") from err
except ValidationError as err:
log.critical(str(err))
raise ParsingError(err.errors()) from err
return data

View file

@ -1,79 +0,0 @@
# flake8: noqa
# WORK IN PROGRESS
"""Linux-style parsers for ping & traceroute."""
# Standard Library
import re
# Project
from hyperglass.exceptions.private import ParsingError
def _process_numbers(numbers):
"""Convert string to float or int."""
for num in numbers:
num = float(num)
if num.is_integer():
num = int(num)
yield num
def parse_linux_ping(output):
"""Parse standard Linux-style ping output to structured data.
Example:
64 bytes from 1.1.1.1: icmp_seq=0 ttl=59 time=1.151 ms
64 bytes from 1.1.1.1: icmp_seq=1 ttl=59 time=1.180 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=59 time=1.170 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=59 time=1.338 ms
64 bytes from 1.1.1.1: icmp_seq=4 ttl=59 time=4.913 ms
--- 1.1.1.1 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max/stddev = 1.151/1.950/4.913/1.483 ms
"""
try:
# Extract target host
host = re.findall(r"^PING (.+) \(.+\): \d+ data bytes", output)[0]
# Separate echo replies from summary info
replies, _stats = re.split(r"--- .+ ---", output)
replies = [l for l in replies.splitlines()[1:] if l]
reply_stats = []
for line in replies:
# Extract the numerical values from each echo reply line
bytes_seq_ttl_rtt = re.findall(
r"(\d+) bytes.+ icmp_seq=(\d+) ttl=(\d+) time=(\d+\.\d+).*", line
)[0]
_bytes, seq, ttl, rtt = _process_numbers(bytes_seq_ttl_rtt)
reply_stats.append({"bytes": _bytes, "sequence": seq, "ttl": ttl, "rtt": rtt})
stats = [l for l in _stats.splitlines() if l]
# Extract the top summary line numbers & process
tx_rx_loss = re.findall(r"(\d+) .+, (\d+) .+, (\d+)\%.+", stats[0])[0]
tx, rx, loss = _process_numbers(tx_rx_loss)
# Extract the bottom summary line numbers & process
rt = stats[1].split(" = ")[1]
min_max_avg = rt.split("/")[:-1]
_min, _max, _avg = _process_numbers(min_max_avg)
return {
"host": host,
"transmitted": tx,
"received": rx,
"loss_percent": loss,
"min_rtt": _min,
"max_rtt": _max,
"avg_rtt": _avg,
"replies": reply_stats,
}
except (KeyError, ValueError) as err:
# KeyError for empty findalls, ValueError for regex errors
raise ParsingError("Error parsing ping response: {e}", e=str(err))

View file

@ -1,18 +0,0 @@
"""Map NOS and Commands to Parsing Functions."""
# Local
from .arista import parse_arista
from .juniper import parse_juniper
structured_parsers = {
"juniper": {
"bgp_route": parse_juniper,
"bgp_aspath": parse_juniper,
"bgp_community": parse_juniper,
},
"arista_eos": {
"bgp_route": parse_arista,
"bgp_aspath": parse_arista,
"bgp_community": parse_arista,
},
}