flwr-nightly 1.21.0.dev20250818__py3-none-any.whl → 1.21.0.dev20250820__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/common/exit/exit.py +4 -1
- flwr/common/exit/exit_code.py +4 -10
- flwr/common/logger.py +1 -1
- flwr/server/app.py +33 -21
- flwr/server/grid/grpc_grid.py +1 -0
- flwr/server/grid/inmemory_grid.py +1 -0
- flwr/server/serverapp/app.py +115 -139
- flwr/server/superlink/serverappio/serverappio_grpc.py +1 -1
- flwr/simulation/app.py +127 -154
- flwr/supercore/app_utils.py +0 -31
- flwr/supercore/cli/flower_superexec.py +6 -0
- flwr/superlink/servicer/control/control_grpc.py +4 -9
- flwr/superlink/servicer/control/control_servicer.py +52 -14
- flwr/supernode/start_client_internal.py +1 -1
- {flwr_nightly-1.21.0.dev20250818.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/METADATA +1 -1
- {flwr_nightly-1.21.0.dev20250818.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/RECORD +18 -26
- flwr/superexec/__init__.py +0 -15
- flwr/superexec/deployment.py +0 -20
- flwr/superexec/simulation.py +0 -20
- flwr/superlink/executor/__init__.py +0 -28
- flwr/superlink/executor/app.py +0 -45
- flwr/superlink/executor/deployment.py +0 -188
- flwr/superlink/executor/executor.py +0 -100
- flwr/superlink/executor/simulation.py +0 -126
- {flwr_nightly-1.21.0.dev20250818.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.21.0.dev20250818.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/entry_points.txt +0 -0
flwr/simulation/app.py
CHANGED
@@ -16,7 +16,6 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
import argparse
|
19
|
-
import gc
|
20
19
|
from logging import DEBUG, ERROR, INFO
|
21
20
|
from queue import Queue
|
22
21
|
from typing import Optional
|
@@ -71,7 +70,7 @@ from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
|
|
71
70
|
from flwr.server.superlink.fleet.vce.backend.backend import BackendConfig
|
72
71
|
from flwr.simulation.run_simulation import _run_simulation
|
73
72
|
from flwr.simulation.simulationio_connection import SimulationIoConnection
|
74
|
-
from flwr.supercore.app_utils import
|
73
|
+
from flwr.supercore.app_utils import start_parent_process_monitor
|
75
74
|
from flwr.supercore.superexec.plugin import SimulationExecPlugin
|
76
75
|
from flwr.supercore.superexec.run_superexec import run_with_deprecation_warning
|
77
76
|
|
@@ -114,7 +113,6 @@ def flwr_simulation() -> None:
|
|
114
113
|
run_simulation_process(
|
115
114
|
simulationio_api_address=args.simulationio_api_address,
|
116
115
|
log_queue=log_queue,
|
117
|
-
run_once=(args.token is not None) or args.run_once,
|
118
116
|
token=args.token,
|
119
117
|
flwr_dir_=args.flwr_dir,
|
120
118
|
certificates=None,
|
@@ -128,8 +126,7 @@ def flwr_simulation() -> None:
|
|
128
126
|
def run_simulation_process( # pylint: disable=R0913, R0914, R0915, R0917, W0212
|
129
127
|
simulationio_api_address: str,
|
130
128
|
log_queue: Queue[Optional[str]],
|
131
|
-
|
132
|
-
token: Optional[str] = None,
|
129
|
+
token: str,
|
133
130
|
flwr_dir_: Optional[str] = None,
|
134
131
|
certificates: Optional[bytes] = None,
|
135
132
|
parent_pid: Optional[int] = None,
|
@@ -150,168 +147,144 @@ def run_simulation_process( # pylint: disable=R0913, R0914, R0915, R0917, W0212
|
|
150
147
|
heartbeat_sender = None
|
151
148
|
run_status = None
|
152
149
|
|
153
|
-
|
150
|
+
try:
|
151
|
+
# Pull SimulationInputs from LinkState
|
152
|
+
req = PullAppInputsRequest(token=token)
|
153
|
+
res: PullAppInputsResponse = conn._stub.PullAppInputs(req)
|
154
|
+
context = context_from_proto(res.context)
|
155
|
+
run = run_from_proto(res.run)
|
156
|
+
fab = fab_from_proto(res.fab)
|
157
|
+
|
158
|
+
# Start log uploader for this run
|
159
|
+
log_uploader = start_log_uploader(
|
160
|
+
log_queue=log_queue,
|
161
|
+
node_id=context.node_id,
|
162
|
+
run_id=run.run_id,
|
163
|
+
stub=conn._stub,
|
164
|
+
)
|
154
165
|
|
155
|
-
|
156
|
-
|
157
|
-
if token is None:
|
158
|
-
log(DEBUG, "[flwr-simulation] Request token")
|
159
|
-
token = simple_get_token(conn._stub)
|
160
|
-
|
161
|
-
# Pull SimulationInputs from LinkState
|
162
|
-
req = PullAppInputsRequest(token=token)
|
163
|
-
res: PullAppInputsResponse = conn._stub.PullAppInputs(req)
|
164
|
-
context = context_from_proto(res.context)
|
165
|
-
run = run_from_proto(res.run)
|
166
|
-
fab = fab_from_proto(res.fab)
|
167
|
-
|
168
|
-
# Start log uploader for this run
|
169
|
-
log_uploader = start_log_uploader(
|
170
|
-
log_queue=log_queue,
|
171
|
-
node_id=context.node_id,
|
172
|
-
run_id=run.run_id,
|
173
|
-
stub=conn._stub,
|
174
|
-
)
|
166
|
+
log(DEBUG, "Simulation process starts FAB installation.")
|
167
|
+
install_from_fab(fab.content, flwr_dir=flwr_dir, skip_prompt=True)
|
175
168
|
|
176
|
-
|
177
|
-
install_from_fab(fab.content, flwr_dir=flwr_dir, skip_prompt=True)
|
169
|
+
fab_id, fab_version = get_fab_metadata(fab.content)
|
178
170
|
|
179
|
-
|
171
|
+
app_path = get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir)
|
172
|
+
config = get_project_config(app_path)
|
180
173
|
|
181
|
-
|
182
|
-
|
174
|
+
# Get ClientApp and SeverApp components
|
175
|
+
app_components = config["tool"]["flwr"]["app"]["components"]
|
176
|
+
client_app_attr = app_components["clientapp"]
|
177
|
+
server_app_attr = app_components["serverapp"]
|
178
|
+
fused_config = get_fused_config_from_dir(app_path, run.override_config)
|
183
179
|
|
184
|
-
|
185
|
-
|
186
|
-
client_app_attr = app_components["clientapp"]
|
187
|
-
server_app_attr = app_components["serverapp"]
|
188
|
-
fused_config = get_fused_config_from_dir(app_path, run.override_config)
|
180
|
+
# Update run_config in context
|
181
|
+
context.run_config = fused_config
|
189
182
|
|
190
|
-
|
191
|
-
|
183
|
+
log(
|
184
|
+
DEBUG,
|
185
|
+
"Flower will load ServerApp `%s` in %s",
|
186
|
+
server_app_attr,
|
187
|
+
app_path,
|
188
|
+
)
|
189
|
+
log(
|
190
|
+
DEBUG,
|
191
|
+
"Flower will load ClientApp `%s` in %s",
|
192
|
+
client_app_attr,
|
193
|
+
app_path,
|
194
|
+
)
|
192
195
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
)
|
199
|
-
log(
|
200
|
-
DEBUG,
|
201
|
-
"Flower will load ClientApp `%s` in %s",
|
202
|
-
client_app_attr,
|
203
|
-
app_path,
|
204
|
-
)
|
196
|
+
# Change status to Running
|
197
|
+
run_status_proto = run_status_to_proto(RunStatus(Status.RUNNING, "", ""))
|
198
|
+
conn._stub.UpdateRunStatus(
|
199
|
+
UpdateRunStatusRequest(run_id=run.run_id, run_status=run_status_proto)
|
200
|
+
)
|
205
201
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
202
|
+
# Pull Federation Options
|
203
|
+
fed_opt_res: GetFederationOptionsResponse = conn._stub.GetFederationOptions(
|
204
|
+
GetFederationOptionsRequest(run_id=run.run_id)
|
205
|
+
)
|
206
|
+
federation_options = config_record_from_proto(fed_opt_res.federation_options)
|
207
|
+
|
208
|
+
# Unflatten underlying dict
|
209
|
+
fed_opt = unflatten_dict({**federation_options})
|
210
|
+
|
211
|
+
# Extract configs values of interest
|
212
|
+
num_supernodes = fed_opt.get("num-supernodes")
|
213
|
+
if num_supernodes is None:
|
214
|
+
raise ValueError("Federation options expects `num-supernodes` to be set.")
|
215
|
+
backend_config: BackendConfig = fed_opt.get("backend", {})
|
216
|
+
verbose: bool = fed_opt.get("verbose", False)
|
217
|
+
enable_tf_gpu_growth: bool = fed_opt.get("enable_tf_gpu_growth", False)
|
218
|
+
|
219
|
+
event(
|
220
|
+
EventType.FLWR_SIMULATION_RUN_ENTER,
|
221
|
+
event_details={
|
222
|
+
"backend": "ray",
|
223
|
+
"num-supernodes": num_supernodes,
|
224
|
+
"run-id-hash": get_sha256_hash(run.run_id),
|
225
|
+
},
|
226
|
+
)
|
211
227
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
228
|
+
# Set up heartbeat sender
|
229
|
+
heartbeat_fn = get_grpc_app_heartbeat_fn(
|
230
|
+
conn._stub,
|
231
|
+
run.run_id,
|
232
|
+
failure_message="Heartbeat failed unexpectedly. The SuperLink could "
|
233
|
+
"not find the provided run ID, or the run status is invalid.",
|
234
|
+
)
|
235
|
+
heartbeat_sender = HeartbeatSender(heartbeat_fn)
|
236
|
+
heartbeat_sender.start()
|
237
|
+
|
238
|
+
# Launch the simulation
|
239
|
+
updated_context = _run_simulation(
|
240
|
+
server_app_attr=server_app_attr,
|
241
|
+
client_app_attr=client_app_attr,
|
242
|
+
num_supernodes=num_supernodes,
|
243
|
+
backend_config=backend_config,
|
244
|
+
app_dir=str(app_path),
|
245
|
+
run=run,
|
246
|
+
enable_tf_gpu_growth=enable_tf_gpu_growth,
|
247
|
+
verbose_logging=verbose,
|
248
|
+
server_app_run_config=fused_config,
|
249
|
+
is_app=True,
|
250
|
+
exit_event=EventType.FLWR_SIMULATION_RUN_LEAVE,
|
251
|
+
)
|
219
252
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
raise ValueError(
|
227
|
-
"Federation options expects `num-supernodes` to be set."
|
228
|
-
)
|
229
|
-
backend_config: BackendConfig = fed_opt.get("backend", {})
|
230
|
-
verbose: bool = fed_opt.get("verbose", False)
|
231
|
-
enable_tf_gpu_growth: bool = fed_opt.get("enable_tf_gpu_growth", False)
|
232
|
-
|
233
|
-
event(
|
234
|
-
EventType.FLWR_SIMULATION_RUN_ENTER,
|
235
|
-
event_details={
|
236
|
-
"backend": "ray",
|
237
|
-
"num-supernodes": num_supernodes,
|
238
|
-
"run-id-hash": get_sha256_hash(run.run_id),
|
239
|
-
},
|
240
|
-
)
|
253
|
+
# Send resulting context
|
254
|
+
context_proto = context_to_proto(updated_context)
|
255
|
+
out_req = PushAppOutputsRequest(
|
256
|
+
token=token, run_id=run.run_id, context=context_proto
|
257
|
+
)
|
258
|
+
_ = conn._stub.PushAppOutputs(out_req)
|
241
259
|
|
242
|
-
|
243
|
-
heartbeat_fn = get_grpc_app_heartbeat_fn(
|
244
|
-
conn._stub,
|
245
|
-
run.run_id,
|
246
|
-
failure_message="Heartbeat failed unexpectedly. The SuperLink could "
|
247
|
-
"not find the provided run ID, or the run status is invalid.",
|
248
|
-
)
|
249
|
-
heartbeat_sender = HeartbeatSender(heartbeat_fn)
|
250
|
-
heartbeat_sender.start()
|
251
|
-
|
252
|
-
# Launch the simulation
|
253
|
-
updated_context = _run_simulation(
|
254
|
-
server_app_attr=server_app_attr,
|
255
|
-
client_app_attr=client_app_attr,
|
256
|
-
num_supernodes=num_supernodes,
|
257
|
-
backend_config=backend_config,
|
258
|
-
app_dir=str(app_path),
|
259
|
-
run=run,
|
260
|
-
enable_tf_gpu_growth=enable_tf_gpu_growth,
|
261
|
-
verbose_logging=verbose,
|
262
|
-
server_app_run_config=fused_config,
|
263
|
-
is_app=True,
|
264
|
-
exit_event=EventType.FLWR_SIMULATION_RUN_LEAVE,
|
265
|
-
)
|
260
|
+
run_status = RunStatus(Status.FINISHED, SubStatus.COMPLETED, "")
|
266
261
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
262
|
+
except Exception as ex: # pylint: disable=broad-exception-caught
|
263
|
+
exc_entity = "Simulation"
|
264
|
+
log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
|
265
|
+
run_status = RunStatus(Status.FINISHED, SubStatus.FAILED, str(ex))
|
266
|
+
|
267
|
+
finally:
|
268
|
+
# Stop heartbeat sender
|
269
|
+
if heartbeat_sender:
|
270
|
+
heartbeat_sender.stop()
|
271
|
+
|
272
|
+
# Stop log uploader for this run and upload final logs
|
273
|
+
if log_uploader:
|
274
|
+
stop_log_uploader(log_queue, log_uploader)
|
275
|
+
|
276
|
+
# Update run status
|
277
|
+
if run_status:
|
278
|
+
run_status_proto = run_status_to_proto(run_status)
|
279
|
+
conn._stub.UpdateRunStatus(
|
280
|
+
UpdateRunStatusRequest(run_id=run.run_id, run_status=run_status_proto)
|
271
281
|
)
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
except
|
277
|
-
|
278
|
-
log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
|
279
|
-
run_status = RunStatus(Status.FINISHED, SubStatus.FAILED, str(ex))
|
280
|
-
|
281
|
-
finally:
|
282
|
-
# Stop heartbeat sender
|
283
|
-
if heartbeat_sender:
|
284
|
-
heartbeat_sender.stop()
|
285
|
-
heartbeat_sender = None
|
286
|
-
|
287
|
-
# Stop log uploader for this run and upload final logs
|
288
|
-
if log_uploader:
|
289
|
-
stop_log_uploader(log_queue, log_uploader)
|
290
|
-
log_uploader = None
|
291
|
-
|
292
|
-
# Update run status
|
293
|
-
if run_status:
|
294
|
-
run_status_proto = run_status_to_proto(run_status)
|
295
|
-
conn._stub.UpdateRunStatus(
|
296
|
-
UpdateRunStatusRequest(
|
297
|
-
run_id=run.run_id, run_status=run_status_proto
|
298
|
-
)
|
299
|
-
)
|
300
|
-
run_status = None
|
301
|
-
|
302
|
-
# Clean up the Context if it exists
|
303
|
-
try:
|
304
|
-
del updated_context
|
305
|
-
except NameError:
|
306
|
-
pass
|
307
|
-
|
308
|
-
# Remove the token
|
309
|
-
token = None
|
310
|
-
gc.collect()
|
311
|
-
|
312
|
-
# Stop the loop if `flwr-simulation` is expected to process a single run
|
313
|
-
if run_once:
|
314
|
-
break
|
282
|
+
|
283
|
+
# Clean up the Context if it exists
|
284
|
+
try:
|
285
|
+
del updated_context
|
286
|
+
except NameError:
|
287
|
+
pass
|
315
288
|
|
316
289
|
|
317
290
|
def _parse_args_run_flwr_simulation() -> argparse.ArgumentParser:
|
flwr/supercore/app_utils.py
CHANGED
@@ -19,17 +19,6 @@ import os
|
|
19
19
|
import signal
|
20
20
|
import threading
|
21
21
|
import time
|
22
|
-
from typing import Union
|
23
|
-
|
24
|
-
from flwr.proto.appio_pb2 import ( # pylint: disable=E0611
|
25
|
-
ListAppsToLaunchRequest,
|
26
|
-
ListAppsToLaunchResponse,
|
27
|
-
RequestTokenRequest,
|
28
|
-
RequestTokenResponse,
|
29
|
-
)
|
30
|
-
from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
31
|
-
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
|
32
|
-
from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
|
33
22
|
|
34
23
|
if os.name == "nt":
|
35
24
|
from ctypes import windll # type: ignore
|
@@ -67,23 +56,3 @@ def start_parent_process_monitor(
|
|
67
56
|
os.kill(os.getpid(), signal.SIGKILL)
|
68
57
|
|
69
58
|
threading.Thread(target=monitor, daemon=True).start()
|
70
|
-
|
71
|
-
|
72
|
-
def simple_get_token(
|
73
|
-
stub: Union[ClientAppIoStub, ServerAppIoStub, SimulationIoStub]
|
74
|
-
) -> str:
|
75
|
-
"""Get a token from SuperLink/SuperNode.
|
76
|
-
|
77
|
-
This shall be removed once the SuperExec is fully implemented.
|
78
|
-
"""
|
79
|
-
while True:
|
80
|
-
res: ListAppsToLaunchResponse = stub.ListAppsToLaunch(ListAppsToLaunchRequest())
|
81
|
-
|
82
|
-
for run_id in res.run_ids:
|
83
|
-
tk_res: RequestTokenResponse = stub.RequestToken(
|
84
|
-
RequestTokenRequest(run_id=run_id)
|
85
|
-
)
|
86
|
-
if tk_res.token:
|
87
|
-
return tk_res.token
|
88
|
-
|
89
|
-
time.sleep(1) # Wait before retrying to get run IDs
|
@@ -20,6 +20,7 @@ from logging import INFO
|
|
20
20
|
|
21
21
|
from flwr.common import EventType, event
|
22
22
|
from flwr.common.constant import ExecPluginType
|
23
|
+
from flwr.common.exit import ExitCode, flwr_exit
|
23
24
|
from flwr.common.logger import log
|
24
25
|
from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
|
25
26
|
from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
|
@@ -36,6 +37,11 @@ from flwr.supercore.superexec.run_superexec import run_superexec
|
|
36
37
|
def flower_superexec() -> None:
|
37
38
|
"""Run `flower-superexec` command."""
|
38
39
|
args = _parse_args().parse_args()
|
40
|
+
if not args.insecure:
|
41
|
+
flwr_exit(
|
42
|
+
ExitCode.COMMON_TLS_NOT_SUPPORTED,
|
43
|
+
"SuperExec does not support TLS yet.",
|
44
|
+
)
|
39
45
|
|
40
46
|
# Log the first message after parsing arguments in case of `--help`
|
41
47
|
log(INFO, "Starting Flower SuperExec")
|
@@ -26,14 +26,12 @@ from flwr.common.event_log_plugin import EventLogWriterPlugin
|
|
26
26
|
from flwr.common.exit import ExitCode, flwr_exit
|
27
27
|
from flwr.common.grpc import generic_create_grpc_server
|
28
28
|
from flwr.common.logger import log
|
29
|
-
from flwr.common.typing import UserConfig
|
30
29
|
from flwr.proto.control_pb2_grpc import add_ControlServicer_to_server
|
31
30
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
32
31
|
from flwr.supercore.ffs import FfsFactory
|
33
32
|
from flwr.supercore.license_plugin import LicensePlugin
|
34
33
|
from flwr.supercore.object_store import ObjectStoreFactory
|
35
34
|
|
36
|
-
from ...executor import Executor
|
37
35
|
from .control_event_log_interceptor import ControlEventLogInterceptor
|
38
36
|
from .control_license_interceptor import ControlLicenseInterceptor
|
39
37
|
from .control_servicer import ControlServicer
|
@@ -50,19 +48,16 @@ except ImportError:
|
|
50
48
|
# pylint: disable-next=too-many-arguments,too-many-positional-arguments,too-many-locals
|
51
49
|
def run_control_api_grpc(
|
52
50
|
address: str,
|
53
|
-
executor: Executor,
|
54
51
|
state_factory: LinkStateFactory,
|
55
52
|
ffs_factory: FfsFactory,
|
56
53
|
objectstore_factory: ObjectStoreFactory,
|
57
54
|
certificates: Optional[tuple[bytes, bytes, bytes]],
|
58
|
-
|
55
|
+
is_simulation: bool,
|
59
56
|
auth_plugin: Optional[ControlAuthPlugin] = None,
|
60
57
|
authz_plugin: Optional[ControlAuthzPlugin] = None,
|
61
58
|
event_log_plugin: Optional[EventLogWriterPlugin] = None,
|
62
59
|
) -> grpc.Server:
|
63
60
|
"""Run Control API (gRPC, request-response)."""
|
64
|
-
executor.set_config(config)
|
65
|
-
|
66
61
|
license_plugin: Optional[LicensePlugin] = get_license_plugin()
|
67
62
|
if license_plugin and not license_plugin.check_license():
|
68
63
|
flwr_exit(ExitCode.SUPERLINK_LICENSE_INVALID)
|
@@ -71,7 +66,7 @@ def run_control_api_grpc(
|
|
71
66
|
linkstate_factory=state_factory,
|
72
67
|
ffs_factory=ffs_factory,
|
73
68
|
objectstore_factory=objectstore_factory,
|
74
|
-
|
69
|
+
is_simulation=is_simulation,
|
75
70
|
auth_plugin=auth_plugin,
|
76
71
|
)
|
77
72
|
interceptors: list[grpc.ServerInterceptor] = []
|
@@ -93,11 +88,11 @@ def run_control_api_grpc(
|
|
93
88
|
)
|
94
89
|
|
95
90
|
if auth_plugin is None:
|
96
|
-
log(INFO, "Flower Deployment
|
91
|
+
log(INFO, "Flower Deployment Runtime: Starting Control API on %s", address)
|
97
92
|
else:
|
98
93
|
log(
|
99
94
|
INFO,
|
100
|
-
"Flower Deployment
|
95
|
+
"Flower Deployment Runtime: Starting Control API with user "
|
101
96
|
"authentication on %s",
|
102
97
|
address,
|
103
98
|
)
|
@@ -15,6 +15,7 @@
|
|
15
15
|
"""Control API servicer."""
|
16
16
|
|
17
17
|
|
18
|
+
import hashlib
|
18
19
|
import time
|
19
20
|
from collections.abc import Generator
|
20
21
|
from logging import ERROR, INFO
|
@@ -22,7 +23,8 @@ from typing import Any, Optional, cast
|
|
22
23
|
|
23
24
|
import grpc
|
24
25
|
|
25
|
-
from flwr.
|
26
|
+
from flwr.cli.config_utils import get_fab_metadata
|
27
|
+
from flwr.common import Context, RecordDict, now
|
26
28
|
from flwr.common.auth_plugin import ControlAuthPlugin
|
27
29
|
from flwr.common.constant import (
|
28
30
|
FAB_MAX_SIZE,
|
@@ -37,7 +39,7 @@ from flwr.common.serde import (
|
|
37
39
|
run_to_proto,
|
38
40
|
user_config_from_proto,
|
39
41
|
)
|
40
|
-
from flwr.common.typing import Run, RunStatus
|
42
|
+
from flwr.common.typing import Fab, Run, RunStatus
|
41
43
|
from flwr.proto import control_pb2_grpc # pylint: disable=E0611
|
42
44
|
from flwr.proto.control_pb2 import ( # pylint: disable=E0611
|
43
45
|
GetAuthTokensRequest,
|
@@ -57,7 +59,6 @@ from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
|
|
57
59
|
from flwr.supercore.ffs import FfsFactory
|
58
60
|
from flwr.supercore.object_store import ObjectStore, ObjectStoreFactory
|
59
61
|
|
60
|
-
from ...executor.executor import Executor
|
61
62
|
from .control_user_auth_interceptor import shared_account_info
|
62
63
|
|
63
64
|
|
@@ -69,14 +70,13 @@ class ControlServicer(control_pb2_grpc.ControlServicer):
|
|
69
70
|
linkstate_factory: LinkStateFactory,
|
70
71
|
ffs_factory: FfsFactory,
|
71
72
|
objectstore_factory: ObjectStoreFactory,
|
72
|
-
|
73
|
+
is_simulation: bool,
|
73
74
|
auth_plugin: Optional[ControlAuthPlugin] = None,
|
74
75
|
) -> None:
|
75
76
|
self.linkstate_factory = linkstate_factory
|
76
77
|
self.ffs_factory = ffs_factory
|
77
78
|
self.objectstore_factory = objectstore_factory
|
78
|
-
self.
|
79
|
-
self.executor.initialize(linkstate_factory, ffs_factory)
|
79
|
+
self.is_simulation = is_simulation
|
80
80
|
self.auth_plugin = auth_plugin
|
81
81
|
|
82
82
|
def StartRun(
|
@@ -84,6 +84,8 @@ class ControlServicer(control_pb2_grpc.ControlServicer):
|
|
84
84
|
) -> StartRunResponse:
|
85
85
|
"""Create run ID."""
|
86
86
|
log(INFO, "ControlServicer.StartRun")
|
87
|
+
state = self.linkstate_factory.state()
|
88
|
+
ffs = self.ffs_factory.ffs()
|
87
89
|
|
88
90
|
if len(request.fab.content) > FAB_MAX_SIZE:
|
89
91
|
log(
|
@@ -94,17 +96,53 @@ class ControlServicer(control_pb2_grpc.ControlServicer):
|
|
94
96
|
return StartRunResponse()
|
95
97
|
|
96
98
|
flwr_aid = shared_account_info.get().flwr_aid if self.auth_plugin else None
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
override_config = user_config_from_proto(request.override_config)
|
100
|
+
federation_options = config_record_from_proto(request.federation_options)
|
101
|
+
fab_file = request.fab.content
|
102
|
+
|
103
|
+
try:
|
104
|
+
# Check that num-supernodes is set
|
105
|
+
if self.is_simulation and "num-supernodes" not in federation_options:
|
106
|
+
raise ValueError(
|
107
|
+
"Federation options doesn't contain key `num-supernodes`."
|
108
|
+
)
|
109
|
+
|
110
|
+
# Create run
|
111
|
+
fab = Fab(hashlib.sha256(fab_file).hexdigest(), fab_file)
|
112
|
+
fab_hash = ffs.put(fab.content, {})
|
113
|
+
if fab_hash != fab.hash_str:
|
114
|
+
raise RuntimeError(
|
115
|
+
f"FAB ({fab.hash_str}) hash from request doesn't match contents"
|
116
|
+
)
|
117
|
+
fab_id, fab_version = get_fab_metadata(fab.content)
|
118
|
+
|
119
|
+
run_id = state.create_run(
|
120
|
+
fab_id,
|
121
|
+
fab_version,
|
122
|
+
fab_hash,
|
123
|
+
override_config,
|
124
|
+
federation_options,
|
125
|
+
flwr_aid,
|
126
|
+
)
|
127
|
+
|
128
|
+
# Create an empty context for the Run
|
129
|
+
context = Context(
|
130
|
+
run_id=run_id,
|
131
|
+
node_id=0,
|
132
|
+
node_config={},
|
133
|
+
state=RecordDict(),
|
134
|
+
run_config={},
|
135
|
+
)
|
136
|
+
|
137
|
+
# Register the context at the LinkState
|
138
|
+
state.set_serverapp_context(run_id=run_id, context=context)
|
103
139
|
|
104
|
-
|
105
|
-
|
140
|
+
# pylint: disable-next=broad-except
|
141
|
+
except Exception as e:
|
142
|
+
log(ERROR, "Could not start run: %s", str(e))
|
106
143
|
return StartRunResponse()
|
107
144
|
|
145
|
+
log(INFO, "Created run %s", str(run_id))
|
108
146
|
return StartRunResponse(run_id=run_id)
|
109
147
|
|
110
148
|
def StreamLogs( # pylint: disable=C0103
|
@@ -532,6 +532,6 @@ def run_clientappio_api_grpc(
|
|
532
532
|
max_message_length=GRPC_MAX_MESSAGE_LENGTH,
|
533
533
|
certificates=certificates,
|
534
534
|
)
|
535
|
-
log(INFO, "Starting
|
535
|
+
log(INFO, "Flower Deployment Runtime: Starting ClientAppIo API on %s", address)
|
536
536
|
clientappio_grpc_server.start()
|
537
537
|
return clientappio_grpc_server
|
{flwr_nightly-1.21.0.dev20250818.dist-info → flwr_nightly-1.21.0.dev20250820.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.21.0.
|
3
|
+
Version: 1.21.0.dev20250820
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
5
5
|
License: Apache-2.0
|
6
6
|
Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
|