mirror of
https://github.com/thatmattlove/hyperglass.git
synced 2026-01-17 00:38:06 +00:00
86 lines
2.5 KiB
Python
86 lines
2.5 KiB
Python
"""Parse FRR JSON Response to Structured Data."""
|
|
|
|
# Standard Library
|
|
import json
|
|
import typing as t
|
|
|
|
# Third Party
|
|
from pydantic import PrivateAttr, ValidationError
|
|
|
|
# Project
|
|
from hyperglass.log import log
|
|
from hyperglass.exceptions.private import ParsingError
|
|
from hyperglass.models.parsing.frr import FRRBGPTable
|
|
|
|
# Local
|
|
from .._output import OutputPlugin
|
|
|
|
if t.TYPE_CHECKING:
|
|
# Project
|
|
from hyperglass.models.data import OutputDataModel
|
|
from hyperglass.models.api.query import Query
|
|
|
|
# Local
|
|
from .._output import OutputType
|
|
|
|
|
|
def parse_frr(output: t.Sequence[str]) -> "OutputDataModel":
|
|
"""Parse a FRR BGP JSON response."""
|
|
result = None
|
|
|
|
_log = log.bind(plugin=BGPRoutePluginFrr.__name__)
|
|
|
|
for response in output:
|
|
try:
|
|
parsed: t.Dict = json.loads(response)
|
|
|
|
_log.debug("Pre-parsed data", data=parsed)
|
|
|
|
validated = FRRBGPTable(**parsed)
|
|
bgp_table = validated.bgp_table()
|
|
|
|
if result is None:
|
|
result = bgp_table
|
|
else:
|
|
result += bgp_table
|
|
|
|
except json.JSONDecodeError as err:
|
|
_log.bind(error=str(err)).critical("Failed to decode JSON")
|
|
raise ParsingError("Error parsing response data") from err
|
|
|
|
except KeyError as err:
|
|
_log.bind(key=str(err)).critical("Missing required key in response")
|
|
raise ParsingError("Error parsing response data") from err
|
|
|
|
except IndexError as err:
|
|
_log.critical(err)
|
|
raise ParsingError("Error parsing response data") from err
|
|
|
|
except ValidationError as err:
|
|
_log.critical(err)
|
|
raise ParsingError(err.errors()) from err
|
|
|
|
return result
|
|
|
|
class BGPRoutePluginFrr(OutputPlugin):
|
|
"""Coerce a FRR route table in JSON format to a standard BGP Table structure."""
|
|
|
|
_hyperglass_builtin: bool = PrivateAttr(True)
|
|
platforms: t.Sequence[str] = ("frr",)
|
|
directives: t.Sequence[str] = (
|
|
"__hyperglass_frr_bgp_route_table__",
|
|
)
|
|
|
|
def process(self, *, output: "OutputType", query: "Query") -> "OutputType":
|
|
"""Parse FRR response if data is a string (and is therefore unparsed)."""
|
|
should_process = all(
|
|
(
|
|
isinstance(output, (list, tuple)),
|
|
query.device.platform in self.platforms,
|
|
query.device.structured_output is True,
|
|
query.device.has_directives(*self.directives),
|
|
)
|
|
)
|
|
if should_process:
|
|
return parse_frr(output)
|
|
return output
|