mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-12-21 01:52:25 +00:00
feat: migrate Inspect API to FastAPI router (#4403)
# What does this PR do? Migrate the Inspect API to the FastAPI router pattern. Changes: - Add inspect API to FastAPI router registry - Add PUBLIC_ROUTE_KEY support for routes that don't require auth - Update WebMethod creation to respect route's openapi_extra for authentication requirements Fixes: https://github.com/llamastack/llama-stack/issues/4346 <!-- Provide a short summary of what this PR does and why. Link to relevant issues if applicable. --> <!-- If resolving an issue, uncomment and update the line below --> <!-- Closes #[issue-number] --> ## Test Plan CI and various curls on /v1/inspect/routes, /v1/health, /v1/version Signed-off-by: Sébastien Han <seb@redhat.com>
This commit is contained in:
parent
cd5095a247
commit
a7d509aaf9
14 changed files with 281 additions and 182 deletions
|
|
@ -28,9 +28,11 @@ class AuthenticationMiddleware:
|
|||
4. Makes these attributes available to the route handlers for access control
|
||||
|
||||
Unauthenticated Access:
|
||||
Endpoints can opt out of authentication by setting require_authentication=False
|
||||
in their @webmethod decorator. This is typically used for operational endpoints
|
||||
like /health and /version to support monitoring, load balancers, and observability tools.
|
||||
Endpoints can opt out of authentication by:
|
||||
- For legacy @webmethod routes: setting require_authentication=False in the decorator
|
||||
- For FastAPI router routes: setting openapi_extra={PUBLIC_ROUTE_KEY: True}
|
||||
This is typically used for operational endpoints like /health and /version to support
|
||||
monitoring, load balancers, and observability tools.
|
||||
|
||||
The middleware supports multiple authentication providers through the AuthProvider interface:
|
||||
- Kubernetes: Validates tokens against the Kubernetes API server
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@ from typing import Any, cast
|
|||
|
||||
from fastapi import APIRouter
|
||||
from fastapi.routing import APIRoute
|
||||
from starlette.routing import Route
|
||||
|
||||
from llama_stack_api import batches, benchmarks, datasets, providers
|
||||
from llama_stack_api import batches, benchmarks, datasets, inspect_api, providers
|
||||
|
||||
# Router factories for APIs that have FastAPI routers
|
||||
# Add new APIs here as they are migrated to the router system
|
||||
|
|
@ -28,6 +27,7 @@ _ROUTER_FACTORIES: dict[str, Callable[[Any], APIRouter]] = {
|
|||
"benchmarks": benchmarks.fastapi_routes.create_router,
|
||||
"datasets": datasets.fastapi_routes.create_router,
|
||||
"providers": providers.fastapi_routes.create_router,
|
||||
"inspect": inspect_api.fastapi_routes.create_router,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -63,38 +63,20 @@ def build_fastapi_router(api: "Api", impl: Any) -> APIRouter | None:
|
|||
return cast(APIRouter, router_factory(impl))
|
||||
|
||||
|
||||
def get_router_routes(router: APIRouter) -> list[Route]:
|
||||
"""Extract routes from a FastAPI router.
|
||||
def get_router_routes(router: APIRouter) -> list[APIRoute]:
|
||||
"""Extract APIRoute objects from a FastAPI router.
|
||||
|
||||
Args:
|
||||
router: The FastAPI router to extract routes from
|
||||
|
||||
Returns:
|
||||
List of Route objects from the router
|
||||
List of APIRoute objects from the router (preserves tags and other metadata)
|
||||
"""
|
||||
routes = []
|
||||
|
||||
for route in router.routes:
|
||||
# FastAPI routers use APIRoute objects, which have path and methods attributes
|
||||
# FastAPI routers use APIRoute objects, which have path, methods, tags, etc.
|
||||
if isinstance(route, APIRoute):
|
||||
# Combine router prefix with route path
|
||||
routes.append(
|
||||
Route(
|
||||
path=route.path,
|
||||
methods=route.methods,
|
||||
name=route.name,
|
||||
endpoint=route.endpoint,
|
||||
)
|
||||
)
|
||||
elif isinstance(route, Route):
|
||||
# Fallback for regular Starlette Route objects
|
||||
routes.append(
|
||||
Route(
|
||||
path=route.path,
|
||||
methods=route.methods,
|
||||
name=route.name,
|
||||
endpoint=route.endpoint,
|
||||
)
|
||||
)
|
||||
routes.append(route)
|
||||
|
||||
return routes
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from llama_stack.core.server.fastapi_router_registry import (
|
|||
get_router_routes,
|
||||
)
|
||||
from llama_stack_api import Api, ExternalApiSpec, WebMethod
|
||||
from llama_stack_api.router_utils import PUBLIC_ROUTE_KEY
|
||||
|
||||
EndpointFunc = Callable[..., Any]
|
||||
PathParams = dict[str, str]
|
||||
|
|
@ -124,7 +125,13 @@ def initialize_route_impls(impls, external_apis: dict[Api, ExternalApiSpec] | No
|
|||
# - Pass summary directly in RouteMatch instead of WebMethod
|
||||
# - Remove this WebMethod() instantiation entirely
|
||||
# - Update library_client.py to use the extracted summary instead of webmethod.descriptive_name
|
||||
webmethod = WebMethod(descriptive_name=None)
|
||||
|
||||
# Routes with openapi_extra[PUBLIC_ROUTE_KEY]=True don't require authentication
|
||||
is_public = (route.openapi_extra or {}).get(PUBLIC_ROUTE_KEY, False)
|
||||
webmethod = WebMethod(
|
||||
descriptive_name=None,
|
||||
require_authentication=not is_public,
|
||||
)
|
||||
route_impls[method][_convert_path_to_regex(route.path)] = (
|
||||
func,
|
||||
route.path,
|
||||
|
|
@ -139,19 +146,19 @@ def initialize_route_impls(impls, external_apis: dict[Api, ExternalApiSpec] | No
|
|||
|
||||
if api not in impls:
|
||||
continue
|
||||
for route, webmethod in api_routes:
|
||||
for legacy_route, webmethod in api_routes:
|
||||
impl = impls[api]
|
||||
func = getattr(impl, route.name)
|
||||
func = getattr(impl, legacy_route.name)
|
||||
# Get the first (and typically only) method from the set, filtering out HEAD
|
||||
available_methods = [m for m in (route.methods or []) if m != "HEAD"]
|
||||
available_methods = [m for m in (legacy_route.methods or []) if m != "HEAD"]
|
||||
if not available_methods:
|
||||
continue # Skip if only HEAD method is available
|
||||
method = available_methods[0].lower()
|
||||
if method not in route_impls:
|
||||
route_impls[method] = {}
|
||||
route_impls[method][_convert_path_to_regex(route.path)] = (
|
||||
route_impls[method][_convert_path_to_regex(legacy_route.path)] = (
|
||||
func,
|
||||
route.path,
|
||||
legacy_route.path,
|
||||
webmethod,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue