Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/SK-545 | Statestore init from api-server lack proper setup #479

Merged
merged 4 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ services:
- PROJECT=project
- FLASK_DEBUG=1
- STATESTORE_CONFIG=/app/config/settings-reducer.yaml
- MODELSTORAGE_CONFIG=/app/config/settings-reducer.yaml
build:
context: .
args:
Expand Down
2 changes: 1 addition & 1 deletion fedn/cli/run_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def dashboard_cmd(ctx, host, port, secret_key, local_package, name, init):
statestore_config = fedn_config['statestore']
if statestore_config['type'] == 'MongoDB':
statestore = MongoStateStore(
network_id, statestore_config['mongo_config'], defaults=config['init'])
network_id, statestore_config['mongo_config'], fedn_config['storage'])
else:
print("Unsupported statestore type, exiting. ", flush=True)
exit(-1)
Expand Down
44 changes: 34 additions & 10 deletions fedn/fedn/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,33 @@

import yaml

STATESTORE_CONFIG = os.environ.get('STATESTORE_CONFIG', '/workspaces/fedn/config/settings-reducer.yaml.template')
MODELSTORAGE_CONFIG = os.environ.get('MODELSTORAGE_CONFIG', '/workspaces/fedn/config/settings-reducer.yaml.template')
global STATESTORE_CONFIG
global MODELSTORAGE_CONFIG


def get_statestore_config(file=STATESTORE_CONFIG):
def get_environment_config():
""" Get the configuration from environment variables.
"""
global STATESTORE_CONFIG
global MODELSTORAGE_CONFIG

STATESTORE_CONFIG = os.environ.get('STATESTORE_CONFIG',
'/workspaces/fedn/config/settings-reducer.yaml.template')
MODELSTORAGE_CONFIG = os.environ.get('MODELSTORAGE_CONFIG',
'/workspaces/fedn/config/settings-reducer.yaml.template')


def get_statestore_config(file=None):
""" Get the statestore configuration from file.

:param file: The statestore configuration file (yaml) path.
:param file: The statestore configuration file (yaml) path (optional).
:type file: str
:return: The statestore configuration as a dict.
:rtype: dict
"""
if file is None:
get_environment_config()
file = STATESTORE_CONFIG
with open(file, 'r') as config_file:
try:
settings = dict(yaml.safe_load(config_file))
Expand All @@ -22,14 +37,17 @@ def get_statestore_config(file=STATESTORE_CONFIG):
return settings["statestore"]


def get_modelstorage_config(file=MODELSTORAGE_CONFIG):
def get_modelstorage_config(file=None):
""" Get the model storage configuration from file.

:param file: The model storage configuration file (yaml) path.
:param file: The model storage configuration file (yaml) path (optional).
:type file: str
:return: The model storage configuration as a dict.
:rtype: dict
"""
if file is None:
get_environment_config()
file = MODELSTORAGE_CONFIG
with open(file, 'r') as config_file:
try:
settings = dict(yaml.safe_load(config_file))
Expand All @@ -38,14 +56,17 @@ def get_modelstorage_config(file=MODELSTORAGE_CONFIG):
return settings["storage"]


def get_network_config(file=STATESTORE_CONFIG):
def get_network_config(file=None):
""" Get the network configuration from file.

:param file: The network configuration file (yaml) path.
:param file: The network configuration file (yaml) path (optional).
:type file: str
:return: The network id.
:rtype: str
"""
if file is None:
get_environment_config()
file = STATESTORE_CONFIG
with open(file, 'r') as config_file:
try:
settings = dict(yaml.safe_load(config_file))
Expand All @@ -54,14 +75,17 @@ def get_network_config(file=STATESTORE_CONFIG):
return settings["network_id"]


def get_controller_config(file=STATESTORE_CONFIG):
def get_controller_config(file=None):
""" Get the controller configuration from file.

:param file: The controller configuration file (yaml) path.
:param file: The controller configuration file (yaml) path (optional).
:type file: str
:return: The controller configuration as a dict.
:rtype: dict
"""
if file is None:
get_environment_config()
file = STATESTORE_CONFIG
with open(file, 'r') as config_file:
try:
settings = dict(yaml.safe_load(config_file))
Expand Down
8 changes: 5 additions & 3 deletions fedn/fedn/network/api/server.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from flask import Flask, jsonify, request

