From ff770f25a35d4d942cb3c00defc4bc17e4ab0bef Mon Sep 17 00:00:00 2001 From: KatHellg Date: Fri, 8 Nov 2024 16:27:21 +0100 Subject: [PATCH 01/26] session_id flag added --- fedn/cli/client_cmd.py | 14 +++++++++++--- fedn/cli/combiner_cmd.py | 14 +++++++++++--- fedn/cli/model_cmd.py | 34 +++++++++++++++++++++++++++++++--- fedn/cli/package_cmd.py | 14 +++++++++++--- fedn/cli/round_cmd.py | 35 ++++++++++++++++++++++++++++++++--- fedn/cli/session_cmd.py | 16 ++++++++++++---- fedn/cli/shared.py | 25 +++++++++++++++++-------- fedn/cli/status_cmd.py | 34 +++++++++++++++++++++++++++++++--- fedn/cli/validation_cmd.py | 34 +++++++++++++++++++++++++++++++--- 9 files changed, 187 insertions(+), 33 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 666bc6545..de97d8807 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -39,10 +39,11 @@ def client_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Client ID") @click.option("--n_max", required=False, help="Number of items to list") @client_cmd.command("list") @click.pass_context -def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): """Return: ------ - count: number of clients @@ -60,12 +61,19 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + + click.echo(f"\nListing clients: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "clients") + if id: + print_response(response, "client", True) + else: + print_response(response, "clients", False) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/combiner_cmd.py b/fedn/cli/combiner_cmd.py index 3e7753e80..d04385231 100644 --- a/fedn/cli/combiner_cmd.py +++ b/fedn/cli/combiner_cmd.py @@ -67,10 +67,11 @@ def start_cmd(ctx, discoverhost, discoverport, token, name, host, port, fqdn, se @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Combiner ID") @click.option("--n_max", required=False, help="Number of items to list") @combiner_cmd.command("list") @click.pass_context -def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): """Return: ------ - count: number of combiners @@ -88,11 +89,18 @@ def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + + click.echo(f"\nListing combiners: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "combiners") + if id: + print_response(response, "combiner", True) + else: + print_response(response, "combiners", False) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index 80a8f795e..a1f2a2343 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -17,10 +17,12 @@ def model_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Model ID") +@click.option("-session_id", "--session_id", required=False, help="models in session with given session id") @click.option("--n_max", required=False, help="Number of items to list") @model_cmd.command("list") @click.pass_context -def list_models(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_models(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of models @@ -38,11 +40,37 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, n_m if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + + click.echo(f"\nListing models: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "models") + if session_id: + if response.status_code == 200: + json_data = response.json() + count, result = json_data.values() + click.echo(f"Found {count} models") + click.echo("\n---------------------------------\n") + for obj in result: + if obj.get("session_id")==session_id: + click.echo("{") + for k, v in obj.items(): + click.echo(f"\t{k}: {v}") + click.echo("}") + + elif response.status_code == 500: + json_data = response.json() + click.echo(f'Error: {json_data["message"]}') + else: + click.echo(f"Error: {response.status_code}") + else: + if id: + print_response(response, "model", True, session_id) + else: + print_response(response, "models", False, session_id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/package_cmd.py b/fedn/cli/package_cmd.py index 3c78d9944..7dab52231 100644 --- a/fedn/cli/package_cmd.py +++ b/fedn/cli/package_cmd.py @@ -45,10 +45,11 @@ def create_cmd(ctx, path, name): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Package ID") @click.option("--n_max", required=False, help="Number of items to list") @package_cmd.command("list") @click.pass_context -def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): """Return: ------ - count: number of packages @@ -66,11 +67,18 @@ def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, n if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + + click.echo(f"\nListing packages: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "packages") + if id: + print_response(response, "package", True) + else: + print_response(response, "packages", False) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/round_cmd.py b/fedn/cli/round_cmd.py index ac42f43ef..dc9b66be5 100644 --- a/fedn/cli/round_cmd.py +++ b/fedn/cli/round_cmd.py @@ -16,11 +16,13 @@ def round_cmd(ctx): @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-id", "--id", required=False, help="Round ID") +@click.option("-session_id", "--session_id", required=False, help="Rounds in session with given session id") @click.option("-t", "--token", required=False, help="Authentication token") @click.option("--n_max", required=False, help="Number of items to list") @round_cmd.command("list") @click.pass_context -def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of rounds @@ -38,11 +40,38 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, n_m if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + click.echo(f"\nListing rounds: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "rounds") + if session_id: + if response.status_code == 200: + json_data = response.json() + count, result = json_data.values() + click.echo(f"Found {count} rounds") + click.echo("\n---------------------------------\n") + for obj in result: + if obj.get("round_config").get("session_id")==session_id: + click.echo("{") + for k, v in obj.items(): + click.echo(f"\t{k}: {v}") + click.echo("}") + + elif response.status_code == 500: + json_data = response.json() + click.echo(f'Error: {json_data["message"]}') + else: + click.echo(f"Error: {response.status_code}") + else: + if id: + print_response(response, "round", True, session_id) + else: + print_response(response, "rounds", False, session_id) + + except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index 65db98c69..287fe186a 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -17,10 +17,11 @@ def session_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Session ID") @click.option("--n_max", required=False, help="Number of items to list") @session_cmd.command("list") @click.pass_context -def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): """Return: ------ - count: number of sessions @@ -38,11 +39,18 @@ def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, n if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + + click.echo(f"\nListing sessions: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "sessions") + if id: + print_response(response, "session", True) + else: + print_response(response, "sessions", False) except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + click.echo(f"Error: Could not connect to {url}") \ No newline at end of file diff --git a/fedn/cli/shared.py b/fedn/cli/shared.py index d32f4ff43..4fb05590d 100644 --- a/fedn/cli/shared.py +++ b/fedn/cli/shared.py @@ -64,7 +64,7 @@ def get_client_package_dir(path: str) -> str: # Print response from api (list of entities) -def print_response(response, entity_name: str): +def print_response(response, entity_name: str, so, session_id): """Prints the api response to the cli. :param response: type: array @@ -72,18 +72,27 @@ def print_response(response, entity_name: str): :param entity_name: type: string description: name of entity + :param so: + type: boolean + desriptions: single output format (y/n) return: None """ if response.status_code == 200: json_data = response.json() - count, result = json_data.values() - click.echo(f"Found {count} {entity_name}") - click.echo("\n---------------------------------\n") - for obj in result: - click.echo("{") - for k, v in obj.items(): + if so: + click.echo(f"Found {entity_name}") + click.echo("\n---------------------------------\n") + for k, v in json_data.items(): click.echo(f"\t{k}: {v}") - click.echo("}") + else: + count, result = json_data.values() + click.echo(f"Found {count} {entity_name}") + click.echo("\n---------------------------------\n") + for obj in result: + click.echo("{") + for k, v in obj.items(): + click.echo(f"\t{k}: {v}") + click.echo("}") elif response.status_code == 500: json_data = response.json() click.echo(f'Error: {json_data["message"]}') diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index c879ca1ef..47acdf940 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -16,10 +16,12 @@ def status_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Status ID") +@click.option("-session_id", "--session_id", required=False, help="statuses with given session id") @click.option("--n_max", required=False, help="Number of items to list") @status_cmd.command("list") @click.pass_context -def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of statuses @@ -37,11 +39,37 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, n if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + + click.echo(f"\nListing statuses: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "statuses") + if session_id: + if response.status_code == 200: + json_data = response.json() + count, result = json_data.values() + click.echo(f"Found {count} statuses") + click.echo("\n---------------------------------\n") + for obj in result: + if obj.get("session_id")==session_id: + click.echo("{") + for k, v in obj.items(): + click.echo(f"\t{k}: {v}") + click.echo("}") + + elif response.status_code == 500: + json_data = response.json() + click.echo(f'Error: {json_data["message"]}') + else: + click.echo(f"Error: {response.status_code}") + else: + if id: + print_response(response, "status", True) + else: + print_response(response, "statuses", False) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/validation_cmd.py b/fedn/cli/validation_cmd.py index 4bf4e63fa..b8b29b4c4 100644 --- a/fedn/cli/validation_cmd.py +++ b/fedn/cli/validation_cmd.py @@ -17,10 +17,12 @@ def validation_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="validation ID") +@click.option("-session_id", "--session_id", required=False, help="validations in session with given session id") @click.option("--n_max", required=False, help="Number of items to list") @validation_cmd.command("list") @click.pass_context -def list_validations(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): +def list_validations(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of validations @@ -38,11 +40,37 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None if _token: headers["Authorization"] = _token + if id: + url = f"{url}{id}" + headers["id"] = id + + click.echo(f"\nListing validations: {url}\n") click.echo(f"Headers: {headers}") - try: response = requests.get(url, headers=headers) - print_response(response, "validations") + if session_id: + if response.status_code == 200: + json_data = response.json() + count, result = json_data.values() + click.echo(f"Found {count} statuses") + click.echo("\n---------------------------------\n") + for obj in result: + if obj.get("session_id")==session_id: + click.echo("{") + for k, v in obj.items(): + click.echo(f"\t{k}: {v}") + click.echo("}") + + elif response.status_code == 500: + json_data = response.json() + click.echo(f'Error: {json_data["message"]}') + else: + click.echo(f"Error: {response.status_code}") + else: + if id: + print_response(response, "validation", True) + else: + print_response(response, "validations", False) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") From 94bfc2ebccd492e5036e9f375e00f49ae469dadc Mon Sep 17 00:00:00 2001 From: KatHellg Date: Mon, 11 Nov 2024 13:12:19 +0100 Subject: [PATCH 02/26] minor code fix --- fedn/cli/model_cmd.py | 7 +++---- fedn/cli/round_cmd.py | 7 +++---- fedn/cli/status_cmd.py | 7 +++---- fedn/cli/validation_cmd.py | 7 +++---- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index a1f2a2343..c3b2d587b 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -67,10 +67,9 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, id: click.echo(f'Error: {json_data["message"]}') else: click.echo(f"Error: {response.status_code}") + elif id: + print_response(response, "model", True, session_id) else: - if id: - print_response(response, "model", True, session_id) - else: - print_response(response, "models", False, session_id) + print_response(response, "models", False, session_id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/round_cmd.py b/fedn/cli/round_cmd.py index dc9b66be5..68364202c 100644 --- a/fedn/cli/round_cmd.py +++ b/fedn/cli/round_cmd.py @@ -66,11 +66,10 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, id: click.echo(f'Error: {json_data["message"]}') else: click.echo(f"Error: {response.status_code}") + elif id: + print_response(response, "round", True, session_id) else: - if id: - print_response(response, "round", True, session_id) - else: - print_response(response, "rounds", False, session_id) + print_response(response, "rounds", False, session_id) except requests.exceptions.ConnectionError: diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index 47acdf940..01f7c497a 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -66,10 +66,9 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, i click.echo(f'Error: {json_data["message"]}') else: click.echo(f"Error: {response.status_code}") + elif id: + print_response(response, "status", True) else: - if id: - print_response(response, "status", True) - else: - print_response(response, "statuses", False) + print_response(response, "statuses", False) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/validation_cmd.py b/fedn/cli/validation_cmd.py index b8b29b4c4..1dc68c311 100644 --- a/fedn/cli/validation_cmd.py +++ b/fedn/cli/validation_cmd.py @@ -67,10 +67,9 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None click.echo(f'Error: {json_data["message"]}') else: click.echo(f"Error: {response.status_code}") + elif id: + print_response(response, "validation", True) else: - if id: - print_response(response, "validation", True) - else: - print_response(response, "validations", False) + print_response(response, "validations", False) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") From 3f9eca6836c01887f7616d3830f3d5b4059bc84b Mon Sep 17 00:00:00 2001 From: KatHellg Date: Mon, 11 Nov 2024 13:15:17 +0100 Subject: [PATCH 03/26] added new line end of session cmd file --- fedn/cli/session_cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index 287fe186a..28f630880 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -53,4 +53,4 @@ def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, i else: print_response(response, "sessions", False) except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") \ No newline at end of file + click.echo(f"Error: Could not connect to {url}") From 71623d97f48ca75cf556407c6b4320a90a4dcdf1 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 13 Nov 2024 14:52:39 +0100 Subject: [PATCH 04/26] fixed acc to feedback --- fedn/cli/client_cmd.py | 45 ++++++++++++++++++++----- fedn/cli/combiner_cmd.py | 42 +++++++++++++++++++---- fedn/cli/model_cmd.py | 68 +++++++++++++++++++++++--------------- fedn/cli/package_cmd.py | 42 +++++++++++++++++++---- fedn/cli/round_cmd.py | 68 +++++++++++++++++++++++--------------- fedn/cli/session_cmd.py | 43 +++++++++++++++++++----- fedn/cli/shared.py | 3 +- fedn/cli/status_cmd.py | 66 +++++++++++++++++++++--------------- fedn/cli/validation_cmd.py | 62 ++++++++++++++++++++-------------- 9 files changed, 304 insertions(+), 135 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index de97d8807..301ff38fd 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -39,11 +39,10 @@ def client_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Client ID") @click.option("--n_max", required=False, help="Number of items to list") @client_cmd.command("list") @click.pass_context -def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): +def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): """Return: ------ - count: number of clients @@ -58,6 +57,38 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, id _token = get_token(token) + if _token: + headers["Authorization"] = _token + + + click.echo(f"\nListing clients: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "clients", None) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Client ID") +@client_cmd.command("get") +@click.pass_context +def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - count: number of clients + - result: list of clients + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="clients") + headers = {} + + _token = get_token(token) + if _token: headers["Authorization"] = _token @@ -66,19 +97,15 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, id headers["id"] = id - click.echo(f"\nListing clients: {url}\n") + click.echo(f"\nRetrieving client: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if id: - print_response(response, "client", True) - else: - print_response(response, "clients", False) + print_response(response, "client", id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") - -@client_cmd.command("start-v1") +@client_cmd.command("start") @click.option("-d", "--discoverhost", required=False, help="Hostname for discovery services(reducer).") @click.option("-p", "--discoverport", required=False, help="Port for discovery services (reducer).") @click.option("--token", required=False, help="Set token provided by reducer if enabled") diff --git a/fedn/cli/combiner_cmd.py b/fedn/cli/combiner_cmd.py index d04385231..f7e937261 100644 --- a/fedn/cli/combiner_cmd.py +++ b/fedn/cli/combiner_cmd.py @@ -67,11 +67,10 @@ def start_cmd(ctx, discoverhost, discoverport, token, name, host, port, fqdn, se @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Combiner ID") @click.option("--n_max", required=False, help="Number of items to list") @combiner_cmd.command("list") @click.pass_context -def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): +def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): """Return: ------ - count: number of combiners @@ -84,6 +83,38 @@ def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, if n_max: headers["X-Limit"] = n_max + _token = get_token(token) + + if _token: + headers["Authorization"] = _token + + + click.echo(f"\nListing combiners: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "combiners", None) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Combiner ID") +@combiner_cmd.command("get") +@click.pass_context +def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: combiner with given id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="combiners") + headers = {} + + _token = get_token(token) if _token: @@ -94,13 +125,10 @@ def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, headers["id"] = id - click.echo(f"\nListing combiners: {url}\n") + click.echo(f"\nRetrieving combiner: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if id: - print_response(response, "combiner", True) - else: - print_response(response, "combiners", False) + print_response(response, "combiner", id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index c3b2d587b..ebf6e6dca 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -17,12 +17,11 @@ def model_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Model ID") @click.option("-session_id", "--session_id", required=False, help="models in session with given session id") @click.option("--n_max", required=False, help="Number of items to list") @model_cmd.command("list") @click.pass_context -def list_models(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): +def list_models(ctx, protocol: str, host: str, port: str, token: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of models @@ -30,11 +29,50 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, id: """ url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") + + headers = {} if n_max: headers["X-Limit"] = n_max + _token = get_token(token) + + if _token: + headers["Authorization"] = _token + + if session_id: + url = f"{url}?session_id={session_id}" + headers["session_id"] = session_id + + click.echo(f"\nListing models: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "models", None) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Model ID") +@model_cmd.command("get") +@click.pass_context +def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: model with given id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") + + + headers = {} + + _token = get_token(token) if _token: @@ -44,32 +82,10 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, id: url = f"{url}{id}" headers["id"] = id - - click.echo(f"\nListing models: {url}\n") + click.echo(f"\nRetrieving model: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if session_id: - if response.status_code == 200: - json_data = response.json() - count, result = json_data.values() - click.echo(f"Found {count} models") - click.echo("\n---------------------------------\n") - for obj in result: - if obj.get("session_id")==session_id: - click.echo("{") - for k, v in obj.items(): - click.echo(f"\t{k}: {v}") - click.echo("}") - - elif response.status_code == 500: - json_data = response.json() - click.echo(f'Error: {json_data["message"]}') - else: - click.echo(f"Error: {response.status_code}") - elif id: - print_response(response, "model", True, session_id) - else: - print_response(response, "models", False, session_id) + print_response(response, "model", id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/package_cmd.py b/fedn/cli/package_cmd.py index 7dab52231..30998b828 100644 --- a/fedn/cli/package_cmd.py +++ b/fedn/cli/package_cmd.py @@ -45,11 +45,10 @@ def create_cmd(ctx, path, name): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Package ID") @click.option("--n_max", required=False, help="Number of items to list") @package_cmd.command("list") @click.pass_context -def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): +def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): """Return: ------ - count: number of packages @@ -62,6 +61,38 @@ def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, i if n_max: headers["X-Limit"] = n_max + _token = get_token(token) + + if _token: + headers["Authorization"] = _token + + + click.echo(f"\nListing packages: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "packages", None) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Package ID") +@package_cmd.command("get") +@click.pass_context +def get_package(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: package with given id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="packages") + headers = {} + + _token = get_token(token) if _token: @@ -72,13 +103,10 @@ def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, i headers["id"] = id - click.echo(f"\nListing packages: {url}\n") + click.echo(f"\nretrieving package: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if id: - print_response(response, "package", True) - else: - print_response(response, "packages", False) + print_response(response, "package", id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/round_cmd.py b/fedn/cli/round_cmd.py index 68364202c..d60ff66e4 100644 --- a/fedn/cli/round_cmd.py +++ b/fedn/cli/round_cmd.py @@ -16,13 +16,12 @@ def round_cmd(ctx): @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") -@click.option("-id", "--id", required=False, help="Round ID") @click.option("-session_id", "--session_id", required=False, help="Rounds in session with given session id") @click.option("-t", "--token", required=False, help="Authentication token") @click.option("--n_max", required=False, help="Number of items to list") @round_cmd.command("list") @click.pass_context -def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): +def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of rounds @@ -30,11 +29,49 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, id: """ url = get_api_url(protocol=protocol, host=host, port=port, endpoint="rounds") + headers = {} if n_max: headers["X-Limit"] = n_max + _token = get_token(token) + + if _token: + headers["Authorization"] = _token + + if session_id: + url = f"{url}?round_config.session_id={session_id}" + headers["session_id"] = session_id + + click.echo(f"\nListing rounds: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "rounds", None) + + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-id", "--id", required=False, help="Round ID") +@click.option("-t", "--token", required=False, help="Authentication token") +@round_cmd.command("get") +@click.pass_context +def get_round(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: round with given id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="rounds") + + headers = {} + + _token = get_token(token) if _token: @@ -44,33 +81,12 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, id: url = f"{url}{id}" headers["id"] = id - click.echo(f"\nListing rounds: {url}\n") + + click.echo(f"\nRetrieving round: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if session_id: - if response.status_code == 200: - json_data = response.json() - count, result = json_data.values() - click.echo(f"Found {count} rounds") - click.echo("\n---------------------------------\n") - for obj in result: - if obj.get("round_config").get("session_id")==session_id: - click.echo("{") - for k, v in obj.items(): - click.echo(f"\t{k}: {v}") - click.echo("}") - - elif response.status_code == 500: - json_data = response.json() - click.echo(f'Error: {json_data["message"]}') - else: - click.echo(f"Error: {response.status_code}") - elif id: - print_response(response, "round", True, session_id) - else: - print_response(response, "rounds", False, session_id) - + print_response(response, "round", id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index 28f630880..56184ef2e 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -17,11 +17,10 @@ def session_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Session ID") @click.option("--n_max", required=False, help="Number of items to list") @session_cmd.command("list") @click.pass_context -def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, n_max: int = None): +def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, n_max: int = None): """Return: ------ - count: number of sessions @@ -36,6 +35,37 @@ def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, i _token = get_token(token) + if _token: + headers["Authorization"] = _token + + + click.echo(f"\nListing sessions: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "sessions", None) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=True, help="Session ID") +@session_cmd.command("get") +@click.pass_context +def get_session(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: session with given session id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="sessions") + headers = {} + + _token = get_token(token) + if _token: headers["Authorization"] = _token @@ -44,13 +74,10 @@ def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, i headers["id"] = id - click.echo(f"\nListing sessions: {url}\n") + click.echo(f"\nRetrieving session: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if id: - print_response(response, "session", True) - else: - print_response(response, "sessions", False) + print_response(response, "session", id) except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + click.echo(f"Error: Could not connect to {url}") \ No newline at end of file diff --git a/fedn/cli/shared.py b/fedn/cli/shared.py index 4fb05590d..5876828fb 100644 --- a/fedn/cli/shared.py +++ b/fedn/cli/shared.py @@ -64,7 +64,7 @@ def get_client_package_dir(path: str) -> str: # Print response from api (list of entities) -def print_response(response, entity_name: str, so, session_id): +def print_response(response, entity_name: str, so): """Prints the api response to the cli. :param response: type: array @@ -89,6 +89,7 @@ def print_response(response, entity_name: str, so, session_id): click.echo(f"Found {count} {entity_name}") click.echo("\n---------------------------------\n") for obj in result: + print(obj.get("session_id")) click.echo("{") for k, v in obj.items(): click.echo(f"\t{k}: {v}") diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index 01f7c497a..ea064a857 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -16,12 +16,11 @@ def status_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Status ID") @click.option("-session_id", "--session_id", required=False, help="statuses with given session id") @click.option("--n_max", required=False, help="Number of items to list") @status_cmd.command("list") @click.pass_context -def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): +def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of statuses @@ -34,6 +33,42 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, i if n_max: headers["X-Limit"] = n_max + _token = get_token(token) + + if _token: + headers["Authorization"] = _token + + if session_id: + url = f"{url}?sessionId={session_id}" + headers["session_id"] = session_id + + + click.echo(f"\nListing statuses: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "statuses", None) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="Status ID") +@status_cmd.command("get") +@click.pass_context +def get_status(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: status with given id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="statuses") + headers = {} + + _token = get_token(token) if _token: @@ -44,31 +79,10 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, i headers["id"] = id - click.echo(f"\nListing statuses: {url}\n") + click.echo(f"\nRetrieving status: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if session_id: - if response.status_code == 200: - json_data = response.json() - count, result = json_data.values() - click.echo(f"Found {count} statuses") - click.echo("\n---------------------------------\n") - for obj in result: - if obj.get("session_id")==session_id: - click.echo("{") - for k, v in obj.items(): - click.echo(f"\t{k}: {v}") - click.echo("}") - - elif response.status_code == 500: - json_data = response.json() - click.echo(f'Error: {json_data["message"]}') - else: - click.echo(f"Error: {response.status_code}") - elif id: - print_response(response, "status", True) - else: - print_response(response, "statuses", False) + print_response(response, "status", id) except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + click.echo(f"Error: Could not connect to {url}") \ No newline at end of file diff --git a/fedn/cli/validation_cmd.py b/fedn/cli/validation_cmd.py index 1dc68c311..10c594398 100644 --- a/fedn/cli/validation_cmd.py +++ b/fedn/cli/validation_cmd.py @@ -17,12 +17,11 @@ def validation_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="validation ID") @click.option("-session_id", "--session_id", required=False, help="validations in session with given session id") @click.option("--n_max", required=False, help="Number of items to list") @validation_cmd.command("list") @click.pass_context -def list_validations(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None, session_id: str = None, n_max: int = None): +def list_validations(ctx, protocol: str, host: str, port: str, token: str = None, session_id: str = None, n_max: int = None): """Return: ------ - count: number of validations @@ -37,6 +36,40 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None _token = get_token(token) + if _token: + headers["Authorization"] = _token + + if session_id: + url = f"{url}?sessionId={session_id}" + headers["session_id"] = session_id + + click.echo(f"\nListing validations: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "validations", None) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=False, help="validation ID") +@validation_cmd.command("get") +@click.pass_context +def get_validation(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: validation with given id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="validations") + headers = {} + + _token = get_token(token) + if _token: headers["Authorization"] = _token @@ -45,31 +78,10 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None headers["id"] = id - click.echo(f"\nListing validations: {url}\n") + click.echo(f"\nRetrieving validation: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) - if session_id: - if response.status_code == 200: - json_data = response.json() - count, result = json_data.values() - click.echo(f"Found {count} statuses") - click.echo("\n---------------------------------\n") - for obj in result: - if obj.get("session_id")==session_id: - click.echo("{") - for k, v in obj.items(): - click.echo(f"\t{k}: {v}") - click.echo("}") - - elif response.status_code == 500: - json_data = response.json() - click.echo(f'Error: {json_data["message"]}') - else: - click.echo(f"Error: {response.status_code}") - elif id: - print_response(response, "validation", True) - else: - print_response(response, "validations", False) + print_response(response, "validation", id) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") From 16549a84e18751d19b33fd9040c85b847d6c0044 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 13 Nov 2024 14:58:10 +0100 Subject: [PATCH 05/26] code fix --- fedn/cli/model_cmd.py | 4 ++-- fedn/cli/session_cmd.py | 2 +- fedn/cli/status_cmd.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index ebf6e6dca..810b573ab 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -30,7 +30,7 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, ses """ url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") - + headers = {} if n_max: @@ -69,7 +69,7 @@ def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: s """ url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") - + headers = {} diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index 56184ef2e..65f45ac16 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -80,4 +80,4 @@ def get_session(ctx, protocol: str, host: str, port: str, token: str = None, id: response = requests.get(url, headers=headers) print_response(response, "session", id) except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") \ No newline at end of file + click.echo(f"Error: Could not connect to {url}") diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index ea064a857..5b445f07e 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -85,4 +85,4 @@ def get_status(ctx, protocol: str, host: str, port: str, token: str = None, id: response = requests.get(url, headers=headers) print_response(response, "status", id) except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") \ No newline at end of file + click.echo(f"Error: Could not connect to {url}") From 2133fcfff08fd19e9301cfe45d9911187721f2a5 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 13 Nov 2024 15:14:37 +0100 Subject: [PATCH 06/26] fixed conflict --- fedn/cli/client_cmd.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 301ff38fd..8cc4343ec 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -106,6 +106,7 @@ def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: click.echo(f"Error: Could not connect to {url}") @client_cmd.command("start") +@client_cmd.command("start-v1") @click.option("-d", "--discoverhost", required=False, help="Hostname for discovery services(reducer).") @click.option("-p", "--discoverport", required=False, help="Port for discovery services (reducer).") @click.option("--token", required=False, help="Set token provided by reducer if enabled") From 8fe7ad09839ea9691d3b5e5270e256397e2792dd Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 13 Nov 2024 15:41:03 +0100 Subject: [PATCH 07/26] conflict + minor fix --- fedn/cli/client_cmd.py | 6 ++---- fedn/cli/combiner_cmd.py | 3 +-- fedn/cli/model_cmd.py | 4 +--- fedn/cli/package_cmd.py | 3 +-- fedn/cli/round_cmd.py | 4 +--- fedn/cli/session_cmd.py | 1 - fedn/cli/status_cmd.py | 5 +---- fedn/cli/validation_cmd.py | 4 +--- 8 files changed, 8 insertions(+), 22 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 8cc4343ec..073b6bb48 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -60,9 +60,9 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ if _token: headers["Authorization"] = _token - click.echo(f"\nListing clients: {url}\n") click.echo(f"Headers: {headers}") + try: response = requests.get(url, headers=headers) print_response(response, "clients", None) @@ -74,7 +74,7 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Client ID") +@click.option("-id", "--id", required=True, help="Client ID") @client_cmd.command("get") @click.pass_context def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): @@ -94,7 +94,6 @@ def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: if id: url = f"{url}{id}" - headers["id"] = id click.echo(f"\nRetrieving client: {url}\n") @@ -105,7 +104,6 @@ def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") -@client_cmd.command("start") @client_cmd.command("start-v1") @click.option("-d", "--discoverhost", required=False, help="Hostname for discovery services(reducer).") @click.option("-p", "--discoverport", required=False, help="Port for discovery services (reducer).") diff --git a/fedn/cli/combiner_cmd.py b/fedn/cli/combiner_cmd.py index f7e937261..c6ccbeb19 100644 --- a/fedn/cli/combiner_cmd.py +++ b/fedn/cli/combiner_cmd.py @@ -102,7 +102,7 @@ def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Combiner ID") +@click.option("-id", "--id", required=True, help="Combiner ID") @combiner_cmd.command("get") @click.pass_context def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): @@ -122,7 +122,6 @@ def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id if id: url = f"{url}{id}" - headers["id"] = id click.echo(f"\nRetrieving combiner: {url}\n") diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index 810b573ab..b5f738aad 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -43,7 +43,6 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, ses if session_id: url = f"{url}?session_id={session_id}" - headers["session_id"] = session_id click.echo(f"\nListing models: {url}\n") click.echo(f"Headers: {headers}") @@ -58,7 +57,7 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, ses @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Model ID") +@click.option("-id", "--id", required=True, help="Model ID") @model_cmd.command("get") @click.pass_context def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): @@ -80,7 +79,6 @@ def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: s if id: url = f"{url}{id}" - headers["id"] = id click.echo(f"\nRetrieving model: {url}\n") click.echo(f"Headers: {headers}") diff --git a/fedn/cli/package_cmd.py b/fedn/cli/package_cmd.py index 30998b828..f34ea4a75 100644 --- a/fedn/cli/package_cmd.py +++ b/fedn/cli/package_cmd.py @@ -80,7 +80,7 @@ def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, n @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Package ID") +@click.option("-id", "--id", required=True, help="Package ID") @package_cmd.command("get") @click.pass_context def get_package(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): @@ -100,7 +100,6 @@ def get_package(ctx, protocol: str, host: str, port: str, token: str = None, id: if id: url = f"{url}{id}" - headers["id"] = id click.echo(f"\nretrieving package: {url}\n") diff --git a/fedn/cli/round_cmd.py b/fedn/cli/round_cmd.py index d60ff66e4..e790a8bdb 100644 --- a/fedn/cli/round_cmd.py +++ b/fedn/cli/round_cmd.py @@ -42,7 +42,6 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, ses if session_id: url = f"{url}?round_config.session_id={session_id}" - headers["session_id"] = session_id click.echo(f"\nListing rounds: {url}\n") click.echo(f"Headers: {headers}") @@ -57,7 +56,7 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, ses @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") -@click.option("-id", "--id", required=False, help="Round ID") +@click.option("-id", "--id", required=True, help="Round ID") @click.option("-t", "--token", required=False, help="Authentication token") @round_cmd.command("get") @click.pass_context @@ -79,7 +78,6 @@ def get_round(ctx, protocol: str, host: str, port: str, token: str = None, id: s if id: url = f"{url}{id}" - headers["id"] = id click.echo(f"\nRetrieving round: {url}\n") diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index 65f45ac16..4cafa9e6b 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -71,7 +71,6 @@ def get_session(ctx, protocol: str, host: str, port: str, token: str = None, id: if id: url = f"{url}{id}" - headers["id"] = id click.echo(f"\nRetrieving session: {url}\n") diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index 5b445f07e..d47e4ab18 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -40,7 +40,6 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, s if session_id: url = f"{url}?sessionId={session_id}" - headers["session_id"] = session_id click.echo(f"\nListing statuses: {url}\n") @@ -56,7 +55,7 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, s @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="Status ID") +@click.option("-id", "--id", required=True, help="Status ID") @status_cmd.command("get") @click.pass_context def get_status(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): @@ -76,8 +75,6 @@ def get_status(ctx, protocol: str, host: str, port: str, token: str = None, id: if id: url = f"{url}{id}" - headers["id"] = id - click.echo(f"\nRetrieving status: {url}\n") click.echo(f"Headers: {headers}") diff --git a/fedn/cli/validation_cmd.py b/fedn/cli/validation_cmd.py index 10c594398..27ff8448d 100644 --- a/fedn/cli/validation_cmd.py +++ b/fedn/cli/validation_cmd.py @@ -41,7 +41,6 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None if session_id: url = f"{url}?sessionId={session_id}" - headers["session_id"] = session_id click.echo(f"\nListing validations: {url}\n") click.echo(f"Headers: {headers}") @@ -56,7 +55,7 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=False, help="validation ID") +@click.option("-id", "--id", required=True, help="validation ID") @validation_cmd.command("get") @click.pass_context def get_validation(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): @@ -75,7 +74,6 @@ def get_validation(ctx, protocol: str, host: str, port: str, token: str = None, if id: url = f"{url}{id}" - headers["id"] = id click.echo(f"\nRetrieving validation: {url}\n") From 7a3f33709a22df25987a835b67e017581dadd76a Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 13 Nov 2024 15:43:01 +0100 Subject: [PATCH 08/26] spelling fix:) --- fedn/cli/package_cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fedn/cli/package_cmd.py b/fedn/cli/package_cmd.py index f34ea4a75..13eb582ea 100644 --- a/fedn/cli/package_cmd.py +++ b/fedn/cli/package_cmd.py @@ -102,7 +102,7 @@ def get_package(ctx, protocol: str, host: str, port: str, token: str = None, id: url = f"{url}{id}" - click.echo(f"\nretrieving package: {url}\n") + click.echo(f"\nRetrieving package: {url}\n") click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) From 18cba87f3e6d32414dc5801b34999315dda9fe18 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 13 Nov 2024 15:52:40 +0100 Subject: [PATCH 09/26] resolving conflict --- fedn/cli/client_cmd.py | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 073b6bb48..586b124ed 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -70,40 +70,6 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ click.echo(f"Error: Could not connect to {url}") -@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") -@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") -@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") -@click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-id", "--id", required=True, help="Client ID") -@client_cmd.command("get") -@click.pass_context -def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): - """Return: - ------ - - count: number of clients - - result: list of clients - - """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="clients") - headers = {} - - _token = get_token(token) - - if _token: - headers["Authorization"] = _token - - if id: - url = f"{url}{id}" - - - click.echo(f"\nRetrieving client: {url}\n") - click.echo(f"Headers: {headers}") - try: - response = requests.get(url, headers=headers) - print_response(response, "client", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") - @client_cmd.command("start-v1") @click.option("-d", "--discoverhost", required=False, help="Hostname for discovery services(reducer).") @click.option("-p", "--discoverport", required=False, help="Port for discovery services (reducer).") From 4149c3eefd8336f9c296a07e78ffc32324533123 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 13 Nov 2024 16:20:20 +0100 Subject: [PATCH 10/26] trying to add get_client function again --- fedn/cli/client_cmd.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 586b124ed..12a19c2ed 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -69,6 +69,40 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="Authentication token") +@click.option("-id", "--id", required=True, help="Client ID") +@client_cmd.command("get") +@click.pass_context +def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: str = None): + """Return: + ------ + - result: client with given id + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="clients") + headers = {} + + + _token = get_token(token) + + if _token: + headers["Authorization"] = _token + + if id: + url = f"{url}{id}" + + + click.echo(f"\nRetrieving client: {url}\n") + click.echo(f"Headers: {headers}") + try: + response = requests.get(url, headers=headers) + print_response(response, "client", id) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + @client_cmd.command("start-v1") @click.option("-d", "--discoverhost", required=False, help="Hostname for discovery services(reducer).") From c9bacbe4cacb4d40770ae741887b022f659b6a6f Mon Sep 17 00:00:00 2001 From: KatHellg Date: Fri, 15 Nov 2024 11:38:24 +0100 Subject: [PATCH 11/26] header prints removed --- fedn/cli/client_cmd.py | 4 ---- fedn/cli/combiner_cmd.py | 2 -- fedn/cli/model_cmd.py | 6 ++---- fedn/cli/package_cmd.py | 4 ---- fedn/cli/round_cmd.py | 5 +---- fedn/cli/session_cmd.py | 4 ---- fedn/cli/shared.py | 2 +- fedn/cli/status_cmd.py | 5 +---- fedn/cli/validation_cmd.py | 5 +---- 9 files changed, 6 insertions(+), 31 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 12a19c2ed..7c9ffc1e7 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -60,8 +60,6 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ if _token: headers["Authorization"] = _token - click.echo(f"\nListing clients: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) @@ -95,8 +93,6 @@ def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: url = f"{url}{id}" - click.echo(f"\nRetrieving client: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "client", id) diff --git a/fedn/cli/combiner_cmd.py b/fedn/cli/combiner_cmd.py index c6ccbeb19..c6b3d19d7 100644 --- a/fedn/cli/combiner_cmd.py +++ b/fedn/cli/combiner_cmd.py @@ -124,8 +124,6 @@ def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id url = f"{url}{id}" - click.echo(f"\nRetrieving combiner: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "combiner", id) diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index b5f738aad..2e522e5a1 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -44,8 +44,7 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, ses if session_id: url = f"{url}?session_id={session_id}" - click.echo(f"\nListing models: {url}\n") - click.echo(f"Headers: {headers}") + try: response = requests.get(url, headers=headers) print_response(response, "models", None) @@ -80,8 +79,7 @@ def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: s if id: url = f"{url}{id}" - click.echo(f"\nRetrieving model: {url}\n") - click.echo(f"Headers: {headers}") + try: response = requests.get(url, headers=headers) print_response(response, "model", id) diff --git a/fedn/cli/package_cmd.py b/fedn/cli/package_cmd.py index 13eb582ea..b8a130f68 100644 --- a/fedn/cli/package_cmd.py +++ b/fedn/cli/package_cmd.py @@ -67,8 +67,6 @@ def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, n headers["Authorization"] = _token - click.echo(f"\nListing packages: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "packages", None) @@ -102,8 +100,6 @@ def get_package(ctx, protocol: str, host: str, port: str, token: str = None, id: url = f"{url}{id}" - click.echo(f"\nRetrieving package: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "package", id) diff --git a/fedn/cli/round_cmd.py b/fedn/cli/round_cmd.py index e790a8bdb..2f889fef3 100644 --- a/fedn/cli/round_cmd.py +++ b/fedn/cli/round_cmd.py @@ -43,8 +43,7 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, ses if session_id: url = f"{url}?round_config.session_id={session_id}" - click.echo(f"\nListing rounds: {url}\n") - click.echo(f"Headers: {headers}") + try: response = requests.get(url, headers=headers) print_response(response, "rounds", None) @@ -80,8 +79,6 @@ def get_round(ctx, protocol: str, host: str, port: str, token: str = None, id: s url = f"{url}{id}" - click.echo(f"\nRetrieving round: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "round", id) diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index 4cafa9e6b..a0f1e64c3 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -39,8 +39,6 @@ def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, n headers["Authorization"] = _token - click.echo(f"\nListing sessions: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "sessions", None) @@ -73,8 +71,6 @@ def get_session(ctx, protocol: str, host: str, port: str, token: str = None, id: url = f"{url}{id}" - click.echo(f"\nRetrieving session: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "session", id) diff --git a/fedn/cli/shared.py b/fedn/cli/shared.py index 5876828fb..21fa2b072 100644 --- a/fedn/cli/shared.py +++ b/fedn/cli/shared.py @@ -74,7 +74,7 @@ def print_response(response, entity_name: str, so): description: name of entity :param so: type: boolean - desriptions: single output format (y/n) + desriptions: single output format return: None """ if response.status_code == 200: diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index d47e4ab18..9b751f65b 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -42,8 +42,6 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, s url = f"{url}?sessionId={session_id}" - click.echo(f"\nListing statuses: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "statuses", None) @@ -76,8 +74,7 @@ def get_status(ctx, protocol: str, host: str, port: str, token: str = None, id: if id: url = f"{url}{id}" - click.echo(f"\nRetrieving status: {url}\n") - click.echo(f"Headers: {headers}") + try: response = requests.get(url, headers=headers) print_response(response, "status", id) diff --git a/fedn/cli/validation_cmd.py b/fedn/cli/validation_cmd.py index 27ff8448d..b7417af5e 100644 --- a/fedn/cli/validation_cmd.py +++ b/fedn/cli/validation_cmd.py @@ -42,8 +42,7 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None if session_id: url = f"{url}?sessionId={session_id}" - click.echo(f"\nListing validations: {url}\n") - click.echo(f"Headers: {headers}") + try: response = requests.get(url, headers=headers) print_response(response, "validations", None) @@ -76,8 +75,6 @@ def get_validation(ctx, protocol: str, host: str, port: str, token: str = None, url = f"{url}{id}" - click.echo(f"\nRetrieving validation: {url}\n") - click.echo(f"Headers: {headers}") try: response = requests.get(url, headers=headers) print_response(response, "validation", id) From 4273a005caf3543232c672c05e9a9ee6a5f7efba Mon Sep 17 00:00:00 2001 From: KatHellg Date: Tue, 26 Nov 2024 11:58:34 +0100 Subject: [PATCH 12/26] fixed feedback --- fedn/cli/.fedn/context.yaml | 2 ++ fedn/cli/__init__.py | 1 + fedn/cli/login_cmd.py | 71 +++++++++++++++++++++++++++++++++++++ fedn/utils/dist.py | 2 +- 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 fedn/cli/.fedn/context.yaml create mode 100644 fedn/cli/login_cmd.py diff --git a/fedn/cli/.fedn/context.yaml b/fedn/cli/.fedn/context.yaml new file mode 100644 index 000000000..40a8ae693 --- /dev/null +++ b/fedn/cli/.fedn/context.yaml @@ -0,0 +1,2 @@ +access: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzM1MjEwMjY5LCJpYXQiOjE3MzI2MTgyNjksImp0aSI6ImIxNDY4ODVlMzM4NTRiYWRhM2I3YTExODUyNzJjOTNjIiwidXNlcl9pZCI6MzQ3LCJjcmVhdG9yIjoiS2F0amFIIiwicm9sZSI6bnVsbCwicHJvamVjdF9zbHVnIjoiIn0.aUpJTSQYe_yTi2QiY0yzhdaAjkS9gd07o4V3X5f6LCg +refresh: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTc0MDM5NDI2OSwiaWF0IjoxNzMyNjE4MjY5LCJqdGkiOiI3M2NmNDhhNDE3Mjc0ZTVlYTUwNTA5YWNiZDBlNDI4MyIsInVzZXJfaWQiOjM0NywiY3JlYXRvciI6IkthdGphSCIsInJvbGUiOm51bGwsInByb2plY3Rfc2x1ZyI6IiJ9.Y1sSbRKlI07kLv2p3YlCwP5lEKUBTOH-QqiOhVG9NBo diff --git a/fedn/cli/__init__.py b/fedn/cli/__init__.py index 7028dbfa6..be680eb23 100644 --- a/fedn/cli/__init__.py +++ b/fedn/cli/__init__.py @@ -11,3 +11,4 @@ from .status_cmd import status_cmd # noqa: F401 from .validation_cmd import validation_cmd # noqa: F401 from .controller_cmd import controller_cmd # noqa: F401 +from .login_cmd import login_cmd # noqa: F401 diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py new file mode 100644 index 000000000..8ba406600 --- /dev/null +++ b/fedn/cli/login_cmd.py @@ -0,0 +1,71 @@ +import os +import yaml +import click +import requests + +from .main import main +from getpass import getpass + +# Replace this with the platform's actual login endpoint +home_dir = os.path.expanduser("~") + +DEFAULT_URL = "https://fedn.scaleoutsystems.com" + + +@main.group("studio") +@click.pass_context +def login_cmd(ctx): + """:param ctx:""" + pass + + +@login_cmd.command("login") +@click.pass_context +def login_cmd(ctx): + """Logging into FEDn Studio + + """ + # Step 1: Display welcome message + click.secho("Welcome to Scaleout FEDn!", fg="green") + + # Step 2: Prompt for domain + domain = input("Please enter your domain or press enter to use default domain: ").strip() + if domain: + URL = f"https//:{domain}/api/token/" + else: + URL = f"{DEFAULT_URL}/api/token/" + + # Step 3: Prompt for username and password + username = input("Please enter your username: ") + password = getpass("Please enter your password: ") + + # Call the authentication API + try: + response = requests.post( + URL, + json={"username": username, "password": password}, + headers={"Content-Type": "application/json"} + ) + response.raise_for_status() # Raise an error for HTTP codes 4xx/5xx + except requests.exceptions.RequestException as e: + click.secho("Error connecting to the platform. Please try again.", fg="red") + click.secho(str(e), fg="red") + return + + # Handle the response + if response.status_code == 200: + data = response.json() + if data.get("access"): + click.secho("Login successful!", fg="green") + context_path = os.path.join(home_dir, ".fedn") + if not os.path.exists(context_path): + os.makedirs(context_path) + try: + with open(f"{context_path}/context.yaml", "w") as yaml_file: + yaml.dump(data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file + except Exception as e: + print(f"Error: Failed to write to YAML file. Details: {e}") + else: + click.secho("Login failed. Please check your credentials.", fg="red") + else: + click.secho(f"Unexpected error: {response.text}", fg="red") diff --git a/fedn/utils/dist.py b/fedn/utils/dist.py index e5fa7192b..82812dfc3 100644 --- a/fedn/utils/dist.py +++ b/fedn/utils/dist.py @@ -3,7 +3,7 @@ import fedn -def get_version(pacakge): +def get_version(package): # Dynamically get the version of the package try: version = importlib.metadata.version("fedn") From 5030a2426e2f3676aafecc242648803f32afd74c Mon Sep 17 00:00:00 2001 From: KatHellg Date: Tue, 26 Nov 2024 15:07:36 +0100 Subject: [PATCH 13/26] ruff linting fix --- fedn/cli/login_cmd.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index 8ba406600..e40012eb4 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -1,10 +1,11 @@ import os -import yaml +from getpass import getpass + import click import requests +import yaml from .main import main -from getpass import getpass # Replace this with the platform's actual login endpoint home_dir = os.path.expanduser("~") @@ -22,9 +23,7 @@ def login_cmd(ctx): @login_cmd.command("login") @click.pass_context def login_cmd(ctx): - """Logging into FEDn Studio - - """ + """Logging into FEDn Studio""" # Step 1: Display welcome message click.secho("Welcome to Scaleout FEDn!", fg="green") @@ -41,11 +40,7 @@ def login_cmd(ctx): # Call the authentication API try: - response = requests.post( - URL, - json={"username": username, "password": password}, - headers={"Content-Type": "application/json"} - ) + response = requests.post(URL, json={"username": username, "password": password}, headers={"Content-Type": "application/json"}) response.raise_for_status() # Raise an error for HTTP codes 4xx/5xx except requests.exceptions.RequestException as e: click.secho("Error connecting to the platform. Please try again.", fg="red") @@ -62,7 +57,7 @@ def login_cmd(ctx): os.makedirs(context_path) try: with open(f"{context_path}/context.yaml", "w") as yaml_file: - yaml.dump(data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file + yaml.dump(data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file except Exception as e: print(f"Error: Failed to write to YAML file. Details: {e}") else: From 2cf9959acfbad18e5072599515793726167301aa Mon Sep 17 00:00:00 2001 From: KatHellg Date: Fri, 29 Nov 2024 13:56:51 +0100 Subject: [PATCH 14/26] in progress --- fedn/cli/__init__.py | 5 +- fedn/cli/project_cmd.py | 102 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 fedn/cli/project_cmd.py diff --git a/fedn/cli/__init__.py b/fedn/cli/__init__.py index be680eb23..f00bb351b 100644 --- a/fedn/cli/__init__.py +++ b/fedn/cli/__init__.py @@ -1,14 +1,15 @@ from .client_cmd import client_cmd # noqa: F401 from .combiner_cmd import combiner_cmd # noqa: F401 from .config_cmd import config_cmd # noqa: F401 +from .controller_cmd import controller_cmd # noqa: F401 from .hooks_cmd import hooks_cmd # noqa: F401 +from .login_cmd import login_cmd # noqa: F401 from .main import main # noqa: F401 from .model_cmd import model_cmd # noqa: F401 from .package_cmd import package_cmd # noqa: F401 +from .project_cmd import project_cmd # noqa: F401 from .round_cmd import round_cmd # noqa: F401 from .run_cmd import run_cmd # noqa: F401 from .session_cmd import session_cmd # noqa: F401 from .status_cmd import status_cmd # noqa: F401 from .validation_cmd import validation_cmd # noqa: F401 -from .controller_cmd import controller_cmd # noqa: F401 -from .login_cmd import login_cmd # noqa: F401 diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py new file mode 100644 index 000000000..de2550d56 --- /dev/null +++ b/fedn/cli/project_cmd.py @@ -0,0 +1,102 @@ +import os + +import click +import requests + +from fedn.common.log_config import logger + +from .main import main +from .shared import get_api_url + + +@main.group("project") +@click.pass_context +def project_cmd(ctx): + """:param ctx:""" + pass + + +@project_cmd.command("create") +@click.option("-n", "--name", required=True, help="Name of project") +@click.option("-d", "--description", required=False, help="Project description") +@click.pass_context +def create_project(ctx, name, description): + """Create compute package. + + :param ctx: + :param name: + :param description: + """ + return 0 + + +@click.option("--n_max", required=False, help="Number of items to list") +@project_cmd.command("list") +@click.pass_context +def list_projects(ctx, n_max: int = None): + """Return: + ------ + - result: list of packages + + """ + url = get_api_url(protocol=protocol, host=host, port=port, endpoint="packages") + headers = {} + + if n_max: + headers["X-Limit"] = n_max + + _token = get_token(token) + + if _token: + headers["Authorization"] = _token + + try: + response = requests.get(url, headers=headers) + print(response.json()) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + + +@click.option("-n", "--name", required=True, help="Authentication token") +@project_cmd.command("get") +@click.pass_context +def get_project(ctx, name: str = None): + """Return: + ------ + - result: project with given name + + """ + # Define the endpoint and headers + url = "http://localhost:8000/api/some-protected-view/" + headers = { + "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU" + } + + # Make the GET request + response = requests.get(url, headers=headers) + + # Print the response + print(f"Status code: {response.status_code}") + print(f"Response body: {response.text}") + + +@click.option("-n", "--name", required=True, help="Project name") +@project_cmd.command("set") +@click.pass_context +def set_project(ctx, name: str = None): + """Return: + ------ + + """ + headers = {} + + _token = None + + if _token: + headers["Authorization"] = _token + + try: + response = requests.get(url, headers=headers) + print(response.json()) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") From c49b7703655f08b1f04f6eb02b2e9a0c3549aca1 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Fri, 3 Jan 2025 15:40:20 +0100 Subject: [PATCH 15/26] added default project to context file --- fedn/cli/login_cmd.py | 70 +++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index e40012eb4..e75bd7081 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -10,8 +10,6 @@ # Replace this with the platform's actual login endpoint home_dir = os.path.expanduser("~") -DEFAULT_URL = "https://fedn.scaleoutsystems.com" - @main.group("studio") @click.pass_context @@ -21,18 +19,15 @@ def login_cmd(ctx): @login_cmd.command("login") +@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") +@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") @click.pass_context -def login_cmd(ctx): +def login_cmd(ctx, protocol: str, host: str): """Logging into FEDn Studio""" # Step 1: Display welcome message click.secho("Welcome to Scaleout FEDn!", fg="green") - # Step 2: Prompt for domain - domain = input("Please enter your domain or press enter to use default domain: ").strip() - if domain: - URL = f"https//:{domain}/api/token/" - else: - URL = f"{DEFAULT_URL}/api/token/" + url = f"{protocol}://{host}/api/token/" # Step 3: Prompt for username and password username = input("Please enter your username: ") @@ -40,7 +35,7 @@ def login_cmd(ctx): # Call the authentication API try: - response = requests.post(URL, json={"username": username, "password": password}, headers={"Content-Type": "application/json"}) + response = requests.post(url, json={"username": username, "password": password}, headers={"Content-Type": "application/json"}) response.raise_for_status() # Raise an error for HTTP codes 4xx/5xx except requests.exceptions.RequestException as e: click.secho("Error connecting to the platform. Please try again.", fg="red") @@ -49,18 +44,47 @@ def login_cmd(ctx): # Handle the response if response.status_code == 200: - data = response.json() - if data.get("access"): - click.secho("Login successful!", fg="green") - context_path = os.path.join(home_dir, ".fedn") - if not os.path.exists(context_path): - os.makedirs(context_path) - try: - with open(f"{context_path}/context.yaml", "w") as yaml_file: - yaml.dump(data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file - except Exception as e: - print(f"Error: Failed to write to YAML file. Details: {e}") - else: - click.secho("Login failed. Please check your credentials.", fg="red") + context_data = get_context(response, protocol, host) + + context_path = os.path.join(home_dir, ".fedn") + if not os.path.exists(context_path): + os.makedirs(context_path) + try: + with open(f"{context_path}/context.yaml", "w") as yaml_file: + yaml.dump(context_data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file + except Exception as e: + print(f"Error: Failed to write to YAML file. Details: {e}") else: click.secho(f"Unexpected error: {response.text}", fg="red") + + +def get_context(response, protocol, host): + user_token_data = response.json() + + if user_token_data.get("access"): + click.secho("Login successful!", fg="green") + user_access_token = user_token_data.get("access") + url_projects = f"{protocol}://{host}/api/v1/projects" + headers_projects = {} + + if user_access_token: + headers_projects = {"Authorization": f"Bearer {user_access_token}"} + + try: + response_projects = requests.get(url_projects, headers=headers_projects) + projects_response_json = response_projects.json() + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url_projects}") + + headers_projects["X-Project-Slug"] = projects_response_json[0].get("slug") + url_project_token = f"{protocol}://{host}/api/v1/admin-token" + try: + response_project_tokens = requests.get(url_project_token, headers=headers_projects) + project_tokens = response_project_tokens.json() + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url_project_token}") + + context_data = {"User tokens": user_token_data, "Active project tokens": project_tokens, "Active project name": projects_response_json[0].get("name")} + return context_data + else: + click.secho("Login failed. Please check your credentials.", fg="red") From c12ada981dd0c283dd3ddc870a58717bd69189a4 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Fri, 3 Jan 2025 17:20:47 +0100 Subject: [PATCH 16/26] changed from project name to project slug in context file --- fedn/cli/login_cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index e75bd7081..ecc8bb1fb 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -84,7 +84,7 @@ def get_context(response, protocol, host): except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url_project_token}") - context_data = {"User tokens": user_token_data, "Active project tokens": project_tokens, "Active project name": projects_response_json[0].get("name")} + context_data = {"User tokens": user_token_data, "Active project tokens": project_tokens, "Active project slug": projects_response_json[0].get("slug")} return context_data else: click.secho("Login failed. Please check your credentials.", fg="red") From 8e551105710596697e1bd8001d5d037a499743e9 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Fri, 3 Jan 2025 17:36:13 +0100 Subject: [PATCH 17/26] first draft of list, get, set and create project --- fedn/cli/project_cmd.py | 79 +++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index 11bcf68d3..515baef45 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -22,31 +22,55 @@ def project_cmd(ctx): @project_cmd.command("create") @click.pass_context def create_project(ctx, protocol: str = None, host: str = None, token: str = None): - """Create compute package. + """Create project. + :param ctx: + """ + url = f"{protocol}://{host}/api/v1/projects/create" + headers = {} + + if token: + headers = {"Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {token}"} + + name = input("Please enter a project name: ") + description = input("Please enter a project description (optional): ") + + # Call the authentication API + try: + requests.post(url, data={"name": name, "description": description}, headers=headers) + except requests.exceptions.RequestException as e: + click.secho(str(e), fg="red") + + click.secho("Project created.", fg="green") + + +@click.option("-s", "--slug", required=True, help="Slug name of project.") +@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") +@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") +@click.option("-t", "--token", required=False, help="User access token") +@project_cmd.command("delete") +@click.pass_context +def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): + """Create project. :param ctx: :param name: :param description: """ - url = f"{protocol}://{host}/api/v1/project/create" + url = f"{protocol}://{host}/api/internal/app/projects/delete/{slug}" headers = {} if token: headers = {"Authorization": f"Bearer {token}"} - name = input("Please enter a project name: ") - description = input("Please enter a project description (optional): ") - # Call the authentication API try: - response = requests.post(url, json={"name": name, "description": description}, headers=headers) - response.raise_for_status() # Raise an error for HTTP codes 4xx/5xx + requests.delete(url, headers=headers) except requests.exceptions.RequestException as e: click.secho(str(e), fg="red") - return - set_active_project(name, protocol, host) - click.secho("Project created and activated.", fg="green") + # if deleted project is active, activate another + set_active_project(None, protocol, host) + click.secho("Project successfully deleted.", fg="green") @click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") @@ -73,13 +97,13 @@ def list_projects(ctx, protocol: str = None, host: str = None, token: str = None except Exception as e: print(f"Error: Failed to read YAML file. Details: {e}") - active_project = context_data.get("Active project name") + active_project = context_data.get("Active project slug") try: response = requests.get(url, headers=headers) response_json = response.json() for i in response_json: - project_name = i.get("name") + project_name = i.get("slug") if project_name == active_project: click.secho(project_name, fg="green") else: @@ -88,18 +112,16 @@ def list_projects(ctx, protocol: str = None, host: str = None, token: str = None click.echo(f"Error: Could not connect to {url}") -@click.option( - "-n", "--name", required=True, help="Name of project. If the name contains a space, make sure to encapsulate the full name with quotation characters." -) +@click.option("-s", "--slug", required=True, help="Slug name of project.") @click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") @click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("get") @click.pass_context -def get_project(ctx, name: str = None, protocol: str = None, host: str = None, token: str = None): +def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): """Return: ------ - - result: project with given name + - result: project with given slug """ url = f"{protocol}://{host}/api/v1/projects" @@ -111,33 +133,30 @@ def get_project(ctx, name: str = None, protocol: str = None, host: str = None, t response = requests.get(url, headers=headers) response_json = response.json() if len(response_json) == 1: - print(response_json[0].get("name")) + print(response_json[0].get("slug")) else: project_found = False for i in response_json: - i_name = i.get("name") - if i_name.lower() == name.lower(): + i_name = i.get("slug") + if i_name.lower() == slug.lower(): project_found = True print(i) if not project_found: - click.secho(f"No project with name {name} exists for this account.", fg="red") + click.secho(f"No project with name {slug} exists for this account.", fg="red") except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") -@click.option( - "-n", "--name", required=True, help="Name of project. If the name contains a space, make sure to encapsulate the full name with quotation characters." -) +@click.option("-s", "--slug", required=True, help="Slug name of project.") @click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") @click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") @project_cmd.command("activate") @click.pass_context -def set_active_project(ctx, name: str = None, protocol: str = None, host: str = None): +def set_active_project(ctx, slug: str = None, protocol: str = None, host: str = None): """Set active project. :param ctx: - :param name: - :param description: + :param slug: """ url_projects = f"{protocol}://{host}/api/v1/projects" url_project_token = f"{protocol}://{host}/api/v1/admin-token" @@ -162,14 +181,14 @@ def set_active_project(ctx, name: str = None, protocol: str = None, host: str = click.echo(f"Error: Could not connect to {url_projects}") for i in projects_response_json: - if i.get("name") == name: + if i.get("slug") == slug: headers_projects["X-Project-Slug"] = i.get("slug") try: response_project_tokens = requests.get(url_project_token, headers=headers_projects) project_tokens = response_project_tokens.json() context_data["Active project tokens"] = project_tokens - context_data["Active project name"] = name + context_data["Active project slug"] = slug except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url_project_token}") @@ -179,4 +198,4 @@ def set_active_project(ctx, name: str = None, protocol: str = None, host: str = except Exception as e: print(f"Error: Failed to write to YAML file. Details: {e}") - click.secho(f"Project with name {name} was succsessfully activated.", fg="green") + click.secho(f"Project with slug {slug} was succsessfully activated.", fg="green") From 08594c0ef52f2c74ecf251467ae02821e9665869 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 8 Jan 2025 14:30:45 +0100 Subject: [PATCH 18/26] Added project resource --- fedn/cli/client_cmd.py | 14 ++-- fedn/cli/combiner_cmd.py | 10 +-- fedn/cli/login_cmd.py | 38 ++++++---- fedn/cli/model_cmd.py | 12 +-- fedn/cli/package_cmd.py | 16 ++-- fedn/cli/project_cmd.py | 147 ++++++++++++++++++++----------------- fedn/cli/round_cmd.py | 17 ++--- fedn/cli/session_cmd.py | 15 ++-- fedn/cli/shared.py | 31 ++++++-- fedn/cli/status_cmd.py | 13 +--- fedn/cli/validation_cmd.py | 15 ++-- 11 files changed, 161 insertions(+), 167 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 7c9ffc1e7..830b66d81 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -55,18 +55,18 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - try: response = requests.get(url, headers=headers) print_response(response, "clients", None) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") + @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @@ -80,19 +80,15 @@ def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: client with given id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="clients") + _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="clients") + url = f"{_url}{id}" headers = {} - - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - if id: - url = f"{url}{id}" - - try: response = requests.get(url, headers=headers) print_response(response, "client", id) diff --git a/fedn/cli/combiner_cmd.py b/fedn/cli/combiner_cmd.py index 0a6403587..57e8652f4 100644 --- a/fedn/cli/combiner_cmd.py +++ b/fedn/cli/combiner_cmd.py @@ -83,7 +83,7 @@ def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token @@ -108,17 +108,15 @@ def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id - result: combiner with given id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="combiners") + _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="combiners") + url = f"{_url}{id}" headers = {} - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - if id: - url = f"{url}{id}" - try: response = requests.get(url, headers=headers) print_response(response, "combiner", id) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index ecc8bb1fb..54d1575e7 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -6,6 +6,7 @@ import yaml from .main import main +from .shared import CONTROLLER_DEFAULTS, get_token # Replace this with the platform's actual login endpoint home_dir = os.path.expanduser("~") @@ -19,10 +20,11 @@ def login_cmd(ctx): @login_cmd.command("login") -@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") -@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.pass_context -def login_cmd(ctx, protocol: str, host: str): +def login_cmd(ctx, protocol: str, host: str, port: str = None): """Logging into FEDn Studio""" # Step 1: Display welcome message click.secho("Welcome to Scaleout FEDn!", fg="green") @@ -44,7 +46,7 @@ def login_cmd(ctx, protocol: str, host: str): # Handle the response if response.status_code == 200: - context_data = get_context(response, protocol, host) + context_data = get_context(response, protocol, host, port) context_path = os.path.join(home_dir, ".fedn") if not os.path.exists(context_path): @@ -58,17 +60,15 @@ def login_cmd(ctx, protocol: str, host: str): click.secho(f"Unexpected error: {response.text}", fg="red") -def get_context(response, protocol, host): +def get_context(response, protocol, host, port): user_token_data = response.json() - if user_token_data.get("access"): - click.secho("Login successful!", fg="green") - user_access_token = user_token_data.get("access") - url_projects = f"{protocol}://{host}/api/v1/projects" + url_projects = f"{protocol}://{host}/api/v1/projects" # get_api_url(protocol=protocol, host=host, port=port, endpoint="projects") headers_projects = {} - - if user_access_token: - headers_projects = {"Authorization": f"Bearer {user_access_token}"} + user_access_token = user_token_data.get("access") + _token = get_token(user_access_token, True) + if _token: + headers_projects["Authorization"] = _token try: response_projects = requests.get(url_projects, headers=headers_projects) @@ -76,15 +76,23 @@ def get_context(response, protocol, host): except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url_projects}") - headers_projects["X-Project-Slug"] = projects_response_json[0].get("slug") - url_project_token = f"{protocol}://{host}/api/v1/admin-token" + slug = projects_response_json[0].get("slug") + headers_projects["X-Project-Slug"] = slug + url_project_token = f"{protocol}://{host}/api/v1/admin-token" # get_api_url(protocol=protocol, host=host, port=port, endpoint="admin-token") try: response_project_tokens = requests.get(url_project_token, headers=headers_projects) project_tokens = response_project_tokens.json() except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url_project_token}") - context_data = {"User tokens": user_token_data, "Active project tokens": project_tokens, "Active project slug": projects_response_json[0].get("slug")} + controller_url = f"{protocol}://{host}/{slug}-fedn-reducer" + context_data = { + "User tokens": user_token_data, + "Active project tokens": project_tokens, + "Active project slug": slug, + "Active project url": controller_url, + } + click.secho("Login successful!", fg="green") return context_data else: click.secho("Login failed. Please check your credentials.", fg="red") diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index 2e522e5a1..8eb6d3ff9 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -8,8 +8,7 @@ @main.group("model") @click.pass_context def model_cmd(ctx): - """:param ctx: - """ + """:param ctx:""" pass @@ -30,13 +29,12 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, ses """ url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") - headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token @@ -44,7 +42,6 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, ses if session_id: url = f"{url}?session_id={session_id}" - try: response = requests.get(url, headers=headers) print_response(response, "models", None) @@ -67,11 +64,9 @@ def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: s """ url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") - headers = {} - - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token @@ -79,7 +74,6 @@ def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: s if id: url = f"{url}{id}" - try: response = requests.get(url, headers=headers) print_response(response, "model", id) diff --git a/fedn/cli/package_cmd.py b/fedn/cli/package_cmd.py index b8a130f68..6315d4359 100644 --- a/fedn/cli/package_cmd.py +++ b/fedn/cli/package_cmd.py @@ -13,8 +13,7 @@ @main.group("package") @click.pass_context def package_cmd(ctx): - """:param ctx: - """ + """:param ctx:""" pass @@ -61,12 +60,11 @@ def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, n if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - try: response = requests.get(url, headers=headers) print_response(response, "packages", None) @@ -87,19 +85,15 @@ def get_package(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: package with given id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="packages") + _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="packages") + url = f"{_url}{id}" headers = {} - - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - if id: - url = f"{url}{id}" - - try: response = requests.get(url, headers=headers) print_response(response, "package", id) diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index 515baef45..c8a6900c2 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -5,6 +5,7 @@ import yaml from .main import main +from .shared import CONTROLLER_DEFAULTS, get_token, print_response home_dir = os.path.expanduser("~") @@ -16,20 +17,51 @@ def project_cmd(ctx): pass -@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") -@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") +@click.option("-s", "--slug", required=True, help="Slug name of project.") +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-t", "--token", required=False, help="User access token") +@project_cmd.command("delete") +@click.pass_context +def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None, port: str = None, token: str = None): + """Delete project.""" + user_input = input(f"Are you sure you want to delete project with slug {slug} (y/n)?: ") + if user_input == "y": + _url = f"{protocol}://{host}/api/v1/projects/delete/" + url = f"{_url}{slug}" + headers = {} + + _token = get_token(token, True) + + if _token: + headers["Authorization"] = _token + # Call the authentication API + try: + requests.delete(url, headers=headers) + click.secho(f"Project with slug {slug} has been removed.", fg="green") + activate_project(None, protocol, host) + except requests.exceptions.RequestException as e: + click.echo(str(e), fg="red") + + +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("create") @click.pass_context -def create_project(ctx, protocol: str = None, host: str = None, token: str = None): +def create_project(ctx, protocol: str = None, host: str = None, port: str = None, token: str = None): """Create project. :param ctx: """ url = f"{protocol}://{host}/api/v1/projects/create" - headers = {} + headers = {"Content-Type": "application/x-www-form-urlencoded"} + + _token = get_token(token, True) - if token: - headers = {"Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Bearer {token}"} + if _token: + headers["Authorization"] = _token name = input("Please enter a project name: ") description = input("Please enter a project description (optional): ") @@ -43,42 +75,13 @@ def create_project(ctx, protocol: str = None, host: str = None, token: str = Non click.secho("Project created.", fg="green") -@click.option("-s", "--slug", required=True, help="Slug name of project.") -@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") -@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") -@click.option("-t", "--token", required=False, help="User access token") -@project_cmd.command("delete") -@click.pass_context -def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): - """Create project. - - :param ctx: - :param name: - :param description: - """ - url = f"{protocol}://{host}/api/internal/app/projects/delete/{slug}" - headers = {} - - if token: - headers = {"Authorization": f"Bearer {token}"} - - # Call the authentication API - try: - requests.delete(url, headers=headers) - except requests.exceptions.RequestException as e: - click.secho(str(e), fg="red") - - # if deleted project is active, activate another - set_active_project(None, protocol, host) - click.secho("Project successfully deleted.", fg="green") - - -@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") -@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("list") @click.pass_context -def list_projects(ctx, protocol: str = None, host: str = None, token: str = None): +def list_projects(ctx, protocol: str = None, host: str = None, port: str = None, token: str = None): """Return: ------ - result: list of packages @@ -87,9 +90,10 @@ def list_projects(ctx, protocol: str = None, host: str = None, token: str = None url = f"{protocol}://{host}/api/v1/projects" headers = {} - if token: - headers = {"Authorization": f"Bearer {token}"} + _token = get_token(token, True) + if _token: + headers["Authorization"] = _token context_path = os.path.join(home_dir, ".fedn") try: with open(f"{context_path}/context.yaml", "r") as yaml_file: @@ -113,51 +117,48 @@ def list_projects(ctx, protocol: str = None, host: str = None, token: str = None @click.option("-s", "--slug", required=True, help="Slug name of project.") -@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") -@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("get") @click.pass_context -def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): +def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, port: str = None, token: str = None): """Return: ------ - result: project with given slug """ - url = f"{protocol}://{host}/api/v1/projects" + url = f"{protocol}://{host}/api/v1/projects/{slug}" headers = {} - if token: - headers = {"Authorization": f"Bearer {token}"} + _token = get_token(token, False) + + if _token: + headers["Authorization"] = _token try: response = requests.get(url, headers=headers) - response_json = response.json() - if len(response_json) == 1: - print(response_json[0].get("slug")) - else: - project_found = False - for i in response_json: - i_name = i.get("slug") - if i_name.lower() == slug.lower(): - project_found = True - print(i) - if not project_found: - click.secho(f"No project with name {slug} exists for this account.", fg="red") + print_response(response, "project", True) except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") @click.option("-s", "--slug", required=True, help="Slug name of project.") -@click.option("-p", "--protocol", required=False, default="https", help="Communication protocol") -@click.option("-H", "--host", required=False, default="fedn.scaleoutsystems.com", help="Hostname of controller (api)") +@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") +@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") +@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @project_cmd.command("activate") @click.pass_context -def set_active_project(ctx, slug: str = None, protocol: str = None, host: str = None): +def set_active_project(ctx, slug: str = None, protocol: str = None, host: str = None, port: str = None): """Set active project. :param ctx: :param slug: """ + activate_project(slug, protocol, host, port) + + +def activate_project(slug: str = None, protocol: str = None, host: str = None, port: str = None): url_projects = f"{protocol}://{host}/api/v1/projects" url_project_token = f"{protocol}://{host}/api/v1/admin-token" context_path = os.path.join(home_dir, ".fedn") @@ -180,22 +181,30 @@ def set_active_project(ctx, slug: str = None, protocol: str = None, host: str = except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url_projects}") - for i in projects_response_json: - if i.get("slug") == slug: - headers_projects["X-Project-Slug"] = i.get("slug") + if slug is None: + headers_projects["X-Project-Slug"] = projects_response_json[0].get("slug") + slug = projects_response_json[0].get("slug") + else: + for i in projects_response_json: + if i.get("slug") == slug: + headers_projects["X-Project-Slug"] = i.get("slug") + + controller_url = f"{protocol}://{host}/{slug}-fedn-reducer" try: response_project_tokens = requests.get(url_project_token, headers=headers_projects) - project_tokens = response_project_tokens.json() - context_data["Active project tokens"] = project_tokens - context_data["Active project slug"] = slug except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url_project_token}") + project_tokens = response_project_tokens.json() + context_data["Active project tokens"] = project_tokens + context_data["Active project slug"] = slug + context_data["Active project url"] = controller_url + try: with open(f"{context_path}/context.yaml", "w") as yaml_file: yaml.dump(context_data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file except Exception as e: print(f"Error: Failed to write to YAML file. Details: {e}") - click.secho(f"Project with slug {slug} was succsessfully activated.", fg="green") + click.secho(f"Project with slug {slug} is now active.", fg="green") diff --git a/fedn/cli/round_cmd.py b/fedn/cli/round_cmd.py index 2f889fef3..58fbb5863 100644 --- a/fedn/cli/round_cmd.py +++ b/fedn/cli/round_cmd.py @@ -8,8 +8,7 @@ @main.group("round") @click.pass_context def round_cmd(ctx): - """:param ctx: - """ + """:param ctx:""" pass @@ -35,7 +34,7 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, ses if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token @@ -43,7 +42,6 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, ses if session_id: url = f"{url}?round_config.session_id={session_id}" - try: response = requests.get(url, headers=headers) print_response(response, "rounds", None) @@ -65,20 +63,15 @@ def get_round(ctx, protocol: str, host: str, port: str, token: str = None, id: s - result: round with given id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="rounds") - + _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="rounds") + url = f"{_url}{id}" headers = {} - - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - if id: - url = f"{url}{id}" - - try: response = requests.get(url, headers=headers) print_response(response, "round", id) diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index a0f1e64c3..776fc2648 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -8,8 +8,7 @@ @main.group("session") @click.pass_context def session_cmd(ctx): - """:param ctx: - """ + """:param ctx:""" pass @@ -33,12 +32,11 @@ def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, n if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - try: response = requests.get(url, headers=headers) print_response(response, "sessions", None) @@ -59,18 +57,15 @@ def get_session(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: session with given session id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="sessions") + _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="sessions") + url = f"{_url}{id}" headers = {} - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - if id: - url = f"{url}{id}" - - try: response = requests.get(url, headers=headers) print_response(response, "session", id) diff --git a/fedn/cli/shared.py b/fedn/cli/shared.py index 21fa2b072..d2bdf6984 100644 --- a/fedn/cli/shared.py +++ b/fedn/cli/shared.py @@ -16,6 +16,8 @@ API_VERSION = "v1" +home_dir = os.path.expanduser("~") + def apply_config(path: str, config: dict): """Parse client config from file. @@ -37,22 +39,37 @@ def apply_config(path: str, config: dict): def get_api_url(protocol: str, host: str, port: str, endpoint: str) -> str: _url = os.environ.get("FEDN_CONTROLLER_URL") - - if _url: - return f"{_url}/api/{API_VERSION}/{endpoint}/" - _protocol = protocol or os.environ.get("FEDN_CONTROLLER_PROTOCOL") or CONTROLLER_DEFAULTS["protocol"] _host = host or os.environ.get("FEDN_CONTROLLER_HOST") or CONTROLLER_DEFAULTS["host"] _port = port or os.environ.get("FEDN_CONTROLLER_PORT") or CONTROLLER_DEFAULTS["port"] - return f"{_protocol}://{_host}:{_port}/api/{API_VERSION}/{endpoint}/" + if _url is None: + context_path = os.path.join(home_dir, ".fedn") + try: + with open(f"{context_path}/context.yaml", "r") as yaml_file: + context_data = yaml.safe_load(yaml_file) + _url = context_data.get("Active project url") + except Exception as e: + click.echo(f"Encountered error {e}. Make sure you are logged in and have activated a project. Using controller defaults instead.", fg="red") + _url = f"{_protocol}://{_host}:{_port}" + + return f"{_url}/api/{API_VERSION}/{endpoint}/" -def get_token(token: str) -> str: +def get_token(token: str, usr_token: bool) -> str: _token = token or os.environ.get("FEDN_AUTH_TOKEN", None) if _token is None: - return None + context_path = os.path.join(home_dir, ".fedn") + try: + with open(f"{context_path}/context.yaml", "r") as yaml_file: + context_data = yaml.safe_load(yaml_file) + if usr_token: + _token = context_data.get("User tokens").get("access") + else: + _token = context_data.get("Active project tokens").get("access") + except Exception as e: + click.echo(f"Encountered error {e}. Make sure you are logged in and have activated a project.", fg="red") scheme = os.environ.get("FEDN_AUTH_SCHEME", "Bearer") diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index 9b751f65b..73b2da735 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -33,7 +33,7 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, s if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token @@ -41,7 +41,6 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, s if session_id: url = f"{url}?sessionId={session_id}" - try: response = requests.get(url, headers=headers) print_response(response, "statuses", None) @@ -62,19 +61,15 @@ def get_status(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: status with given id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="statuses") + _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="statuses") + url = f"{_url}{id}" headers = {} - - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - if id: - url = f"{url}{id}" - - try: response = requests.get(url, headers=headers) print_response(response, "status", id) diff --git a/fedn/cli/validation_cmd.py b/fedn/cli/validation_cmd.py index b7417af5e..2be991bc5 100644 --- a/fedn/cli/validation_cmd.py +++ b/fedn/cli/validation_cmd.py @@ -8,8 +8,7 @@ @main.group("validation") @click.pass_context def validation_cmd(ctx): - """:param ctx: - """ + """:param ctx:""" pass @@ -34,7 +33,7 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None if n_max: headers["X-Limit"] = n_max - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token @@ -42,7 +41,6 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None if session_id: url = f"{url}?sessionId={session_id}" - try: response = requests.get(url, headers=headers) print_response(response, "validations", None) @@ -63,18 +61,15 @@ def get_validation(ctx, protocol: str, host: str, port: str, token: str = None, - result: validation with given id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="validations") + _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="validations") + url = f"{_url}{id}" headers = {} - _token = get_token(token) + _token = get_token(token, False) if _token: headers["Authorization"] = _token - if id: - url = f"{url}{id}" - - try: response = requests.get(url, headers=headers) print_response(response, "validation", id) From de6fa386e985e2fb2711b41b81cf3c8ad53da707 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 8 Jan 2025 14:50:46 +0100 Subject: [PATCH 19/26] bug fix in delete project --- fedn/cli/project_cmd.py | 52 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index c8a6900c2..ca49ed107 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -169,42 +169,42 @@ def activate_project(slug: str = None, protocol: str = None, host: str = None, p print(f"Error: Failed to read YAML file. Details: {e}") user_access_token = context_data.get("User tokens").get("access") - + _token = get_token(user_access_token, True) headers_projects = {} - if user_access_token: - headers_projects = {"Authorization": f"Bearer {user_access_token}"} + if _token: + headers_projects["Authorization"] = _token try: response_projects = requests.get(url_projects, headers=headers_projects) projects_response_json = response_projects.json() except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url_projects}") + if len(projects_response_json) > 0: + if slug is None: + headers_projects["X-Project-Slug"] = projects_response_json[0].get("slug") + slug = projects_response_json[0].get("slug") + else: + for i in projects_response_json: + if i.get("slug") == slug: + headers_projects["X-Project-Slug"] = i.get("slug") - if slug is None: - headers_projects["X-Project-Slug"] = projects_response_json[0].get("slug") - slug = projects_response_json[0].get("slug") - else: - for i in projects_response_json: - if i.get("slug") == slug: - headers_projects["X-Project-Slug"] = i.get("slug") - - controller_url = f"{protocol}://{host}/{slug}-fedn-reducer" + controller_url = f"{protocol}://{host}/{slug}-fedn-reducer" - try: - response_project_tokens = requests.get(url_project_token, headers=headers_projects) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url_project_token}") + try: + response_project_tokens = requests.get(url_project_token, headers=headers_projects) + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url_project_token}") - project_tokens = response_project_tokens.json() - context_data["Active project tokens"] = project_tokens - context_data["Active project slug"] = slug - context_data["Active project url"] = controller_url + project_tokens = response_project_tokens.json() + context_data["Active project tokens"] = project_tokens + context_data["Active project slug"] = slug + context_data["Active project url"] = controller_url - try: - with open(f"{context_path}/context.yaml", "w") as yaml_file: - yaml.dump(context_data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file - except Exception as e: - print(f"Error: Failed to write to YAML file. Details: {e}") + try: + with open(f"{context_path}/context.yaml", "w") as yaml_file: + yaml.dump(context_data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file + except Exception as e: + print(f"Error: Failed to write to YAML file. Details: {e}") - click.secho(f"Project with slug {slug} is now active.", fg="green") + click.secho(f"Project with slug {slug} is now active.", fg="green") From d8d38ea70413c8284a78a84af0ab193159ada4d7 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 8 Jan 2025 15:10:51 +0100 Subject: [PATCH 20/26] handle wrong project slug from user input --- fedn/cli/project_cmd.py | 54 +++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index ca49ed107..6efd65ca2 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -26,23 +26,40 @@ def project_cmd(ctx): @click.pass_context def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None, port: str = None, token: str = None): """Delete project.""" - user_input = input(f"Are you sure you want to delete project with slug {slug} (y/n)?: ") - if user_input == "y": - _url = f"{protocol}://{host}/api/v1/projects/delete/" - url = f"{_url}{slug}" - headers = {} + # Check if project with given slug exists + url = f"{protocol}://{host}/api/v1/projects/{slug}" + headers = {} - _token = get_token(token, True) + _token = get_token(token, False) - if _token: - headers["Authorization"] = _token - # Call the authentication API - try: - requests.delete(url, headers=headers) - click.secho(f"Project with slug {slug} has been removed.", fg="green") - activate_project(None, protocol, host) - except requests.exceptions.RequestException as e: - click.echo(str(e), fg="red") + if _token: + headers["Authorization"] = _token + try: + response = requests.get(url, headers=headers) + response_json = response.json() + except requests.exceptions.ConnectionError: + click.echo(f"Error: Could not connect to {url}") + if response_json.get("error") is None: + # Check if user wants to delete project with given slug + user_input = input(f"Are you sure you want to delete project with slug {slug} (y/n)?: ") + if user_input == "y": + _url = f"{protocol}://{host}/api/v1/projects/delete/" + url = f"{_url}{slug}" + headers = {} + + _token = get_token(token, True) + + if _token: + headers["Authorization"] = _token + # Call the authentication API + try: + requests.delete(url, headers=headers) + click.secho(f"Project with slug {slug} has been removed.", fg="green") + activate_project(None, protocol, host) + except requests.exceptions.RequestException as e: + click.echo(str(e), fg="red") + else: + click.secho(f"No project with slug '{slug}' exists.", fg="red") @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -138,10 +155,15 @@ def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, p headers["Authorization"] = _token try: response = requests.get(url, headers=headers) - print_response(response, "project", True) + response_json = response.json() except requests.exceptions.ConnectionError: click.echo(f"Error: Could not connect to {url}") + if response_json.get("error"): + click.secho(f"No project with slug '{slug}' exists.", fg="red") + else: + print_response(response, "project", True) + @click.option("-s", "--slug", required=True, help="Slug name of project.") @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") From e174f771ee1bc9e60b46071ff8e3c61656479c65 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Wed, 8 Jan 2025 15:13:22 +0100 Subject: [PATCH 21/26] minor bug fix --- fedn/cli/project_cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index 6efd65ca2..14f3f9310 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -55,9 +55,9 @@ def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None try: requests.delete(url, headers=headers) click.secho(f"Project with slug {slug} has been removed.", fg="green") - activate_project(None, protocol, host) except requests.exceptions.RequestException as e: click.echo(str(e), fg="red") + activate_project(None, protocol, host) else: click.secho(f"No project with slug '{slug}' exists.", fg="red") From d5bf9df8fc4b1cd3042a6913c647a7a55da6d977 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Thu, 9 Jan 2025 10:29:42 +0100 Subject: [PATCH 22/26] bug fixes and studio default values added --- fedn/cli/login_cmd.py | 19 +++++----- fedn/cli/project_cmd.py | 80 +++++++++++++++++++++-------------------- fedn/cli/shared.py | 40 +++++++++++++-------- 3 files changed, 77 insertions(+), 62 deletions(-) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index 54d1575e7..740654d0f 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -6,7 +6,7 @@ import yaml from .main import main -from .shared import CONTROLLER_DEFAULTS, get_token +from .shared import STUDIO_DEFAULTS, get_api_url, get_token # Replace this with the platform's actual login endpoint home_dir = os.path.expanduser("~") @@ -20,11 +20,10 @@ def login_cmd(ctx): @login_cmd.command("login") -@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") -@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") -@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") +@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @click.pass_context -def login_cmd(ctx, protocol: str, host: str, port: str = None): +def login_cmd(ctx, protocol: str, host: str): """Logging into FEDn Studio""" # Step 1: Display welcome message click.secho("Welcome to Scaleout FEDn!", fg="green") @@ -46,7 +45,7 @@ def login_cmd(ctx, protocol: str, host: str, port: str = None): # Handle the response if response.status_code == 200: - context_data = get_context(response, protocol, host, port) + context_data = get_context(response, protocol, host) context_path = os.path.join(home_dir, ".fedn") if not os.path.exists(context_path): @@ -60,10 +59,11 @@ def login_cmd(ctx, protocol: str, host: str, port: str = None): click.secho(f"Unexpected error: {response.text}", fg="red") -def get_context(response, protocol, host, port): +def get_context(response, protocol, host): user_token_data = response.json() if user_token_data.get("access"): - url_projects = f"{protocol}://{host}/api/v1/projects" # get_api_url(protocol=protocol, host=host, port=port, endpoint="projects") + studio_api = True + url_projects = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects", usr_api=studio_api) headers_projects = {} user_access_token = user_token_data.get("access") _token = get_token(user_access_token, True) @@ -78,7 +78,8 @@ def get_context(response, protocol, host, port): slug = projects_response_json[0].get("slug") headers_projects["X-Project-Slug"] = slug - url_project_token = f"{protocol}://{host}/api/v1/admin-token" # get_api_url(protocol=protocol, host=host, port=port, endpoint="admin-token") + url_project_token = get_api_url(protocol=protocol, host=host, port=None, endpoint="admin-token", usr_api=studio_api) + try: response_project_tokens = requests.get(url_project_token, headers=headers_projects) project_tokens = response_project_tokens.json() diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index 14f3f9310..24265ee7a 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -5,7 +5,7 @@ import yaml from .main import main -from .shared import CONTROLLER_DEFAULTS, get_token, print_response +from .shared import STUDIO_DEFAULTS, get_api_url, get_token, print_response home_dir = os.path.expanduser("~") @@ -18,16 +18,16 @@ def project_cmd(ctx): @click.option("-s", "--slug", required=True, help="Slug name of project.") -@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") -@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") -@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") +@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("delete") @click.pass_context -def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None, port: str = None, token: str = None): +def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): """Delete project.""" # Check if project with given slug exists - url = f"{protocol}://{host}/api/v1/projects/{slug}" + studio_api = True + url = get_api_url(protocol=protocol, host=host, port=None, endpoint=f"projects/{slug}", usr_api=studio_api) headers = {} _token = get_token(token, False) @@ -43,8 +43,7 @@ def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None # Check if user wants to delete project with given slug user_input = input(f"Are you sure you want to delete project with slug {slug} (y/n)?: ") if user_input == "y": - _url = f"{protocol}://{host}/api/v1/projects/delete/" - url = f"{_url}{slug}" + url = get_api_url(protocol=protocol, host=host, port=None, endpoint=f"projects/delete/{slug}", usr_api=studio_api) headers = {} _token = get_token(token, True) @@ -62,17 +61,18 @@ def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None click.secho(f"No project with slug '{slug}' exists.", fg="red") -@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") -@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") -@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") +@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("create") @click.pass_context -def create_project(ctx, protocol: str = None, host: str = None, port: str = None, token: str = None): +def create_project(ctx, protocol: str = None, host: str = None, token: str = None): """Create project. :param ctx: """ - url = f"{protocol}://{host}/api/v1/projects/create" + # Check if user can create project + studio_api = True + url = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects/create", usr_api=studio_api) headers = {"Content-Type": "application/x-www-form-urlencoded"} _token = get_token(token, True) @@ -82,29 +82,30 @@ def create_project(ctx, protocol: str = None, host: str = None, port: str = None name = input("Please enter a project name: ") description = input("Please enter a project description (optional): ") - - # Call the authentication API - try: - requests.post(url, data={"name": name, "description": description}, headers=headers) - except requests.exceptions.RequestException as e: - click.secho(str(e), fg="red") - - click.secho("Project created.", fg="green") + if len(name) > 46 or len(description) >= 255: + click.secho("Project name or description too long.", fg="red") + else: + # Call the authentication API + try: + requests.post(url, data={"name": name, "description": description}, headers=headers) + except requests.exceptions.RequestException as e: + click.secho(str(e), fg="red") + click.secho("Project created.", fg="green") -@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") -@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") -@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") +@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("list") @click.pass_context -def list_projects(ctx, protocol: str = None, host: str = None, port: str = None, token: str = None): +def list_projects(ctx, protocol: str = None, host: str = None, token: str = None): """Return: ------ - result: list of packages """ - url = f"{protocol}://{host}/api/v1/projects" + studio_api = True + url = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects", usr_api=studio_api) headers = {} _token = get_token(token, True) @@ -134,19 +135,19 @@ def list_projects(ctx, protocol: str = None, host: str = None, port: str = None, @click.option("-s", "--slug", required=True, help="Slug name of project.") -@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") -@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") -@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") +@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("get") @click.pass_context -def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, port: str = None, token: str = None): +def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): """Return: ------ - result: project with given slug """ - url = f"{protocol}://{host}/api/v1/projects/{slug}" + studio_api = True + url = get_api_url(protocol=protocol, host=host, port=None, endpoint=f"projects/{slug}", usr_api=studio_api) headers = {} _token = get_token(token, False) @@ -166,23 +167,24 @@ def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, p @click.option("-s", "--slug", required=True, help="Slug name of project.") -@click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") -@click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") -@click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") +@click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") +@click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @project_cmd.command("activate") @click.pass_context -def set_active_project(ctx, slug: str = None, protocol: str = None, host: str = None, port: str = None): +def set_active_project(ctx, slug: str = None, protocol: str = None, host: str = None): """Set active project. :param ctx: :param slug: """ - activate_project(slug, protocol, host, port) + activate_project(slug, protocol, host) + +def activate_project(slug: str = None, protocol: str = None, host: str = None): + studio_api = True + url_projects = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects", usr_api=studio_api) + url_project_token = get_api_url(protocol=protocol, host=host, port=None, endpoint="admin-token", usr_api=studio_api) -def activate_project(slug: str = None, protocol: str = None, host: str = None, port: str = None): - url_projects = f"{protocol}://{host}/api/v1/projects" - url_project_token = f"{protocol}://{host}/api/v1/admin-token" context_path = os.path.join(home_dir, ".fedn") try: with open(f"{context_path}/context.yaml", "r") as yaml_file: diff --git a/fedn/cli/shared.py b/fedn/cli/shared.py index d2bdf6984..9fe9f345c 100644 --- a/fedn/cli/shared.py +++ b/fedn/cli/shared.py @@ -7,6 +7,8 @@ CONTROLLER_DEFAULTS = {"protocol": "http", "host": "localhost", "port": 8092, "debug": False} +STUDIO_DEFAULTS = {"protocol": "https", "host": "fedn.scaleoutsystems.com"} + COMBINER_DEFAULTS = {"discover_host": "localhost", "discover_port": 8092, "host": "localhost", "port": 12080, "name": "combiner", "max_clients": 30} CLIENT_DEFAULTS = { @@ -37,21 +39,31 @@ def apply_config(path: str, config: dict): config[key] = val -def get_api_url(protocol: str, host: str, port: str, endpoint: str) -> str: - _url = os.environ.get("FEDN_CONTROLLER_URL") - _protocol = protocol or os.environ.get("FEDN_CONTROLLER_PROTOCOL") or CONTROLLER_DEFAULTS["protocol"] - _host = host or os.environ.get("FEDN_CONTROLLER_HOST") or CONTROLLER_DEFAULTS["host"] - _port = port or os.environ.get("FEDN_CONTROLLER_PORT") or CONTROLLER_DEFAULTS["port"] +def get_api_url(protocol: str, host: str, port: str, endpoint: str, usr_api: bool) -> str: + if usr_api: + _url = os.environ.get("FEDN_STUDIO_URL") + _protocol = protocol or os.environ.get("FEDN_STUDIO_PROTOCOL") or STUDIO_DEFAULTS["protocol"] + _host = host or os.environ.get("FEDN_STUDIO_HOST") or STUDIO_DEFAULTS["host"] - if _url is None: - context_path = os.path.join(home_dir, ".fedn") - try: - with open(f"{context_path}/context.yaml", "r") as yaml_file: - context_data = yaml.safe_load(yaml_file) - _url = context_data.get("Active project url") - except Exception as e: - click.echo(f"Encountered error {e}. Make sure you are logged in and have activated a project. Using controller defaults instead.", fg="red") - _url = f"{_protocol}://{_host}:{_port}" + if _url is None: + return f"{_protocol}://{_host}/api/{API_VERSION}/{endpoint}" + + return f"{_url}/api/{API_VERSION}/{endpoint}" + else: + _url = os.environ.get("FEDN_CONTROLLER_URL") + _protocol = protocol or os.environ.get("FEDN_CONTROLLER_PROTOCOL") or CONTROLLER_DEFAULTS["protocol"] + _host = host or os.environ.get("FEDN_CONTROLLER_HOST") or CONTROLLER_DEFAULTS["host"] + _port = port or os.environ.get("FEDN_CONTROLLER_PORT") or CONTROLLER_DEFAULTS["port"] + + if _url is None: + context_path = os.path.join(home_dir, ".fedn") + try: + with open(f"{context_path}/context.yaml", "r") as yaml_file: + context_data = yaml.safe_load(yaml_file) + _url = context_data.get("Active project url") + except Exception as e: + click.echo(f"Encountered error {e}. Make sure you are logged in and have activated a project. Using controller defaults instead.", fg="red") + _url = f"{_protocol}://{_host}:{_port}" return f"{_url}/api/{API_VERSION}/{endpoint}/" From 91ad574e8d2a715502d915a9ba1f3004fb956d59 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Thu, 9 Jan 2025 11:22:17 +0100 Subject: [PATCH 23/26] added option to write username and password as arguments in login --- fedn/cli/login_cmd.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index 740654d0f..ec20848a7 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -20,10 +20,12 @@ def login_cmd(ctx): @login_cmd.command("login") +@click.option("-", "--name", required=False, default=None, help="username in studio") +@click.option("-pw", "--password", required=False, default=None, help="password in studio") @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @click.pass_context -def login_cmd(ctx, protocol: str, host: str): +def login_cmd(ctx, protocol: str, host: str, username: str, password: str): """Logging into FEDn Studio""" # Step 1: Display welcome message click.secho("Welcome to Scaleout FEDn!", fg="green") @@ -31,8 +33,13 @@ def login_cmd(ctx, protocol: str, host: str): url = f"{protocol}://{host}/api/token/" # Step 3: Prompt for username and password - username = input("Please enter your username: ") - password = getpass("Please enter your password: ") + if username is None and password is None: + username = input("Please enter your username: ") + password = getpass("Please enter your password: ") + elif password is None: + password = getpass("Please enter your password: ") + else: + username = input("Please enter your username: ") # Call the authentication API try: @@ -79,7 +86,7 @@ def get_context(response, protocol, host): slug = projects_response_json[0].get("slug") headers_projects["X-Project-Slug"] = slug url_project_token = get_api_url(protocol=protocol, host=host, port=None, endpoint="admin-token", usr_api=studio_api) - + print(url_project_token) try: response_project_tokens = requests.get(url_project_token, headers=headers_projects) project_tokens = response_project_tokens.json() From a430156fffa22ff517753686ce78fe118d94c101 Mon Sep 17 00:00:00 2001 From: KatHellg Date: Fri, 10 Jan 2025 13:42:45 +0100 Subject: [PATCH 24/26] bug and code redundancy fixes --- fedn/cli/login_cmd.py | 91 +++++++------- fedn/cli/project_cmd.py | 258 +++++++++++++++++++--------------------- fedn/cli/shared.py | 42 ++++++- 3 files changed, 210 insertions(+), 181 deletions(-) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index ec20848a7..785a1d9eb 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -3,10 +3,9 @@ import click import requests -import yaml from .main import main -from .shared import STUDIO_DEFAULTS, get_api_url, get_token +from .shared import STUDIO_DEFAULTS, get_response, set_context # Replace this with the platform's actual login endpoint home_dir = os.path.expanduser("~") @@ -20,13 +19,13 @@ def login_cmd(ctx): @login_cmd.command("login") -@click.option("-", "--name", required=False, default=None, help="username in studio") -@click.option("-pw", "--password", required=False, default=None, help="password in studio") +@click.option("-n", "--username", required=False, default=None, help="username in studio") +@click.option("-P", "--password", required=False, default=None, help="password in studio") @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @click.pass_context def login_cmd(ctx, protocol: str, host: str, username: str, password: str): - """Logging into FEDn Studio""" + """Login to FEDn Studio""" # Step 1: Display welcome message click.secho("Welcome to Scaleout FEDn!", fg="green") @@ -57,50 +56,62 @@ def login_cmd(ctx, protocol: str, host: str, username: str, password: str): context_path = os.path.join(home_dir, ".fedn") if not os.path.exists(context_path): os.makedirs(context_path) - try: - with open(f"{context_path}/context.yaml", "w") as yaml_file: - yaml.dump(context_data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file - except Exception as e: - print(f"Error: Failed to write to YAML file. Details: {e}") + set_context(context_path, context_data) else: - click.secho(f"Unexpected error: {response.text}", fg="red") + click.secho(f"Unexpected error: {response.status_code}", fg="red") def get_context(response, protocol, host): + """Generates content for context file with the following data: + User tokens: access and refresh token to authenticate user towards Studio + Active project tokens: access and refresh token to authenticate user towards controller + Active project id: slug of active project + Active project url: controller url of active project + """ + context_data = {"User tokens": {}, "Active project tokens": {}, "Active project id": {}, "Active project url": {}} user_token_data = response.json() if user_token_data.get("access"): + context_data["User tokens"] = user_token_data studio_api = True - url_projects = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects", usr_api=studio_api) headers_projects = {} user_access_token = user_token_data.get("access") - _token = get_token(user_access_token, True) - if _token: - headers_projects["Authorization"] = _token - - try: - response_projects = requests.get(url_projects, headers=headers_projects) + response_projects = get_response( + protocol=protocol, + host=host, + port=None, + endpoint="projects", + token=user_access_token, + headers=headers_projects, + usr_api=studio_api, + usr_token=True, + ) + if response_projects.status_code == 200: projects_response_json = response_projects.json() - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url_projects}") - - slug = projects_response_json[0].get("slug") - headers_projects["X-Project-Slug"] = slug - url_project_token = get_api_url(protocol=protocol, host=host, port=None, endpoint="admin-token", usr_api=studio_api) - print(url_project_token) - try: - response_project_tokens = requests.get(url_project_token, headers=headers_projects) - project_tokens = response_project_tokens.json() - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url_project_token}") - - controller_url = f"{protocol}://{host}/{slug}-fedn-reducer" - context_data = { - "User tokens": user_token_data, - "Active project tokens": project_tokens, - "Active project slug": slug, - "Active project url": controller_url, - } - click.secho("Login successful!", fg="green") - return context_data + if len(projects_response_json) > 0: + id = projects_response_json[0].get("slug") + context_data["Active project id"] = id + headers_projects["X-Project-Slug"] = id + response_project_tokens = get_response( + protocol=protocol, + host=host, + port=None, + endpoint="admin-token", + token=user_access_token, + headers=headers_projects, + usr_api=studio_api, + usr_token=False, + ) + if response_project_tokens.status_code == 200: + project_tokens = response_project_tokens.json() + context_data["Active project tokens"] = project_tokens + controller_url = f"{protocol}://{host}/{id}-fedn-reducer" + context_data["Active project url"] = controller_url + click.secho("Login successful!", fg="green") + else: + click.secho(f"Unexpected error: {response_project_tokens.status_code}", fg="red") + else: + click.secho(f"Unexpected error: {response_projects.status_code}", fg="red") else: click.secho("Login failed. Please check your credentials.", fg="red") + + return context_data diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index 24265ee7a..ab9d200c6 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -2,10 +2,9 @@ import click import requests -import yaml from .main import main -from .shared import STUDIO_DEFAULTS, get_api_url, get_token, print_response +from .shared import STUDIO_DEFAULTS, get_api_url, get_context, get_response, get_token, print_response, set_context home_dir = os.path.expanduser("~") @@ -17,56 +16,49 @@ def project_cmd(ctx): pass -@click.option("-s", "--slug", required=True, help="Slug name of project.") +@click.option("-id", "--id", required=True, help="ID of project.") @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") -@click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("delete") @click.pass_context -def delete_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): - """Delete project.""" - # Check if project with given slug exists +def delete_project(ctx, id: str = None, protocol: str = None, host: str = None): + """Delete project with given ID.""" + # Check if project with given id exists studio_api = True - url = get_api_url(protocol=protocol, host=host, port=None, endpoint=f"projects/{slug}", usr_api=studio_api) - headers = {} - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - try: - response = requests.get(url, headers=headers) - response_json = response.json() - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") - if response_json.get("error") is None: - # Check if user wants to delete project with given slug - user_input = input(f"Are you sure you want to delete project with slug {slug} (y/n)?: ") - if user_input == "y": - url = get_api_url(protocol=protocol, host=host, port=None, endpoint=f"projects/delete/{slug}", usr_api=studio_api) - headers = {} - - _token = get_token(token, True) - - if _token: - headers["Authorization"] = _token - # Call the authentication API - try: - requests.delete(url, headers=headers) - click.secho(f"Project with slug {slug} has been removed.", fg="green") - except requests.exceptions.RequestException as e: - click.echo(str(e), fg="red") - activate_project(None, protocol, host) + response = get_response(protocol=protocol, host=host, port=None, endpoint=f"projects/{id}", token=None, headers={}, usr_api=studio_api, usr_token=False) + if response.status_code == 200: + if response.json().get("error"): + click.secho(f"No project with id '{id}' exists.", fg="red") + else: + # Check if user wants to delete project with given id + user_input = input(f"Are you sure you want to delete project with id {id} (y/n)?: ") + if user_input == "y": + url = get_api_url(protocol=protocol, host=host, port=None, endpoint=f"projects/delete/{id}", usr_api=studio_api) + headers = {} + + _token = get_token(None, True) + + if _token: + headers["Authorization"] = _token + # Call the authentication API + try: + requests.delete(url, headers=headers) + click.secho(f"Project with slug {id} has been removed.", fg="green") + except requests.exceptions.RequestException as e: + click.echo(str(e), fg="red") + activate_project(None, protocol, host) else: - click.secho(f"No project with slug '{slug}' exists.", fg="red") + click.secho(f"Unexpected error: {response.status_code}", fg="red") +@click.option("-n", "--name", required=False, default=None, help="Name of new projec.") +@click.option("-d", "--description", required=False, default=None, help="Description of new projec.") @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") -@click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("create") @click.pass_context -def create_project(ctx, protocol: str = None, host: str = None, token: str = None): +def create_project(ctx, name: str = None, description: str = None, protocol: str = None, host: str = None): """Create project. :param ctx: """ @@ -75,13 +67,14 @@ def create_project(ctx, protocol: str = None, host: str = None, token: str = Non url = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects/create", usr_api=studio_api) headers = {"Content-Type": "application/x-www-form-urlencoded"} - _token = get_token(token, True) + _token = get_token(None, True) if _token: headers["Authorization"] = _token - - name = input("Please enter a project name: ") - description = input("Please enter a project description (optional): ") + if name is None: + name = input("Please enter a project name: ") + if description is None: + description = input("Please enter a project description (optional): ") if len(name) > 46 or len(description) >= 255: click.secho("Project name or description too long.", fg="red") else: @@ -95,140 +88,133 @@ def create_project(ctx, protocol: str = None, host: str = None, token: str = Non @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") -@click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("list") @click.pass_context -def list_projects(ctx, protocol: str = None, host: str = None, token: str = None): +def list_projects(ctx, protocol: str = None, host: str = None): """Return: ------ - - result: list of packages + - result: list of projects """ studio_api = True - url = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects", usr_api=studio_api) - headers = {} - - _token = get_token(token, True) - - if _token: - headers["Authorization"] = _token - context_path = os.path.join(home_dir, ".fedn") - try: - with open(f"{context_path}/context.yaml", "r") as yaml_file: - context_data = yaml.safe_load(yaml_file) - except Exception as e: - print(f"Error: Failed to read YAML file. Details: {e}") - active_project = context_data.get("Active project slug") + response = get_response(protocol=protocol, host=host, port=None, endpoint="projects", token=None, headers={}, usr_api=studio_api, usr_token=True) - try: - response = requests.get(url, headers=headers) + if response.status_code == 200: response_json = response.json() - for i in response_json: - project_name = i.get("slug") - if project_name == active_project: - click.secho(project_name, fg="green") - else: - click.secho(project_name) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + if len(response_json) > 0: + context_path = os.path.join(home_dir, ".fedn") + context_data = get_context(context_path) + active_project = context_data.get("Active project id") + + for i in response_json: + project_name = i.get("slug") + if project_name == active_project: + click.secho(f"{project_name} (active)", fg="green") + else: + click.secho(project_name) + else: + click.secho(f"Unexpected error: {response.status_code}", fg="red") -@click.option("-s", "--slug", required=True, help="Slug name of project.") +@click.option("-id", "--id", required=True, help="ID of project.") @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") -@click.option("-t", "--token", required=False, help="User access token") @project_cmd.command("get") @click.pass_context -def get_project(ctx, slug: str = None, protocol: str = None, host: str = None, token: str = None): +def get_project(ctx, id: str = None, protocol: str = None, host: str = None): """Return: ------ - - result: project with given slug + - result: project with given id """ studio_api = True - url = get_api_url(protocol=protocol, host=host, port=None, endpoint=f"projects/{slug}", usr_api=studio_api) - headers = {} - _token = get_token(token, False) + response = get_response(protocol=protocol, host=host, port=None, endpoint=f"projects/{id}", token=None, headers={}, usr_api=studio_api, usr_token=False) - if _token: - headers["Authorization"] = _token - try: - response = requests.get(url, headers=headers) + if response.status_code == 200: response_json = response.json() - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") - if response_json.get("error"): - click.secho(f"No project with slug '{slug}' exists.", fg="red") + if response_json.get("error"): + click.secho(f"No project with id '{id}' exists.", fg="red") + else: + print_response(response, "project", True) else: - print_response(response, "project", True) + click.secho(f"Unexpected error: {response.status_code}", fg="red") -@click.option("-s", "--slug", required=True, help="Slug name of project.") +@click.option("-id", "--id", required=True, help="id name of project.") @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") -@project_cmd.command("activate") +@project_cmd.command("set-context") @click.pass_context -def set_active_project(ctx, slug: str = None, protocol: str = None, host: str = None): +def set_active_project(ctx, id: str = None, protocol: str = None, host: str = None): """Set active project. :param ctx: - :param slug: + :param id: """ - activate_project(slug, protocol, host) + activate_project(id, protocol, host) -def activate_project(slug: str = None, protocol: str = None, host: str = None): +def activate_project(id: str = None, protocol: str = None, host: str = None): + """Sets project with give ID as active by updating context file.""" studio_api = True - url_projects = get_api_url(protocol=protocol, host=host, port=None, endpoint="projects", usr_api=studio_api) - url_project_token = get_api_url(protocol=protocol, host=host, port=None, endpoint="admin-token", usr_api=studio_api) - + headers_projects = {} context_path = os.path.join(home_dir, ".fedn") - try: - with open(f"{context_path}/context.yaml", "r") as yaml_file: - context_data = yaml.safe_load(yaml_file) - except Exception as e: - print(f"Error: Failed to read YAML file. Details: {e}") + context_data = get_context(context_path) user_access_token = context_data.get("User tokens").get("access") - _token = get_token(user_access_token, True) - headers_projects = {} - - if _token: - headers_projects["Authorization"] = _token - try: - response_projects = requests.get(url_projects, headers=headers_projects) + response_projects = get_response( + protocol=protocol, host=host, port=None, endpoint="projects", token=user_access_token, headers=headers_projects, usr_api=studio_api, usr_token=False + ) + if response_projects.status_code == 200: projects_response_json = response_projects.json() - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url_projects}") - if len(projects_response_json) > 0: - if slug is None: - headers_projects["X-Project-Slug"] = projects_response_json[0].get("slug") - slug = projects_response_json[0].get("slug") + if len(projects_response_json) > 0: + if id is None: + headers_projects["X-Project-Slug"] = projects_response_json[0].get("slug") + id = projects_response_json[0].get("slug") + else: + for i in projects_response_json: + if i.get("slug") == id: + headers_projects["X-Project-Slug"] = i.get("slug") + + controller_url = f"{protocol}://{host}/{id}-fedn-reducer" + + response_project_tokens = get_response( + protocol=protocol, + host=host, + port=None, + endpoint="admin-token", + token=user_access_token, + headers=headers_projects, + usr_api=studio_api, + usr_token=False, + ) + if response_project_tokens.status_code == 200: + project_tokens = response_project_tokens.json() + context_data["Active project tokens"] = project_tokens + context_data["Active project id"] = id + context_data["Active project url"] = controller_url + + set_context(context_path, context_data) + + click.secho(f"Project with slug {id} is now active.", fg="green") + else: + click.secho(f"Unexpected error: {response_project_tokens.status_code}", fg="red") else: - for i in projects_response_json: - if i.get("slug") == slug: - headers_projects["X-Project-Slug"] = i.get("slug") - - controller_url = f"{protocol}://{host}/{slug}-fedn-reducer" - - try: - response_project_tokens = requests.get(url_project_token, headers=headers_projects) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url_project_token}") - - project_tokens = response_project_tokens.json() - context_data["Active project tokens"] = project_tokens - context_data["Active project slug"] = slug - context_data["Active project url"] = controller_url - - try: - with open(f"{context_path}/context.yaml", "w") as yaml_file: - yaml.dump(context_data, yaml_file, default_flow_style=False) # Add access and refresh tokens to context yaml file - except Exception as e: - print(f"Error: Failed to write to YAML file. Details: {e}") - - click.secho(f"Project with slug {slug} is now active.", fg="green") + click.echo("No projects available to activate.") + else: + click.secho(f"Unexpected error: {response_projects.status_code}", fg="red") + + +def no_project_exists(response) -> bool: + """Returns true if no project exists.""" + response_json = response.json() + print(response_json) + if type(response_json) is list: + return False + elif response_json.get("error"): + return True + return False diff --git a/fedn/cli/shared.py b/fedn/cli/shared.py index 9fe9f345c..989633029 100644 --- a/fedn/cli/shared.py +++ b/fedn/cli/shared.py @@ -1,6 +1,7 @@ import os import click +import requests import yaml from fedn.common.log_config import logger @@ -58,8 +59,7 @@ def get_api_url(protocol: str, host: str, port: str, endpoint: str, usr_api: boo if _url is None: context_path = os.path.join(home_dir, ".fedn") try: - with open(f"{context_path}/context.yaml", "r") as yaml_file: - context_data = yaml.safe_load(yaml_file) + context_data = get_context(context_path) _url = context_data.get("Active project url") except Exception as e: click.echo(f"Encountered error {e}. Make sure you are logged in and have activated a project. Using controller defaults instead.", fg="red") @@ -74,14 +74,13 @@ def get_token(token: str, usr_token: bool) -> str: if _token is None: context_path = os.path.join(home_dir, ".fedn") try: - with open(f"{context_path}/context.yaml", "r") as yaml_file: - context_data = yaml.safe_load(yaml_file) + context_data = get_context(context_path) if usr_token: _token = context_data.get("User tokens").get("access") else: _token = context_data.get("Active project tokens").get("access") except Exception as e: - click.echo(f"Encountered error {e}. Make sure you are logged in and have activated a project.", fg="red") + click.secho(f"Encountered error {e}. Make sure you are logged in and have activated a project.", fg="red") scheme = os.environ.get("FEDN_AUTH_SCHEME", "Bearer") @@ -128,3 +127,36 @@ def print_response(response, entity_name: str, so): click.echo(f'Error: {json_data["message"]}') else: click.echo(f"Error: {response.status_code}") + + +def set_context(context_path, context_data): + """Saves context data as yaml file in given path""" + try: + with open(f"{context_path}/context.yaml", "w") as yaml_file: + yaml.dump(context_data, yaml_file, default_flow_style=False) + except Exception as e: + print(f"Error: Failed to write to YAML file. Details: {e}") + + +def get_context(context_path): + """Retrieves context data from yaml file in given path""" + try: + with open(f"{context_path}/context.yaml", "r") as yaml_file: + context_data = yaml.safe_load(yaml_file) + except Exception as e: + print(f"Error: Failed to write to YAML file. Details: {e}") + return context_data + + +def get_response(protocol: str, host: str, port: str, endpoint: str, token: str, headers: dict, usr_api: bool, usr_token: str): + """Utility function to retrieve response from get request based on provided information.""" + url = get_api_url(protocol=protocol, host=host, port=port, endpoint=endpoint, usr_api=usr_api) + + _token = get_token(token=token, usr_token=usr_token) + + if _token: + headers["Authorization"] = _token + + response = requests.get(url, headers=headers) + + return response From f236c8902cb1b29a1acd2723379c22404a2591ba Mon Sep 17 00:00:00 2001 From: KatHellg Date: Sun, 12 Jan 2025 18:06:16 +0100 Subject: [PATCH 25/26] fix --- fedn/cli/client_cmd.py | 32 ++++----------------- fedn/cli/combiner_cmd.py | 32 ++++----------------- fedn/cli/model_cmd.py | 44 +++++++--------------------- fedn/cli/package_cmd.py | 32 ++++----------------- fedn/cli/round_cmd.py | 59 +++++++++++++++++--------------------- fedn/cli/session_cmd.py | 32 ++++----------------- fedn/cli/shared.py | 4 +-- fedn/cli/status_cmd.py | 40 +++++++------------------- fedn/cli/validation_cmd.py | 47 +++++++++++------------------- 9 files changed, 85 insertions(+), 237 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 830b66d81..762fbe818 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -1,10 +1,9 @@ import uuid import click -import requests from fedn.cli.main import main -from fedn.cli.shared import CONTROLLER_DEFAULTS, apply_config, get_api_url, get_token, print_response +from fedn.cli.shared import CONTROLLER_DEFAULTS, apply_config, get_response, print_response from fedn.common.exceptions import InvalidClientConfig from fedn.network.clients.client import Client from fedn.network.clients.client_v2 import Client as ClientV2 @@ -49,22 +48,13 @@ def list_clients(ctx, protocol: str, host: str, port: str, token: str = None, n_ - result: list of clients """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="clients") headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "clients", None) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint="clients", token=token, headers=headers, usr_api=False, usr_token=False) + print_response(response, "clients", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -80,20 +70,8 @@ def get_client(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: client with given id """ - _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="clients") - url = f"{_url}{id}" - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "client", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"clients/{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "client", id) @client_cmd.command("start-v1") diff --git a/fedn/cli/combiner_cmd.py b/fedn/cli/combiner_cmd.py index 57e8652f4..4df5846a4 100644 --- a/fedn/cli/combiner_cmd.py +++ b/fedn/cli/combiner_cmd.py @@ -1,10 +1,9 @@ import uuid import click -import requests from .main import main -from .shared import CONTROLLER_DEFAULTS, apply_config, get_api_url, get_token, print_response +from .shared import CONTROLLER_DEFAULTS, apply_config, get_response, print_response @main.group("combiner") @@ -77,22 +76,13 @@ def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None, - result: list of combiners """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="combiners") headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "combiners", None) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint="combiners", token=token, headers=headers, usr_api=False, usr_token=False) + print_response(response, "combiners", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -108,17 +98,5 @@ def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id - result: combiner with given id """ - _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="combiners") - url = f"{_url}{id}" - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "combiner", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"combiners/{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "combiner", id) diff --git a/fedn/cli/model_cmd.py b/fedn/cli/model_cmd.py index 8eb6d3ff9..ae1dafe32 100644 --- a/fedn/cli/model_cmd.py +++ b/fedn/cli/model_cmd.py @@ -1,8 +1,7 @@ import click -import requests from .main import main -from .shared import CONTROLLER_DEFAULTS, get_api_url, get_token, print_response +from .shared import CONTROLLER_DEFAULTS, get_response, print_response @main.group("model") @@ -16,7 +15,7 @@ def model_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-session_id", "--session_id", required=False, help="models in session with given session id") +@click.option("-s", "--session_id", required=False, help="models in session with given session id") @click.option("--n_max", required=False, help="Number of items to list") @model_cmd.command("list") @click.pass_context @@ -27,26 +26,18 @@ def list_models(ctx, protocol: str, host: str, port: str, token: str = None, ses - result: list of models """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") - headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - if session_id: - url = f"{url}?session_id={session_id}" - - try: - response = requests.get(url, headers=headers) - print_response(response, "models", None) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response( + protocol=protocol, host=host, port=port, endpoint=f"models/?session_id={session_id}", token=token, headers=headers, usr_api=False, usr_token=False + ) + else: + response = get_response(protocol=protocol, host=host, port=port, endpoint="models", token=token, headers=headers, usr_api=False, usr_token=False) + print_response(response, "models", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -62,20 +53,5 @@ def get_model(ctx, protocol: str, host: str, port: str, token: str = None, id: s - result: model with given id """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="models") - - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - if id: - url = f"{url}{id}" - - try: - response = requests.get(url, headers=headers) - print_response(response, "model", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"models/{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "model", id) diff --git a/fedn/cli/package_cmd.py b/fedn/cli/package_cmd.py index 6315d4359..e6ec14329 100644 --- a/fedn/cli/package_cmd.py +++ b/fedn/cli/package_cmd.py @@ -2,12 +2,11 @@ import tarfile import click -import requests from fedn.common.log_config import logger from .main import main -from .shared import CONTROLLER_DEFAULTS, get_api_url, get_token, print_response +from .shared import CONTROLLER_DEFAULTS, get_response, print_response @main.group("package") @@ -54,22 +53,13 @@ def list_packages(ctx, protocol: str, host: str, port: str, token: str = None, n - result: list of packages """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="packages") headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "packages", None) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint="packages", token=token, headers=headers, usr_api=False, usr_token=False) + print_response(response, "packages", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -85,17 +75,5 @@ def get_package(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: package with given id """ - _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="packages") - url = f"{_url}{id}" - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "package", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"packages/{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "package", id) diff --git a/fedn/cli/round_cmd.py b/fedn/cli/round_cmd.py index 58fbb5863..71c68df69 100644 --- a/fedn/cli/round_cmd.py +++ b/fedn/cli/round_cmd.py @@ -1,8 +1,7 @@ import click -import requests from .main import main -from .shared import CONTROLLER_DEFAULTS, get_api_url, get_token, print_response +from .shared import CONTROLLER_DEFAULTS, get_response, print_response @main.group("round") @@ -15,7 +14,7 @@ def round_cmd(ctx): @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") -@click.option("-session_id", "--session_id", required=False, help="Rounds in session with given session id") +@click.option("-s", "--session_id", required=False, help="Rounds in session with given session id") @click.option("-t", "--token", required=False, help="Authentication token") @click.option("--n_max", required=False, help="Number of items to list") @round_cmd.command("list") @@ -27,27 +26,34 @@ def list_rounds(ctx, protocol: str, host: str, port: str, token: str = None, ses - result: list of rounds """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="rounds") - headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - if session_id: - url = f"{url}?round_config.session_id={session_id}" - - try: - response = requests.get(url, headers=headers) - print_response(response, "rounds", None) - - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response( + protocol=protocol, + host=host, + port=port, + endpoint=f"rounds/?round_config.session_id={session_id}", + token=token, + headers=headers, + usr_api=False, + usr_token=False, + ) + else: + response = get_response( + protocol=protocol, + host=host, + port=port, + endpoint="rounds", + token=token, + headers=headers, + usr_api=False, + usr_token=False, + ) + print_response(response, "rounds", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -63,18 +69,5 @@ def get_round(ctx, protocol: str, host: str, port: str, token: str = None, id: s - result: round with given id """ - _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="rounds") - url = f"{_url}{id}" - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "round", id) - - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"rounds/{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "round", id) diff --git a/fedn/cli/session_cmd.py b/fedn/cli/session_cmd.py index 776fc2648..4a1624f4d 100644 --- a/fedn/cli/session_cmd.py +++ b/fedn/cli/session_cmd.py @@ -1,8 +1,7 @@ import click -import requests from .main import main -from .shared import CONTROLLER_DEFAULTS, get_api_url, get_token, print_response +from .shared import CONTROLLER_DEFAULTS, get_response, print_response @main.group("session") @@ -26,22 +25,13 @@ def list_sessions(ctx, protocol: str, host: str, port: str, token: str = None, n - result: list of sessions """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="sessions") headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "sessions", None) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint="sessions", token=token, headers=headers, usr_api=False, usr_token=False) + print_response(response, "sessions", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -57,17 +47,5 @@ def get_session(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: session with given session id """ - _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="sessions") - url = f"{_url}{id}" - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "session", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"sessions/{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "session", id) diff --git a/fedn/cli/shared.py b/fedn/cli/shared.py index 989633029..f463b5554 100644 --- a/fedn/cli/shared.py +++ b/fedn/cli/shared.py @@ -8,7 +8,7 @@ CONTROLLER_DEFAULTS = {"protocol": "http", "host": "localhost", "port": 8092, "debug": False} -STUDIO_DEFAULTS = {"protocol": "https", "host": "fedn.scaleoutsystems.com"} +STUDIO_DEFAULTS = {"protocol": "https", "host": "fedn.scaleoutstudio.com"} COMBINER_DEFAULTS = {"discover_host": "localhost", "discover_port": 8092, "host": "localhost", "port": 12080, "name": "combiner", "max_clients": 30} @@ -65,7 +65,7 @@ def get_api_url(protocol: str, host: str, port: str, endpoint: str, usr_api: boo click.echo(f"Encountered error {e}. Make sure you are logged in and have activated a project. Using controller defaults instead.", fg="red") _url = f"{_protocol}://{_host}:{_port}" - return f"{_url}/api/{API_VERSION}/{endpoint}/" + return f"{_url}/api/{API_VERSION}/{endpoint}" def get_token(token: str, usr_token: bool) -> str: diff --git a/fedn/cli/status_cmd.py b/fedn/cli/status_cmd.py index 73b2da735..56fd22801 100644 --- a/fedn/cli/status_cmd.py +++ b/fedn/cli/status_cmd.py @@ -1,8 +1,7 @@ import click -import requests from .main import main -from .shared import CONTROLLER_DEFAULTS, get_api_url, get_token, print_response +from .shared import CONTROLLER_DEFAULTS, get_response, print_response @main.group("status") @@ -16,7 +15,7 @@ def status_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-session_id", "--session_id", required=False, help="statuses with given session id") +@click.option("-s", "--session_id", required=False, help="statuses with given session id") @click.option("--n_max", required=False, help="Number of items to list") @status_cmd.command("list") @click.pass_context @@ -27,25 +26,18 @@ def list_statuses(ctx, protocol: str, host: str, port: str, token: str = None, s - result: list of statuses """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="statuses") headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - if session_id: - url = f"{url}?sessionId={session_id}" - - try: - response = requests.get(url, headers=headers) - print_response(response, "statuses", None) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response( + protocol=protocol, host=host, port=port, endpoint=f"statuses/?sessionId={session_id}", token=token, headers=headers, usr_api=False, usr_token=False + ) + else: + response = get_response(protocol=protocol, host=host, port=port, endpoint="statuses", token=token, headers=headers, usr_api=False, usr_token=False) + print_response(response, "statuses", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -61,17 +53,5 @@ def get_status(ctx, protocol: str, host: str, port: str, token: str = None, id: - result: status with given id """ - _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="statuses") - url = f"{_url}{id}" - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "status", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"statuses{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "status", id) diff --git a/fedn/cli/validation_cmd.py b/fedn/cli/validation_cmd.py index 2be991bc5..37600deb4 100644 --- a/fedn/cli/validation_cmd.py +++ b/fedn/cli/validation_cmd.py @@ -1,8 +1,7 @@ import click -import requests from .main import main -from .shared import CONTROLLER_DEFAULTS, get_api_url, get_token, print_response +from .shared import CONTROLLER_DEFAULTS, get_response, print_response @main.group("validation") @@ -16,7 +15,7 @@ def validation_cmd(ctx): @click.option("-H", "--host", required=False, default=CONTROLLER_DEFAULTS["host"], help="Hostname of controller (api)") @click.option("-P", "--port", required=False, default=CONTROLLER_DEFAULTS["port"], help="Port of controller (api)") @click.option("-t", "--token", required=False, help="Authentication token") -@click.option("-session_id", "--session_id", required=False, help="validations in session with given session id") +@click.option("-s", "--session_id", required=False, help="validations in session with given session id") @click.option("--n_max", required=False, help="Number of items to list") @validation_cmd.command("list") @click.pass_context @@ -27,25 +26,25 @@ def list_validations(ctx, protocol: str, host: str, port: str, token: str = None - result: list of validations """ - url = get_api_url(protocol=protocol, host=host, port=port, endpoint="validations") headers = {} if n_max: headers["X-Limit"] = n_max - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - if session_id: - url = f"{url}?sessionId={session_id}" - - try: - response = requests.get(url, headers=headers) - print_response(response, "validations", None) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response( + protocol=protocol, + host=host, + port=port, + endpoint=f"validations/?sessionId={session_id}", + token=token, + headers=headers, + usr_api=False, + usr_token=False, + ) + else: + response = get_response(protocol=protocol, host=host, port=port, endpoint="validations", token=token, headers=headers, usr_api=False, usr_token=False) + print_response(response, "validations", None) @click.option("-p", "--protocol", required=False, default=CONTROLLER_DEFAULTS["protocol"], help="Communication protocol of controller (api)") @@ -61,17 +60,5 @@ def get_validation(ctx, protocol: str, host: str, port: str, token: str = None, - result: validation with given id """ - _url = get_api_url(protocol=protocol, host=host, port=port, endpoint="validations") - url = f"{_url}{id}" - headers = {} - - _token = get_token(token, False) - - if _token: - headers["Authorization"] = _token - - try: - response = requests.get(url, headers=headers) - print_response(response, "validation", id) - except requests.exceptions.ConnectionError: - click.echo(f"Error: Could not connect to {url}") + response = get_response(protocol=protocol, host=host, port=port, endpoint=f"validations/{id}", token=token, headers={}, usr_api=False, usr_token=False) + print_response(response, "validation", id) From 9361304848d8a251be5b276803e70aeb3b93206c Mon Sep 17 00:00:00 2001 From: KatHellg Date: Tue, 21 Jan 2025 09:49:47 +0100 Subject: [PATCH 26/26] resolved fix requests --- fedn/cli/login_cmd.py | 5 +++-- fedn/cli/project_cmd.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fedn/cli/login_cmd.py b/fedn/cli/login_cmd.py index 785a1d9eb..91cb49ddf 100644 --- a/fedn/cli/login_cmd.py +++ b/fedn/cli/login_cmd.py @@ -19,7 +19,7 @@ def login_cmd(ctx): @login_cmd.command("login") -@click.option("-n", "--username", required=False, default=None, help="username in studio") +@click.option("-u", "--username", required=False, default=None, help="username in studio") @click.option("-P", "--password", required=False, default=None, help="password in studio") @click.option("-p", "--protocol", required=False, default=STUDIO_DEFAULTS["protocol"], help="Communication protocol of studio (api)") @click.option("-H", "--host", required=False, default=STUDIO_DEFAULTS["host"], help="Hostname of studio (api)") @@ -61,7 +61,8 @@ def login_cmd(ctx, protocol: str, host: str, username: str, password: str): click.secho(f"Unexpected error: {response.status_code}", fg="red") -def get_context(response, protocol, host): +# Sets the context for a given user +def get_context(response, protocol: str, host: str): """Generates content for context file with the following data: User tokens: access and refresh token to authenticate user towards Studio Active project tokens: access and refresh token to authenticate user towards controller diff --git a/fedn/cli/project_cmd.py b/fedn/cli/project_cmd.py index ab9d200c6..111f226a4 100644 --- a/fedn/cli/project_cmd.py +++ b/fedn/cli/project_cmd.py @@ -204,7 +204,7 @@ def activate_project(id: str = None, protocol: str = None, host: str = None): else: click.secho(f"Unexpected error: {response_project_tokens.status_code}", fg="red") else: - click.echo("No projects available to activate.") + click.echo("Set current context.") else: click.secho(f"Unexpected error: {response_projects.status_code}", fg="red")