mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
Clean up API routes
This commit is contained in:
@@ -18,21 +18,12 @@ from fastapi.middleware.gzip import GZipMiddleware
|
||||
# Project
|
||||
from hyperglass.log import log
|
||||
from hyperglass.util import cpu_count
|
||||
from hyperglass.constants import TRANSPORT_REST, __version__
|
||||
from hyperglass.constants import __version__
|
||||
from hyperglass.models.ui import UIParameters
|
||||
from hyperglass.api.events import on_startup, on_shutdown
|
||||
from hyperglass.api.routes import (
|
||||
docs,
|
||||
info,
|
||||
query,
|
||||
queries,
|
||||
routers,
|
||||
ui_props,
|
||||
communities,
|
||||
import_certificate,
|
||||
)
|
||||
from hyperglass.api.routes import docs, info, query, router, queries, routers, ui_props
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
from hyperglass.configuration import URL_DEV, STATIC_PATH, params, devices
|
||||
from hyperglass.configuration import URL_DEV, STATIC_PATH, params
|
||||
from hyperglass.api.error_handlers import (
|
||||
app_handler,
|
||||
http_handler,
|
||||
@@ -211,12 +202,14 @@ app.add_api_route(
|
||||
)
|
||||
|
||||
app.add_api_route(
|
||||
path="/api/communities",
|
||||
endpoint=communities,
|
||||
path="/api/devices/{id}",
|
||||
endpoint=router,
|
||||
methods=["GET"],
|
||||
response_model=List[CommunityResponse],
|
||||
summary=params.docs.communities.summary,
|
||||
tags=[params.docs.communities.title],
|
||||
response_model=RoutersResponse,
|
||||
response_class=JSONResponse,
|
||||
summary=params.docs.devices.summary,
|
||||
description=params.docs.devices.description,
|
||||
tags=[params.docs.devices.title],
|
||||
)
|
||||
|
||||
app.add_api_route(
|
||||
@@ -255,15 +248,6 @@ app.add_api_route(
|
||||
response_model_by_alias=True,
|
||||
)
|
||||
|
||||
# Enable certificate import route only if a device using
|
||||
# hyperglass-agent is defined.
|
||||
if [n for n in devices.all_nos if n in TRANSPORT_REST]:
|
||||
app.add_api_route(
|
||||
path="/api/import-agent-certificate/",
|
||||
endpoint=import_certificate,
|
||||
methods=["POST"],
|
||||
include_in_schema=False,
|
||||
)
|
||||
|
||||
if params.docs.enable:
|
||||
app.add_api_route(path=params.docs.uri, endpoint=docs, include_in_schema=False)
|
||||
|
@@ -14,12 +14,11 @@ from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
|
||||
# Project
|
||||
from hyperglass.log import log
|
||||
from hyperglass.cache import AsyncCache
|
||||
from hyperglass.encode import jwt_decode
|
||||
from hyperglass.external import Webhook, bgptools
|
||||
from hyperglass.api.tasks import process_headers, import_public_key
|
||||
from hyperglass.api.tasks import process_headers
|
||||
from hyperglass.constants import __version__
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
from hyperglass.models.api import Query, EncodedRequest
|
||||
from hyperglass.models.api import Query
|
||||
from hyperglass.configuration import REDIS_CONFIG, params, devices, ui_params
|
||||
from hyperglass.execution.main import execute
|
||||
|
||||
@@ -30,15 +29,7 @@ APP_PATH = os.environ["hyperglass_directory"]
|
||||
|
||||
|
||||
async def send_webhook(query_data: Query, request: Request, timestamp: datetime):
|
||||
"""If webhooks are enabled, get request info and send a webhook.
|
||||
|
||||
Args:
|
||||
query_data (Query): Valid query
|
||||
request (Request): Starlette/FastAPI request
|
||||
|
||||
Returns:
|
||||
int: Returns 1 regardless of result
|
||||
"""
|
||||
"""If webhooks are enabled, get request info and send a webhook."""
|
||||
try:
|
||||
if params.logging.http is not None:
|
||||
headers = await process_headers(headers=request.headers)
|
||||
@@ -173,47 +164,6 @@ async def query(query_data: Query, request: Request, background_tasks: Backgroun
|
||||
}
|
||||
|
||||
|
||||
async def import_certificate(encoded_request: EncodedRequest):
|
||||
"""Import a certificate from hyperglass-agent."""
|
||||
|
||||
# Try to match the requested device name with configured devices
|
||||
log.debug(
|
||||
"Attempting certificate import for device '{}'", devices[encoded_request.device]
|
||||
)
|
||||
try:
|
||||
matched_device = devices[encoded_request.device]
|
||||
except AttributeError:
|
||||
raise HTTPException(
|
||||
detail=f"Device {str(encoded_request.device)} not found", status_code=404
|
||||
)
|
||||
|
||||
try:
|
||||
# Decode JSON Web Token
|
||||
decoded_request = await jwt_decode(
|
||||
payload=encoded_request.encoded,
|
||||
secret=matched_device.credential.password.get_secret_value(),
|
||||
)
|
||||
except HyperglassError as decode_error:
|
||||
raise HTTPException(detail=str(decode_error), status_code=400)
|
||||
|
||||
try:
|
||||
# Write certificate to file
|
||||
import_public_key(
|
||||
app_path=APP_PATH,
|
||||
device_name=matched_device._id,
|
||||
keystring=decoded_request,
|
||||
)
|
||||
except RuntimeError as err:
|
||||
raise HyperglassError(str(err), level="danger")
|
||||
|
||||
log.info("Added public key for {}", encoded_request.device)
|
||||
return {
|
||||
"output": f"Added public key for {encoded_request.device}",
|
||||
"level": "success",
|
||||
"keywords": [encoded_request.device],
|
||||
}
|
||||
|
||||
|
||||
async def docs():
|
||||
"""Serve custom docs."""
|
||||
if params.docs.enable:
|
||||
@@ -226,27 +176,14 @@ async def docs():
|
||||
raise HTTPException(detail="Not found", status_code=404)
|
||||
|
||||
|
||||
async def router(id: str):
|
||||
"""Get a device's API-facing attributes."""
|
||||
return devices[id].export_api()
|
||||
|
||||
|
||||
async def routers():
|
||||
"""Serve list of configured routers and attributes."""
|
||||
return [
|
||||
d.dict(
|
||||
include={
|
||||
"name": ...,
|
||||
"network": ...,
|
||||
"display_name": ...,
|
||||
"vrfs": {-1: {"name", "display_name"}},
|
||||
}
|
||||
)
|
||||
for d in devices.objects
|
||||
]
|
||||
|
||||
|
||||
async def communities():
|
||||
"""Serve list of configured communities if mode is select."""
|
||||
if params.queries.bgp_community.mode != "select":
|
||||
raise HTTPException(detail="BGP community mode is not select", status_code=404)
|
||||
|
||||
return [c.export_dict() for c in params.queries.bgp_community.communities]
|
||||
return devices.export_api()
|
||||
|
||||
|
||||
async def queries():
|
||||
@@ -260,7 +197,7 @@ async def info():
|
||||
"name": params.site_title,
|
||||
"organization": params.org_name,
|
||||
"primary_asn": int(params.primary_asn),
|
||||
"version": f"hyperglass {__version__}",
|
||||
"version": __version__,
|
||||
}
|
||||
|
||||
|
||||
|
@@ -178,16 +178,24 @@ class Network(BaseModel):
|
||||
class RoutersResponse(BaseModel):
|
||||
"""Response model for /api/devices list items."""
|
||||
|
||||
id: StrictStr
|
||||
name: StrictStr
|
||||
network: Network
|
||||
vrfs: List[Vrf]
|
||||
network: StrictStr
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
||||
title = "Device"
|
||||
description = "Per-device attributes"
|
||||
schema_extra = {"examples": [{"name": "router01-nyc01", "location": "nyc01"}]}
|
||||
description = "Device attributes"
|
||||
schema_extra = {
|
||||
"examples": [
|
||||
{
|
||||
"id": "nyc_router_1",
|
||||
"name": "NYC Router 1",
|
||||
"network": "New York City, NY",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class CommunityResponse(BaseModel):
|
||||
|
@@ -103,6 +103,14 @@ class Device(HyperglassModel, extra="allow"):
|
||||
|
||||
return device_id, {"name": display_name, "display_name": None, **values}
|
||||
|
||||
def export_api(self) -> Dict[str, Any]:
|
||||
"""Export API-facing device fields."""
|
||||
return {
|
||||
"id": self._id,
|
||||
"name": self.name,
|
||||
"network": self.network.display_name,
|
||||
}
|
||||
|
||||
@property
|
||||
def directive_commands(self) -> List[str]:
|
||||
"""Get all commands associated with the device."""
|
||||
@@ -278,6 +286,10 @@ class Devices(HyperglassModel, extra="allow"):
|
||||
|
||||
raise AttributeError(f"No device named '{accessor}'")
|
||||
|
||||
def export_api(self) -> List[Dict[str, Any]]:
|
||||
"""Export API-facing device fields."""
|
||||
return [d.export_api() for d in self.objects]
|
||||
|
||||
def networks(self, params: Params) -> List[Dict[str, Any]]:
|
||||
"""Group devices by network."""
|
||||
names = {device.network.display_name for device in self.objects}
|
||||
|
Reference in New Issue
Block a user