flwr 1.19.0__py3-none-any.whl → 1.21.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flwr/__init__.py +4 -1
- flwr/app/__init__.py +28 -0
- flwr/app/exception.py +31 -0
- flwr/cli/auth_plugin/oidc_cli_plugin.py +4 -4
- flwr/cli/build.py +15 -5
- flwr/cli/cli_user_auth_interceptor.py +1 -1
- flwr/cli/config_utils.py +3 -3
- flwr/cli/constant.py +25 -8
- flwr/cli/log.py +9 -9
- flwr/cli/login/login.py +3 -3
- flwr/cli/ls.py +5 -5
- flwr/cli/new/new.py +23 -4
- flwr/cli/new/templates/app/README.flowertune.md.tpl +2 -0
- flwr/cli/new/templates/app/README.md.tpl +5 -0
- flwr/cli/new/templates/app/code/__init__.pytorch_msg_api.py.tpl +1 -0
- flwr/cli/new/templates/app/code/client.pytorch_msg_api.py.tpl +80 -0
- flwr/cli/new/templates/app/code/server.pytorch_msg_api.py.tpl +41 -0
- flwr/cli/new/templates/app/code/task.pytorch_msg_api.py.tpl +98 -0
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +14 -3
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +13 -1
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +21 -2
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +18 -1
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +19 -2
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +18 -1
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +20 -3
- flwr/cli/new/templates/app/pyproject.pytorch_msg_api.toml.tpl +53 -0
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +18 -1
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +18 -1
- flwr/cli/run/run.py +53 -50
- flwr/cli/stop.py +7 -4
- flwr/cli/utils.py +29 -11
- flwr/client/grpc_adapter_client/connection.py +11 -4
- flwr/client/grpc_rere_client/connection.py +93 -129
- flwr/client/rest_client/connection.py +134 -164
- flwr/clientapp/__init__.py +10 -0
- flwr/clientapp/mod/__init__.py +26 -0
- flwr/clientapp/mod/centraldp_mods.py +132 -0
- flwr/common/args.py +20 -6
- flwr/common/auth_plugin/__init__.py +4 -4
- flwr/common/auth_plugin/auth_plugin.py +7 -7
- flwr/common/constant.py +26 -5
- flwr/common/event_log_plugin/event_log_plugin.py +1 -1
- flwr/common/exit/__init__.py +4 -0
- flwr/common/exit/exit.py +8 -1
- flwr/common/exit/exit_code.py +42 -8
- flwr/common/exit/exit_handler.py +62 -0
- flwr/common/{exit_handlers.py → exit/signal_handler.py} +20 -37
- flwr/common/grpc.py +1 -1
- flwr/common/{inflatable_grpc_utils.py → inflatable_protobuf_utils.py} +52 -10
- flwr/common/inflatable_utils.py +191 -24
- flwr/common/logger.py +1 -1
- flwr/common/record/array.py +101 -22
- flwr/common/record/arraychunk.py +59 -0
- flwr/common/retry_invoker.py +30 -11
- flwr/common/serde.py +0 -28
- flwr/common/telemetry.py +4 -0
- flwr/compat/client/app.py +14 -31
- flwr/compat/server/app.py +2 -2
- flwr/proto/appio_pb2.py +51 -0
- flwr/proto/appio_pb2.pyi +195 -0
- flwr/proto/appio_pb2_grpc.py +4 -0
- flwr/proto/appio_pb2_grpc.pyi +4 -0
- flwr/proto/clientappio_pb2.py +4 -19
- flwr/proto/clientappio_pb2.pyi +0 -125
- flwr/proto/clientappio_pb2_grpc.py +269 -29
- flwr/proto/clientappio_pb2_grpc.pyi +114 -21
- flwr/proto/control_pb2.py +62 -0
- flwr/proto/{exec_pb2_grpc.py → control_pb2_grpc.py} +54 -54
- flwr/proto/{exec_pb2_grpc.pyi → control_pb2_grpc.pyi} +28 -28
- flwr/proto/fleet_pb2.py +12 -20
- flwr/proto/fleet_pb2.pyi +6 -36
- flwr/proto/serverappio_pb2.py +8 -31
- flwr/proto/serverappio_pb2.pyi +0 -152
- flwr/proto/serverappio_pb2_grpc.py +107 -38
- flwr/proto/serverappio_pb2_grpc.pyi +47 -20
- flwr/proto/simulationio_pb2.py +4 -11
- flwr/proto/simulationio_pb2.pyi +0 -58
- flwr/proto/simulationio_pb2_grpc.py +129 -27
- flwr/proto/simulationio_pb2_grpc.pyi +52 -13
- flwr/server/app.py +130 -153
- flwr/server/fleet_event_log_interceptor.py +4 -0
- flwr/server/grid/grpc_grid.py +94 -54
- flwr/server/grid/inmemory_grid.py +1 -0
- flwr/server/serverapp/app.py +165 -144
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +8 -0
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +1 -1
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -5
- flwr/server/superlink/fleet/message_handler/message_handler.py +10 -16
- flwr/server/superlink/fleet/rest_rere/rest_api.py +1 -2
- flwr/server/superlink/fleet/vce/backend/raybackend.py +3 -1
- flwr/server/superlink/fleet/vce/vce_api.py +6 -6
- flwr/server/superlink/linkstate/in_memory_linkstate.py +34 -0
- flwr/server/superlink/linkstate/linkstate.py +2 -1
- flwr/server/superlink/linkstate/sqlite_linkstate.py +45 -0
- flwr/server/superlink/serverappio/serverappio_grpc.py +2 -2
- flwr/server/superlink/serverappio/serverappio_servicer.py +95 -48
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
- flwr/server/superlink/simulation/simulationio_servicer.py +98 -22
- flwr/server/superlink/utils.py +0 -35
- flwr/serverapp/__init__.py +12 -0
- flwr/serverapp/dp_fixed_clipping.py +352 -0
- flwr/serverapp/exception.py +38 -0
- flwr/serverapp/strategy/__init__.py +38 -0
- flwr/serverapp/strategy/dp_fixed_clipping.py +352 -0
- flwr/serverapp/strategy/fedadagrad.py +162 -0
- flwr/serverapp/strategy/fedadam.py +181 -0
- flwr/serverapp/strategy/fedavg.py +295 -0
- flwr/serverapp/strategy/fedopt.py +218 -0
- flwr/serverapp/strategy/fedyogi.py +173 -0
- flwr/serverapp/strategy/result.py +105 -0
- flwr/serverapp/strategy/strategy.py +285 -0
- flwr/serverapp/strategy/strategy_utils.py +251 -0
- flwr/serverapp/strategy/strategy_utils_tests.py +304 -0
- flwr/simulation/app.py +159 -154
- flwr/simulation/run_simulation.py +17 -0
- flwr/supercore/app_utils.py +58 -0
- flwr/supercore/cli/__init__.py +22 -0
- flwr/supercore/cli/flower_superexec.py +141 -0
- flwr/supercore/corestate/__init__.py +22 -0
- flwr/supercore/corestate/corestate.py +81 -0
- flwr/{server/superlink → supercore}/ffs/disk_ffs.py +1 -1
- flwr/supercore/grpc_health/__init__.py +25 -0
- flwr/supercore/grpc_health/health_server.py +53 -0
- flwr/supercore/grpc_health/simple_health_servicer.py +38 -0
- flwr/supercore/license_plugin/__init__.py +22 -0
- flwr/supercore/license_plugin/license_plugin.py +26 -0
- flwr/supercore/object_store/in_memory_object_store.py +31 -31
- flwr/supercore/object_store/object_store.py +20 -42
- flwr/supercore/object_store/utils.py +43 -0
- flwr/{superexec → supercore/superexec}/__init__.py +1 -1
- flwr/supercore/superexec/plugin/__init__.py +28 -0
- flwr/supercore/superexec/plugin/base_exec_plugin.py +53 -0
- flwr/supercore/superexec/plugin/clientapp_exec_plugin.py +28 -0
- flwr/supercore/superexec/plugin/exec_plugin.py +71 -0
- flwr/supercore/superexec/plugin/serverapp_exec_plugin.py +28 -0
- flwr/supercore/superexec/plugin/simulation_exec_plugin.py +28 -0
- flwr/supercore/superexec/run_superexec.py +185 -0
- flwr/supercore/utils.py +32 -0
- flwr/superlink/servicer/__init__.py +15 -0
- flwr/superlink/servicer/control/__init__.py +22 -0
- flwr/{superexec/exec_event_log_interceptor.py → superlink/servicer/control/control_event_log_interceptor.py} +9 -5
- flwr/{superexec/exec_grpc.py → superlink/servicer/control/control_grpc.py} +39 -28
- flwr/superlink/servicer/control/control_license_interceptor.py +82 -0
- flwr/{superexec/exec_servicer.py → superlink/servicer/control/control_servicer.py} +79 -31
- flwr/{superexec/exec_user_auth_interceptor.py → superlink/servicer/control/control_user_auth_interceptor.py} +18 -10
- flwr/supernode/cli/flower_supernode.py +3 -7
- flwr/supernode/cli/flwr_clientapp.py +20 -16
- flwr/supernode/nodestate/in_memory_nodestate.py +13 -4
- flwr/supernode/nodestate/nodestate.py +3 -44
- flwr/supernode/runtime/run_clientapp.py +129 -115
- flwr/supernode/servicer/clientappio/__init__.py +1 -3
- flwr/supernode/servicer/clientappio/clientappio_servicer.py +217 -165
- flwr/supernode/start_client_internal.py +205 -148
- {flwr-1.19.0.dist-info → flwr-1.21.0.dist-info}/METADATA +5 -3
- {flwr-1.19.0.dist-info → flwr-1.21.0.dist-info}/RECORD +161 -117
- {flwr-1.19.0.dist-info → flwr-1.21.0.dist-info}/entry_points.txt +1 -0
- flwr/common/inflatable_rest_utils.py +0 -99
- flwr/proto/exec_pb2.py +0 -62
- flwr/superexec/app.py +0 -45
- flwr/superexec/deployment.py +0 -192
- flwr/superexec/executor.py +0 -100
- flwr/superexec/simulation.py +0 -130
- /flwr/proto/{exec_pb2.pyi → control_pb2.pyi} +0 -0
- /flwr/{server/superlink → supercore}/ffs/__init__.py +0 -0
- /flwr/{server/superlink → supercore}/ffs/ffs.py +0 -0
- /flwr/{server/superlink → supercore}/ffs/ffs_factory.py +0 -0
- {flwr-1.19.0.dist-info → flwr-1.21.0.dist-info}/WHEEL +0 -0
flwr/server/app.py
CHANGED
|
@@ -18,9 +18,8 @@
|
|
|
18
18
|
import argparse
|
|
19
19
|
import csv
|
|
20
20
|
import importlib.util
|
|
21
|
-
import multiprocessing
|
|
22
|
-
import multiprocessing.context
|
|
23
21
|
import os
|
|
22
|
+
import subprocess
|
|
24
23
|
import sys
|
|
25
24
|
import threading
|
|
26
25
|
from collections.abc import Sequence
|
|
@@ -37,13 +36,13 @@ from cryptography.hazmat.primitives.serialization import load_ssh_public_key
|
|
|
37
36
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
|
|
38
37
|
from flwr.common.address import parse_address
|
|
39
38
|
from flwr.common.args import try_obtain_server_certificates
|
|
40
|
-
from flwr.common.auth_plugin import
|
|
41
|
-
from flwr.common.config import get_flwr_dir
|
|
39
|
+
from flwr.common.auth_plugin import ControlAuthPlugin, ControlAuthzPlugin
|
|
40
|
+
from flwr.common.config import get_flwr_dir
|
|
42
41
|
from flwr.common.constant import (
|
|
43
42
|
AUTH_TYPE_YAML_KEY,
|
|
44
43
|
AUTHZ_TYPE_YAML_KEY,
|
|
45
44
|
CLIENT_OCTET,
|
|
46
|
-
|
|
45
|
+
CONTROL_API_DEFAULT_SERVER_ADDRESS,
|
|
47
46
|
FLEET_API_GRPC_RERE_DEFAULT_ADDRESS,
|
|
48
47
|
FLEET_API_REST_DEFAULT_ADDRESS,
|
|
49
48
|
ISOLATION_MODE_PROCESS,
|
|
@@ -55,10 +54,10 @@ from flwr.common.constant import (
|
|
|
55
54
|
TRANSPORT_TYPE_GRPC_RERE,
|
|
56
55
|
TRANSPORT_TYPE_REST,
|
|
57
56
|
EventLogWriterType,
|
|
57
|
+
ExecPluginType,
|
|
58
58
|
)
|
|
59
59
|
from flwr.common.event_log_plugin import EventLogWriterPlugin
|
|
60
|
-
from flwr.common.exit import ExitCode, flwr_exit
|
|
61
|
-
from flwr.common.exit_handlers import register_exit_handlers
|
|
60
|
+
from flwr.common.exit import ExitCode, flwr_exit, register_signal_handlers
|
|
62
61
|
from flwr.common.grpc import generic_create_grpc_server
|
|
63
62
|
from flwr.common.logger import log
|
|
64
63
|
from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
|
|
@@ -69,13 +68,11 @@ from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
|
69
68
|
)
|
|
70
69
|
from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
|
71
70
|
from flwr.server.fleet_event_log_interceptor import FleetEventLogInterceptor
|
|
72
|
-
from flwr.
|
|
73
|
-
from flwr.
|
|
71
|
+
from flwr.supercore.ffs import FfsFactory
|
|
72
|
+
from flwr.supercore.grpc_health import add_args_health, run_health_server_grpc_no_tls
|
|
74
73
|
from flwr.supercore.object_store import ObjectStoreFactory
|
|
75
|
-
from flwr.
|
|
76
|
-
from flwr.superexec.exec_grpc import run_exec_api_grpc
|
|
74
|
+
from flwr.superlink.servicer.control import run_control_api_grpc
|
|
77
75
|
|
|
78
|
-
from .superlink.ffs.ffs_factory import FfsFactory
|
|
79
76
|
from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
|
|
80
77
|
from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
|
|
81
78
|
from .superlink.fleet.grpc_rere.server_interceptor import AuthenticateServerInterceptor
|
|
@@ -85,15 +82,15 @@ from .superlink.simulation.simulationio_grpc import run_simulationio_api_grpc
|
|
|
85
82
|
|
|
86
83
|
DATABASE = ":flwr-in-memory-state:"
|
|
87
84
|
BASE_DIR = get_flwr_dir() / "superlink" / "ffs"
|
|
88
|
-
P = TypeVar("P",
|
|
85
|
+
P = TypeVar("P", ControlAuthPlugin, ControlAuthzPlugin)
|
|
89
86
|
|
|
90
87
|
|
|
91
88
|
try:
|
|
92
89
|
from flwr.ee import (
|
|
93
90
|
add_ee_args_superlink,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
get_control_auth_plugins,
|
|
92
|
+
get_control_authz_plugins,
|
|
93
|
+
get_control_event_log_writer_plugins,
|
|
97
94
|
get_fleet_event_log_writer_plugins,
|
|
98
95
|
)
|
|
99
96
|
except ImportError:
|
|
@@ -102,16 +99,16 @@ except ImportError:
|
|
|
102
99
|
def add_ee_args_superlink(parser: argparse.ArgumentParser) -> None:
|
|
103
100
|
"""Add EE-specific arguments to the parser."""
|
|
104
101
|
|
|
105
|
-
def
|
|
106
|
-
"""Return all
|
|
102
|
+
def get_control_auth_plugins() -> dict[str, type[ControlAuthPlugin]]:
|
|
103
|
+
"""Return all Control API authentication plugins."""
|
|
107
104
|
raise NotImplementedError("No authentication plugins are currently supported.")
|
|
108
105
|
|
|
109
|
-
def
|
|
110
|
-
"""Return all
|
|
106
|
+
def get_control_authz_plugins() -> dict[str, type[ControlAuthzPlugin]]:
|
|
107
|
+
"""Return all Control API authorization plugins."""
|
|
111
108
|
raise NotImplementedError("No authorization plugins are currently supported.")
|
|
112
109
|
|
|
113
|
-
def
|
|
114
|
-
"""Return all
|
|
110
|
+
def get_control_event_log_writer_plugins() -> dict[str, type[EventLogWriterPlugin]]:
|
|
111
|
+
"""Return all Control API event log writer plugins."""
|
|
115
112
|
raise NotImplementedError(
|
|
116
113
|
"No event log writer plugins are currently supported."
|
|
117
114
|
)
|
|
@@ -138,10 +135,50 @@ def run_superlink() -> None:
|
|
|
138
135
|
WARN, "The `--flwr-dir` option is currently not in use and will be ignored."
|
|
139
136
|
)
|
|
140
137
|
|
|
138
|
+
# Detect if `--executor*` arguments were set
|
|
139
|
+
if args.executor or args.executor_dir or args.executor_config:
|
|
140
|
+
flwr_exit(
|
|
141
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
|
142
|
+
"The arguments `--executor`, `--executor-dir`, and `--executor-config` are "
|
|
143
|
+
"deprecated and will be removed in a future release. To run SuperLink with "
|
|
144
|
+
"the SimulationIo API, please use `--simulation`.",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Detect if both Control API and Exec API addresses were set explicitly
|
|
148
|
+
explicit_args = set()
|
|
149
|
+
for arg in sys.argv[1:]:
|
|
150
|
+
if arg.startswith("--"):
|
|
151
|
+
explicit_args.add(
|
|
152
|
+
arg.split("=")[0]
|
|
153
|
+
) # handles both `--arg val` and `--arg=val`
|
|
154
|
+
|
|
155
|
+
control_api_set = "--control-api-address" in explicit_args
|
|
156
|
+
exec_api_set = "--exec-api-address" in explicit_args
|
|
157
|
+
|
|
158
|
+
if control_api_set and exec_api_set:
|
|
159
|
+
flwr_exit(
|
|
160
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
|
161
|
+
"Both `--control-api-address` and `--exec-api-address` are set. "
|
|
162
|
+
"Please use only `--control-api-address` as `--exec-api-address` is "
|
|
163
|
+
"deprecated.",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Warn deprecated `--exec-api-address` argument
|
|
167
|
+
if args.exec_api_address is not None:
|
|
168
|
+
log(
|
|
169
|
+
WARN,
|
|
170
|
+
"The `--exec-api-address` argument is deprecated and will be removed in a "
|
|
171
|
+
"future release. Use `--control-api-address` instead.",
|
|
172
|
+
)
|
|
173
|
+
args.control_api_address = args.exec_api_address
|
|
174
|
+
|
|
141
175
|
# Parse IP addresses
|
|
142
176
|
serverappio_address, _, _ = _format_address(args.serverappio_api_address)
|
|
143
|
-
|
|
177
|
+
control_address, _, _ = _format_address(args.control_api_address)
|
|
144
178
|
simulationio_address, _, _ = _format_address(args.simulationio_api_address)
|
|
179
|
+
health_server_address = None
|
|
180
|
+
if args.health_server_address is not None:
|
|
181
|
+
health_server_address, _, _ = _format_address(args.health_server_address)
|
|
145
182
|
|
|
146
183
|
# Obtain certificates
|
|
147
184
|
certificates = try_obtain_server_certificates(args)
|
|
@@ -150,17 +187,17 @@ def run_superlink() -> None:
|
|
|
150
187
|
# provided
|
|
151
188
|
verify_tls_cert = not getattr(args, "disable_oidc_tls_cert_verification", None)
|
|
152
189
|
|
|
153
|
-
auth_plugin: Optional[
|
|
154
|
-
authz_plugin: Optional[
|
|
190
|
+
auth_plugin: Optional[ControlAuthPlugin] = None
|
|
191
|
+
authz_plugin: Optional[ControlAuthzPlugin] = None
|
|
155
192
|
event_log_plugin: Optional[EventLogWriterPlugin] = None
|
|
156
193
|
# Load the auth plugin if the args.user_auth_config is provided
|
|
157
194
|
if cfg_path := getattr(args, "user_auth_config", None):
|
|
158
|
-
auth_plugin, authz_plugin =
|
|
195
|
+
auth_plugin, authz_plugin = _try_obtain_control_auth_plugins(
|
|
159
196
|
Path(cfg_path), verify_tls_cert
|
|
160
197
|
)
|
|
161
198
|
# Enable event logging if the args.enable_event_log is True
|
|
162
199
|
if args.enable_event_log:
|
|
163
|
-
event_log_plugin =
|
|
200
|
+
event_log_plugin = _try_obtain_control_event_log_writer_plugin()
|
|
164
201
|
|
|
165
202
|
# Initialize StateFactory
|
|
166
203
|
state_factory = LinkStateFactory(args.database)
|
|
@@ -171,30 +208,23 @@ def run_superlink() -> None:
|
|
|
171
208
|
# Initialize ObjectStoreFactory
|
|
172
209
|
objectstore_factory = ObjectStoreFactory()
|
|
173
210
|
|
|
174
|
-
# Start
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
address=
|
|
211
|
+
# Start Control API
|
|
212
|
+
is_simulation = args.simulation
|
|
213
|
+
control_server: grpc.Server = run_control_api_grpc(
|
|
214
|
+
address=control_address,
|
|
178
215
|
state_factory=state_factory,
|
|
179
216
|
ffs_factory=ffs_factory,
|
|
180
217
|
objectstore_factory=objectstore_factory,
|
|
181
|
-
executor=executor,
|
|
182
218
|
certificates=certificates,
|
|
183
|
-
|
|
184
|
-
[args.executor_config] if args.executor_config else args.executor_config
|
|
185
|
-
),
|
|
219
|
+
is_simulation=is_simulation,
|
|
186
220
|
auth_plugin=auth_plugin,
|
|
187
221
|
authz_plugin=authz_plugin,
|
|
188
222
|
event_log_plugin=event_log_plugin,
|
|
189
223
|
)
|
|
190
|
-
grpc_servers = [
|
|
191
|
-
|
|
192
|
-
# Determine Exec plugin
|
|
193
|
-
# If simulation is used, don't start ServerAppIo and Fleet APIs
|
|
194
|
-
sim_exec = executor.__class__.__qualname__ == "SimulationEngine"
|
|
224
|
+
grpc_servers = [control_server]
|
|
195
225
|
bckg_threads: list[threading.Thread] = []
|
|
196
226
|
|
|
197
|
-
if
|
|
227
|
+
if is_simulation:
|
|
198
228
|
simulationio_server: grpc.Server = run_simulationio_api_grpc(
|
|
199
229
|
address=simulationio_address,
|
|
200
230
|
state_factory=state_factory,
|
|
@@ -312,28 +342,26 @@ def run_superlink() -> None:
|
|
|
312
342
|
io_address = (
|
|
313
343
|
f"{CLIENT_OCTET}:{_port}" if _octet == SERVER_OCTET else serverappio_address
|
|
314
344
|
)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
)
|
|
332
|
-
scheduler_th.start()
|
|
333
|
-
bckg_threads.append(scheduler_th)
|
|
345
|
+
command = ["flower-superexec", "--insecure"]
|
|
346
|
+
command += [
|
|
347
|
+
"--appio-api-address",
|
|
348
|
+
simulationio_address if is_simulation else io_address,
|
|
349
|
+
]
|
|
350
|
+
command += [
|
|
351
|
+
"--plugin-type",
|
|
352
|
+
ExecPluginType.SIMULATION if is_simulation else ExecPluginType.SERVER_APP,
|
|
353
|
+
]
|
|
354
|
+
command += ["--parent-pid", str(os.getpid())]
|
|
355
|
+
# pylint: disable-next=consider-using-with
|
|
356
|
+
subprocess.Popen(command)
|
|
357
|
+
|
|
358
|
+
# Launch gRPC health server
|
|
359
|
+
if health_server_address is not None:
|
|
360
|
+
health_server = run_health_server_grpc_no_tls(health_server_address)
|
|
361
|
+
grpc_servers.append(health_server)
|
|
334
362
|
|
|
335
363
|
# Graceful shutdown
|
|
336
|
-
|
|
364
|
+
register_signal_handlers(
|
|
337
365
|
event_type=EventType.RUN_SUPERLINK_LEAVE,
|
|
338
366
|
exit_message="SuperLink terminated gracefully.",
|
|
339
367
|
grpc_servers=grpc_servers,
|
|
@@ -348,75 +376,6 @@ def run_superlink() -> None:
|
|
|
348
376
|
flwr_exit(ExitCode.SUPERLINK_THREAD_CRASH)
|
|
349
377
|
|
|
350
378
|
|
|
351
|
-
def _run_flwr_command(args: list[str], main_pid: int) -> None:
|
|
352
|
-
# Monitor the main process in case of SIGKILL
|
|
353
|
-
def main_process_monitor() -> None:
|
|
354
|
-
while True:
|
|
355
|
-
sleep(1)
|
|
356
|
-
if os.getppid() != main_pid:
|
|
357
|
-
os.kill(os.getpid(), 9)
|
|
358
|
-
|
|
359
|
-
threading.Thread(target=main_process_monitor, daemon=True).start()
|
|
360
|
-
|
|
361
|
-
# Run the command
|
|
362
|
-
sys.argv = args
|
|
363
|
-
if args[0] == "flwr-serverapp":
|
|
364
|
-
flwr_serverapp()
|
|
365
|
-
elif args[0] == "flwr-simulation":
|
|
366
|
-
flwr_simulation()
|
|
367
|
-
else:
|
|
368
|
-
raise ValueError(f"Unknown command: {args[0]}")
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
def _flwr_scheduler(
|
|
372
|
-
state_factory: LinkStateFactory,
|
|
373
|
-
io_api_arg: str,
|
|
374
|
-
io_api_address: str,
|
|
375
|
-
cmd: str,
|
|
376
|
-
) -> None:
|
|
377
|
-
log(DEBUG, "Started %s scheduler thread.", cmd)
|
|
378
|
-
state = state_factory.state()
|
|
379
|
-
run_id_to_proc: dict[int, multiprocessing.context.SpawnProcess] = {}
|
|
380
|
-
|
|
381
|
-
# Use the "spawn" start method for multiprocessing.
|
|
382
|
-
mp_spawn_context = multiprocessing.get_context("spawn")
|
|
383
|
-
|
|
384
|
-
# Periodically check for a pending run in the LinkState
|
|
385
|
-
while True:
|
|
386
|
-
sleep(0.1)
|
|
387
|
-
pending_run_id = state.get_pending_run_id()
|
|
388
|
-
|
|
389
|
-
if pending_run_id and pending_run_id not in run_id_to_proc:
|
|
390
|
-
|
|
391
|
-
log(
|
|
392
|
-
INFO,
|
|
393
|
-
"Launching %s subprocess. Connects to SuperLink on %s",
|
|
394
|
-
cmd,
|
|
395
|
-
io_api_address,
|
|
396
|
-
)
|
|
397
|
-
# Start subprocess
|
|
398
|
-
command = [
|
|
399
|
-
cmd,
|
|
400
|
-
"--run-once",
|
|
401
|
-
io_api_arg,
|
|
402
|
-
io_api_address,
|
|
403
|
-
"--insecure",
|
|
404
|
-
]
|
|
405
|
-
|
|
406
|
-
proc = mp_spawn_context.Process(
|
|
407
|
-
target=_run_flwr_command, args=(command, os.getpid()), daemon=True
|
|
408
|
-
)
|
|
409
|
-
proc.start()
|
|
410
|
-
|
|
411
|
-
# Store the process
|
|
412
|
-
run_id_to_proc[pending_run_id] = proc
|
|
413
|
-
|
|
414
|
-
# Clean up finished processes
|
|
415
|
-
for run_id, proc in list(run_id_to_proc.items()):
|
|
416
|
-
if not proc.is_alive():
|
|
417
|
-
del run_id_to_proc[run_id]
|
|
418
|
-
|
|
419
|
-
|
|
420
379
|
def _format_address(address: str) -> tuple[str, str, int]:
|
|
421
380
|
parsed_address = parse_address(address)
|
|
422
381
|
if not parsed_address:
|
|
@@ -470,10 +429,10 @@ def _try_load_public_keys_node_authentication(
|
|
|
470
429
|
return node_public_keys
|
|
471
430
|
|
|
472
431
|
|
|
473
|
-
def
|
|
432
|
+
def _try_obtain_control_auth_plugins(
|
|
474
433
|
config_path: Path, verify_tls_cert: bool
|
|
475
|
-
) -> tuple[
|
|
476
|
-
"""Obtain
|
|
434
|
+
) -> tuple[ControlAuthPlugin, ControlAuthzPlugin]:
|
|
435
|
+
"""Obtain Control API authentication and authorization plugins."""
|
|
477
436
|
# Load YAML file
|
|
478
437
|
with config_path.open("r", encoding="utf-8") as file:
|
|
479
438
|
config: dict[str, Any] = yaml.safe_load(file)
|
|
@@ -503,24 +462,24 @@ def _try_obtain_exec_auth_plugins(
|
|
|
503
462
|
auth_plugin = _load_plugin(
|
|
504
463
|
section="authentication",
|
|
505
464
|
yaml_key=AUTH_TYPE_YAML_KEY,
|
|
506
|
-
loader=
|
|
465
|
+
loader=get_control_auth_plugins,
|
|
507
466
|
)
|
|
508
467
|
|
|
509
468
|
# Load authorization plugin
|
|
510
469
|
authz_plugin = _load_plugin(
|
|
511
470
|
section="authorization",
|
|
512
471
|
yaml_key=AUTHZ_TYPE_YAML_KEY,
|
|
513
|
-
loader=
|
|
472
|
+
loader=get_control_authz_plugins,
|
|
514
473
|
)
|
|
515
474
|
|
|
516
475
|
return auth_plugin, authz_plugin
|
|
517
476
|
|
|
518
477
|
|
|
519
|
-
def
|
|
478
|
+
def _try_obtain_control_event_log_writer_plugin() -> Optional[EventLogWriterPlugin]:
|
|
520
479
|
"""Return an instance of the event log writer plugin."""
|
|
521
480
|
try:
|
|
522
481
|
all_plugins: dict[str, type[EventLogWriterPlugin]] = (
|
|
523
|
-
|
|
482
|
+
get_control_event_log_writer_plugins()
|
|
524
483
|
)
|
|
525
484
|
plugin_class = all_plugins[EventLogWriterType.STDOUT]
|
|
526
485
|
return plugin_class()
|
|
@@ -568,7 +527,9 @@ def _run_fleet_api_grpc_rere( # pylint: disable=R0913, R0917
|
|
|
568
527
|
interceptors=interceptors,
|
|
569
528
|
)
|
|
570
529
|
|
|
571
|
-
log(
|
|
530
|
+
log(
|
|
531
|
+
INFO, "Flower Deployment Runtime: Starting Fleet API (gRPC-rere) on %s", address
|
|
532
|
+
)
|
|
572
533
|
fleet_grpc_server.start()
|
|
573
534
|
|
|
574
535
|
return fleet_grpc_server
|
|
@@ -596,7 +557,11 @@ def _run_fleet_api_grpc_adapter(
|
|
|
596
557
|
certificates=certificates,
|
|
597
558
|
)
|
|
598
559
|
|
|
599
|
-
log(
|
|
560
|
+
log(
|
|
561
|
+
INFO,
|
|
562
|
+
"Flower Deployment Runtime: Starting Fleet API (GrpcAdapter) on %s",
|
|
563
|
+
address,
|
|
564
|
+
)
|
|
600
565
|
fleet_grpc_server.start()
|
|
601
566
|
|
|
602
567
|
return fleet_grpc_server
|
|
@@ -651,8 +616,9 @@ def _parse_args_run_superlink() -> argparse.ArgumentParser:
|
|
|
651
616
|
add_ee_args_superlink(parser=parser)
|
|
652
617
|
_add_args_serverappio_api(parser=parser)
|
|
653
618
|
_add_args_fleet_api(parser=parser)
|
|
654
|
-
|
|
619
|
+
_add_args_control_api(parser=parser)
|
|
655
620
|
_add_args_simulationio_api(parser=parser)
|
|
621
|
+
add_args_health(parser=parser)
|
|
656
622
|
|
|
657
623
|
return parser
|
|
658
624
|
|
|
@@ -775,30 +741,41 @@ def _add_args_fleet_api(parser: argparse.ArgumentParser) -> None:
|
|
|
775
741
|
)
|
|
776
742
|
|
|
777
743
|
|
|
778
|
-
def
|
|
779
|
-
"""Add command line arguments for
|
|
744
|
+
def _add_args_control_api(parser: argparse.ArgumentParser) -> None:
|
|
745
|
+
"""Add command line arguments for Control API."""
|
|
746
|
+
parser.add_argument(
|
|
747
|
+
"--control-api-address",
|
|
748
|
+
help="Control API server address (IPv4, IPv6, or a domain name) "
|
|
749
|
+
f"By default, it is set to {CONTROL_API_DEFAULT_SERVER_ADDRESS}.",
|
|
750
|
+
default=CONTROL_API_DEFAULT_SERVER_ADDRESS,
|
|
751
|
+
)
|
|
780
752
|
parser.add_argument(
|
|
781
753
|
"--exec-api-address",
|
|
782
|
-
help="
|
|
783
|
-
|
|
784
|
-
default=
|
|
754
|
+
help="This argument is deprecated and will be removed in a future release. "
|
|
755
|
+
"Use `--control-api-address` instead.",
|
|
756
|
+
default=None,
|
|
785
757
|
)
|
|
786
758
|
parser.add_argument(
|
|
787
759
|
"--executor",
|
|
788
|
-
help="
|
|
789
|
-
|
|
790
|
-
default="flwr.superexec.deployment:executor",
|
|
760
|
+
help="This argument is deprecated and will be removed in a future release.",
|
|
761
|
+
default=None,
|
|
791
762
|
)
|
|
792
763
|
parser.add_argument(
|
|
793
764
|
"--executor-dir",
|
|
794
|
-
help="
|
|
795
|
-
default=
|
|
765
|
+
help="This argument is deprecated and will be removed in a future release.",
|
|
766
|
+
default=None,
|
|
796
767
|
)
|
|
797
768
|
parser.add_argument(
|
|
798
769
|
"--executor-config",
|
|
799
|
-
help="
|
|
800
|
-
|
|
801
|
-
|
|
770
|
+
help="This argument is deprecated and will be removed in a future release.",
|
|
771
|
+
default=None,
|
|
772
|
+
)
|
|
773
|
+
parser.add_argument(
|
|
774
|
+
"--simulation",
|
|
775
|
+
action="store_true",
|
|
776
|
+
default=False,
|
|
777
|
+
help="Launch the SimulationIo API server in place of "
|
|
778
|
+
"the ServerAppIo API server.",
|
|
802
779
|
)
|
|
803
780
|
|
|
804
781
|
|
|
@@ -41,6 +41,10 @@ class FleetEventLogInterceptor(grpc.ServerInterceptor): # type: ignore
|
|
|
41
41
|
if event logger is enabled on the SuperLink, else, terminate RPC call by setting
|
|
42
42
|
context to abort.
|
|
43
43
|
"""
|
|
44
|
+
# Only apply to Fleet service
|
|
45
|
+
if not handler_call_details.method.startswith("/flwr.proto.Fleet/"):
|
|
46
|
+
return continuation(handler_call_details)
|
|
47
|
+
|
|
44
48
|
# One of the method handlers in
|
|
45
49
|
# `flwr.server.superlink.fleet.grpc_rere.fleet_servicer.FleetServicer`
|
|
46
50
|
method_handler: grpc.RpcMethodHandler = continuation(handler_call_details)
|