Skip to content

Commit

Permalink
Add new methods for the /status/filesystems endpoint (#88)
Browse files Browse the repository at this point in the history
* Add filesystems endpoint

* Add /filesystems/{system} endpoint

* Fix variable pop
  • Loading branch information
ekouts authored Feb 29, 2024
1 parent afdfdb6 commit a3752c7
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 0 deletions.
20 changes: 20 additions & 0 deletions firecrest/AsyncClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,26 @@ async def parameters(self) -> t.Parameters:
resp = await self._get_request(endpoint="/status/parameters")
return self._json_response([resp], 200)["out"]

async def filesystems(self, system_name: Optional[str] = None) -> dict[str, List[t.Filesystem]]:
"""Returns the status of the filesystems per system.
:param system_name: the system name
:calls: GET `/status/filesystems`
:calls: GET `/status/filesystems/{system_name}`
.. warning:: This is available only for FirecREST>=1.15.0
"""
if system_name:
resp = await self._get_request(endpoint=f"/status/filesystems/{system_name}")
# Return the result in the same structure
result = {
system_name: self._json_response([resp], 200)["out"]
}
return result
else:
resp = await self._get_request(endpoint="/status/filesystems")
return self._json_response([resp], 200)["out"]

# Utilities
async def list_files(
self, machine: str, target_path: str, show_hidden: bool = False
Expand Down
20 changes: 20 additions & 0 deletions firecrest/BasicClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,26 @@ def parameters(self) -> t.Parameters:
resp = self._get_request(endpoint="/status/parameters")
return self._json_response([resp], 200)["out"]

def filesystems(self, system_name: Optional[str] = None) -> dict[str, List[t.Filesystem]]:
"""Returns the status of the filesystems per system.
:param system_name: the system name
:calls: GET `/status/filesystems`
:calls: GET `/status/filesystems/{system_name}`
.. warning:: This is available only for FirecREST>=1.15.0
"""
if system_name:
resp = self._get_request(endpoint=f"/status/filesystems/{system_name}")
# Return the result in the same structure
result = {
system_name: self._json_response([resp], 200)["out"]
}
return result
else:
resp = self._get_request(endpoint="/status/filesystems")
return self._json_response([resp], 200)["out"]

# Utilities
def list_files(
self, machine: str, target_path: str, show_hidden: bool = False
Expand Down
29 changes: 29 additions & 0 deletions firecrest/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,35 @@ def parameters():
raise typer.Exit(code=1)


@app.command(rich_help_panel="Status commands")
def filesystems(
system: Optional[str] = typer.Option(
None,
"-s",
"--system",
help="The name of the system where the filesystems belongs to.",
envvar="FIRECREST_SYSTEM",
),
):
"""Information about the filesystems that are available through FirecREST"""
try:
result = client.filesystems(system)
for system in result.keys():
table = create_table(
f"Status of filesystems for `{system}`",
result[system],
("Name", "name"),
("Path", "path"),
("Status code", "status_code"),
("Status", "status"),
("Description", "description"),
)
console.print(table, overflow="fold")
except Exception as e:
examine_exeption(e)
raise typer.Exit(code=1)


@app.command(rich_help_panel="Status commands")
def tasks(
taskids: Optional[List[str]] = typer.Argument(
Expand Down
10 changes: 10 additions & 0 deletions firecrest/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ class System(TypedDict):
system: str


class Filesystem(TypedDict):
"""A filesystem record, from `status/filesystems`"""

name: str
path: str
description: str
status: int
status_code: str


class Task(TypedDict):
"""A task record, from `/tasks`"""

Expand Down
114 changes: 114 additions & 0 deletions tests/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import pytest
import re
import os
import test_authorisation as auth

from context import firecrest
Expand Down Expand Up @@ -60,6 +61,10 @@ def fc_server(httpserver):
parameters_handler
)

httpserver.expect_request(
re.compile("^/status/filesystems.*"), method="GET"
).respond_with_handler(filesystems_handler)

return httpserver


Expand Down Expand Up @@ -195,6 +200,49 @@ def parameters_handler(request: Request):
return Response(json.dumps(ret), status=200, content_type="application/json")


def filesystems_handler(request: Request):
if request.headers["Authorization"] != "Bearer VALID_TOKEN":
return Response(
json.dumps({"message": "Bad token; invalid JSON"}),
status=401,
content_type="application/json",
)

ret = {
"description": "Filesystem information",
"out": {
"cluster": [
{
"description": "Users home filesystem",
"name": "HOME",
"path": "/home",
"status": "available",
"status_code": 200
},
{
"description": "Scratch filesystem",
"name": "SCRATCH",
"path": "/scratch",
"status": "not available",
"status_code": 400
}
]
}
}
ret_status = 200
uri = request.url
if not uri.endswith("/status/filesystems"):
system = uri.split("/")[-1]
if system == "cluster":
ret["description"] = f"Filesystem information for system {system}"
ret["out"] = ret["out"][system]
else:
ret = {"description": f"System '{system}' does not exists."}
ret_status = 400

return Response(json.dumps(ret), status=ret_status, content_type="application/json")


def test_all_services(valid_client):
assert valid_client.all_services() == [
{
Expand Down Expand Up @@ -334,3 +382,69 @@ def test_cli_parameters(valid_credentials):
def test_parameters_invalid(invalid_client):
with pytest.raises(firecrest.UnauthorizedException):
invalid_client.parameters()


def test_filesystems(valid_client):
assert valid_client.filesystems() == {
"cluster": [
{
"description": "Users home filesystem",
"name": "HOME",
"path": "/home",
"status": "available",
"status_code": 200
},
{
"description": "Scratch filesystem",
"name": "SCRATCH",
"path": "/scratch",
"status": "not available",
"status_code": 400
}
]
}

assert valid_client.filesystems(system_name="cluster") == {
"cluster": [
{
"description": "Users home filesystem",
"name": "HOME",
"path": "/home",
"status": "available",
"status_code": 200
},
{
"description": "Scratch filesystem",
"name": "SCRATCH",
"path": "/scratch",
"status": "not available",
"status_code": 400
}
]
}


def test_cli_filesystems(valid_credentials):
# Clean up the env var that may be set in the environment
os.environ.pop("FIRECREST_SYSTEM", None)
args = valid_credentials + ["filesystems"]
result = runner.invoke(cli.app, args=args)
stdout = common.clean_stdout(result.stdout)
assert result.exit_code == 0
assert "Status of filesystems for `cluster`" in stdout

args = valid_credentials + ["filesystems", "--system", "cluster"]
result = runner.invoke(cli.app, args=args)
stdout = common.clean_stdout(result.stdout)
assert result.exit_code == 0
assert "Status of filesystems for `cluster`" in stdout

args = valid_credentials + ["filesystems", "--system", "invalid_cluster"]
result = runner.invoke(cli.app, args=args)
stdout = common.clean_stdout(result.stdout)
assert result.exit_code == 1


def test_filesystems_invalid(invalid_client):
with pytest.raises(firecrest.UnauthorizedException):
invalid_client.filesystems()
51 changes: 51 additions & 0 deletions tests/test_status_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ def fc_server(httpserver):
basic_status.parameters_handler
)

httpserver.expect_request(
re.compile("^/status/filesystems.*"), method="GET"
).respond_with_handler(basic_status.filesystems_handler)

return httpserver


Expand Down Expand Up @@ -167,3 +171,50 @@ async def test_parameters(valid_client):
async def test_parameters_invalid(invalid_client):
with pytest.raises(firecrest.UnauthorizedException):
await invalid_client.parameters()


@pytest.mark.asyncio
async def test_filesystems(valid_client):
assert await valid_client.filesystems() == {
"cluster": [
{
"description": "Users home filesystem",
"name": "HOME",
"path": "/home",
"status": "available",
"status_code": 200
},
{
"description": "Scratch filesystem",
"name": "SCRATCH",
"path": "/scratch",
"status": "not available",
"status_code": 400
}
]
}

assert await valid_client.filesystems(system_name="cluster") == {
"cluster": [
{
"description": "Users home filesystem",
"name": "HOME",
"path": "/home",
"status": "available",
"status_code": 200
},
{
"description": "Scratch filesystem",
"name": "SCRATCH",
"path": "/scratch",
"status": "not available",
"status_code": 400
}
]
}


@pytest.mark.asyncio
async def test_filesystems_invalid(invalid_client):
with pytest.raises(firecrest.UnauthorizedException):
await invalid_client.filesystems()

0 comments on commit a3752c7

Please sign in to comment.