From d181f16cbd01f4c4224926881ccb95295e4b6bf8 Mon Sep 17 00:00:00 2001 From: Eirini Koutsaniti Date: Fri, 7 Jul 2023 17:47:43 +0200 Subject: [PATCH 1/2] Add whoami endpoint in pyfirecrest --- firecrest/BasicClient.py | 15 +++++++++++---- firecrest/cli/__init__.py | 11 ++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/firecrest/BasicClient.py b/firecrest/BasicClient.py index 12db312..9172f4e 100644 --- a/firecrest/BasicClient.py +++ b/firecrest/BasicClient.py @@ -957,13 +957,20 @@ def view(self, machine: str, target_path: str) -> str: ) return self._json_response([resp], 200)["output"] - def whoami(self) -> Optional[str]: + def whoami(self, machine=None) -> Optional[str]: """Returns the username that FirecREST will be using to perform the other calls. - Will return `None` if the token is not valid. + In the case the machine name is passed in the arguments, a call is made to the respective endpoint and the command whoami is run on the machine. + Otherwise, the library decodes the token and will return `None` if the token is not valid. + + :calls: GET `/utilities/whoami` """ + if machine: + resp = self._get_request( + endpoint="/utilities/whoami", + additional_headers={"X-Machine-Name": machine}, + ) + return self._json_response([resp], 200)["output"] - # FIXME This needs to be added as an endpoint in FirecREST, - # now it's making a guess and it could be wrong. try: decoded = jwt.decode( self._authorization.get_access_token(), diff --git a/firecrest/cli/__init__.py b/firecrest/cli/__init__.py index 8934345..8f1f004 100644 --- a/firecrest/cli/__init__.py +++ b/firecrest/cli/__init__.py @@ -577,11 +577,16 @@ def tail( @app.command(rich_help_panel="Utilities commands") -def whoami(): - """Return the username that FirecREST will be using to perform the other calls +def whoami( + machine: Optional[str] = typer.Argument( + None, help="The machine name where the `whoami` command will run." + ), +): + """Return the username that FirecREST will be using to perform the other calls. + If no machine name is passed the username will be deduced from the token. """ try: - console.print(client.whoami()) + console.print(client.whoami(machine)) except Exception as e: examine_exeption(e) raise typer.Exit(code=1) From 348e968b0c6ad173e77156c042bca338802fbb86 Mon Sep 17 00:00:00 2001 From: Eirini Koutsaniti Date: Tue, 11 Jul 2023 16:22:38 +0200 Subject: [PATCH 2/2] Add unittests for whoami endpoint --- firecrest/cli/__init__.py | 3 ++- tests/test_utilities.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/firecrest/cli/__init__.py b/firecrest/cli/__init__.py index 8f1f004..eff7d59 100644 --- a/firecrest/cli/__init__.py +++ b/firecrest/cli/__init__.py @@ -1107,7 +1107,7 @@ def main( api_version: str = typer.Option( None, help="Set the version of the api of firecrest. By default it will be assumed that you are using version 1.13.0 or " - "compatible. The version is parsed by the `packaging` library.", + "compatible. The version is parsed by the `packaging` library.", envvar="FIRECREST_API_VERSION", ), verbose: Optional[bool] = typer.Option( @@ -1159,4 +1159,5 @@ def main( handlers=[RichHandler(console=console)], ) + typer_click_object = typer.main.get_command(app) diff --git a/tests/test_utilities.py b/tests/test_utilities.py index 4efc545..9a577f7 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -532,6 +532,25 @@ def head_tail_callback(request, uri, response_headers): return [status_code, response_headers, json.dumps(ret)] +def whoami_callback(request, uri, response_headers): + if request.headers["Authorization"] != "Bearer VALID_TOKEN": + return [401, response_headers, '{"message": "Bad token; invalid JSON"}'] + + if request.headers["X-Machine-Name"] != "cluster1": + response_headers["X-Machine-Does-Not-Exist"] = "Machine does not exist" + return [ + 400, + response_headers, + '{"description": "Error on whoami operation", "error": "Machine does not exist"}', + ] + + return [ + 200, + response_headers, + '{"description": "Success on whoami operation.", "output": "username"}' + ] + + @pytest.fixture(autouse=True) def setup_callbacks(): httpretty.enable(allow_net_connect=False, verbose=True) @@ -612,6 +631,10 @@ def setup_callbacks(): httpretty.GET, "http://firecrest.cscs.ch/utilities/tail", body=head_tail_callback ) + httpretty.register_uri( + httpretty.GET, "http://firecrest.cscs.ch/utilities/whoami", body=whoami_callback + ) + httpretty.register_uri( httpretty.POST, "https://myauth.com/auth/realms/cscs/protocol/openid-connect/token", @@ -1299,3 +1322,17 @@ def test_view_invalid_machine(valid_client): def test_view_invalid_client(invalid_client): with pytest.raises(firecrest.UnauthorizedException): invalid_client.view("cluster1", "/path/to/file") + + +def test_whoami(valid_client): + assert valid_client.whoami('cluster1') == "username" + + +def test_whoami_invalid_machine(valid_client): + with pytest.raises(firecrest.HeaderException): + valid_client.whoami('cluster2') + + +def test_whoami_invalid_client(invalid_client): + with pytest.raises(firecrest.UnauthorizedException): + invalid_client.whoami('cluster1')