Skip to content

Commit

Permalink
Merge branch 'master' into feature/SK-1235
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreas Hellander committed Dec 9, 2024
2 parents 2e90c4c + c416b72 commit e712d52
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 160 deletions.
1 change: 1 addition & 0 deletions fedn/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 0 additions & 3 deletions fedn/cli/combiner_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ def list_combiners(ctx, protocol: str, host: str, port: str, token: str = None,
if _token:
headers["Authorization"] = _token


try:
response = requests.get(url, headers=headers)
print_response(response, "combiners", None)
Expand All @@ -112,7 +111,6 @@ def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id
url = get_api_url(protocol=protocol, host=host, port=port, endpoint="combiners")
headers = {}


_token = get_token(token)

if _token:
Expand All @@ -121,7 +119,6 @@ def get_combiner(ctx, protocol: str, host: str, port: str, token: str = None, id
if id:
url = f"{url}{id}"


try:
response = requests.get(url, headers=headers)
print_response(response, "combiner", id)
Expand Down
61 changes: 61 additions & 0 deletions fedn/cli/login_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
from getpass import getpass

import click
import requests
import yaml

from .main import main

# Replace this with the platform's actual login endpoint
home_dir = os.path.expanduser("~")


@main.group("studio")
@click.pass_context
def login_cmd(ctx):
""":param ctx:"""
pass


@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, protocol: str, host: str):
"""Logging into FEDn Studio"""
# Step 1: Display welcome message
click.secho("Welcome to Scaleout FEDn!", fg="green")

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: ")

# 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")
5 changes: 2 additions & 3 deletions fedn/network/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,10 +645,9 @@ def start_session(
headers=self.headers,
)

if id is None:
id = response.json()["session_id"]

if response.status_code == 201:
if id is None:
id = response.json()["session_id"]
response = requests.post(
self._get_url_api_v1("sessions/start"),
json={
Expand Down
34 changes: 19 additions & 15 deletions fedn/network/clients/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ def get_model_from_combiner(self, id, timeout=20):
time_start = time.time()
request = fedn.ModelRequest(id=id)
request.sender.name = self.name
request.sender.role = fedn.WORKER
request.sender.role = fedn.CLIENT

try:
for part in self.modelStub.Download(request, metadata=self.metadata):
Expand Down Expand Up @@ -388,7 +388,7 @@ def _listen_to_task_stream(self):
"""
r = fedn.ClientAvailableMessage()
r.sender.name = self.name
r.sender.role = fedn.WORKER
r.sender.role = fedn.CLIENT
r.sender.client_id = self.id
# Add client to metadata
self._add_grpc_metadata("client", self.name)
Expand All @@ -406,7 +406,7 @@ def _listen_to_task_stream(self):
# Process training request
self.send_status(
"Received model update request.",
log_level=fedn.Status.AUDIT,
log_level=fedn.LogLevel.AUDIT,
type=fedn.StatusType.MODEL_UPDATE_REQUEST,
request=request,
sesssion_id=request.session_id,
Expand Down Expand Up @@ -628,7 +628,7 @@ def process_request(self):
update = fedn.ModelUpdate()
update.sender.name = self.name
update.sender.client_id = self.id
update.sender.role = fedn.WORKER
update.sender.role = fedn.CLIENT
update.receiver.name = request.sender.name
update.receiver.role = request.sender.role
update.model_id = request.model_id
Expand All @@ -641,7 +641,7 @@ def process_request(self):
_ = self.combinerStub.SendModelUpdate(update, metadata=self.metadata)
self.send_status(
"Model update completed.",
log_level=fedn.Status.AUDIT,
log_level=fedn.LogLevel.AUDIT,
type=fedn.StatusType.MODEL_UPDATE,
request=update,
sesssion_id=request.session_id,
Expand All @@ -655,7 +655,7 @@ def process_request(self):
logger.debug(e)
else:
self.send_status(
"Client {} failed to complete model update.", log_level=fedn.Status.WARNING, request=request, sesssion_id=request.session_id
"Client {} failed to complete model update.", log_level=fedn.LogLevel.WARNING, request=request, sesssion_id=request.session_id
)

self.state = ClientState.idle
Expand All @@ -669,7 +669,7 @@ def process_request(self):
# Send validation
validation = fedn.ModelValidation()
validation.sender.name = self.name
validation.sender.role = fedn.WORKER
validation.sender.role = fedn.CLIENT
validation.receiver.name = request.sender.name
validation.receiver.role = request.sender.role
validation.model_id = str(request.model_id)
Expand All @@ -683,7 +683,11 @@ def process_request(self):

status_type = fedn.StatusType.MODEL_VALIDATION
self.send_status(
"Model validation completed.", log_level=fedn.Status.AUDIT, type=status_type, request=validation, sesssion_id=request.session_id
"Model validation completed.",
log_level=fedn.LogLevel.AUDIT,
type=status_type,
request=validation,
sesssion_id=request.session_id,
)
except grpc.RpcError as e:
status_code = e.code()
Expand All @@ -695,7 +699,7 @@ def process_request(self):
else:
self.send_status(
"Client {} failed to complete model validation.".format(self.name),
log_level=fedn.Status.WARNING,
log_level=fedn.LogLevel.WARNING,
request=request,
sesssion_id=request.session_id,
)
Expand All @@ -720,7 +724,7 @@ def process_request(self):
_ = self._process_prediction_request(request.model_id, request.session_id, presigned_url)
prediction = fedn.ModelPrediction()
prediction.sender.name = self.name
prediction.sender.role = fedn.WORKER
prediction.sender.role = fedn.CLIENT
prediction.receiver.name = request.sender.name
prediction.receiver.name = request.sender.name
prediction.receiver.role = request.sender.role
Expand All @@ -736,7 +740,7 @@ def process_request(self):
_ = self.combinerStub.SendModelPrediction(prediction, metadata=self.metadata)
status_type = fedn.StatusType.MODEL_PREDICTION
self.send_status(
"Model prediction completed.", log_level=fedn.Status.AUDIT, type=status_type, request=prediction, sesssion_id=request.session_id
"Model prediction completed.", log_level=fedn.LogLevel.AUDIT, type=status_type, request=prediction, sesssion_id=request.session_id
)
except grpc.RpcError as e:
status_code = e.code()
Expand All @@ -758,7 +762,7 @@ def _send_heartbeat(self, update_frequency=2.0):
:rtype: None
"""
while True:
heartbeat = fedn.Heartbeat(sender=fedn.Client(name=self.name, role=fedn.WORKER, client_id=self.id))
heartbeat = fedn.Heartbeat(sender=fedn.Client(name=self.name, role=fedn.CLIENT, client_id=self.id))
try:
self.connectorStub.SendHeartbeat(heartbeat, metadata=self.metadata)
if self._missed_heartbeat > 0:
Expand Down Expand Up @@ -789,13 +793,13 @@ def _send_heartbeat(self, update_frequency=2.0):
logger.info("SendStatus: Client disconnected.")
return

def send_status(self, msg, log_level=fedn.Status.INFO, type=None, request=None, sesssion_id: str = None):
def send_status(self, msg, log_level=fedn.LogLevel.INFO, type=None, request=None, sesssion_id: str = None):
"""Send status message.
:param msg: The message to send.
:type msg: str
:param log_level: The log level of the message.
:type log_level: fedn.Status.INFO, fedn.Status.WARNING, fedn.Status.ERROR
:type log_level: fedn.LogLevel.INFO, fedn.LogLevel.WARNING, fedn.LogLevel.ERROR
:param type: The type of the message.
:type type: str
:param request: The request message.
Expand All @@ -808,7 +812,7 @@ def send_status(self, msg, log_level=fedn.Status.INFO, type=None, request=None,
status = fedn.Status()
status.timestamp.GetCurrentTime()
status.sender.name = self.name
status.sender.role = fedn.WORKER
status.sender.role = fedn.CLIENT
status.log_level = log_level
status.status = str(msg)
status.session_id = sesssion_id
Expand Down
32 changes: 21 additions & 11 deletions fedn/network/clients/fedn_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,9 @@ def connect_to_api(self, url: str, token: str, json: dict) -> Tuple[ConnectToApi
elif response.status_code == 404:
logger.warning("Connect to FEDn Api - Incorrect URL")
return ConnectToApiResult.IncorrectUrl, "Incorrect URL"
except Exception:
pass

logger.warning("Connect to FEDn Api - Unknown error occurred")
return ConnectToApiResult.UnknownError, "Unknown error occurred"
except Exception as e:
logger.warning(f"Connect to FEDn Api - Error occurred: {str(e)}")
return ConnectToApiResult.UnknownError, str(e)

def download_compute_package(self, url: str, token: str, name: str = None) -> bool:
"""Download compute package from controller
Expand Down Expand Up @@ -222,7 +220,13 @@ def update_local_model(self, request):
logger.error("No train callback set")
return

self.send_status(f"\t Starting processing of training request for model_id {model_id}", sesssion_id=request.session_id, sender_name=self.name)
self.send_status(
f"\t Starting processing of training request for model_id {model_id}",
sesssion_id=request.session_id,
sender_name=self.name,
log_level=fedn.LogLevel.INFO,
type=fedn.StatusType.MODEL_UPDATE,
)

logger.info(f"Running train callback with model ID: {model_id}")
client_settings = json.loads(request.data).get("client_settings", {})
Expand All @@ -243,7 +247,7 @@ def update_local_model(self, request):

self.send_status(
"Model update completed.",
log_level=fedn.Status.AUDIT,
log_level=fedn.LogLevel.AUDIT,
type=fedn.StatusType.MODEL_UPDATE,
request=update,
sesssion_id=request.session_id,
Expand All @@ -253,7 +257,13 @@ def update_local_model(self, request):
def validate_global_model(self, request):
model_id = request.model_id

self.send_status(f"Processing validate request for model_id {model_id}", sesssion_id=request.session_id, sender_name=self.name)
self.send_status(
f"Processing validate request for model_id {model_id}",
sesssion_id=request.session_id,
sender_name=self.name,
log_level=fedn.LogLevel.INFO,
type=fedn.StatusType.MODEL_VALIDATION,
)

in_model = self.get_model_from_combiner(id=model_id, client_id=self.client_id)

Expand All @@ -277,7 +287,7 @@ def validate_global_model(self, request):
if result:
self.send_status(
"Model validation completed.",
log_level=fedn.Status.AUDIT,
log_level=fedn.LogLevel.AUDIT,
type=fedn.StatusType.MODEL_VALIDATION,
request=validation,
sesssion_id=request.session_id,
Expand All @@ -286,7 +296,7 @@ def validate_global_model(self, request):
else:
self.send_status(
"Client {} failed to complete model validation.".format(self.name),
log_level=fedn.Status.WARNING,
log_level=fedn.LogLevel.WARNING,
request=request,
sesssion_id=request.session_id,
sender_name=self.name,
Expand Down Expand Up @@ -364,7 +374,7 @@ def get_model_from_combiner(self, id: str, client_id: str, timeout: int = 20) ->
def send_model_to_combiner(self, model: BytesIO, id: str):
return self.grpc_handler.send_model_to_combiner(model, id)

def send_status(self, msg: str, log_level=fedn.Status.INFO, type=None, request=None, sesssion_id: str = None, sender_name: str = None):
def send_status(self, msg: str, log_level=fedn.LogLevel.INFO, type=None, request=None, sesssion_id: str = None, sender_name: str = None):
return self.grpc_handler.send_status(msg, log_level, type, request, sesssion_id, sender_name)

def send_model_update(self, update: fedn.ModelUpdate) -> bool:
Expand Down
Loading

0 comments on commit e712d52

Please sign in to comment.