From fb1e2f27cbf81930d5734e4c44893381f5050c37 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Sun, 29 Sep 2024 20:42:59 -0400 Subject: [PATCH 01/13] instrument api and add dependency to pyproject.toml --- src/leapfrogai_api/main.py | 3 +++ src/leapfrogai_api/pyproject.toml | 1 + 2 files changed, 4 insertions(+) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index 85822f7f3..cd19acb67 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -29,6 +29,7 @@ vector_stores, ) from leapfrogai_api.utils import get_model_config +from prometheus_fastapi_instrumentator import Instrumentator logging.basicConfig( level=os.getenv("LFAI_LOG_LEVEL", logging.INFO), @@ -60,6 +61,8 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) +Instrumentator().instrument(app).expose(app) + @app.exception_handler(RequestValidationError) async def validation_exception_handler(request, exc): diff --git a/src/leapfrogai_api/pyproject.toml b/src/leapfrogai_api/pyproject.toml index a18f6422f..1639b6f63 100644 --- a/src/leapfrogai_api/pyproject.toml +++ b/src/leapfrogai_api/pyproject.toml @@ -26,6 +26,7 @@ dependencies = [ "postgrest==0.16.11", # required by supabase, bug when using previous versions "openpyxl == 3.1.5", "psutil == 6.0.0", + "prometheus-fastapi-instrumentator == 7.0.0", ] requires-python = "~=3.11" From 0de81cf92180ce9638ac2d79d30eac784407f583 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Mon, 30 Sep 2024 13:36:12 -0400 Subject: [PATCH 02/13] add uds package for monitor --- packages/api/chart/templates/uds-package.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/api/chart/templates/uds-package.yaml b/packages/api/chart/templates/uds-package.yaml index a6a83dea8..6e4df8416 100644 --- a/packages/api/chart/templates/uds-package.yaml +++ b/packages/api/chart/templates/uds-package.yaml @@ -7,6 +7,11 @@ metadata: labels: {{- include "chart.labels" . | nindent 4 }} spec: + monitor: + - portName: {{ include "chart.fullname" . }} + targetPort: {{ .Values.api.service.port }} + selector: + {{- include "chart.selectorLabels" . | nindent 8 }} network: expose: - service: {{ include "chart.fullname" . }} From fb710133001931ab786dda6e1b68f1a0509126b0 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Mon, 30 Sep 2024 13:36:23 -0400 Subject: [PATCH 03/13] add base url redirect --- src/leapfrogai_api/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index cd19acb67..0b38a9700 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -8,6 +8,7 @@ from fastapi import FastAPI from fastapi.exception_handlers import request_validation_exception_handler from fastapi.exceptions import RequestValidationError +from fastapi.responses import RedirectResponse from leapfrogai_api.routers.base import router as base_router from leapfrogai_api.routers.leapfrogai import auth @@ -64,6 +65,11 @@ async def lifespan(app: FastAPI): Instrumentator().instrument(app).expose(app) +@app.get("/") +async def root(): + return RedirectResponse(url="/redoc") + + @app.exception_handler(RequestValidationError) async def validation_exception_handler(request, exc): logger.error(f"The client sent invalid data!: {exc}") From 455048f0467f9153094e6957a1d45869a2ccd1aa Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Mon, 30 Sep 2024 17:59:11 -0400 Subject: [PATCH 04/13] move base path intercepter --- src/leapfrogai_api/main.py | 7 ------- src/leapfrogai_api/routers/base.py | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index 0b38a9700..0fdc65f1f 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -8,8 +8,6 @@ from fastapi import FastAPI from fastapi.exception_handlers import request_validation_exception_handler from fastapi.exceptions import RequestValidationError -from fastapi.responses import RedirectResponse - from leapfrogai_api.routers.base import router as base_router from leapfrogai_api.routers.leapfrogai import auth from leapfrogai_api.routers.leapfrogai import models as lfai_models @@ -65,11 +63,6 @@ async def lifespan(app: FastAPI): Instrumentator().instrument(app).expose(app) -@app.get("/") -async def root(): - return RedirectResponse(url="/redoc") - - @app.exception_handler(RequestValidationError) async def validation_exception_handler(request, exc): logger.error(f"The client sent invalid data!: {exc}") diff --git a/src/leapfrogai_api/routers/base.py b/src/leapfrogai_api/routers/base.py index 58032a62c..95951eb50 100644 --- a/src/leapfrogai_api/routers/base.py +++ b/src/leapfrogai_api/routers/base.py @@ -1,11 +1,18 @@ """Base router for the API.""" from fastapi import APIRouter +from fastapi.responses import RedirectResponse router = APIRouter(tags=["/"]) +@router.get("") +async def root(): + """Intercepts the root path and redirects to the API documentation.""" + return RedirectResponse(url="/redoc") + + @router.get("/healthz") async def healthz(): """Health check endpoint.""" From e85a9fd82389e58c0a47d4b563d94d350fe58cd7 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Mon, 30 Sep 2024 18:06:06 -0400 Subject: [PATCH 05/13] add excluded handlers and ungroup status codes --- src/leapfrogai_api/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index 0fdc65f1f..00140a8e3 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -60,7 +60,10 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) -Instrumentator().instrument(app).expose(app) +Instrumentator( + excluded_handlers=["/healthz", "/metrics"], + should_group_status_codes=False, +).instrument(app).expose(app) @app.exception_handler(RequestValidationError) From 2aa31268c5d5e4eeb549d54a811204a4dc34faea Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Mon, 30 Sep 2024 18:23:56 -0400 Subject: [PATCH 06/13] move intercepter back to main because errors --- src/leapfrogai_api/main.py | 8 ++++++++ src/leapfrogai_api/routers/base.py | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index 00140a8e3..9631aeb01 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -8,6 +8,7 @@ from fastapi import FastAPI from fastapi.exception_handlers import request_validation_exception_handler from fastapi.exceptions import RequestValidationError +from fastapi.responses import RedirectResponse from leapfrogai_api.routers.base import router as base_router from leapfrogai_api.routers.leapfrogai import auth from leapfrogai_api.routers.leapfrogai import models as lfai_models @@ -60,6 +61,13 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) + +@app.get("") +async def root(): + """Intercepts the root path and redirects to the API documentation.""" + return RedirectResponse(url="/redoc") + + Instrumentator( excluded_handlers=["/healthz", "/metrics"], should_group_status_codes=False, diff --git a/src/leapfrogai_api/routers/base.py b/src/leapfrogai_api/routers/base.py index 95951eb50..3b3f6d071 100644 --- a/src/leapfrogai_api/routers/base.py +++ b/src/leapfrogai_api/routers/base.py @@ -1,18 +1,10 @@ """Base router for the API.""" from fastapi import APIRouter -from fastapi.responses import RedirectResponse - router = APIRouter(tags=["/"]) -@router.get("") -async def root(): - """Intercepts the root path and redirects to the API documentation.""" - return RedirectResponse(url="/redoc") - - @router.get("/healthz") async def healthz(): """Health check endpoint.""" From b655c10d3f752b321f3d084881ea396012aaf137 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Wed, 2 Oct 2024 11:45:20 -0400 Subject: [PATCH 07/13] missing / --- src/leapfrogai_api/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index 9352e1ec0..83f28a035 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -63,7 +63,7 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) -@app.get("") +@app.get("/") async def root(): """Intercepts the root path and redirects to the API documentation.""" return RedirectResponse(url="/redoc") From 4c1e661a918cdc8ec54362c77067312982efaae9 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Wed, 2 Oct 2024 15:26:29 -0400 Subject: [PATCH 08/13] add auth policy for istio --- packages/api/chart/templates/istio-admin.yaml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/api/chart/templates/istio-admin.yaml diff --git a/packages/api/chart/templates/istio-admin.yaml b/packages/api/chart/templates/istio-admin.yaml new file mode 100644 index 000000000..c369e8786 --- /dev/null +++ b/packages/api/chart/templates/istio-admin.yaml @@ -0,0 +1,24 @@ +{{- if .Capabilities.APIVersions.Has "security.istio.io/v1beta1" }} +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: api-block-metrics-access-from-public-gateway + namespace: {{ .Release.Namespace }} +spec: + selector: + matchLabels: + {{- include "chart.selectorLabels" . | nindent 6 }} + action: DENY + rules: + - to: + - operation: + ports: + - "8080" + paths: + - /metrics* + from: + - source: + notNamespaces: + - istio-admin-gateway + - monitoring +{{- end }} From f33c21973d2cf564ce9791174c6345704f8f14e8 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Wed, 2 Oct 2024 16:22:32 -0400 Subject: [PATCH 09/13] change portname --- packages/api/chart/templates/uds-package.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/chart/templates/uds-package.yaml b/packages/api/chart/templates/uds-package.yaml index 6e4df8416..17220788d 100644 --- a/packages/api/chart/templates/uds-package.yaml +++ b/packages/api/chart/templates/uds-package.yaml @@ -8,7 +8,7 @@ metadata: {{- include "chart.labels" . | nindent 4 }} spec: monitor: - - portName: {{ include "chart.fullname" . }} + - portName: http targetPort: {{ .Values.api.service.port }} selector: {{- include "chart.selectorLabels" . | nindent 8 }} From 302ef4d2c59408ef8fbcb6b0760b1657fa1de8f4 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Wed, 2 Oct 2024 16:40:41 -0400 Subject: [PATCH 10/13] adding back whitespace --- src/leapfrogai_api/routers/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/leapfrogai_api/routers/base.py b/src/leapfrogai_api/routers/base.py index 3b3f6d071..58032a62c 100644 --- a/src/leapfrogai_api/routers/base.py +++ b/src/leapfrogai_api/routers/base.py @@ -2,6 +2,7 @@ from fastapi import APIRouter + router = APIRouter(tags=["/"]) From fbff15e235c4e29c9978e15bbc4e16d09c69a082 Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Wed, 2 Oct 2024 16:57:28 -0400 Subject: [PATCH 11/13] /docs instead of /redoc --- src/leapfrogai_api/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index 83f28a035..f6d692c90 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -66,7 +66,7 @@ async def lifespan(app: FastAPI): @app.get("/") async def root(): """Intercepts the root path and redirects to the API documentation.""" - return RedirectResponse(url="/redoc") + return RedirectResponse(url="/docs") Instrumentator( From 6dc7fb79a54d4fbc71bc07156582bc4f0a08bb2b Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Wed, 2 Oct 2024 16:59:59 -0400 Subject: [PATCH 12/13] remove base url redirect from schema --- src/leapfrogai_api/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index f6d692c90..35e45cfbe 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -63,7 +63,7 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) -@app.get("/") +@app.get("/", include_in_schema=False) async def root(): """Intercepts the root path and redirects to the API documentation.""" return RedirectResponse(url="/docs") From b1a0efc00df7deb5f28cb8424219bafdfa05eb9a Mon Sep 17 00:00:00 2001 From: Gregory Horvath Date: Wed, 2 Oct 2024 17:11:46 -0400 Subject: [PATCH 13/13] exlude metrics endpoint from schema --- src/leapfrogai_api/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/leapfrogai_api/main.py b/src/leapfrogai_api/main.py index 35e45cfbe..108ccd51e 100644 --- a/src/leapfrogai_api/main.py +++ b/src/leapfrogai_api/main.py @@ -72,7 +72,10 @@ async def root(): Instrumentator( excluded_handlers=["/healthz", "/metrics"], should_group_status_codes=False, -).instrument(app).expose(app) +).instrument(app).expose( + app, + include_in_schema=False, +) @app.exception_handler(RequestValidationError)