pyfirecrest 2.2.1__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/.github/workflows/testing.yml +1 -1
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/PKG-INFO +1 -1
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/AsyncClient.py +37 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/AsyncExternalStorage.py +2 -2
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/BasicClient.py +74 -29
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/__init__.py +1 -1
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/cli/__init__.py +57 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/types.py +23 -0
- pyfirecrest-2.3.0/firecrest/utilities.py +11 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_status.py +114 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_status_async.py +51 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_utilities.py +48 -1
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_utilities_async.py +22 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/.github/workflows/python-publish.yml +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/.gitignore +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/.readthedocs.yml +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/LICENSE +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/README.md +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/async-example.md +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/Makefile +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/authorization.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/conf.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/index.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/reference_async.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/reference_basic.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/reference_cli.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/reference_index.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/tutorial_async.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/tutorial_basic.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/tutorial_cli.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/tutorial_errors.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/tutorial_index.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/docs/source/tutorial_logging.rst +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/Authorization.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/ExternalStorage.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/FirecrestException.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/cli_script.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/path.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/firecrest/py.typed +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/pyproject.toml +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/common.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/context.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_authorisation.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_compute.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_compute_async.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_extras.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_extras_async.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_reservation.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_reservation_async.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_storage.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tests/test_storage_async.py +0 -0
- {pyfirecrest-2.2.1 → pyfirecrest-2.3.0}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyfirecrest
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: pyFirecrest is a python wrapper for FirecREST
|
|
5
5
|
Author: CSCS Swiss National Supercomputing Center
|
|
6
6
|
Maintainer-email: Eirini Koutsaniti <eirini.koutsaniti@cscs.ch>, Juan Pablo Dorsch <juanpablo.dorsch@cscs.ch>
|
|
@@ -26,6 +26,7 @@ from packaging.version import Version, parse
|
|
|
26
26
|
import firecrest.FirecrestException as fe
|
|
27
27
|
import firecrest.types as t
|
|
28
28
|
from firecrest.AsyncExternalStorage import AsyncExternalUpload, AsyncExternalDownload
|
|
29
|
+
from firecrest.utilities import time_block
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
if sys.version_info >= (3, 8):
|
|
@@ -589,6 +590,26 @@ class AsyncFirecrest:
|
|
|
589
590
|
resp = await self._get_request(endpoint="/status/parameters")
|
|
590
591
|
return self._json_response([resp], 200)["out"]
|
|
591
592
|
|
|
593
|
+
async def filesystems(self, system_name: Optional[str] = None) -> dict[str, List[t.Filesystem]]:
|
|
594
|
+
"""Returns the status of the filesystems per system.
|
|
595
|
+
|
|
596
|
+
:param system_name: the system name
|
|
597
|
+
:calls: GET `/status/filesystems`
|
|
598
|
+
:calls: GET `/status/filesystems/{system_name}`
|
|
599
|
+
|
|
600
|
+
.. warning:: This is available only for FirecREST>=1.15.0
|
|
601
|
+
"""
|
|
602
|
+
if system_name:
|
|
603
|
+
resp = await self._get_request(endpoint=f"/status/filesystems/{system_name}")
|
|
604
|
+
# Return the result in the same structure
|
|
605
|
+
result = {
|
|
606
|
+
system_name: self._json_response([resp], 200)["out"]
|
|
607
|
+
}
|
|
608
|
+
return result
|
|
609
|
+
else:
|
|
610
|
+
resp = await self._get_request(endpoint="/status/filesystems")
|
|
611
|
+
return self._json_response([resp], 200)["out"]
|
|
612
|
+
|
|
592
613
|
# Utilities
|
|
593
614
|
async def list_files(
|
|
594
615
|
self, machine: str, target_path: str, show_hidden: bool = False
|
|
@@ -973,6 +994,22 @@ class AsyncFirecrest:
|
|
|
973
994
|
# Invalid token, cannot retrieve username
|
|
974
995
|
return None
|
|
975
996
|
|
|
997
|
+
async def groups(self, machine) -> t.UserId:
|
|
998
|
+
"""Returns the output of the `id` command, user and group ids.
|
|
999
|
+
|
|
1000
|
+
:calls: GET `/utilities/whoami`
|
|
1001
|
+
|
|
1002
|
+
.. warning:: This is available only for FirecREST>=1.15.0
|
|
1003
|
+
"""
|
|
1004
|
+
resp = await self._get_request(
|
|
1005
|
+
endpoint="/utilities/whoami",
|
|
1006
|
+
additional_headers={"X-Machine-Name": machine},
|
|
1007
|
+
params={
|
|
1008
|
+
"groups": True
|
|
1009
|
+
}
|
|
1010
|
+
)
|
|
1011
|
+
return self._json_response([resp], 200)["output"]
|
|
1012
|
+
|
|
976
1013
|
# Compute
|
|
977
1014
|
async def submit(
|
|
978
1015
|
self,
|
|
@@ -229,7 +229,7 @@ class AsyncExternalDownload(AsyncExternalStorage):
|
|
|
229
229
|
:calls: GET `/tasks/{taskid}`
|
|
230
230
|
"""
|
|
231
231
|
if self._client._api_version > Version("1.13.0"):
|
|
232
|
-
return await self.object_storage_data["url"]
|
|
232
|
+
return (await self.object_storage_data)["url"]
|
|
233
233
|
else:
|
|
234
234
|
return await self.object_storage_data
|
|
235
235
|
|
|
@@ -240,7 +240,7 @@ class AsyncExternalDownload(AsyncExternalStorage):
|
|
|
240
240
|
|
|
241
241
|
:param target_path: the local path to save the file
|
|
242
242
|
"""
|
|
243
|
-
url = await self.
|
|
243
|
+
url = await self.object_storage_link
|
|
244
244
|
logger.info(f"Downloading the file from {url} and saving to {target_path}")
|
|
245
245
|
# LOCAL FIX FOR MAC
|
|
246
246
|
# url = url.replace("192.168.220.19", "localhost")
|
|
@@ -25,6 +25,7 @@ from packaging.version import Version, parse
|
|
|
25
25
|
import firecrest.FirecrestException as fe
|
|
26
26
|
import firecrest.types as t
|
|
27
27
|
from firecrest.ExternalStorage import ExternalUpload, ExternalDownload
|
|
28
|
+
from firecrest.utilities import time_block
|
|
28
29
|
|
|
29
30
|
if sys.version_info >= (3, 8):
|
|
30
31
|
from typing import Literal
|
|
@@ -157,13 +158,15 @@ class Firecrest:
|
|
|
157
158
|
headers.update(additional_headers)
|
|
158
159
|
|
|
159
160
|
logger.info(f"Making GET request to {endpoint}")
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
with time_block(f"GET request to {endpoint}", logger):
|
|
162
|
+
resp = self._session.get(
|
|
163
|
+
url=url,
|
|
164
|
+
headers=headers,
|
|
165
|
+
params=params,
|
|
166
|
+
verify=self._verify,
|
|
167
|
+
timeout=self.timeout,
|
|
168
|
+
)
|
|
169
|
+
|
|
167
170
|
return resp
|
|
168
171
|
|
|
169
172
|
@_retry_requests # type: ignore
|
|
@@ -176,14 +179,16 @@ class Firecrest:
|
|
|
176
179
|
headers.update(additional_headers)
|
|
177
180
|
|
|
178
181
|
logger.info(f"Making POST request to {endpoint}")
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
182
|
+
with time_block(f"POST request to {endpoint}", logger):
|
|
183
|
+
resp = self._session.post(
|
|
184
|
+
url=url,
|
|
185
|
+
headers=headers,
|
|
186
|
+
data=data,
|
|
187
|
+
files=files,
|
|
188
|
+
verify=self._verify,
|
|
189
|
+
timeout=self.timeout,
|
|
190
|
+
)
|
|
191
|
+
|
|
187
192
|
return resp
|
|
188
193
|
|
|
189
194
|
@_retry_requests # type: ignore
|
|
@@ -196,13 +201,15 @@ class Firecrest:
|
|
|
196
201
|
headers.update(additional_headers)
|
|
197
202
|
|
|
198
203
|
logger.info(f"Making PUT request to {endpoint}")
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
with time_block(f"PUT request to {endpoint}", logger):
|
|
205
|
+
resp = self._session.put(
|
|
206
|
+
url=url,
|
|
207
|
+
headers=headers,
|
|
208
|
+
data=data,
|
|
209
|
+
verify=self._verify,
|
|
210
|
+
timeout=self.timeout,
|
|
211
|
+
)
|
|
212
|
+
|
|
206
213
|
return resp
|
|
207
214
|
|
|
208
215
|
@_retry_requests # type: ignore
|
|
@@ -215,13 +222,15 @@ class Firecrest:
|
|
|
215
222
|
headers.update(additional_headers)
|
|
216
223
|
|
|
217
224
|
logger.info(f"Making DELETE request to {endpoint}")
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
+
with time_block(f"DELETE request to {endpoint}", logger):
|
|
226
|
+
resp = self._session.delete(
|
|
227
|
+
url=url,
|
|
228
|
+
headers=headers,
|
|
229
|
+
data=data,
|
|
230
|
+
verify=self._verify,
|
|
231
|
+
timeout=self.timeout,
|
|
232
|
+
)
|
|
233
|
+
|
|
225
234
|
return resp
|
|
226
235
|
|
|
227
236
|
@overload
|
|
@@ -417,6 +426,26 @@ class Firecrest:
|
|
|
417
426
|
resp = self._get_request(endpoint="/status/parameters")
|
|
418
427
|
return self._json_response([resp], 200)["out"]
|
|
419
428
|
|
|
429
|
+
def filesystems(self, system_name: Optional[str] = None) -> dict[str, List[t.Filesystem]]:
|
|
430
|
+
"""Returns the status of the filesystems per system.
|
|
431
|
+
|
|
432
|
+
:param system_name: the system name
|
|
433
|
+
:calls: GET `/status/filesystems`
|
|
434
|
+
:calls: GET `/status/filesystems/{system_name}`
|
|
435
|
+
|
|
436
|
+
.. warning:: This is available only for FirecREST>=1.15.0
|
|
437
|
+
"""
|
|
438
|
+
if system_name:
|
|
439
|
+
resp = self._get_request(endpoint=f"/status/filesystems/{system_name}")
|
|
440
|
+
# Return the result in the same structure
|
|
441
|
+
result = {
|
|
442
|
+
system_name: self._json_response([resp], 200)["out"]
|
|
443
|
+
}
|
|
444
|
+
return result
|
|
445
|
+
else:
|
|
446
|
+
resp = self._get_request(endpoint="/status/filesystems")
|
|
447
|
+
return self._json_response([resp], 200)["out"]
|
|
448
|
+
|
|
420
449
|
# Utilities
|
|
421
450
|
def list_files(
|
|
422
451
|
self, machine: str, target_path: str, show_hidden: bool = False
|
|
@@ -799,6 +828,22 @@ class Firecrest:
|
|
|
799
828
|
# Invalid token, cannot retrieve username
|
|
800
829
|
return None
|
|
801
830
|
|
|
831
|
+
def groups(self, machine) -> t.UserId:
|
|
832
|
+
"""Returns the output of the `id` command, user and group ids.
|
|
833
|
+
|
|
834
|
+
:calls: GET `/utilities/whoami`
|
|
835
|
+
|
|
836
|
+
.. warning:: This is available only for FirecREST>=1.15.0
|
|
837
|
+
"""
|
|
838
|
+
resp = self._get_request(
|
|
839
|
+
endpoint="/utilities/whoami",
|
|
840
|
+
additional_headers={"X-Machine-Name": machine},
|
|
841
|
+
params={
|
|
842
|
+
"groups": True
|
|
843
|
+
}
|
|
844
|
+
)
|
|
845
|
+
return self._json_response([resp], 200)["output"]
|
|
846
|
+
|
|
802
847
|
# Compute
|
|
803
848
|
def _submit_request(self, machine: str, job_script, local_file, account=None, env_vars=None):
|
|
804
849
|
data = {}
|
|
@@ -207,6 +207,35 @@ def parameters():
|
|
|
207
207
|
raise typer.Exit(code=1)
|
|
208
208
|
|
|
209
209
|
|
|
210
|
+
@app.command(rich_help_panel="Status commands")
|
|
211
|
+
def filesystems(
|
|
212
|
+
system: Optional[str] = typer.Option(
|
|
213
|
+
None,
|
|
214
|
+
"-s",
|
|
215
|
+
"--system",
|
|
216
|
+
help="The name of the system where the filesystems belongs to.",
|
|
217
|
+
envvar="FIRECREST_SYSTEM",
|
|
218
|
+
),
|
|
219
|
+
):
|
|
220
|
+
"""Information about the filesystems that are available through FirecREST"""
|
|
221
|
+
try:
|
|
222
|
+
result = client.filesystems(system)
|
|
223
|
+
for system in result.keys():
|
|
224
|
+
table = create_table(
|
|
225
|
+
f"Status of filesystems for `{system}`",
|
|
226
|
+
result[system],
|
|
227
|
+
("Name", "name"),
|
|
228
|
+
("Path", "path"),
|
|
229
|
+
("Status code", "status_code"),
|
|
230
|
+
("Status", "status"),
|
|
231
|
+
("Description", "description"),
|
|
232
|
+
)
|
|
233
|
+
console.print(table, overflow="fold")
|
|
234
|
+
except Exception as e:
|
|
235
|
+
examine_exeption(e)
|
|
236
|
+
raise typer.Exit(code=1)
|
|
237
|
+
|
|
238
|
+
|
|
210
239
|
@app.command(rich_help_panel="Status commands")
|
|
211
240
|
def tasks(
|
|
212
241
|
taskids: Optional[List[str]] = typer.Argument(
|
|
@@ -769,6 +798,34 @@ def whoami(
|
|
|
769
798
|
raise typer.Exit(code=1)
|
|
770
799
|
|
|
771
800
|
|
|
801
|
+
@app.command(rich_help_panel="Utilities commands")
|
|
802
|
+
def id(
|
|
803
|
+
config_from_parent: str = typer.Option(None,
|
|
804
|
+
callback=config_parent_load_callback,
|
|
805
|
+
is_eager=True,
|
|
806
|
+
hidden=True
|
|
807
|
+
),
|
|
808
|
+
system: str = typer.Option(
|
|
809
|
+
None,
|
|
810
|
+
"-s",
|
|
811
|
+
"--system",
|
|
812
|
+
help="The name of the system where the `id` command will run.",
|
|
813
|
+
envvar="FIRECREST_SYSTEM",
|
|
814
|
+
),
|
|
815
|
+
):
|
|
816
|
+
"""Return the identity of the user in the remote system.
|
|
817
|
+
"""
|
|
818
|
+
try:
|
|
819
|
+
result = client.groups(system)
|
|
820
|
+
user = f"{result['user']['id']}({result['user']['name']})"
|
|
821
|
+
group = f"{result['group']['id']}({result['group']['name']})"
|
|
822
|
+
all_groups = ",".join([f"{g['id']}({g['name']})" for g in result["groups"]])
|
|
823
|
+
console.print(f"uid={user} gid={group} groups={all_groups}")
|
|
824
|
+
except Exception as e:
|
|
825
|
+
examine_exeption(e)
|
|
826
|
+
raise typer.Exit(code=1)
|
|
827
|
+
|
|
828
|
+
|
|
772
829
|
class TransferType(str, Enum):
|
|
773
830
|
direct = "direct"
|
|
774
831
|
external = "external"
|
|
@@ -46,6 +46,16 @@ class System(TypedDict):
|
|
|
46
46
|
system: str
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
class Filesystem(TypedDict):
|
|
50
|
+
"""A filesystem record, from `status/filesystems`"""
|
|
51
|
+
|
|
52
|
+
name: str
|
|
53
|
+
path: str
|
|
54
|
+
description: str
|
|
55
|
+
status: int
|
|
56
|
+
status_code: str
|
|
57
|
+
|
|
58
|
+
|
|
49
59
|
class Task(TypedDict):
|
|
50
60
|
"""A task record, from `/tasks`"""
|
|
51
61
|
|
|
@@ -140,3 +150,16 @@ class JobSubmit(TypedDict):
|
|
|
140
150
|
job_file_out: str
|
|
141
151
|
jobid: int
|
|
142
152
|
result: str
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class Id(TypedDict):
|
|
156
|
+
name: str
|
|
157
|
+
id: str
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class UserId(TypedDict):
|
|
161
|
+
"""A record from the `id` command"""
|
|
162
|
+
|
|
163
|
+
user: Id
|
|
164
|
+
group: Id
|
|
165
|
+
groups: list[Id]
|
|
@@ -2,6 +2,7 @@ import common
|
|
|
2
2
|
import json
|
|
3
3
|
import pytest
|
|
4
4
|
import re
|
|
5
|
+
import os
|
|
5
6
|
import test_authorisation as auth
|
|
6
7
|
|
|
7
8
|
from context import firecrest
|
|
@@ -60,6 +61,10 @@ def fc_server(httpserver):
|
|
|
60
61
|
parameters_handler
|
|
61
62
|
)
|
|
62
63
|
|
|
64
|
+
httpserver.expect_request(
|
|
65
|
+
re.compile("^/status/filesystems.*"), method="GET"
|
|
66
|
+
).respond_with_handler(filesystems_handler)
|
|
67
|
+
|
|
63
68
|
return httpserver
|
|
64
69
|
|
|
65
70
|
|
|
@@ -195,6 +200,49 @@ def parameters_handler(request: Request):
|
|
|
195
200
|
return Response(json.dumps(ret), status=200, content_type="application/json")
|
|
196
201
|
|
|
197
202
|
|
|
203
|
+
def filesystems_handler(request: Request):
|
|
204
|
+
if request.headers["Authorization"] != "Bearer VALID_TOKEN":
|
|
205
|
+
return Response(
|
|
206
|
+
json.dumps({"message": "Bad token; invalid JSON"}),
|
|
207
|
+
status=401,
|
|
208
|
+
content_type="application/json",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
ret = {
|
|
212
|
+
"description": "Filesystem information",
|
|
213
|
+
"out": {
|
|
214
|
+
"cluster": [
|
|
215
|
+
{
|
|
216
|
+
"description": "Users home filesystem",
|
|
217
|
+
"name": "HOME",
|
|
218
|
+
"path": "/home",
|
|
219
|
+
"status": "available",
|
|
220
|
+
"status_code": 200
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"description": "Scratch filesystem",
|
|
224
|
+
"name": "SCRATCH",
|
|
225
|
+
"path": "/scratch",
|
|
226
|
+
"status": "not available",
|
|
227
|
+
"status_code": 400
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
ret_status = 200
|
|
233
|
+
uri = request.url
|
|
234
|
+
if not uri.endswith("/status/filesystems"):
|
|
235
|
+
system = uri.split("/")[-1]
|
|
236
|
+
if system == "cluster":
|
|
237
|
+
ret["description"] = f"Filesystem information for system {system}"
|
|
238
|
+
ret["out"] = ret["out"][system]
|
|
239
|
+
else:
|
|
240
|
+
ret = {"description": f"System '{system}' does not exists."}
|
|
241
|
+
ret_status = 400
|
|
242
|
+
|
|
243
|
+
return Response(json.dumps(ret), status=ret_status, content_type="application/json")
|
|
244
|
+
|
|
245
|
+
|
|
198
246
|
def test_all_services(valid_client):
|
|
199
247
|
assert valid_client.all_services() == [
|
|
200
248
|
{
|
|
@@ -334,3 +382,69 @@ def test_cli_parameters(valid_credentials):
|
|
|
334
382
|
def test_parameters_invalid(invalid_client):
|
|
335
383
|
with pytest.raises(firecrest.UnauthorizedException):
|
|
336
384
|
invalid_client.parameters()
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def test_filesystems(valid_client):
|
|
388
|
+
assert valid_client.filesystems() == {
|
|
389
|
+
"cluster": [
|
|
390
|
+
{
|
|
391
|
+
"description": "Users home filesystem",
|
|
392
|
+
"name": "HOME",
|
|
393
|
+
"path": "/home",
|
|
394
|
+
"status": "available",
|
|
395
|
+
"status_code": 200
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"description": "Scratch filesystem",
|
|
399
|
+
"name": "SCRATCH",
|
|
400
|
+
"path": "/scratch",
|
|
401
|
+
"status": "not available",
|
|
402
|
+
"status_code": 400
|
|
403
|
+
}
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
assert valid_client.filesystems(system_name="cluster") == {
|
|
408
|
+
"cluster": [
|
|
409
|
+
{
|
|
410
|
+
"description": "Users home filesystem",
|
|
411
|
+
"name": "HOME",
|
|
412
|
+
"path": "/home",
|
|
413
|
+
"status": "available",
|
|
414
|
+
"status_code": 200
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"description": "Scratch filesystem",
|
|
418
|
+
"name": "SCRATCH",
|
|
419
|
+
"path": "/scratch",
|
|
420
|
+
"status": "not available",
|
|
421
|
+
"status_code": 400
|
|
422
|
+
}
|
|
423
|
+
]
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def test_cli_filesystems(valid_credentials):
|
|
428
|
+
# Clean up the env var that may be set in the environment
|
|
429
|
+
os.environ.pop("FIRECREST_SYSTEM", None)
|
|
430
|
+
args = valid_credentials + ["filesystems"]
|
|
431
|
+
result = runner.invoke(cli.app, args=args)
|
|
432
|
+
stdout = common.clean_stdout(result.stdout)
|
|
433
|
+
assert result.exit_code == 0
|
|
434
|
+
assert "Status of filesystems for `cluster`" in stdout
|
|
435
|
+
|
|
436
|
+
args = valid_credentials + ["filesystems", "--system", "cluster"]
|
|
437
|
+
result = runner.invoke(cli.app, args=args)
|
|
438
|
+
stdout = common.clean_stdout(result.stdout)
|
|
439
|
+
assert result.exit_code == 0
|
|
440
|
+
assert "Status of filesystems for `cluster`" in stdout
|
|
441
|
+
|
|
442
|
+
args = valid_credentials + ["filesystems", "--system", "invalid_cluster"]
|
|
443
|
+
result = runner.invoke(cli.app, args=args)
|
|
444
|
+
stdout = common.clean_stdout(result.stdout)
|
|
445
|
+
assert result.exit_code == 1
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def test_filesystems_invalid(invalid_client):
|
|
449
|
+
with pytest.raises(firecrest.UnauthorizedException):
|
|
450
|
+
invalid_client.filesystems()
|
|
@@ -62,6 +62,10 @@ def fc_server(httpserver):
|
|
|
62
62
|
basic_status.parameters_handler
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
+
httpserver.expect_request(
|
|
66
|
+
re.compile("^/status/filesystems.*"), method="GET"
|
|
67
|
+
).respond_with_handler(basic_status.filesystems_handler)
|
|
68
|
+
|
|
65
69
|
return httpserver
|
|
66
70
|
|
|
67
71
|
|
|
@@ -167,3 +171,50 @@ async def test_parameters(valid_client):
|
|
|
167
171
|
async def test_parameters_invalid(invalid_client):
|
|
168
172
|
with pytest.raises(firecrest.UnauthorizedException):
|
|
169
173
|
await invalid_client.parameters()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@pytest.mark.asyncio
|
|
177
|
+
async def test_filesystems(valid_client):
|
|
178
|
+
assert await valid_client.filesystems() == {
|
|
179
|
+
"cluster": [
|
|
180
|
+
{
|
|
181
|
+
"description": "Users home filesystem",
|
|
182
|
+
"name": "HOME",
|
|
183
|
+
"path": "/home",
|
|
184
|
+
"status": "available",
|
|
185
|
+
"status_code": 200
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"description": "Scratch filesystem",
|
|
189
|
+
"name": "SCRATCH",
|
|
190
|
+
"path": "/scratch",
|
|
191
|
+
"status": "not available",
|
|
192
|
+
"status_code": 400
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
assert await valid_client.filesystems(system_name="cluster") == {
|
|
198
|
+
"cluster": [
|
|
199
|
+
{
|
|
200
|
+
"description": "Users home filesystem",
|
|
201
|
+
"name": "HOME",
|
|
202
|
+
"path": "/home",
|
|
203
|
+
"status": "available",
|
|
204
|
+
"status_code": 200
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"description": "Scratch filesystem",
|
|
208
|
+
"name": "SCRATCH",
|
|
209
|
+
"path": "/scratch",
|
|
210
|
+
"status": "not available",
|
|
211
|
+
"status_code": 400
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@pytest.mark.asyncio
|
|
218
|
+
async def test_filesystems_invalid(invalid_client):
|
|
219
|
+
with pytest.raises(firecrest.UnauthorizedException):
|
|
220
|
+
await invalid_client.filesystems()
|
|
@@ -730,8 +730,21 @@ def whoami_handler(request: Request):
|
|
|
730
730
|
content_type="application/json",
|
|
731
731
|
)
|
|
732
732
|
|
|
733
|
+
groups = request.args.get("groups", False)
|
|
734
|
+
if groups:
|
|
735
|
+
ret = {
|
|
736
|
+
"description": "User information",
|
|
737
|
+
"output": {
|
|
738
|
+
"group": {"id": "1000", "name": "group1"},
|
|
739
|
+
"groups": [{"id": "1000", "name": "group1"}, {"id": "1001", "name": "group2"}],
|
|
740
|
+
"user": {"id": "10000", "name": "test_user"},
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
else:
|
|
744
|
+
ret = {"description": "Success on whoami operation.", "output": "username"}
|
|
745
|
+
|
|
733
746
|
return Response(
|
|
734
|
-
json.dumps(
|
|
747
|
+
json.dumps(ret),
|
|
735
748
|
status=200,
|
|
736
749
|
content_type="application/json",
|
|
737
750
|
)
|
|
@@ -1510,3 +1523,37 @@ def test_whoami_invalid_machine(valid_client):
|
|
|
1510
1523
|
def test_whoami_invalid_client(invalid_client):
|
|
1511
1524
|
with pytest.raises(firecrest.UnauthorizedException):
|
|
1512
1525
|
invalid_client.whoami("cluster1")
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
def test_cli_whoami(valid_credentials):
|
|
1529
|
+
args = valid_credentials + ["whoami", "--system", "cluster1"]
|
|
1530
|
+
result = runner.invoke(cli.app, args=args)
|
|
1531
|
+
stdout = common.clean_stdout(result.stdout)
|
|
1532
|
+
assert result.exit_code == 0
|
|
1533
|
+
assert "username" in stdout
|
|
1534
|
+
|
|
1535
|
+
|
|
1536
|
+
def test_groups(valid_client):
|
|
1537
|
+
assert valid_client.groups("cluster1") == {
|
|
1538
|
+
"group": {"id": "1000", "name": "group1"},
|
|
1539
|
+
"groups": [{"id": "1000", "name": "group1"}, {"id": "1001", "name": "group2"}],
|
|
1540
|
+
"user": {"id": "10000", "name": "test_user"},
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
|
|
1544
|
+
def test_groups_invalid_machine(valid_client):
|
|
1545
|
+
with pytest.raises(firecrest.HeaderException):
|
|
1546
|
+
valid_client.groups("cluster2")
|
|
1547
|
+
|
|
1548
|
+
|
|
1549
|
+
def test_groups_invalid_client(invalid_client):
|
|
1550
|
+
with pytest.raises(firecrest.UnauthorizedException):
|
|
1551
|
+
invalid_client.groups("cluster1")
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
def test_cli_id(valid_credentials):
|
|
1555
|
+
args = valid_credentials + ["id", "--system", "cluster1"]
|
|
1556
|
+
result = runner.invoke(cli.app, args=args)
|
|
1557
|
+
stdout = common.clean_stdout(result.stdout)
|
|
1558
|
+
assert result.exit_code == 0
|
|
1559
|
+
assert "uid=10000(test_user) gid=1000(group1) groups=1000(group1),1001(group2)" in stdout
|
|
@@ -651,3 +651,25 @@ async def test_whoami_invalid_machine(valid_client):
|
|
|
651
651
|
async def test_whoami_invalid_client(invalid_client):
|
|
652
652
|
with pytest.raises(firecrest.UnauthorizedException):
|
|
653
653
|
await invalid_client.whoami("cluster1")
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
@pytest.mark.asyncio
|
|
657
|
+
async def test_groups(valid_client):
|
|
658
|
+
assert await valid_client.groups("cluster1") == {
|
|
659
|
+
"group": {"id": "1000", "name": "group1"},
|
|
660
|
+
"groups": [{"id": "1000", "name": "group1"}, {"id": "1001", "name": "group2"}],
|
|
661
|
+
"user": {"id": "10000", "name": "test_user"},
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
@pytest.mark.asyncio
|
|
666
|
+
async def test_groups_invalid_machine(valid_client):
|
|
667
|
+
with pytest.raises(firecrest.HeaderException):
|
|
668
|
+
await valid_client.groups("cluster2")
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
@pytest.mark.asyncio
|
|
672
|
+
async def test_groups_invalid_client(invalid_client):
|
|
673
|
+
with pytest.raises(firecrest.UnauthorizedException):
|
|
674
|
+
await invalid_client.groups("cluster1")
|
|
675
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|