mirror of
https://github.com/thatmattlove/hyperglass.git
synced 2026-01-17 08:48:05 +00:00
add API docs examples
This commit is contained in:
parent
0ca5bc0ff6
commit
7ff8fa317d
16 changed files with 273 additions and 187 deletions
|
|
@ -1,46 +1,63 @@
|
|||
"""hyperglass REST API & Web UI."""
|
||||
|
||||
# Standard Library Imports
|
||||
# Standard Library
|
||||
from typing import List
|
||||
from pathlib import Path
|
||||
|
||||
# Third Party Imports
|
||||
# Third Party
|
||||
from fastapi import FastAPI
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
from starlette.responses import UJSONResponse
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
from starlette.staticfiles import StaticFiles
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
|
||||
# Project Imports
|
||||
from hyperglass.api.error_handlers import app_handler
|
||||
from hyperglass.api.error_handlers import default_handler
|
||||
from hyperglass.api.error_handlers import http_handler
|
||||
from hyperglass.api.error_handlers import validation_handler
|
||||
from hyperglass.api.events import on_shutdown
|
||||
from hyperglass.api.events import on_startup
|
||||
from hyperglass.api.models.response import QueryResponse
|
||||
from hyperglass.api.models.response import RoutersResponse
|
||||
from hyperglass.api.models.response import SupportedQueryResponse
|
||||
from hyperglass.api.routes import docs
|
||||
from hyperglass.api.routes import queries
|
||||
from hyperglass.api.routes import query
|
||||
from hyperglass.api.routes import routers
|
||||
from hyperglass.configuration import URL_DEV
|
||||
from hyperglass.configuration import params
|
||||
from hyperglass.constants import __version__
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
# Project
|
||||
from hyperglass.util import log
|
||||
from hyperglass.constants import __version__
|
||||
from hyperglass.api.events import on_startup, on_shutdown
|
||||
from hyperglass.api.routes import docs, query, queries, routers
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
from hyperglass.configuration import URL_DEV, params
|
||||
from hyperglass.api.error_handlers import (
|
||||
app_handler,
|
||||
http_handler,
|
||||
default_handler,
|
||||
validation_handler,
|
||||
)
|
||||
from hyperglass.api.models.response import (
|
||||
QueryError,
|
||||
QueryResponse,
|
||||
RoutersResponse,
|
||||
SupportedQueryResponse,
|
||||
)
|
||||
|
||||
STATIC_DIR = Path(__file__).parent.parent / "static"
|
||||
WORKING_DIR = Path(__file__).parent
|
||||
STATIC_DIR = WORKING_DIR.parent / "static"
|
||||
UI_DIR = STATIC_DIR / "ui"
|
||||
IMAGES_DIR = STATIC_DIR / "images"
|
||||
EXAMPLES_DIR = WORKING_DIR / "examples"
|
||||
|
||||
EXAMPLE_DEVICES_PY = EXAMPLES_DIR / "devices.py"
|
||||
EXAMPLE_QUERIES_PY = EXAMPLES_DIR / "queries.py"
|
||||
EXAMPLE_QUERY_PY = EXAMPLES_DIR / "query.py"
|
||||
EXAMPLE_DEVICES_CURL = EXAMPLES_DIR / "devices.sh"
|
||||
EXAMPLE_QUERIES_CURL = EXAMPLES_DIR / "queries.sh"
|
||||
EXAMPLE_QUERY_CURL = EXAMPLES_DIR / "query.sh"
|
||||
|
||||
ASGI_PARAMS = {
|
||||
"host": str(params.listen_address),
|
||||
"port": params.listen_port,
|
||||
"debug": params.debug,
|
||||
}
|
||||
DOCS_PARAMS = {}
|
||||
if params.docs.enable:
|
||||
DOCS_PARAMS.update({"openapi_url": params.docs.openapi_uri})
|
||||
if params.docs.mode == "redoc":
|
||||
DOCS_PARAMS.update({"docs_url": None, "redoc_url": params.docs.uri})
|
||||
elif params.docs.mode == "swagger":
|
||||
DOCS_PARAMS.update({"docs_url": params.docs.uri, "redoc_url": None})
|
||||
|
||||
# Main App Definition
|
||||
app = FastAPI(
|
||||
|
|
@ -49,9 +66,7 @@ app = FastAPI(
|
|||
description=params.site_description,
|
||||
version=__version__,
|
||||
default_response_class=UJSONResponse,
|
||||
docs_url=None,
|
||||
redoc_url=None,
|
||||
openapi_url=params.docs.openapi_uri,
|
||||
**DOCS_PARAMS,
|
||||
)
|
||||
|
||||
# Add Event Handlers
|
||||
|
|
@ -77,20 +92,60 @@ app.add_exception_handler(Exception, default_handler)
|
|||
def _custom_openapi():
|
||||
"""Generate custom OpenAPI config."""
|
||||
openapi_schema = get_openapi(
|
||||
title=params.site_title,
|
||||
title=params.docs.title.format(site_title=params.site_title),
|
||||
version=__version__,
|
||||
description=params.site_description,
|
||||
description=params.docs.description,
|
||||
routes=app.routes,
|
||||
)
|
||||
openapi_schema["info"]["x-logo"] = {"url": str(params.web.logo.light)}
|
||||
|
||||
query_samples = []
|
||||
queries_samples = []
|
||||
devices_samples = []
|
||||
|
||||
with EXAMPLE_QUERY_CURL.open("r") as e:
|
||||
example = e.read()
|
||||
query_samples.append(
|
||||
{"lang": "cURL", "source": example % str(params.docs.base_url)}
|
||||
)
|
||||
|
||||
with EXAMPLE_QUERY_PY.open("r") as e:
|
||||
example = e.read()
|
||||
query_samples.append(
|
||||
{"lang": "Python", "source": example % str(params.docs.base_url)}
|
||||
)
|
||||
|
||||
with EXAMPLE_DEVICES_CURL.open("r") as e:
|
||||
example = e.read()
|
||||
queries_samples.append(
|
||||
{"lang": "cURL", "source": example % str(params.docs.base_url)}
|
||||
)
|
||||
with EXAMPLE_DEVICES_PY.open("r") as e:
|
||||
example = e.read()
|
||||
queries_samples.append(
|
||||
{"lang": "Python", "source": example % str(params.docs.base_url)}
|
||||
)
|
||||
|
||||
with EXAMPLE_QUERIES_CURL.open("r") as e:
|
||||
example = e.read()
|
||||
devices_samples.append(
|
||||
{"lang": "cURL", "source": example % str(params.docs.base_url)}
|
||||
)
|
||||
|
||||
with EXAMPLE_QUERIES_PY.open("r") as e:
|
||||
example = e.read()
|
||||
devices_samples.append(
|
||||
{"lang": "Python", "source": example % str(params.docs.base_url)}
|
||||
)
|
||||
|
||||
openapi_schema["paths"]["/api/query/"]["post"]["x-code-samples"] = query_samples
|
||||
openapi_schema["paths"]["/api/devices"]["get"]["x-code-samples"] = devices_samples
|
||||
openapi_schema["paths"]["/api/queries"]["get"]["x-code-samples"] = queries_samples
|
||||
|
||||
app.openapi_schema = openapi_schema
|
||||
return app.openapi_schema
|
||||
|
||||
|
||||
app.openapi = _custom_openapi
|
||||
|
||||
if params.docs.enable:
|
||||
log.debug(f"API Docs config: {app.openapi()}")
|
||||
|
||||
CORS_ORIGINS = params.cors_origins.copy()
|
||||
if params.developer_mode:
|
||||
CORS_ORIGINS.append(URL_DEV)
|
||||
|
|
@ -107,7 +162,7 @@ app.add_api_route(
|
|||
path="/api/devices",
|
||||
endpoint=routers,
|
||||
methods=["GET"],
|
||||
response_model=RoutersResponse,
|
||||
response_model=List[RoutersResponse],
|
||||
response_class=UJSONResponse,
|
||||
summary=params.docs.devices.summary,
|
||||
description=params.docs.devices.description,
|
||||
|
|
@ -118,7 +173,7 @@ app.add_api_route(
|
|||
endpoint=queries,
|
||||
methods=["GET"],
|
||||
response_class=UJSONResponse,
|
||||
response_model=SupportedQueryResponse,
|
||||
response_model=List[SupportedQueryResponse],
|
||||
summary=params.docs.queries.summary,
|
||||
description=params.docs.queries.description,
|
||||
tags=[params.docs.queries.title],
|
||||
|
|
@ -129,6 +184,11 @@ app.add_api_route(
|
|||
methods=["POST"],
|
||||
summary=params.docs.query.summary,
|
||||
description=params.docs.query.description,
|
||||
responses={
|
||||
400: {"model": QueryError, "description": "Request Content Error"},
|
||||
422: {"model": QueryError, "description": "Request Format Error"},
|
||||
500: {"model": QueryError, "description": "Server Error"},
|
||||
},
|
||||
response_model=QueryResponse,
|
||||
tags=[params.docs.query.title],
|
||||
response_class=UJSONResponse,
|
||||
|
|
@ -136,6 +196,8 @@ app.add_api_route(
|
|||
|
||||
if params.docs.enable:
|
||||
app.add_api_route(path=params.docs.uri, endpoint=docs, include_in_schema=False)
|
||||
app.openapi = _custom_openapi
|
||||
log.debug(f"API Docs config: {app.openapi()}")
|
||||
|
||||
app.mount("/images", StaticFiles(directory=IMAGES_DIR), name="images")
|
||||
app.mount("/", StaticFiles(directory=UI_DIR, html=True), name="ui")
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
"""API Error Handlers."""
|
||||
|
||||
# Third Party Imports
|
||||
# Third Party
|
||||
from starlette.responses import UJSONResponse
|
||||
|
||||
# Project Imports
|
||||
# Project
|
||||
from hyperglass.configuration import params
|
||||
|
||||
|
||||
|
|
@ -36,5 +36,5 @@ async def validation_handler(request, exc):
|
|||
error = exc.errors()[0]
|
||||
return UJSONResponse(
|
||||
{"output": error["msg"], "level": "error", "keywords": error["loc"]},
|
||||
status_code=400,
|
||||
status_code=422,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,23 @@
|
|||
"""API Events."""
|
||||
# Third Party Imports
|
||||
# Third Party
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
# Project Imports
|
||||
from hyperglass.configuration import REDIS_CONFIG
|
||||
from hyperglass.configuration import URL_DEV
|
||||
from hyperglass.configuration import URL_PROD
|
||||
from hyperglass.configuration import frontend_params
|
||||
from hyperglass.configuration import params
|
||||
# Project
|
||||
from hyperglass.util import (
|
||||
log,
|
||||
check_redis,
|
||||
check_python,
|
||||
build_frontend,
|
||||
clear_redis_cache,
|
||||
)
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
from hyperglass.util import build_frontend
|
||||
from hyperglass.util import check_python
|
||||
from hyperglass.util import check_redis
|
||||
from hyperglass.util import clear_redis_cache
|
||||
from hyperglass.util import log
|
||||
from hyperglass.configuration import (
|
||||
URL_DEV,
|
||||
URL_PROD,
|
||||
REDIS_CONFIG,
|
||||
params,
|
||||
frontend_params,
|
||||
)
|
||||
|
||||
|
||||
async def check_python_version():
|
||||
|
|
|
|||
6
hyperglass/api/examples/devices.py
Normal file
6
hyperglass/api/examples/devices.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Third Party
|
||||
import httpx
|
||||
|
||||
request = httpx.get("%s/api/devices")
|
||||
|
||||
print(request.json())
|
||||
1
hyperglass/api/examples/devices.sh
Normal file
1
hyperglass/api/examples/devices.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
curl %s/api/devices
|
||||
6
hyperglass/api/examples/queries.py
Normal file
6
hyperglass/api/examples/queries.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Third Party
|
||||
import httpx
|
||||
|
||||
request = httpx.get("%s/api/queries")
|
||||
|
||||
print(request.json())
|
||||
1
hyperglass/api/examples/queries.sh
Normal file
1
hyperglass/api/examples/queries.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
curl %s/api/queries
|
||||
13
hyperglass/api/examples/query.py
Normal file
13
hyperglass/api/examples/query.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Third Party
|
||||
import httpx
|
||||
|
||||
query = {
|
||||
"query_location": "router01",
|
||||
"query_type": "bgp_route",
|
||||
"query_vrf": "default",
|
||||
"query_target": "1.1.1.0/24",
|
||||
}
|
||||
|
||||
request = httpx.post("%s/api/query/", data=query)
|
||||
|
||||
print(request.json().get("output"))
|
||||
7
hyperglass/api/examples/query.sh
Normal file
7
hyperglass/api/examples/query.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
curl -X POST %s/api/query/ -d \
|
||||
'{
|
||||
"query_location": "router01",
|
||||
"query_type": "bgp_route",
|
||||
"query_vrf": "default",
|
||||
"query_target": "1.1.1.0/24"
|
||||
}'
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
"""Query & Response Validation Models."""
|
||||
|
||||
# Project Imports
|
||||
from hyperglass.api.models import query
|
||||
from hyperglass.api.models import response
|
||||
from hyperglass.api.models import rfc8522
|
||||
from hyperglass.api.models import types
|
||||
from hyperglass.api.models import validators
|
||||
# Project
|
||||
from hyperglass.api.models import query, types, rfc8522, response, validators
|
||||
|
||||
# flake8: noqa: F401
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
"""Input query validation model."""
|
||||
|
||||
# Standard Library Imports
|
||||
# Standard Library
|
||||
import hashlib
|
||||
|
||||
# Third Party Imports
|
||||
from pydantic import BaseModel
|
||||
from pydantic import StrictStr
|
||||
from pydantic import validator
|
||||
# Third Party
|
||||
from pydantic import BaseModel, StrictStr, validator
|
||||
|
||||
# Project Imports
|
||||
from hyperglass.api.models.types import SupportedQuery
|
||||
from hyperglass.api.models.validators import validate_aspath
|
||||
from hyperglass.api.models.validators import validate_community
|
||||
from hyperglass.api.models.validators import validate_ip
|
||||
from hyperglass.configuration import devices
|
||||
from hyperglass.configuration import params
|
||||
from hyperglass.configuration.models.vrfs import Vrf
|
||||
# Project
|
||||
from hyperglass.util import log
|
||||
from hyperglass.exceptions import InputInvalid
|
||||
from hyperglass.configuration import params, devices
|
||||
from hyperglass.api.models.types import SupportedQuery
|
||||
from hyperglass.api.models.validators import (
|
||||
validate_ip,
|
||||
validate_aspath,
|
||||
validate_community,
|
||||
)
|
||||
|
||||
|
||||
def get_vrf_object(vrf_name):
|
||||
|
|
@ -51,14 +50,43 @@ class Query(BaseModel):
|
|||
|
||||
query_location: StrictStr
|
||||
query_type: SupportedQuery
|
||||
query_vrf: Vrf
|
||||
query_vrf: StrictStr
|
||||
query_target: StrictStr
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
||||
fields = {
|
||||
"query_location": {
|
||||
"title": params.web.text.query_location,
|
||||
"description": "Router/Location Name",
|
||||
"example": "router01",
|
||||
},
|
||||
"query_type": {
|
||||
"title": params.web.text.query_type,
|
||||
"description": "Type of Query to Execute",
|
||||
"example": "bgp_route",
|
||||
},
|
||||
"query_vrf": {
|
||||
"title": params.web.text.query_vrf,
|
||||
"description": "Routing Table/VRF",
|
||||
"example": "default",
|
||||
},
|
||||
"query_target": {
|
||||
"title": params.web.text.query_target,
|
||||
"description": "IP Address, Community, or AS Path",
|
||||
"example": "1.1.1.0/24",
|
||||
},
|
||||
}
|
||||
schema_extra = {
|
||||
"x-code-samples": [{"lang": "Python", "source": "print('stuff')"}]
|
||||
}
|
||||
|
||||
def digest(self):
|
||||
"""Create SHA256 hash digest of model representation."""
|
||||
return hashlib.sha256(repr(self).encode()).hexdigest()
|
||||
|
||||
@validator("query_location", pre=True, always=True)
|
||||
@validator("query_location")
|
||||
def validate_query_location(cls, value):
|
||||
"""Ensure query_location is defined.
|
||||
|
||||
|
|
@ -80,7 +108,7 @@ class Query(BaseModel):
|
|||
)
|
||||
return value
|
||||
|
||||
@validator("query_vrf", always=True, pre=True)
|
||||
@validator("query_vrf")
|
||||
def validate_query_vrf(cls, value, values):
|
||||
"""Ensure query_vrf is defined.
|
||||
|
||||
|
|
@ -108,10 +136,11 @@ class Query(BaseModel):
|
|||
)
|
||||
return device_vrf
|
||||
|
||||
@validator("query_target", always=True)
|
||||
@validator("query_target")
|
||||
def validate_query_target(cls, value, values):
|
||||
"""Validate query target value based on query_type."""
|
||||
|
||||
log.debug(values)
|
||||
query_type = values["query_type"]
|
||||
|
||||
# Use relevant function based on query_type.
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
"""Response model."""
|
||||
# Standard Library Imports
|
||||
# Standard Library
|
||||
from typing import List
|
||||
|
||||
# Third Party Imports
|
||||
from pydantic import BaseModel
|
||||
from pydantic import StrictBool
|
||||
from pydantic import StrictStr
|
||||
from pydantic import constr
|
||||
# Third Party
|
||||
from pydantic import BaseModel, StrictStr, StrictBool, constr
|
||||
|
||||
# Project
|
||||
from hyperglass.configuration import params
|
||||
|
||||
|
||||
class QueryError(BaseModel):
|
||||
"""Query response model."""
|
||||
|
||||
output: StrictStr
|
||||
level: constr(regex=r"(success|warning|error|danger)")
|
||||
keywords: List[StrictStr]
|
||||
output: StrictStr = params.messages.general
|
||||
level: constr(regex=r"(success|warning|error|danger)") = "danger"
|
||||
keywords: List[StrictStr] = []
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
|
@ -23,6 +23,23 @@ class QueryError(BaseModel):
|
|||
description = (
|
||||
"Response received when there is an error executing the requested query."
|
||||
)
|
||||
fields = {
|
||||
"output": {
|
||||
"title": "Output",
|
||||
"description": "Error Details",
|
||||
"example": "192.0.2.1/32 is not allowed.",
|
||||
},
|
||||
"level": {
|
||||
"title": "Level",
|
||||
"description": "Error Severity",
|
||||
"example": "danger",
|
||||
},
|
||||
"keywords": {
|
||||
"title": "Keywords",
|
||||
"description": "Relevant keyword values contained in the `output` field, which can be used for formatting.",
|
||||
"example": ["192.0.2.1/32"],
|
||||
},
|
||||
}
|
||||
schema_extra = {
|
||||
"examples": [
|
||||
{
|
||||
|
|
@ -38,7 +55,7 @@ class QueryResponse(BaseModel):
|
|||
"""Query response model."""
|
||||
|
||||
output: StrictStr
|
||||
level: constr(regex=r"(success|warning|error|danger)")
|
||||
level: constr(regex=r"success") = "success"
|
||||
keywords: List[StrictStr] = []
|
||||
|
||||
class Config:
|
||||
|
|
@ -46,66 +63,45 @@ class QueryResponse(BaseModel):
|
|||
|
||||
title = "Query Response"
|
||||
description = "Looking glass response"
|
||||
fields = {
|
||||
"level": {"title": "Level", "description": "Severity"},
|
||||
"keywords": {
|
||||
"title": "Keywords",
|
||||
"description": "Relevant keyword values contained in the `output` field, which can be used for formatting.",
|
||||
"example": ["1.1.1.0/24", "best #1"],
|
||||
},
|
||||
"output": {
|
||||
"title": "Output",
|
||||
"description": "Looking Glass Response",
|
||||
"example": """
|
||||
BGP routing table entry for 1.1.1.0/24, version 224184946
|
||||
BGP Bestpath: deterministic-med
|
||||
Paths: (12 available, best #1, table default)
|
||||
Advertised to update-groups:
|
||||
1 40
|
||||
13335, (aggregated by 13335 172.68.129.1), (received & used)
|
||||
192.0.2.1 (metric 51) from 192.0.2.1 (192.0.2.1)
|
||||
Origin IGP, metric 0, localpref 250, valid, internal
|
||||
Community: 65000:1 65000:2
|
||||
""",
|
||||
},
|
||||
}
|
||||
schema_extra = {
|
||||
"examples": [
|
||||
{
|
||||
"output": """
|
||||
BGP routing table entry for 1.1.1.0/24, version 224184946
|
||||
BGP Bestpath: deterministic-med
|
||||
Paths: (12 available, best #9, table default)
|
||||
Paths: (12 available, best #1, table default)
|
||||
Advertised to update-groups:
|
||||
1 40
|
||||
13335, (aggregated by 13335 172.68.129.1), (received & used)
|
||||
199.34.92.5 (metric 51) from 199.34.92.5 (199.34.92.5)
|
||||
192.0.2.1 (metric 51) from 192.0.2.1 (192.0.2.1)
|
||||
Origin IGP, metric 0, localpref 250, valid, internal
|
||||
Community: 14525:1021 14525:2840 14525:3003 14525:4003 14525:5200 14525:5300 14525:5306
|
||||
13335, (aggregated by 13335 172.68.129.1), (received & used)
|
||||
199.34.92.6 (metric 51) from 199.34.92.6 (199.34.92.6)
|
||||
Origin IGP, metric 0, localpref 250, valid, internal
|
||||
Community: 14525:1021 14525:2840 14525:3003 14525:4003 14525:5200 14525:5300 14525:5306
|
||||
1299 13335, (aggregated by 13335 162.158.140.1)
|
||||
62.115.171.124 from 62.115.171.124 (2.255.254.51)
|
||||
Origin IGP, metric 0, localpref 100, weight 200, valid, external
|
||||
Community: 14525:0 14525:1021 14525:2840 14525:3001 14525:4001 14525:5100 14525:5103
|
||||
1299 13335, (aggregated by 13335 162.158.140.1), (received-only)
|
||||
62.115.171.124 from 62.115.171.124 (2.255.254.51)
|
||||
Origin IGP, localpref 100, valid, external
|
||||
Community: 1299:35000
|
||||
174 13335, (aggregated by 13335 108.162.239.1)
|
||||
199.34.92.7 (metric 1100) from 199.34.92.7 (199.34.92.7)
|
||||
Origin IGP, metric 0, localpref 100, weight 125, valid, internal
|
||||
Community: 14525:0 14525:840 14525:1021 14525:3004 14525:4004 14525:5100 14525:5101
|
||||
174 13335, (aggregated by 13335 108.162.239.1), (received-only)
|
||||
199.34.92.7 (metric 1100) from 199.34.92.7 (199.34.92.7)
|
||||
Origin IGP, metric 0, localpref 100, valid, internal
|
||||
Community: 14525:0 14525:840 14525:1021 14525:3004 14525:4004 14525:5100 14525:5101
|
||||
174 13335, (aggregated by 13335 162.158.140.1), (Received from a RR-client)
|
||||
199.34.92.2 (metric 26) from 199.34.92.2 (199.34.92.2)
|
||||
Origin IGP, metric 0, localpref 100, weight 200, valid, internal
|
||||
Community: 14525:0 14525:1021 14525:2840 14525:3001 14525:4001 14525:5100 14525:5101
|
||||
174 13335, (aggregated by 13335 162.158.140.1), (Received from a RR-client), (received-only)
|
||||
199.34.92.2 (metric 26) from 199.34.92.2 (199.34.92.2)
|
||||
Origin IGP, metric 0, localpref 100, valid, internal
|
||||
Community: 14525:0 14525:1021 14525:2840 14525:3001 14525:4001 14525:5100 14525:5101
|
||||
174 13335, (aggregated by 13335 162.158.140.1)
|
||||
38.140.141.25 from 38.140.141.25 (154.26.6.194)
|
||||
Origin IGP, metric 0, localpref 100, weight 200, valid, external, best
|
||||
Community: 14525:0 14525:1021 14525:2840 14525:3001 14525:4001 14525:5100 14525:5101
|
||||
174 13335, (aggregated by 13335 162.158.140.1), (received-only)
|
||||
38.140.141.25 from 38.140.141.25 (154.26.6.194)
|
||||
Origin IGP, metric 2020, localpref 100, valid, external
|
||||
Community: 174:21001 174:22013
|
||||
3257 13335, (aggregated by 13335 141.101.72.1)
|
||||
199.34.92.3 (metric 200) from 199.34.92.3 (199.34.92.3)
|
||||
Origin IGP, metric 0, localpref 100, weight 200, valid, internal
|
||||
Community: 14525:0 14525:840 14525:1021 14525:3002 14525:4002 14525:5100 14525:5104
|
||||
3257 13335, (aggregated by 13335 141.101.72.1), (received-only)
|
||||
199.34.92.3 (metric 200) from 199.34.92.3 (199.34.92.3)
|
||||
Origin IGP, metric 0, localpref 100, valid, internal
|
||||
Community: 14525:0 14525:840 14525:1021 14525:3002 14525:4002 14525:5100 14525:5104
|
||||
Community: 65000:1 65000:2
|
||||
""",
|
||||
"level": "success",
|
||||
"keywords": ["1.1.1.0/24", "best #9"],
|
||||
"keywords": ["1.1.1.0/24", "best #1"],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -144,7 +140,7 @@ class Network(BaseModel):
|
|||
schema_extra = {"examples": [{"name": "primary", "display_name": "AS65000"}]}
|
||||
|
||||
|
||||
class Router(BaseModel):
|
||||
class RoutersResponse(BaseModel):
|
||||
"""Response model for /api/devices list items."""
|
||||
|
||||
name: StrictStr
|
||||
|
|
@ -169,19 +165,7 @@ class Router(BaseModel):
|
|||
}
|
||||
|
||||
|
||||
class RoutersResponse(BaseModel):
|
||||
"""Response model for /api/devices endpoint."""
|
||||
|
||||
__root__: List[Router]
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
||||
title = "Devices"
|
||||
description = "List of all devices"
|
||||
|
||||
|
||||
class SupportedQuery(BaseModel):
|
||||
class SupportedQueryResponse(BaseModel):
|
||||
"""Response model for /api/queries list items."""
|
||||
|
||||
name: StrictStr
|
||||
|
|
@ -198,15 +182,3 @@ class SupportedQuery(BaseModel):
|
|||
{"name": "bgp_route", "display_name": "BGP Route", "enable": True}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class SupportedQueryResponse(BaseModel):
|
||||
"""Response model for /api/queries endpoint."""
|
||||
|
||||
__root__: List[SupportedQuery]
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
||||
title = "Supported Query Types"
|
||||
description = "Enabled query type attributes."
|
||||
|
|
|
|||
|
|
@ -1,22 +1,15 @@
|
|||
"""Response model."""
|
||||
|
||||
# Standard Library Imports
|
||||
# Standard Library
|
||||
# flake8: noqa
|
||||
import math
|
||||
import secrets
|
||||
from typing import List, Union, Optional
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
|
||||
# Third Party Imports
|
||||
# Third Party
|
||||
import ujson
|
||||
from pydantic import BaseModel
|
||||
from pydantic import StrictFloat
|
||||
from pydantic import StrictInt
|
||||
from pydantic import StrictStr
|
||||
from pydantic import constr
|
||||
from pydantic import validator
|
||||
from pydantic import BaseModel, StrictInt, StrictStr, StrictFloat, constr, validator
|
||||
|
||||
|
||||
"""Patterns:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""Custom validation types."""
|
||||
|
||||
# Project Imports
|
||||
# Project
|
||||
from hyperglass.constants import SUPPORTED_QUERY_TYPES
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
"""Input validation functions for submitted queries."""
|
||||
|
||||
# Standard Library Imports
|
||||
import operator
|
||||
# Standard Library
|
||||
import re
|
||||
import operator
|
||||
from ipaddress import ip_network
|
||||
|
||||
# Project Imports
|
||||
from hyperglass.configuration import params
|
||||
from hyperglass.exceptions import InputInvalid
|
||||
from hyperglass.exceptions import InputNotAllowed
|
||||
# Project
|
||||
from hyperglass.util import log
|
||||
from hyperglass.exceptions import InputInvalid, InputNotAllowed
|
||||
from hyperglass.configuration import params
|
||||
|
||||
|
||||
def _member_of(target, network):
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
"""API Routes."""
|
||||
|
||||
# Standard Library Imports
|
||||
# Standard Library
|
||||
import time
|
||||
|
||||
# Third Party Imports
|
||||
# Third Party
|
||||
import aredis
|
||||
from fastapi import HTTPException
|
||||
from fastapi.openapi.docs import get_redoc_html
|
||||
from fastapi.openapi.docs import get_swagger_ui_html
|
||||
from starlette.requests import Request
|
||||
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
|
||||
|
||||
# Project Imports
|
||||
from hyperglass.api.models.query import Query
|
||||
from hyperglass.configuration import REDIS_CONFIG
|
||||
from hyperglass.configuration import devices
|
||||
from hyperglass.configuration import params
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
from hyperglass.execution.execute import Execute
|
||||
# Project
|
||||
from hyperglass.util import log
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
from hyperglass.configuration import REDIS_CONFIG, params, devices
|
||||
from hyperglass.api.models.query import Query
|
||||
from hyperglass.execution.execute import Execute
|
||||
|
||||
Cache = aredis.StrictRedis(db=params.cache.database, **REDIS_CONFIG)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue