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

fix an issue with juniper as_path queries that only returned ipv4 or ipv6 routes (not both), causing queries to fail

This commit is contained in:
checktheroads
2021-04-24 17:03:39 -07:00
parent e2f1601553
commit 4c948fd97f
5 changed files with 31294 additions and 9 deletions

View File

@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- [#135](https://github.com/checktheroads/hyperglass/issues/135): Fix an issue where Juniper indirect next-hops were empty. - [#135](https://github.com/checktheroads/hyperglass/issues/135): Fix an issue where Juniper indirect next-hops were empty.
- Fix an issue where Juniper structured AS_PATH or Community queries would appear to fail if one address family (IPv4 or IPv6) had an empty response. For example, if an AS_PATH query for `.* 29414 .*` was made (which only returns IPv4 routes), the query would fail.
### Changed ### Changed
- Updated major Python dependencies (FastAPI, Scrapli, Netmiko, Pydantic, Uvicorn, Gunicorn, etc.) - Updated major Python dependencies (FastAPI, Scrapli, Netmiko, Pydantic, Uvicorn, Gunicorn, etc.)

View File

@@ -75,8 +75,20 @@ async def execute(query: Query) -> Union[str, Sequence[Dict]]:
output = await driver.parsed_response(response) output = await driver.parsed_response(response)
if output == "" or output == "\n": if isinstance(output, str):
raise ResponseEmpty(params.messages.no_output, device_name=query.device.name) # If the output is a string (not structured) and is empty,
# produce an error.
if output == "" or output == "\n":
raise ResponseEmpty(
params.messages.no_output, device_name=query.device.name
)
elif isinstance(output, Dict):
# If the output an empty dict, responses have data, produce an
# error.
if not output:
raise ResponseEmpty(
params.messages.no_output, device_name=query.device.name
)
log.debug("Output for query: {}:\n{}", query.json(), repr(output)) log.debug("Output for query: {}:\n{}", query.json(), repr(output))
signal.alarm(0) signal.alarm(0)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
# Standard Library # Standard Library
import re import re
from typing import Dict, List, Iterable, Generator from typing import Dict, List, Sequence, Generator
# Third Party # Third Party
import xmltodict import xmltodict
@@ -10,8 +10,7 @@ from pydantic import ValidationError
# Project # Project
from hyperglass.log import log from hyperglass.log import log
from hyperglass.exceptions import ParsingError, ResponseEmpty from hyperglass.exceptions import ParsingError
from hyperglass.configuration import params
from hyperglass.models.parsing.juniper import JuniperRoute from hyperglass.models.parsing.juniper import JuniperRoute
REMOVE_PATTERNS = ( REMOVE_PATTERNS = (
@@ -51,7 +50,7 @@ def clean_xml_output(output: str) -> str:
return "\n".join(lines) return "\n".join(lines)
def parse_juniper(output: Iterable) -> Dict: # noqa: C901 def parse_juniper(output: Sequence) -> Dict: # noqa: C901
"""Parse a Juniper BGP XML response.""" """Parse a Juniper BGP XML response."""
data = {} data = {}
@@ -71,10 +70,10 @@ def parse_juniper(output: Iterable) -> Dict: # noqa: C901
parsed_base = parsed["route-information"] parsed_base = parsed["route-information"]
if "route-table" not in parsed_base: if "route-table" not in parsed_base:
raise ResponseEmpty(params.messages.no_output) return data
if "rt" not in parsed_base["route-table"]: if "rt" not in parsed_base["route-table"]:
raise ResponseEmpty(params.messages.no_output) return data
parsed = parsed_base["route-table"] parsed = parsed_base["route-table"]

View File

@@ -14,9 +14,13 @@ from .juniper import parse_juniper
SAMPLE_FILES = ( SAMPLE_FILES = (
Path(__file__).parent.parent / "models" / "parsing" / "juniper_route_direct.xml", Path(__file__).parent.parent / "models" / "parsing" / "juniper_route_direct.xml",
Path(__file__).parent.parent / "models" / "parsing" / "juniper_route_indirect.xml", Path(__file__).parent.parent / "models" / "parsing" / "juniper_route_indirect.xml",
Path(__file__).parent.parent / "models" / "parsing" / "juniper_route_aspath.xml",
) )
if __name__ == "__main__":
@log.catch
def run():
"""Run tests."""
samples = () samples = ()
if len(sys.argv) == 2: if len(sys.argv) == 2:
samples += (sys.argv[1],) samples += (sys.argv[1],)
@@ -29,3 +33,7 @@ if __name__ == "__main__":
parsed = parse_juniper([sample]) parsed = parse_juniper([sample])
log.info(json.dumps(parsed, indent=2)) log.info(json.dumps(parsed, indent=2))
sys.exit(0) sys.exit(0)
if __name__ == "__main__":
run()