From f7ea2622d0367fed0c666d243f171b60b81d6a72 Mon Sep 17 00:00:00 2001 From: Amith Murthy Date: Wed, 1 Jul 2026 16:05:19 -0700 Subject: [PATCH 1/2] changed the reporting of resources and their status definitions --- app/s3df/status_registry.py | 96 +++++++++++++------------- app/s3df/tests/test_status_adapter.py | 22 +++--- app/s3df/tests/test_status_registry.py | 37 ++++------ 3 files changed, 74 insertions(+), 81 deletions(-) diff --git a/app/s3df/status_registry.py b/app/s3df/status_registry.py index 8c4551d1..0588b942 100644 --- a/app/s3df/status_registry.py +++ b/app/s3df/status_registry.py @@ -32,81 +32,81 @@ class ResourceMeta: meta.id: meta for meta in ( ResourceMeta( - id="s3df-ssh-bastions", - name="SSH Bastions", - description="S3DF SSH bastion hosts for command-line access.", - group="access", - resource_type=status_models.ResourceType.service, + id="ada", + name="Batch (ada)", + description="S3DF Slurm batch partition for Ada GPU nodes.", + group="compute", + resource_type=status_models.ResourceType.compute, ), ResourceMeta( - id="s3df-interactive-nodes", - name="Interactive Nodes", - description="S3DF interactive login and analysis nodes.", + id="ampere", + name="Batch (ampere)", + description="S3DF Slurm batch partition for Ampere GPU nodes.", group="compute", resource_type=status_models.ResourceType.compute, ), ResourceMeta( - id="s3df-docs", - name="S3DF Docs", - description="S3DF user documentation site.", - group="documentation", - resource_type=status_models.ResourceType.website, + id="turing", + name="Batch (turing)", + description="S3DF Slurm batch partition for Turing GPU nodes.", + group="compute", + resource_type=status_models.ResourceType.compute, ), ResourceMeta( - id="s3df-batch-servers", - name="Batch Servers", - description="S3DF batch submission and scheduling servers.", + id="milano", + name="Batch (milano)", + description="S3DF Slurm batch partition for Milano CPU nodes.", group="compute", resource_type=status_models.ResourceType.compute, ), ResourceMeta( - id="s3df-slurm", - name="Slurm", - description="S3DF Slurm workload management service.", + id="torino", + name="Batch (torino)", + description="S3DF Slurm batch partition for Torino CPU nodes.", group="compute", - resource_type=status_models.ResourceType.service, + resource_type=status_models.ResourceType.compute, ), ResourceMeta( - id="s3df-monitoring", - name="Monitoring", - description="S3DF monitoring and observability services.", - group="operations", - resource_type=status_models.ResourceType.service, + id="roma", + name="Batch (roma)", + description="S3DF Slurm batch partition for Roma CPU nodes.", + group="compute", + resource_type=status_models.ResourceType.compute, ), ResourceMeta( - id="s3df-coact", - name="Coact", - description="S3DF Coact allocation and account service.", - group="accounts", - resource_type=status_models.ResourceType.service, + id="hopper", + name="Batch (hopper)", + description="S3DF Slurm batch partition for Hopper GPU nodes.", + group="compute", + resource_type=status_models.ResourceType.compute, ), ResourceMeta( - id="s3df-ondemand", - name="OnDemand", - description="S3DF Open OnDemand web service.", - group="access", - resource_type=status_models.ResourceType.website, + id="sdfhome", + name="Storage (sdfhome)", + description="S3DF Weka cluster for home directories (/sdf/home).", + group="storage", + resource_type=status_models.ResourceType.storage, ), ResourceMeta( - id="s3df-kubernetes", - name="Kubernetes", - description="S3DF Kubernetes platform.", - group="platform", - resource_type=status_models.ResourceType.system, + id="sdfdata", + name="Storage (sdfdata)", + description="S3DF Weka cluster for project/group data (sdfdata).", + group="storage", + resource_type=status_models.ResourceType.storage, ), ResourceMeta( - id="s3df-storage", - name="Storage", - description="S3DF storage services.", + id="sdfk8s", + name="Storage (sdfk8s)", + description="S3DF Weka cluster for Kubernetes persistent volumes (sdfk8s).", group="storage", resource_type=status_models.ResourceType.storage, ), ResourceMeta( - id="s3df-dtns", - name="DTNs", - description="S3DF data transfer nodes.", - group="data-transfer", - resource_type=status_models.ResourceType.network, + id="sdfscratch", + name="Storage (sdfscratch)", + description="S3DF Weka cluster for scratch storage (/sdf/scratch).", + group="storage", + resource_type=status_models.ResourceType.storage, ), ) } diff --git a/app/s3df/tests/test_status_adapter.py b/app/s3df/tests/test_status_adapter.py index e7199026..08ce5133 100644 --- a/app/s3df/tests/test_status_adapter.py +++ b/app/s3df/tests/test_status_adapter.py @@ -45,11 +45,11 @@ async def test_get_resources_merges_registry_and_status(monkeypatch): resources = await adapter.get_resources(offset=0, limit=100) assert len(resources) == len(S3DF_RESOURCES) by_id = {r.id: r for r in resources} - bastions = by_id["s3df-ssh-bastions"] - assert bastions.name == "SSH Bastions" - assert bastions.group == "access" - assert bastions.resource_type is status_models.ResourceType.service - assert bastions.current_status is status_models.Status.up + ada = by_id["ada"] + assert ada.name == "Batch (ada)" + assert ada.group == "compute" + assert ada.resource_type is status_models.ResourceType.compute + assert ada.current_status is status_models.Status.up @pytest.mark.asyncio @@ -57,15 +57,15 @@ async def test_get_resources_filter_by_group(monkeypatch): adapter, _ = _make_adapter(monkeypatch) resources = await adapter.get_resources(offset=0, limit=100, group="compute") ids = {r.id for r in resources} - assert ids == {"s3df-interactive-nodes", "s3df-batch-servers", "s3df-slurm"} + assert ids == {"ada", "ampere", "turing", "milano", "torino", "roma", "hopper"} @pytest.mark.asyncio async def test_get_resources_filter_by_current_status(monkeypatch): - payload = _statuses_payload({"s3df-storage": "down", "s3df-dtns": "degraded"}) + payload = _statuses_payload({"sdfhome": "down", "sdfdata": "degraded"}) adapter, _ = _make_adapter(monkeypatch, list_resources=payload) down = await adapter.get_resources(offset=0, limit=100, current_status=status_models.Status.down) - assert [r.id for r in down] == ["s3df-storage"] + assert [r.id for r in down] == ["sdfhome"] @pytest.mark.asyncio @@ -91,7 +91,7 @@ async def test_get_resource_unknown_returns_none(monkeypatch): async def test_get_resource_known_id(monkeypatch): async def get_resource(_id): return { - "resource_id": "s3df-coact", + "resource_id": "ada", "status": "degraded", "last_changed_at": "2026-06-01T12:00:00Z", "last_poll": "2026-06-01T12:00:00Z", @@ -101,9 +101,9 @@ async def get_resource(_id): adapter = S3DFStatusAdapter.__new__(S3DFStatusAdapter) adapter._client = AsyncMock() adapter._client.get_resource_status = AsyncMock(side_effect=get_resource) - res = await adapter.get_resource("s3df-coact") + res = await adapter.get_resource("ada") assert res is not None - assert res.id == "s3df-coact" + assert res.id == "ada" assert res.current_status is status_models.Status.degraded diff --git a/app/s3df/tests/test_status_registry.py b/app/s3df/tests/test_status_registry.py index 74612483..d3b534cb 100644 --- a/app/s3df/tests/test_status_registry.py +++ b/app/s3df/tests/test_status_registry.py @@ -5,17 +5,17 @@ EXPECTED_IDS = [ - "s3df-ssh-bastions", - "s3df-interactive-nodes", - "s3df-docs", - "s3df-batch-servers", - "s3df-slurm", - "s3df-monitoring", - "s3df-coact", - "s3df-ondemand", - "s3df-kubernetes", - "s3df-storage", - "s3df-dtns", + "ada", + "ampere", + "turing", + "milano", + "torino", + "roma", + "hopper", + "sdfhome", + "sdfdata", + "sdfk8s", + "sdfscratch", ] @@ -25,21 +25,14 @@ def test_registry_has_all_expected_resources(): def test_registry_resource_types_match_yaml(): by_id = S3DF_RESOURCES - assert by_id["s3df-ssh-bastions"].resource_type is status_models.ResourceType.service - assert by_id["s3df-interactive-nodes"].resource_type is status_models.ResourceType.compute - assert by_id["s3df-docs"].resource_type is status_models.ResourceType.website - assert by_id["s3df-storage"].resource_type is status_models.ResourceType.storage - assert by_id["s3df-kubernetes"].resource_type is status_models.ResourceType.system - assert by_id["s3df-dtns"].resource_type is status_models.ResourceType.network + assert by_id["ada"].resource_type is status_models.ResourceType.compute + assert by_id["sdfhome"].resource_type is status_models.ResourceType.storage def test_registry_groups_match_yaml(): by_id = S3DF_RESOURCES - assert by_id["s3df-ssh-bastions"].group == "access" - assert by_id["s3df-batch-servers"].group == "compute" - assert by_id["s3df-coact"].group == "accounts" - assert by_id["s3df-storage"].group == "storage" - assert by_id["s3df-dtns"].group == "data-transfer" + assert by_id["ada"].group == "compute" + assert by_id["sdfhome"].group == "storage" def test_parse_status_round_trip(): From 0c3f12a157f037f65b553a70708a1ef2a3619f97 Mon Sep 17 00:00:00 2001 From: Amith Murthy Date: Mon, 6 Jul 2026 15:45:10 -0700 Subject: [PATCH 2/2] adding logo to docs --- Makefile | 2 +- app/config.py | 2 +- {logo => app/logo}/SLAC_primary_red.png | Bin app/main.py | 6 ++++++ 4 files changed, 8 insertions(+), 2 deletions(-) rename {logo => app/logo}/SLAC_primary_red.png (100%) diff --git a/Makefile b/Makefile index 388ab2c4..5b8b5284 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ dev-s3df: deps # --- Docker / GHCR targets --- GHCR_USERNAME ?= slaclab GHCR_IMAGE ?= ghcr.io/$(GHCR_USERNAME)/iri-s3df -IMAGE_TAG ?= prod +IMAGE_TAG ?= dev docker-build: docker build --platform linux/amd64 -t $(GHCR_IMAGE):$(IMAGE_TAG) . diff --git a/app/config.py b/app/config.py index ebf176de..5f970fc1 100644 --- a/app/config.py +++ b/app/config.py @@ -17,7 +17,7 @@ - + """ # version is the openapi.json spec version diff --git a/logo/SLAC_primary_red.png b/app/logo/SLAC_primary_red.png similarity index 100% rename from logo/SLAC_primary_red.png rename to app/logo/SLAC_primary_red.png diff --git a/app/main.py b/app/main.py index 92c662c3..295f79ed 100644 --- a/app/main.py +++ b/app/main.py @@ -2,7 +2,9 @@ """Main API application""" import logging +from pathlib import Path from fastapi import FastAPI, Request +from fastapi.staticfiles import StaticFiles from opentelemetry import trace from starlette.middleware.base import BaseHTTPMiddleware from opentelemetry.sdk.resources import Resource @@ -50,6 +52,10 @@ app = FastAPI(servers=[{"url": config.API_URL_ROOT}], **config.API_CONFIG) +logo_dir = Path(__file__).resolve().parent / "logo" +if logo_dir.is_dir(): + app.mount("/logo", StaticFiles(directory=str(logo_dir)), name="logo") + class _ExternalRequestContextMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next):