diff --git a/pyproject.toml b/pyproject.toml index c75d9a0..97b3c09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,6 +176,9 @@ select = ["ALL"] "SLF001", # tests are allowed to access private members "T201", # tests are allowed to use print ] +"src/noteburst/worker/main.py" = [ + "PLR0915", # along a long function +] [tool.ruff.lint.isort] known-first-party = ["noteburst", "tests"] diff --git a/src/noteburst/jupyterclient/jupyterlab.py b/src/noteburst/jupyterclient/jupyterlab.py index 8399b5a..f74f903 100644 --- a/src/noteburst/jupyterclient/jupyterlab.py +++ b/src/noteburst/jupyterclient/jupyterlab.py @@ -16,7 +16,7 @@ import websockets from httpx import Cookies, Timeout from pydantic import BaseModel, Field -from structlog import BoundLogger +from structlog.stdlib import BoundLogger from websockets.client import WebSocketClientProtocol from websockets.exceptions import WebSocketException from websockets.typing import Data as WebsocketData @@ -442,6 +442,7 @@ def lab_controller(self) -> LabControllerClient: http_client=self.http_client, token=noteburst_config.gafaelfawr_token.get_secret_value(), url_prefix=noteburst_config.nublado_controller_path_prefix, + logger=self.logger, ) return self._lab_controller_client diff --git a/src/noteburst/jupyterclient/labcontroller.py b/src/noteburst/jupyterclient/labcontroller.py index 79365a8..e99d6cd 100644 --- a/src/noteburst/jupyterclient/labcontroller.py +++ b/src/noteburst/jupyterclient/labcontroller.py @@ -7,6 +7,7 @@ import httpx from pydantic import BaseModel, ConfigDict, Field +from structlog.stdlib import BoundLogger from noteburst.config import config @@ -95,7 +96,9 @@ class LabControllerImages(BaseModel): ) """Pydantic model configuration.""" - def get_by_reference(self, reference: str) -> JupyterImage | None: + def get_by_reference( + self, reference: str, logger: BoundLogger + ) -> JupyterImage | None: """Get the JupyterImage with a corresponding reference. Parameters @@ -109,6 +112,7 @@ def get_by_reference(self, reference: str) -> JupyterImage | None: Returns the JupyterImage if found, None otherwise. """ for image in self.all: + logger.info("Image reference", image=image.reference) if reference == image.reference: return image @@ -142,10 +146,12 @@ def __init__( http_client: httpx.AsyncClient, token: str, url_prefix: str, + logger: BoundLogger, ) -> None: self._http_client = http_client self._token = token self._url_prefix = url_prefix + self._logger = logger async def get_latest_weekly(self) -> JupyterImage: """Image for the latest weekly version. @@ -200,7 +206,7 @@ async def get_by_reference(self, reference: str) -> JupyterImage: An error occurred talking to JupyterLab Controller. """ images = await self._get_images() - image = images.get_by_reference(reference) + image = images.get_by_reference(reference, logger=self._logger) if image is None: raise LabControllerError( f"No image with reference {reference} found." diff --git a/src/noteburst/jupyterclient/user.py b/src/noteburst/jupyterclient/user.py index 51bc8f2..23737ed 100644 --- a/src/noteburst/jupyterclient/user.py +++ b/src/noteburst/jupyterclient/user.py @@ -98,7 +98,6 @@ async def create( "username": username, "name": "Noteburst", "token_type": "service", - "token_name": f"noteburst {float(time.time())!s}", "scopes": scopes, "expires": int(time.time() + lifetime), } diff --git a/src/noteburst/worker/main.py b/src/noteburst/worker/main.py index 1f9e12a..3d73d2a 100644 --- a/src/noteburst/worker/main.py +++ b/src/noteburst/worker/main.py @@ -73,17 +73,35 @@ async def startup(ctx: dict[Any, Any]) -> None: user = User( username=identity.username, uid=identity.uid, gid=identity.gid ) - authed_user = await user.login( - scopes=config.parsed_worker_token_scopes, - http_client=http_client, - token_lifetime=config.worker_token_lifetime, - ) + try: + authed_user = await user.login( + scopes=config.parsed_worker_token_scopes, + http_client=http_client, + token_lifetime=config.worker_token_lifetime, + ) + except httpx.HTTPStatusError as e: + logger.exception( + "Error authenticating the worker's user", + body=e.response.json(), + status_code=e.response.status_code, + ) + raise logger.info("Authenticated the worker's user.") jupyter_client = JupyterClient( user=authed_user, logger=logger, config=jupyter_config ) - await jupyter_client.log_into_hub() + try: + await jupyter_client.log_into_hub() + except httpx.HTTPStatusError as e: + logger.exception( + "Error logging into JupyterHub", + body=e.response.json(), + ) + raise + except Exception: + logger.exception("Generic error logging into JupyterHub") + raise try: image_info = await jupyter_client.spawn_lab() logger = logger.bind(image_ref=image_info.reference) diff --git a/tests/support/gafaelfawr.py b/tests/support/gafaelfawr.py index 2a31b17..2d854bd 100644 --- a/tests/support/gafaelfawr.py +++ b/tests/support/gafaelfawr.py @@ -56,7 +56,6 @@ def handler(request: httpx.Request) -> httpx.Response: assert request_json == { "username": ANY, "token_type": "service", - "token_name": ANY, "scopes": ["exec:notebook"], "expires": ANY, "name": "Noteburst", @@ -69,7 +68,6 @@ def handler(request: httpx.Request) -> httpx.Response: assert request_json["uid"] == uid if gid: assert request_json["gid"] == gid - assert request_json["token_name"].startswith("noteburst ") assert request_json["expires"] > time.time() response = {"token": make_gafaelfawr_token(request_json["username"])} return httpx.Response(200, json=response, request=request)