sts-sponsors team mailing list archive
-
sts-sponsors team
-
Mailing list archive
-
Message #06966
[Merge] ~ack/maas-site-manager:site-stats into maas-site-manager:main
Alberto Donato has proposed merging ~ack/maas-site-manager:site-stats into maas-site-manager:main.
Commit message:
add site stats to listing API
Requested reviews:
MAAS Committers (maas-committers)
For more details, see:
https://code.launchpad.net/~ack/maas-site-manager/+git/site-manager/+merge/440941
--
Your team MAAS Committers is requested to review the proposed merge of ~ack/maas-site-manager:site-stats into maas-site-manager:main.
diff --git a/backend/msm/db/queries.py b/backend/msm/db/queries.py
index 222e2d3..3a35472 100644
--- a/backend/msm/db/queries.py
+++ b/backend/msm/db/queries.py
@@ -1,5 +1,3 @@
-from __future__ import annotations
-
from collections.abc import Iterable
from datetime import (
datetime,
@@ -9,13 +7,14 @@ from typing import (
Any,
Sequence,
Type,
- TYPE_CHECKING,
TypeVar,
)
from uuid import UUID
from sqlalchemy import (
+ case,
func,
+ Operators,
Row,
select,
Table,
@@ -29,12 +28,10 @@ from ..schema import (
)
from ._tables import (
Site,
+ SiteData,
Token,
)
-if TYPE_CHECKING:
- from sqlalchemy import Operators
-
def filters_from_arguments(
table: Table,
@@ -131,8 +128,28 @@ async def get_filtered_sites(
Site.c.street,
Site.c.timezone,
Site.c.url,
+ case(
+ (
+ SiteData.c.site_id != None, # noqa: E711
+ func.json_build_object(
+ "allocated_machines",
+ SiteData.c.allocated_machines,
+ "deployed_machines",
+ SiteData.c.deployed_machines,
+ "ready_machines",
+ SiteData.c.ready_machines,
+ "error_machines",
+ SiteData.c.error_machines,
+ "last_seen",
+ SiteData.c.last_seen,
+ ),
+ ),
+ else_=None,
+ ).label("stats"),
+ )
+ .select_from(
+ Site.join(SiteData, SiteData.c.site_id == Site.c.id, isouter=True)
)
- .select_from(Site)
.limit(limit)
.offset(offset)
)
diff --git a/backend/msm/schema.py b/backend/msm/schema.py
index d57933f..69c4a66 100644
--- a/backend/msm/schema.py
+++ b/backend/msm/schema.py
@@ -61,20 +61,9 @@ class CreateSite(BaseModel):
# TODO: we will need to add tags
-class Site(CreateSite):
- """
- Site persisted to the database
- """
+class SiteData(BaseModel):
+ """Data for a site"""
- id: int
-
-
-class CreateSiteData(BaseModel):
- """
- All SiteData is obligatory
- """
-
- site_id: int
allocated_machines: int
deployed_machines: int
ready_machines: int
@@ -82,12 +71,19 @@ class CreateSiteData(BaseModel):
last_seen: datetime
-class SiteData(CreateSiteData):
+class Site(CreateSite):
"""
- SiteData persisted to the database
+ Site persisted to the database
"""
id: int
+ stats: SiteData | None
+
+
+class CreateSiteData(SiteData):
+ """Site data"""
+
+ site_id: int
class PaginatedSites(PaginatedResults):
diff --git a/backend/tests/user_api/test_handlers.py b/backend/tests/user_api/test_handlers.py
index f2cace2..0a60ee4 100644
--- a/backend/tests/user_api/test_handlers.py
+++ b/backend/tests/user_api/test_handlers.py
@@ -2,6 +2,7 @@ from datetime import (
datetime,
timedelta,
)
+from typing import Any
# from fastapi.testclient import TestClient
from httpx import AsyncClient
@@ -51,6 +52,7 @@ async def test_list_sites(
"longitude": "-0.118092",
"note": "the first site",
"region": "Blue Fin Bldg",
+ "stats": None,
"street": "110 Southwark St",
"timezone": "0.00",
"url": "https://londoncalling.example.com",
@@ -89,6 +91,51 @@ async def test_list_sites(
@pytest.mark.asyncio
+async def test_list_sites_with_stats(
+ user_app_client: AsyncClient, fixture: Fixture
+) -> None:
+ site: dict[str, Any] = {
+ "name": "LondonHQ",
+ "city": "London",
+ "country": "gb",
+ "latitude": "51.509865",
+ "longitude": "-0.118092",
+ "note": "the first site",
+ "region": "Blue Fin Bldg",
+ "street": "110 Southwark St",
+ "timezone": "0.00",
+ "url": "https://londoncalling.example.com",
+ }
+ await fixture.create("site", [site])
+ last_seen = datetime.utcnow()
+ site_data = {
+ "site_id": 1,
+ "allocated_machines": 10,
+ "deployed_machines": 20,
+ "ready_machines": 30,
+ "error_machines": 40,
+ "last_seen": last_seen,
+ }
+ await fixture.create("site_data", [site_data])
+ del site_data["site_id"]
+ site_data["last_seen"] = last_seen.isoformat()
+ site.update(
+ {
+ "id": 1,
+ "stats": site_data,
+ }
+ )
+ page = await user_app_client.get("/sites")
+ assert page.status_code == 200
+ assert page.json() == {
+ "page": 1,
+ "size": 20,
+ "total": 1,
+ "items": [site],
+ }
+
+
+@pytest.mark.asyncio
@pytest.mark.parametrize("time_format", ["ISO 8601", "Float"])
async def test_token_time_format(
time_format: str, user_app_client: AsyncClient
Follow ups