from fedn.common.config import (get_controller_config, get_network_config,
get_statestore_config)
from fedn.common.config import (get_controller_config, get_modelstorage_config,
get_network_config, get_statestore_config)
from fedn.network.api.interface import API
from fedn.network.controller.control import Control
from fedn.network.statestore.mongostatestore import MongoStateStore

statestore_config = get_statestore_config()
network_id = get_network_config()
modelstorage_config = get_modelstorage_config()
statestore = MongoStateStore(
network_id,
statestore_config['mongo_config']
statestore_config['mongo_config'],
modelstorage_config
)
control = Control(statestore=statestore)
api = API(statestore, control)
Expand Down
9 changes: 9 additions & 0 deletions fedn/fedn/network/controller/controlbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from fedn.network.combiner.interfaces import CombinerUnavailableError
from fedn.network.state import ReducerState

# Maximum number of tries to connect to statestore and retrieve storage configuration
MAX_TRIES_BACKEND = os.getenv('MAX_TRIES_BACKEND', 10)


class UnsupportedStorageBackend(Exception):
pass
Expand Down Expand Up @@ -42,12 +45,18 @@ def __init__(self, statestore):

try:
not_ready = True
tries = 0
while not_ready:
storage_config = self.statestore.get_storage_backend()
if storage_config:
not_ready = False
else:
print(
"REDUCER CONTROL: Storage backend not configured, waiting...", flush=True)
sleep(5)
tries += 1
if tries > MAX_TRIES_BACKEND:
raise Exception
except Exception:
print(
"REDUCER CONTROL: Failed to retrive storage configuration, exiting.", flush=True)
Expand Down
56 changes: 4 additions & 52 deletions fedn/fedn/network/statestore/mongostatestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from datetime import datetime

import pymongo
import yaml

from fedn.common.storage.db.mongo import connect_to_mongodb
from fedn.network.state import ReducerStateToString, StringToReducerState
Expand All @@ -21,7 +20,7 @@ class MongoStateStore(StateStoreBase):
:type defaults: dict
"""

def __init__(self, network_id, config, defaults=None):
def __init__(self, network_id, config, model_storage_config):
""" Constructor."""
self.__inited = False
try:
Expand Down Expand Up @@ -58,56 +57,9 @@ def __init__(self, network_id, config, defaults=None):
self.clients = None
raise

if defaults:
with open(defaults, 'r') as file:
try:
settings = dict(yaml.safe_load(file))
print(settings, flush=True)

# Control settings
if "control" in settings and settings["control"]:
control = settings['control']
try:
self.transition(str(control['state']))
except KeyError:
self.transition("idle")

if "model" in control:
if not self.get_latest():
self.set_latest(str(control['model']))
else:
print(
"Model trail already initialized - refusing to overwrite from config. Purge model trail if you want to reseed the system.",
flush=True)

if "context" in control:
print("Setting filepath to {}".format(
control['context']), flush=True)
# TODO Fix the ugly latering of indirection due to a bug in secure_filename returning an object with filename as attribute
# TODO fix with unboxing of value before storing and where consuming.
self.control.config.update_one({'key': 'package'},
{'$set': {'filename': control['context']}}, True)
if "helper" in control:
# self.set_framework(control['helper'])
pass

round_config = {'timeout': 180, 'validate': True}
try:
round_config['timeout'] = control['timeout']
except Exception:
pass

try:
round_config['validate'] = control['validate']
except Exception:
pass

# Storage settings
self.set_storage_backend(settings['storage'])

self.__inited = True
except yaml.YAMLError as e:
print(e)
# Storage settings
self.set_storage_backend(model_storage_config)
self.__inited = True

def is_inited(self):
""" Check if the statestore is intialized.
Expand Down
Loading