flwr-nightly 1.13.0.dev20241021__py3-none-any.whl → 1.13.0.dev20241106__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.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/cli/build.py +2 -2
- flwr/cli/config_utils.py +97 -0
- flwr/cli/log.py +63 -97
- flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -0
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
- flwr/cli/run/run.py +18 -83
- flwr/client/app.py +13 -14
- flwr/client/clientapp/app.py +1 -2
- flwr/client/{node_state.py → run_info_store.py} +4 -3
- flwr/client/supernode/app.py +6 -8
- flwr/common/constant.py +39 -4
- flwr/common/context.py +9 -4
- flwr/common/date.py +3 -3
- flwr/common/logger.py +103 -0
- flwr/common/serde.py +24 -0
- flwr/common/telemetry.py +0 -6
- flwr/common/typing.py +9 -0
- flwr/proto/exec_pb2.py +6 -6
- flwr/proto/exec_pb2.pyi +8 -2
- flwr/proto/log_pb2.py +29 -0
- flwr/proto/log_pb2.pyi +39 -0
- flwr/proto/log_pb2_grpc.py +4 -0
- flwr/proto/log_pb2_grpc.pyi +4 -0
- flwr/proto/message_pb2.py +8 -8
- flwr/proto/message_pb2.pyi +4 -1
- flwr/proto/serverappio_pb2.py +52 -0
- flwr/proto/{driver_pb2.pyi → serverappio_pb2.pyi} +54 -0
- flwr/proto/serverappio_pb2_grpc.py +376 -0
- flwr/proto/serverappio_pb2_grpc.pyi +147 -0
- flwr/proto/simulationio_pb2.py +38 -0
- flwr/proto/simulationio_pb2.pyi +65 -0
- flwr/proto/simulationio_pb2_grpc.py +171 -0
- flwr/proto/simulationio_pb2_grpc.pyi +68 -0
- flwr/server/app.py +247 -105
- flwr/server/driver/driver.py +15 -1
- flwr/server/driver/grpc_driver.py +26 -33
- flwr/server/driver/inmemory_driver.py +6 -14
- flwr/server/run_serverapp.py +29 -23
- flwr/server/{superlink/state → serverapp}/__init__.py +3 -9
- flwr/server/serverapp/app.py +270 -0
- flwr/server/strategy/fedadam.py +11 -1
- flwr/server/superlink/driver/__init__.py +1 -1
- flwr/server/superlink/driver/{driver_grpc.py → serverappio_grpc.py} +19 -16
- flwr/server/superlink/driver/{driver_servicer.py → serverappio_servicer.py} +125 -39
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +4 -2
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -2
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +4 -2
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -2
- flwr/server/superlink/fleet/message_handler/message_handler.py +7 -7
- flwr/server/superlink/fleet/rest_rere/rest_api.py +7 -7
- flwr/server/superlink/fleet/vce/vce_api.py +23 -23
- flwr/server/superlink/linkstate/__init__.py +28 -0
- flwr/server/superlink/{state/in_memory_state.py → linkstate/in_memory_linkstate.py} +180 -21
- flwr/server/superlink/{state/state.py → linkstate/linkstate.py} +144 -15
- flwr/server/superlink/{state/state_factory.py → linkstate/linkstate_factory.py} +9 -9
- flwr/server/superlink/{state/sqlite_state.py → linkstate/sqlite_linkstate.py} +300 -50
- flwr/server/superlink/{state → linkstate}/utils.py +84 -2
- flwr/server/superlink/simulation/__init__.py +15 -0
- flwr/server/superlink/simulation/simulationio_grpc.py +65 -0
- flwr/server/superlink/simulation/simulationio_servicer.py +132 -0
- flwr/simulation/__init__.py +2 -0
- flwr/simulation/app.py +1 -1
- flwr/simulation/ray_transport/ray_client_proxy.py +2 -2
- flwr/simulation/run_simulation.py +57 -131
- flwr/simulation/simulationio_connection.py +86 -0
- flwr/superexec/app.py +6 -134
- flwr/superexec/deployment.py +60 -65
- flwr/superexec/exec_grpc.py +15 -8
- flwr/superexec/exec_servicer.py +34 -63
- flwr/superexec/executor.py +22 -4
- flwr/superexec/simulation.py +13 -8
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241106.dist-info}/METADATA +1 -1
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241106.dist-info}/RECORD +77 -64
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241106.dist-info}/entry_points.txt +1 -0
- flwr/client/node_state_tests.py +0 -66
- flwr/proto/driver_pb2.py +0 -42
- flwr/proto/driver_pb2_grpc.py +0 -239
- flwr/proto/driver_pb2_grpc.pyi +0 -94
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241106.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241106.dist-info}/WHEEL +0 -0
flwr/server/app.py
CHANGED
|
@@ -17,12 +17,14 @@
|
|
|
17
17
|
import argparse
|
|
18
18
|
import csv
|
|
19
19
|
import importlib.util
|
|
20
|
+
import subprocess
|
|
20
21
|
import sys
|
|
21
22
|
import threading
|
|
22
23
|
from collections.abc import Sequence
|
|
23
|
-
from logging import INFO, WARN
|
|
24
|
+
from logging import DEBUG, INFO, WARN
|
|
24
25
|
from os.path import isfile
|
|
25
26
|
from pathlib import Path
|
|
27
|
+
from time import sleep
|
|
26
28
|
from typing import Optional
|
|
27
29
|
|
|
28
30
|
import grpc
|
|
@@ -35,13 +37,17 @@ from cryptography.hazmat.primitives.serialization import (
|
|
|
35
37
|
|
|
36
38
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
|
|
37
39
|
from flwr.common.address import parse_address
|
|
38
|
-
from flwr.common.config import get_flwr_dir
|
|
40
|
+
from flwr.common.config import get_flwr_dir, parse_config_args
|
|
39
41
|
from flwr.common.constant import (
|
|
40
|
-
|
|
42
|
+
EXEC_API_DEFAULT_ADDRESS,
|
|
41
43
|
FLEET_API_GRPC_BIDI_DEFAULT_ADDRESS,
|
|
42
44
|
FLEET_API_GRPC_RERE_DEFAULT_ADDRESS,
|
|
43
45
|
FLEET_API_REST_DEFAULT_ADDRESS,
|
|
46
|
+
ISOLATION_MODE_PROCESS,
|
|
47
|
+
ISOLATION_MODE_SUBPROCESS,
|
|
44
48
|
MISSING_EXTRA_REST,
|
|
49
|
+
SERVERAPPIO_API_DEFAULT_ADDRESS,
|
|
50
|
+
SIMULATIONIO_API_DEFAULT_ADDRESS,
|
|
45
51
|
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
46
52
|
TRANSPORT_TYPE_GRPC_RERE,
|
|
47
53
|
TRANSPORT_TYPE_REST,
|
|
@@ -56,13 +62,16 @@ from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
|
56
62
|
add_FleetServicer_to_server,
|
|
57
63
|
)
|
|
58
64
|
from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
|
65
|
+
from flwr.superexec.app import load_executor
|
|
66
|
+
from flwr.superexec.exec_grpc import run_exec_api_grpc
|
|
67
|
+
from flwr.superexec.simulation import SimulationEngine
|
|
59
68
|
|
|
60
69
|
from .client_manager import ClientManager
|
|
61
70
|
from .history import History
|
|
62
71
|
from .server import Server, init_defaults, run_fl
|
|
63
72
|
from .server_config import ServerConfig
|
|
64
73
|
from .strategy import Strategy
|
|
65
|
-
from .superlink.driver.
|
|
74
|
+
from .superlink.driver.serverappio_grpc import run_serverappio_api_grpc
|
|
66
75
|
from .superlink.ffs.ffs_factory import FfsFactory
|
|
67
76
|
from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
|
|
68
77
|
from .superlink.fleet.grpc_bidi.grpc_server import (
|
|
@@ -71,7 +80,8 @@ from .superlink.fleet.grpc_bidi.grpc_server import (
|
|
|
71
80
|
)
|
|
72
81
|
from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
|
|
73
82
|
from .superlink.fleet.grpc_rere.server_interceptor import AuthenticateServerInterceptor
|
|
74
|
-
from .superlink.
|
|
83
|
+
from .superlink.linkstate import LinkStateFactory
|
|
84
|
+
from .superlink.simulation.simulationio_grpc import run_simulationio_api_grpc
|
|
75
85
|
|
|
76
86
|
DATABASE = ":flwr-in-memory-state:"
|
|
77
87
|
BASE_DIR = get_flwr_dir() / "superlink" / "ffs"
|
|
@@ -198,125 +208,169 @@ def start_server( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
198
208
|
|
|
199
209
|
# pylint: disable=too-many-branches, too-many-locals, too-many-statements
|
|
200
210
|
def run_superlink() -> None:
|
|
201
|
-
"""Run Flower SuperLink (
|
|
211
|
+
"""Run Flower SuperLink (ServerAppIo API and Fleet API)."""
|
|
202
212
|
args = _parse_args_run_superlink().parse_args()
|
|
203
213
|
|
|
204
214
|
log(INFO, "Starting Flower SuperLink")
|
|
205
215
|
|
|
206
216
|
event(EventType.RUN_SUPERLINK_ENTER)
|
|
207
217
|
|
|
208
|
-
# Parse IP
|
|
209
|
-
|
|
218
|
+
# Parse IP addresses
|
|
219
|
+
serverappio_address, _, _ = _format_address(args.serverappio_api_address)
|
|
220
|
+
exec_address, _, _ = _format_address(args.exec_api_address)
|
|
221
|
+
simulationio_address, _, _ = _format_address(args.simulationio_api_address)
|
|
210
222
|
|
|
211
223
|
# Obtain certificates
|
|
212
224
|
certificates = _try_obtain_certificates(args)
|
|
213
225
|
|
|
214
226
|
# Initialize StateFactory
|
|
215
|
-
state_factory =
|
|
227
|
+
state_factory = LinkStateFactory(args.database)
|
|
216
228
|
|
|
217
229
|
# Initialize FfsFactory
|
|
218
230
|
ffs_factory = FfsFactory(args.storage_dir)
|
|
219
231
|
|
|
220
|
-
# Start
|
|
221
|
-
|
|
222
|
-
|
|
232
|
+
# Start Exec API
|
|
233
|
+
executor = load_executor(args)
|
|
234
|
+
exec_server: grpc.Server = run_exec_api_grpc(
|
|
235
|
+
address=exec_address,
|
|
223
236
|
state_factory=state_factory,
|
|
224
237
|
ffs_factory=ffs_factory,
|
|
238
|
+
executor=executor,
|
|
225
239
|
certificates=certificates,
|
|
240
|
+
config=parse_config_args(
|
|
241
|
+
[args.executor_config] if args.executor_config else args.executor_config
|
|
242
|
+
),
|
|
226
243
|
)
|
|
244
|
+
grpc_servers = [exec_server]
|
|
227
245
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if args.fleet_api_type in [
|
|
232
|
-
TRANSPORT_TYPE_GRPC_RERE,
|
|
233
|
-
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
234
|
-
]:
|
|
235
|
-
args.fleet_api_address = FLEET_API_GRPC_RERE_DEFAULT_ADDRESS
|
|
236
|
-
elif args.fleet_api_type == TRANSPORT_TYPE_REST:
|
|
237
|
-
args.fleet_api_address = FLEET_API_REST_DEFAULT_ADDRESS
|
|
238
|
-
|
|
239
|
-
fleet_address, host, port = _format_address(args.fleet_api_address)
|
|
240
|
-
|
|
241
|
-
num_workers = args.fleet_api_num_workers
|
|
242
|
-
if num_workers != 1:
|
|
243
|
-
log(
|
|
244
|
-
WARN,
|
|
245
|
-
"The Fleet API currently supports only 1 worker. "
|
|
246
|
-
"You have specified %d workers. "
|
|
247
|
-
"Support for multiple workers will be added in future releases. "
|
|
248
|
-
"Proceeding with a single worker.",
|
|
249
|
-
args.fleet_api_num_workers,
|
|
250
|
-
)
|
|
251
|
-
num_workers = 1
|
|
252
|
-
|
|
253
|
-
# Start Fleet API
|
|
254
|
-
if args.fleet_api_type == TRANSPORT_TYPE_REST:
|
|
255
|
-
if (
|
|
256
|
-
importlib.util.find_spec("requests")
|
|
257
|
-
and importlib.util.find_spec("starlette")
|
|
258
|
-
and importlib.util.find_spec("uvicorn")
|
|
259
|
-
) is None:
|
|
260
|
-
sys.exit(MISSING_EXTRA_REST)
|
|
261
|
-
|
|
262
|
-
_, ssl_certfile, ssl_keyfile = (
|
|
263
|
-
certificates if certificates is not None else (None, None, None)
|
|
264
|
-
)
|
|
246
|
+
# Determine Exec plugin
|
|
247
|
+
# If simulation is used, don't start ServerAppIo and Fleet APIs
|
|
248
|
+
sim_exec = isinstance(executor, SimulationEngine)
|
|
265
249
|
|
|
266
|
-
|
|
267
|
-
target=_run_fleet_api_rest,
|
|
268
|
-
args=(
|
|
269
|
-
host,
|
|
270
|
-
port,
|
|
271
|
-
ssl_keyfile,
|
|
272
|
-
ssl_certfile,
|
|
273
|
-
state_factory,
|
|
274
|
-
ffs_factory,
|
|
275
|
-
num_workers,
|
|
276
|
-
),
|
|
277
|
-
)
|
|
278
|
-
fleet_thread.start()
|
|
279
|
-
bckg_threads.append(fleet_thread)
|
|
280
|
-
elif args.fleet_api_type == TRANSPORT_TYPE_GRPC_RERE:
|
|
281
|
-
maybe_keys = _try_setup_node_authentication(args, certificates)
|
|
282
|
-
interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None
|
|
283
|
-
if maybe_keys is not None:
|
|
284
|
-
(
|
|
285
|
-
node_public_keys,
|
|
286
|
-
server_private_key,
|
|
287
|
-
server_public_key,
|
|
288
|
-
) = maybe_keys
|
|
289
|
-
state = state_factory.state()
|
|
290
|
-
state.store_node_public_keys(node_public_keys)
|
|
291
|
-
state.store_server_private_public_key(
|
|
292
|
-
private_key_to_bytes(server_private_key),
|
|
293
|
-
public_key_to_bytes(server_public_key),
|
|
294
|
-
)
|
|
295
|
-
log(
|
|
296
|
-
INFO,
|
|
297
|
-
"Node authentication enabled with %d known public keys",
|
|
298
|
-
len(node_public_keys),
|
|
299
|
-
)
|
|
300
|
-
interceptors = [AuthenticateServerInterceptor(state)]
|
|
250
|
+
bckg_threads = []
|
|
301
251
|
|
|
302
|
-
|
|
303
|
-
|
|
252
|
+
if sim_exec:
|
|
253
|
+
simulationio_server: grpc.Server = run_simulationio_api_grpc(
|
|
254
|
+
address=simulationio_address,
|
|
304
255
|
state_factory=state_factory,
|
|
305
256
|
ffs_factory=ffs_factory,
|
|
306
257
|
certificates=certificates,
|
|
307
|
-
interceptors=interceptors,
|
|
308
258
|
)
|
|
309
|
-
grpc_servers.append(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
259
|
+
grpc_servers.append(simulationio_server)
|
|
260
|
+
|
|
261
|
+
else:
|
|
262
|
+
# Start ServerAppIo API
|
|
263
|
+
serverappio_server: grpc.Server = run_serverappio_api_grpc(
|
|
264
|
+
address=serverappio_address,
|
|
313
265
|
state_factory=state_factory,
|
|
314
266
|
ffs_factory=ffs_factory,
|
|
315
267
|
certificates=certificates,
|
|
316
268
|
)
|
|
317
|
-
grpc_servers.append(
|
|
318
|
-
|
|
319
|
-
|
|
269
|
+
grpc_servers.append(serverappio_server)
|
|
270
|
+
|
|
271
|
+
# Start Fleet API
|
|
272
|
+
if not args.fleet_api_address:
|
|
273
|
+
if args.fleet_api_type in [
|
|
274
|
+
TRANSPORT_TYPE_GRPC_RERE,
|
|
275
|
+
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
276
|
+
]:
|
|
277
|
+
args.fleet_api_address = FLEET_API_GRPC_RERE_DEFAULT_ADDRESS
|
|
278
|
+
elif args.fleet_api_type == TRANSPORT_TYPE_REST:
|
|
279
|
+
args.fleet_api_address = FLEET_API_REST_DEFAULT_ADDRESS
|
|
280
|
+
|
|
281
|
+
fleet_address, host, port = _format_address(args.fleet_api_address)
|
|
282
|
+
|
|
283
|
+
num_workers = args.fleet_api_num_workers
|
|
284
|
+
if num_workers != 1:
|
|
285
|
+
log(
|
|
286
|
+
WARN,
|
|
287
|
+
"The Fleet API currently supports only 1 worker. "
|
|
288
|
+
"You have specified %d workers. "
|
|
289
|
+
"Support for multiple workers will be added in future releases. "
|
|
290
|
+
"Proceeding with a single worker.",
|
|
291
|
+
args.fleet_api_num_workers,
|
|
292
|
+
)
|
|
293
|
+
num_workers = 1
|
|
294
|
+
|
|
295
|
+
if args.fleet_api_type == TRANSPORT_TYPE_REST:
|
|
296
|
+
if (
|
|
297
|
+
importlib.util.find_spec("requests")
|
|
298
|
+
and importlib.util.find_spec("starlette")
|
|
299
|
+
and importlib.util.find_spec("uvicorn")
|
|
300
|
+
) is None:
|
|
301
|
+
sys.exit(MISSING_EXTRA_REST)
|
|
302
|
+
|
|
303
|
+
_, ssl_certfile, ssl_keyfile = (
|
|
304
|
+
certificates if certificates is not None else (None, None, None)
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
fleet_thread = threading.Thread(
|
|
308
|
+
target=_run_fleet_api_rest,
|
|
309
|
+
args=(
|
|
310
|
+
host,
|
|
311
|
+
port,
|
|
312
|
+
ssl_keyfile,
|
|
313
|
+
ssl_certfile,
|
|
314
|
+
state_factory,
|
|
315
|
+
ffs_factory,
|
|
316
|
+
num_workers,
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
fleet_thread.start()
|
|
320
|
+
bckg_threads.append(fleet_thread)
|
|
321
|
+
elif args.fleet_api_type == TRANSPORT_TYPE_GRPC_RERE:
|
|
322
|
+
maybe_keys = _try_setup_node_authentication(args, certificates)
|
|
323
|
+
interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None
|
|
324
|
+
if maybe_keys is not None:
|
|
325
|
+
(
|
|
326
|
+
node_public_keys,
|
|
327
|
+
server_private_key,
|
|
328
|
+
server_public_key,
|
|
329
|
+
) = maybe_keys
|
|
330
|
+
state = state_factory.state()
|
|
331
|
+
state.store_node_public_keys(node_public_keys)
|
|
332
|
+
state.store_server_private_public_key(
|
|
333
|
+
private_key_to_bytes(server_private_key),
|
|
334
|
+
public_key_to_bytes(server_public_key),
|
|
335
|
+
)
|
|
336
|
+
log(
|
|
337
|
+
INFO,
|
|
338
|
+
"Node authentication enabled with %d known public keys",
|
|
339
|
+
len(node_public_keys),
|
|
340
|
+
)
|
|
341
|
+
interceptors = [AuthenticateServerInterceptor(state)]
|
|
342
|
+
|
|
343
|
+
fleet_server = _run_fleet_api_grpc_rere(
|
|
344
|
+
address=fleet_address,
|
|
345
|
+
state_factory=state_factory,
|
|
346
|
+
ffs_factory=ffs_factory,
|
|
347
|
+
certificates=certificates,
|
|
348
|
+
interceptors=interceptors,
|
|
349
|
+
)
|
|
350
|
+
grpc_servers.append(fleet_server)
|
|
351
|
+
elif args.fleet_api_type == TRANSPORT_TYPE_GRPC_ADAPTER:
|
|
352
|
+
fleet_server = _run_fleet_api_grpc_adapter(
|
|
353
|
+
address=fleet_address,
|
|
354
|
+
state_factory=state_factory,
|
|
355
|
+
ffs_factory=ffs_factory,
|
|
356
|
+
certificates=certificates,
|
|
357
|
+
)
|
|
358
|
+
grpc_servers.append(fleet_server)
|
|
359
|
+
else:
|
|
360
|
+
raise ValueError(f"Unknown fleet_api_type: {args.fleet_api_type}")
|
|
361
|
+
|
|
362
|
+
if args.isolation == ISOLATION_MODE_SUBPROCESS:
|
|
363
|
+
# Scheduler thread
|
|
364
|
+
scheduler_th = threading.Thread(
|
|
365
|
+
target=_flwr_serverapp_scheduler,
|
|
366
|
+
args=(
|
|
367
|
+
state_factory,
|
|
368
|
+
args.serverappio_api_address,
|
|
369
|
+
args.ssl_ca_certfile,
|
|
370
|
+
),
|
|
371
|
+
)
|
|
372
|
+
scheduler_th.start()
|
|
373
|
+
bckg_threads.append(scheduler_th)
|
|
320
374
|
|
|
321
375
|
# Graceful shutdown
|
|
322
376
|
register_exit_handlers(
|
|
@@ -331,7 +385,46 @@ def run_superlink() -> None:
|
|
|
331
385
|
for thread in bckg_threads:
|
|
332
386
|
if not thread.is_alive():
|
|
333
387
|
sys.exit(1)
|
|
334
|
-
|
|
388
|
+
exec_server.wait_for_termination(timeout=1)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _flwr_serverapp_scheduler(
|
|
392
|
+
state_factory: LinkStateFactory,
|
|
393
|
+
serverappio_api_address: str,
|
|
394
|
+
ssl_ca_certfile: Optional[str],
|
|
395
|
+
) -> None:
|
|
396
|
+
log(DEBUG, "Started flwr-serverapp scheduler thread.")
|
|
397
|
+
|
|
398
|
+
state = state_factory.state()
|
|
399
|
+
|
|
400
|
+
# Periodically check for a pending run in the LinkState
|
|
401
|
+
while True:
|
|
402
|
+
sleep(3)
|
|
403
|
+
pending_run_id = state.get_pending_run_id()
|
|
404
|
+
|
|
405
|
+
if pending_run_id:
|
|
406
|
+
|
|
407
|
+
log(
|
|
408
|
+
INFO,
|
|
409
|
+
"Launching `flwr-serverapp` subprocess. Connects to SuperLink on %s",
|
|
410
|
+
serverappio_api_address,
|
|
411
|
+
)
|
|
412
|
+
# Start ServerApp subprocess
|
|
413
|
+
command = [
|
|
414
|
+
"flwr-serverapp",
|
|
415
|
+
"--superlink",
|
|
416
|
+
serverappio_api_address,
|
|
417
|
+
]
|
|
418
|
+
if ssl_ca_certfile:
|
|
419
|
+
command.append("--root-certificates")
|
|
420
|
+
command.append(ssl_ca_certfile)
|
|
421
|
+
else:
|
|
422
|
+
command.append("--insecure")
|
|
423
|
+
|
|
424
|
+
subprocess.Popen( # pylint: disable=consider-using-with
|
|
425
|
+
command,
|
|
426
|
+
text=True,
|
|
427
|
+
)
|
|
335
428
|
|
|
336
429
|
|
|
337
430
|
def _format_address(address: str) -> tuple[str, str, int]:
|
|
@@ -489,7 +582,7 @@ def _try_obtain_certificates(
|
|
|
489
582
|
|
|
490
583
|
def _run_fleet_api_grpc_rere(
|
|
491
584
|
address: str,
|
|
492
|
-
state_factory:
|
|
585
|
+
state_factory: LinkStateFactory,
|
|
493
586
|
ffs_factory: FfsFactory,
|
|
494
587
|
certificates: Optional[tuple[bytes, bytes, bytes]],
|
|
495
588
|
interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
|
|
@@ -517,7 +610,7 @@ def _run_fleet_api_grpc_rere(
|
|
|
517
610
|
|
|
518
611
|
def _run_fleet_api_grpc_adapter(
|
|
519
612
|
address: str,
|
|
520
|
-
state_factory:
|
|
613
|
+
state_factory: LinkStateFactory,
|
|
521
614
|
ffs_factory: FfsFactory,
|
|
522
615
|
certificates: Optional[tuple[bytes, bytes, bytes]],
|
|
523
616
|
) -> grpc.Server:
|
|
@@ -548,11 +641,11 @@ def _run_fleet_api_rest(
|
|
|
548
641
|
port: int,
|
|
549
642
|
ssl_keyfile: Optional[str],
|
|
550
643
|
ssl_certfile: Optional[str],
|
|
551
|
-
state_factory:
|
|
644
|
+
state_factory: LinkStateFactory,
|
|
552
645
|
ffs_factory: FfsFactory,
|
|
553
646
|
num_workers: int,
|
|
554
647
|
) -> None:
|
|
555
|
-
"""Run
|
|
648
|
+
"""Run ServerAppIo API (REST-based)."""
|
|
556
649
|
try:
|
|
557
650
|
import uvicorn
|
|
558
651
|
|
|
@@ -579,14 +672,16 @@ def _run_fleet_api_rest(
|
|
|
579
672
|
|
|
580
673
|
|
|
581
674
|
def _parse_args_run_superlink() -> argparse.ArgumentParser:
|
|
582
|
-
"""Parse command line arguments for both
|
|
675
|
+
"""Parse command line arguments for both ServerAppIo API and Fleet API."""
|
|
583
676
|
parser = argparse.ArgumentParser(
|
|
584
677
|
description="Start a Flower SuperLink",
|
|
585
678
|
)
|
|
586
679
|
|
|
587
680
|
_add_args_common(parser=parser)
|
|
588
|
-
|
|
681
|
+
_add_args_serverappio_api(parser=parser)
|
|
589
682
|
_add_args_fleet_api(parser=parser)
|
|
683
|
+
_add_args_exec_api(parser=parser)
|
|
684
|
+
_add_args_simulationio_api(parser=parser)
|
|
590
685
|
|
|
591
686
|
return parser
|
|
592
687
|
|
|
@@ -618,6 +713,19 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
618
713
|
"to create a secure connection.",
|
|
619
714
|
type=str,
|
|
620
715
|
)
|
|
716
|
+
parser.add_argument(
|
|
717
|
+
"--isolation",
|
|
718
|
+
default=ISOLATION_MODE_SUBPROCESS,
|
|
719
|
+
required=False,
|
|
720
|
+
choices=[
|
|
721
|
+
ISOLATION_MODE_SUBPROCESS,
|
|
722
|
+
ISOLATION_MODE_PROCESS,
|
|
723
|
+
],
|
|
724
|
+
help="Isolation mode when running a `ServerApp` (`subprocess` by default, "
|
|
725
|
+
"possible values: `subprocess`, `process`). Use `subprocess` to configure "
|
|
726
|
+
"SuperLink to run a `ServerApp` in a subprocess. Use `process` to indicate "
|
|
727
|
+
"that a separate independent process gets created outside of SuperLink.",
|
|
728
|
+
)
|
|
621
729
|
parser.add_argument(
|
|
622
730
|
"--database",
|
|
623
731
|
help="A string representing the path to the database "
|
|
@@ -650,11 +758,11 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
650
758
|
)
|
|
651
759
|
|
|
652
760
|
|
|
653
|
-
def
|
|
761
|
+
def _add_args_serverappio_api(parser: argparse.ArgumentParser) -> None:
|
|
654
762
|
parser.add_argument(
|
|
655
|
-
"--
|
|
656
|
-
help="
|
|
657
|
-
default=
|
|
763
|
+
"--serverappio-api-address",
|
|
764
|
+
help="ServerAppIo API (gRPC) server address (IPv4, IPv6, or a domain name).",
|
|
765
|
+
default=SERVERAPPIO_API_DEFAULT_ADDRESS,
|
|
658
766
|
)
|
|
659
767
|
|
|
660
768
|
|
|
@@ -681,3 +789,37 @@ def _add_args_fleet_api(parser: argparse.ArgumentParser) -> None:
|
|
|
681
789
|
type=int,
|
|
682
790
|
help="Set the number of concurrent workers for the Fleet API server.",
|
|
683
791
|
)
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
def _add_args_exec_api(parser: argparse.ArgumentParser) -> None:
|
|
795
|
+
"""Add command line arguments for Exec API."""
|
|
796
|
+
parser.add_argument(
|
|
797
|
+
"--exec-api-address",
|
|
798
|
+
help="Exec API server address (IPv4, IPv6, or a domain name)",
|
|
799
|
+
default=EXEC_API_DEFAULT_ADDRESS,
|
|
800
|
+
)
|
|
801
|
+
parser.add_argument(
|
|
802
|
+
"--executor",
|
|
803
|
+
help="For example: `deployment:exec` or `project.package.module:wrapper.exec`. "
|
|
804
|
+
"The default is `flwr.superexec.deployment:executor`",
|
|
805
|
+
default="flwr.superexec.deployment:executor",
|
|
806
|
+
)
|
|
807
|
+
parser.add_argument(
|
|
808
|
+
"--executor-dir",
|
|
809
|
+
help="The directory for the executor.",
|
|
810
|
+
default=".",
|
|
811
|
+
)
|
|
812
|
+
parser.add_argument(
|
|
813
|
+
"--executor-config",
|
|
814
|
+
help="Key-value pairs for the executor config, separated by spaces. "
|
|
815
|
+
"For example:\n\n`--executor-config 'verbose=true "
|
|
816
|
+
'root-certificates="certificates/superlink-ca.crt"\'`',
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
def _add_args_simulationio_api(parser: argparse.ArgumentParser) -> None:
|
|
821
|
+
parser.add_argument(
|
|
822
|
+
"--simulationio-api-address",
|
|
823
|
+
help="SimulationIo API (gRPC) server address (IPv4, IPv6, or a domain name).",
|
|
824
|
+
default=SIMULATIONIO_API_DEFAULT_ADDRESS,
|
|
825
|
+
)
|
flwr/server/driver/driver.py
CHANGED
|
@@ -24,7 +24,21 @@ from flwr.common.typing import Run
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class Driver(ABC):
|
|
27
|
-
"""Abstract base Driver class for the
|
|
27
|
+
"""Abstract base Driver class for the ServerAppIo API."""
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def init_run(self, run_id: int) -> None:
|
|
31
|
+
"""Request a run to the SuperLink with a given `run_id`.
|
|
32
|
+
|
|
33
|
+
If a Run with the specified `run_id` exists, a local Run
|
|
34
|
+
object will be created. It enables further functionality
|
|
35
|
+
in the driver, such as sending `Messages`.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
run_id : int
|
|
40
|
+
The `run_id` of the Run this Driver object operates in.
|
|
41
|
+
"""
|
|
28
42
|
|
|
29
43
|
@property
|
|
30
44
|
@abstractmethod
|