Skip to content

Commit

Permalink
Feature/SK-1096 | Add set helper to v1 api (#723)
Browse files Browse the repository at this point in the history
  • Loading branch information
niklastheman authored Oct 11, 2024
1 parent 9bca945 commit 8a8c4c4
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 13 deletions.
3 changes: 2 additions & 1 deletion fedn/network/api/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fedn.network.api.v1.client_routes import bp as client_bp
from fedn.network.api.v1.combiner_routes import bp as combiner_bp
from fedn.network.api.v1.helper_routes import bp as helper_bp
from fedn.network.api.v1.inference_routes import bp as inference_bp
from fedn.network.api.v1.model_routes import bp as model_bp
from fedn.network.api.v1.package_routes import bp as package_bp
Expand All @@ -8,4 +9,4 @@
from fedn.network.api.v1.status_routes import bp as status_bp
from fedn.network.api.v1.validation_routes import bp as validation_bp

_routes = [client_bp, combiner_bp, model_bp, package_bp, round_bp, session_bp, status_bp, validation_bp, inference_bp]
_routes = [client_bp, combiner_bp, model_bp, package_bp, round_bp, session_bp, status_bp, validation_bp, inference_bp, helper_bp]
62 changes: 62 additions & 0 deletions fedn/network/api/v1/helper_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from flask import Blueprint, jsonify, request

from fedn.network.api.auth import jwt_auth_required
from fedn.network.api.v1.shared import api_version, package_store
from fedn.network.storage.statestore.stores.shared import EntityNotFound

bp = Blueprint("helper", __name__, url_prefix=f"/api/{api_version}/helpers")



@bp.route("/active", methods=["GET"])
@jwt_auth_required(role="admin")
def get_active_helper():
"""Get active helper
Retrieves the active helper
---
tags:
- Helpers
responses:
200:
description: Active helper
404:
description: No active helper
500:
description: An unexpected error occurred
"""
try:

active_package = package_store.get_active()

response = active_package["helper"]

return jsonify(response), 200
except EntityNotFound:
return jsonify({"message": "No active helper"}), 404
except Exception:
return jsonify({"message": "An unexpected error occurred"}), 500

@bp.route("/active", methods=["PUT"])
@jwt_auth_required(role="admin")
def set_active_helper():
"""Set active helper
Sets the active helper
---
tags:
- Helpers
responses:
200:
description: Active helper set
500:
description: An unexpected error occurred
"""
try:
data = request.get_json()
helper = data["helper"]
package_store.set_active_helper(helper)

return jsonify({"message": "Active helper set"}), 200
except ValueError:
return jsonify({"message": "Helper is required to be either 'numpyhelper', 'binaryhelper' or 'androidhelper'"}), 400
except Exception:
return jsonify({"message": "An unexpected error occurred"}), 500
6 changes: 3 additions & 3 deletions fedn/network/api/v1/package_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

from fedn.common.config import FEDN_COMPUTE_PACKAGE_DIR
from fedn.network.api.auth import jwt_auth_required
from fedn.network.api.v1.shared import api_version, get_post_data_to_kwargs, get_typed_list_headers, get_use_typing, mdb, repository
from fedn.network.storage.statestore.stores.package_store import PackageStore
from fedn.network.api.v1.shared import (api_version, get_post_data_to_kwargs,
get_typed_list_headers, get_use_typing,
package_store, repository)
from fedn.network.storage.statestore.stores.shared import EntityNotFound

bp = Blueprint("package", __name__, url_prefix=f"/api/{api_version}/packages")

package_store = PackageStore(mdb, "control.package")


@bp.route("/", methods=["GET"])
Expand Down
5 changes: 4 additions & 1 deletion fedn/network/api/v1/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
import pymongo
from pymongo.database import Database

from fedn.network.api.shared import modelstorage_config, network_id, statestore_config
from fedn.network.api.shared import (modelstorage_config, network_id,
statestore_config)
from fedn.network.storage.s3.base import RepositoryBase
from fedn.network.storage.s3.miniorepository import MINIORepository
from fedn.network.storage.s3.repository import Repository
from fedn.network.storage.statestore.stores.client_store import ClientStore
from fedn.network.storage.statestore.stores.package_store import PackageStore

api_version = "v1"
mc = pymongo.MongoClient(**statestore_config["mongo_config"])
mc.server_info()
mdb: Database = mc[network_id]

client_store = ClientStore(mdb, "network.clients")
package_store = PackageStore(mdb, "control.package")

minio_repository: RepositoryBase = None

Expand Down
14 changes: 14 additions & 0 deletions fedn/network/storage/statestore/stores/package_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@ def get_active(self, use_typing: bool = False) -> Package:

return Package.from_dict(response, response) if use_typing else from_document(response)

def set_active_helper(self, helper: str) -> bool:
"""Set the active helper
param helper: The helper to set as active
type: str
return: Whether the operation was successful
"""
if not helper or helper == "" or helper not in ["numpyhelper", "binaryhelper", "androidhelper"]:
raise ValueError()

try:
self.database[self.collection].update_one({"key": "active"}, {"$set": {"helper": helper}}, upsert=True)
except Exception:
return False

def _allowed_file_extension(self, filename: str, ALLOWED_EXTENSIONS={"gz", "bz2", "tar", "zip", "tgz"}) -> bool:
"""Check if file extension is allowed.
Expand Down
12 changes: 4 additions & 8 deletions fedn/network/storage/statestore/stores/session_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def from_dict(data: dict) -> "Session":
id=str(data["_id"]),
session_id=data["session_id"] if "session_id" in data else None,
status=data["status"] if "status" in data else None,
session_config=data["session_config"] if "session_config" in data else None
session_config=data["session_config"] if "session_config" in data else None,
)


Expand Down Expand Up @@ -71,7 +71,7 @@ def _validate_session_config(self, session_config: dict) -> Tuple[bool, str]:
if not isinstance(session_config["validate"], bool):
return False, "session_config.validate must be a boolean"

if "helper_type" not in session_config:
if "helper_type" not in session_config or session_config["helper_type"] == "":
return False, "session_config.helper_type is required"

if not isinstance(session_config["helper_type"], str):
Expand All @@ -92,7 +92,7 @@ def _validate(self, item: Session) -> Tuple[bool, str]:
else:
return False, "session_config must be a dict"

return self._validate_session_config(session_config)
return self._validate_session_config(session_config)

def _complement(self, item: Session):
item["status"] = "Created"
Expand All @@ -101,7 +101,6 @@ def _complement(self, item: Session):
if "session_id" not in item or item["session_id"] == "" or not isinstance(item["session_id"], str):
item["session_id"] = str(uuid.uuid4())


def get(self, id: str, use_typing: bool = False) -> Session:
"""Get an entity by id
param id: The id of the entity
Expand Down Expand Up @@ -173,7 +172,4 @@ def list(self, limit: int, skip: int, sort_key: str, sort_order=pymongo.DESCENDI

result = [Session.from_dict(item) for item in response["result"]] if use_typing else response["result"]

return {
"count": response["count"],
"result": result
}
return {"count": response["count"], "result": result}

0 comments on commit 8a8c4c4

Please sign in to comment.