1
0
mirror of https://github.com/checktheroads/hyperglass synced 2024-05-11 05:55:08 +00:00

92 lines
2.6 KiB
Python
Raw Normal View History

"""Parse Juniper XML Response to Structured Data."""
# Standard Library
import re
from typing import Dict, Iterable
# Third Party
import xmltodict
from pydantic import ValidationError
# Project
from hyperglass.log import log
2020-05-29 17:47:53 -07:00
from hyperglass.exceptions import ParsingError, ResponseEmpty
from hyperglass.configuration import params
2020-12-13 01:48:20 -07:00
from hyperglass.models.parsing.juniper import JuniperRoute
def clean_xml_output(output: str) -> str:
"""Remove Juniper-specific patterns from output."""
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}
```
This pattern will remove anything inside braces, including the braces.
"""
r"\{.+\}",
)
lines = (line.strip() for line in output.split())
scrubbed_lines = (re.sub(pat, "", line) for pat in patterns for line in lines)
return "\n".join(scrubbed_lines)
def parse_juniper(output: Iterable) -> Dict: # noqa: C901
"""Parse a Juniper BGP XML response."""
2020-05-29 17:47:53 -07:00
data = {}
2020-05-29 17:47:53 -07:00
for i, response in enumerate(output):
cleaned = clean_xml_output(response)
2020-05-29 17:47:53 -07:00
try:
2020-06-03 11:30:04 -07:00
parsed = xmltodict.parse(
cleaned, force_list=("rt", "rt-entry", "community")
2020-06-03 11:30:04 -07:00
)
2020-05-29 17:47:53 -07:00
log.debug("Initially Parsed Response: \n{}", parsed)
2020-05-29 17:47:53 -07:00
if "rpc-reply" in parsed.keys():
parsed_base = parsed["rpc-reply"]["route-information"]
2020-05-29 17:47:53 -07:00
elif "route-information" in parsed.keys():
parsed_base = parsed["route-information"]
2020-05-29 17:47:53 -07:00
if "route-table" not in parsed_base:
2020-05-29 17:47:53 -07:00
raise ResponseEmpty(params.messages.no_output)
if "rt" not in parsed_base["route-table"]:
raise ResponseEmpty(params.messages.no_output)
parsed = parsed_base["route-table"]
2020-05-29 17:47:53 -07:00
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
2020-05-29 17:47:53 -07:00
except KeyError as err:
2020-09-28 12:37:44 -07:00
log.critical("{} was not found in the response", str(err))
2020-05-29 17:47:53 -07:00
raise ParsingError("Error parsing response data")
except ValidationError as err:
log.critical(str(err))
raise ParsingError(err.errors())
2020-05-29 17:47:53 -07:00
return data