mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
92 lines
2.7 KiB
Python
92 lines
2.7 KiB
Python
"""Parse Arista 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.arista_eos import AristaBGPTable
|
|
|
|
# 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_arista(output: t.Sequence[str]) -> "OutputDataModel":
|
|
"""Parse a Arista BGP JSON response."""
|
|
result = None
|
|
|
|
for response in output:
|
|
|
|
try:
|
|
parsed: t.Dict = json.loads(response)
|
|
|
|
log.debug("Pre-parsed data:\n{}", parsed)
|
|
|
|
vrf = list(parsed["vrfs"].keys())[0]
|
|
routes = parsed["vrfs"][vrf]
|
|
|
|
validated = AristaBGPTable(**routes)
|
|
bgp_table = validated.bgp_table()
|
|
|
|
if result is None:
|
|
result = bgp_table
|
|
else:
|
|
result += bgp_table
|
|
|
|
except json.JSONDecodeError as err:
|
|
log.critical("Error decoding JSON: {}", str(err))
|
|
raise ParsingError("Error parsing response data")
|
|
|
|
except KeyError as err:
|
|
log.critical("'{}' was not found in the response", str(err))
|
|
raise ParsingError("Error parsing response data")
|
|
|
|
except IndexError as err:
|
|
log.critical(str(err))
|
|
raise ParsingError("Error parsing response data")
|
|
|
|
except ValidationError as err:
|
|
log.critical(str(err))
|
|
raise ParsingError(err.errors())
|
|
|
|
return result
|
|
|
|
|
|
class BGPRoutePluginArista(OutputPlugin):
|
|
"""Coerce a Arista route table in JSON format to a standard BGP Table structure."""
|
|
|
|
__hyperglass_builtin__: bool = PrivateAttr(True)
|
|
platforms: t.Sequence[str] = ("arista_eos",)
|
|
directives: t.Sequence[str] = (
|
|
"__hyperglass_arista_eos_bgp_route_table__",
|
|
"__hyperglass_arista_eos_bgp_aspath_table__",
|
|
"__hyperglass_arista_eos_bgp_community_table__",
|
|
)
|
|
|
|
def process(self, *, output: "OutputType", query: "Query") -> "OutputType":
|
|
"""Parse Arista 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_arista(output)
|
|
return output
|