flwr-nightly 1.13.0.dev20241106__py3-none-any.whl → 1.13.0.dev20241117__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/app.py +2 -0
- flwr/cli/build.py +37 -0
- flwr/cli/install.py +5 -3
- flwr/cli/ls.py +228 -0
- flwr/cli/run/run.py +16 -5
- flwr/client/app.py +68 -19
- flwr/client/clientapp/app.py +51 -35
- flwr/client/grpc_rere_client/connection.py +2 -12
- flwr/client/nodestate/__init__.py +25 -0
- flwr/client/nodestate/in_memory_nodestate.py +38 -0
- flwr/client/nodestate/nodestate.py +30 -0
- flwr/client/nodestate/nodestate_factory.py +37 -0
- flwr/client/rest_client/connection.py +4 -14
- flwr/client/supernode/app.py +57 -53
- flwr/common/args.py +148 -0
- flwr/common/config.py +10 -0
- flwr/common/constant.py +21 -7
- flwr/common/date.py +18 -0
- flwr/common/logger.py +6 -2
- flwr/common/object_ref.py +47 -16
- flwr/common/serde.py +10 -0
- flwr/common/typing.py +32 -11
- flwr/proto/exec_pb2.py +23 -17
- flwr/proto/exec_pb2.pyi +50 -20
- flwr/proto/exec_pb2_grpc.py +34 -0
- flwr/proto/exec_pb2_grpc.pyi +13 -0
- flwr/proto/run_pb2.py +32 -27
- flwr/proto/run_pb2.pyi +44 -1
- flwr/proto/simulationio_pb2.py +2 -2
- flwr/proto/simulationio_pb2_grpc.py +34 -0
- flwr/proto/simulationio_pb2_grpc.pyi +13 -0
- flwr/server/app.py +83 -87
- flwr/server/driver/driver.py +1 -1
- flwr/server/driver/grpc_driver.py +6 -20
- flwr/server/driver/inmemory_driver.py +1 -3
- flwr/server/run_serverapp.py +8 -238
- flwr/server/serverapp/app.py +44 -89
- flwr/server/strategy/aggregate.py +4 -4
- flwr/server/superlink/fleet/rest_rere/rest_api.py +10 -9
- flwr/server/superlink/linkstate/in_memory_linkstate.py +76 -62
- flwr/server/superlink/linkstate/linkstate.py +24 -9
- flwr/server/superlink/linkstate/sqlite_linkstate.py +87 -128
- flwr/server/superlink/linkstate/utils.py +191 -32
- flwr/server/superlink/simulation/simulationio_servicer.py +22 -1
- flwr/simulation/__init__.py +3 -1
- flwr/simulation/app.py +245 -352
- flwr/simulation/legacy_app.py +402 -0
- flwr/simulation/run_simulation.py +8 -19
- flwr/simulation/simulationio_connection.py +2 -2
- flwr/superexec/deployment.py +13 -7
- flwr/superexec/exec_servicer.py +32 -3
- flwr/superexec/executor.py +4 -3
- flwr/superexec/simulation.py +52 -145
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/METADATA +10 -7
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/RECORD +58 -51
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/entry_points.txt +1 -0
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/WHEEL +0 -0
flwr/server/run_serverapp.py
CHANGED
|
@@ -15,33 +15,15 @@
|
|
|
15
15
|
"""Run ServerApp."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
import argparse
|
|
19
18
|
import sys
|
|
20
|
-
from logging import DEBUG,
|
|
21
|
-
from pathlib import Path
|
|
19
|
+
from logging import DEBUG, ERROR
|
|
22
20
|
from typing import Optional
|
|
23
21
|
|
|
24
|
-
from flwr.
|
|
25
|
-
from flwr.
|
|
26
|
-
from flwr.common import Context, EventType, RecordSet, event
|
|
27
|
-
from flwr.common.config import (
|
|
28
|
-
get_flwr_dir,
|
|
29
|
-
get_fused_config_from_dir,
|
|
30
|
-
get_metadata_from_config,
|
|
31
|
-
get_project_config,
|
|
32
|
-
get_project_dir,
|
|
33
|
-
)
|
|
34
|
-
from flwr.common.constant import SERVERAPPIO_API_DEFAULT_ADDRESS
|
|
35
|
-
from flwr.common.logger import log, update_console_handler, warn_deprecated_feature
|
|
22
|
+
from flwr.common import Context
|
|
23
|
+
from flwr.common.logger import log, warn_unsupported_feature
|
|
36
24
|
from flwr.common.object_ref import load_app
|
|
37
|
-
from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=E0611
|
|
38
|
-
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
|
39
|
-
CreateRunRequest,
|
|
40
|
-
CreateRunResponse,
|
|
41
|
-
)
|
|
42
25
|
|
|
43
26
|
from .driver import Driver
|
|
44
|
-
from .driver.grpc_driver import GrpcDriver
|
|
45
27
|
from .server_app import LoadServerAppError, ServerApp
|
|
46
28
|
|
|
47
29
|
|
|
@@ -87,221 +69,9 @@ def run(
|
|
|
87
69
|
# pylint: disable-next=too-many-branches,too-many-statements,too-many-locals
|
|
88
70
|
def run_server_app() -> None:
|
|
89
71
|
"""Run Flower server app."""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# Check if the server app reference is passed.
|
|
95
|
-
# Since Flower 1.11, passing a reference is not allowed.
|
|
96
|
-
app_path: Optional[str] = args.app
|
|
97
|
-
# If the provided app_path doesn't exist, and contains a ":",
|
|
98
|
-
# it is likely to be a server app reference instead of a path.
|
|
99
|
-
if app_path is not None and not Path(app_path).exists() and ":" in app_path:
|
|
100
|
-
sys.exit(
|
|
101
|
-
"It appears you've passed a reference like `server:app`.\n\n"
|
|
102
|
-
"Note that since version `1.11.0`, `flower-server-app` no longer supports "
|
|
103
|
-
"passing a reference to a `ServerApp` attribute. Instead, you need to pass "
|
|
104
|
-
"the path to Flower app via the argument `--app`. This is the path to a "
|
|
105
|
-
"directory containing a `pyproject.toml`. You can create a valid Flower "
|
|
106
|
-
"app by executing `flwr new` and following the prompt."
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
if args.server != SERVERAPPIO_API_DEFAULT_ADDRESS:
|
|
110
|
-
warn = "Passing flag --server is deprecated. Use --superlink instead."
|
|
111
|
-
warn_deprecated_feature(warn)
|
|
112
|
-
|
|
113
|
-
if args.superlink != SERVERAPPIO_API_DEFAULT_ADDRESS:
|
|
114
|
-
# if `--superlink` also passed, then
|
|
115
|
-
# warn user that this argument overrides what was passed with `--server`
|
|
116
|
-
log(
|
|
117
|
-
WARN,
|
|
118
|
-
"Both `--server` and `--superlink` were passed. "
|
|
119
|
-
"`--server` will be ignored. Connecting to the "
|
|
120
|
-
"SuperLink ServerAppIo API at %s.",
|
|
121
|
-
args.superlink,
|
|
122
|
-
)
|
|
123
|
-
else:
|
|
124
|
-
args.superlink = args.server
|
|
125
|
-
|
|
126
|
-
update_console_handler(
|
|
127
|
-
level=DEBUG if args.verbose else INFO,
|
|
128
|
-
timestamps=args.verbose,
|
|
129
|
-
colored=True,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
# Obtain certificates
|
|
133
|
-
if args.insecure:
|
|
134
|
-
if args.root_certificates is not None:
|
|
135
|
-
sys.exit(
|
|
136
|
-
"Conflicting options: The '--insecure' flag disables HTTPS, "
|
|
137
|
-
"but '--root-certificates' was also specified. Please remove "
|
|
138
|
-
"the '--root-certificates' option when running in insecure mode, "
|
|
139
|
-
"or omit '--insecure' to use HTTPS."
|
|
140
|
-
)
|
|
141
|
-
log(
|
|
142
|
-
WARN,
|
|
143
|
-
"Option `--insecure` was set. "
|
|
144
|
-
"Starting insecure HTTP client connected to %s.",
|
|
145
|
-
args.superlink,
|
|
146
|
-
)
|
|
147
|
-
root_certificates = None
|
|
148
|
-
else:
|
|
149
|
-
# Load the certificates if provided, or load the system certificates
|
|
150
|
-
cert_path = args.root_certificates
|
|
151
|
-
if cert_path is None:
|
|
152
|
-
root_certificates = None
|
|
153
|
-
else:
|
|
154
|
-
root_certificates = Path(cert_path).read_bytes()
|
|
155
|
-
log(
|
|
156
|
-
DEBUG,
|
|
157
|
-
"Starting secure HTTPS client connected to %s "
|
|
158
|
-
"with the following certificates: %s.",
|
|
159
|
-
args.superlink,
|
|
160
|
-
cert_path,
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
if not (app_path is None) ^ (args.run_id is None):
|
|
164
|
-
raise sys.exit(
|
|
165
|
-
"Please provide either a Flower App path or a Run ID, but not both. "
|
|
166
|
-
"For more details, use: ``flower-server-app -h``"
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
# Initialize GrpcDriver
|
|
170
|
-
if app_path is None:
|
|
171
|
-
# User provided `--run-id`, but not `app_dir`
|
|
172
|
-
driver = GrpcDriver(
|
|
173
|
-
serverappio_service_address=args.superlink,
|
|
174
|
-
root_certificates=root_certificates,
|
|
175
|
-
)
|
|
176
|
-
flwr_dir = get_flwr_dir(args.flwr_dir)
|
|
177
|
-
driver.init_run(args.run_id)
|
|
178
|
-
run_ = driver.run
|
|
179
|
-
if not run_.fab_hash:
|
|
180
|
-
raise ValueError("FAB hash not provided.")
|
|
181
|
-
fab_req = GetFabRequest(hash_str=run_.fab_hash)
|
|
182
|
-
# pylint: disable-next=W0212
|
|
183
|
-
fab_res: GetFabResponse = driver._stub.GetFab(fab_req)
|
|
184
|
-
if fab_res.fab.hash_str != run_.fab_hash:
|
|
185
|
-
raise ValueError("FAB hashes don't match.")
|
|
186
|
-
install_from_fab(fab_res.fab.content, flwr_dir, True)
|
|
187
|
-
fab_id, fab_version = get_fab_metadata(fab_res.fab.content)
|
|
188
|
-
|
|
189
|
-
app_path = str(get_project_dir(fab_id, fab_version, run_.fab_hash, flwr_dir))
|
|
190
|
-
config = get_project_config(app_path)
|
|
191
|
-
run_id = run_.run_id
|
|
192
|
-
else:
|
|
193
|
-
# User provided `app_dir`, but not `--run-id`
|
|
194
|
-
# Create run if run_id is not provided
|
|
195
|
-
driver = GrpcDriver(
|
|
196
|
-
serverappio_service_address=args.superlink,
|
|
197
|
-
root_certificates=root_certificates,
|
|
198
|
-
)
|
|
199
|
-
# Load config from the project directory
|
|
200
|
-
config = get_project_config(app_path)
|
|
201
|
-
fab_version, fab_id = get_metadata_from_config(config)
|
|
202
|
-
|
|
203
|
-
# Create run
|
|
204
|
-
req = CreateRunRequest(fab_id=fab_id, fab_version=fab_version)
|
|
205
|
-
res: CreateRunResponse = driver._stub.CreateRun(req) # pylint: disable=W0212
|
|
206
|
-
# Fetch full `Run` using `run_id`
|
|
207
|
-
driver.init_run(res.run_id) # pylint: disable=W0212
|
|
208
|
-
run_id = res.run_id
|
|
209
|
-
|
|
210
|
-
# Obtain server app reference and the run config
|
|
211
|
-
server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
|
|
212
|
-
server_app_run_config = get_fused_config_from_dir(
|
|
213
|
-
Path(app_path), driver.run.override_config
|
|
72
|
+
warn_unsupported_feature(
|
|
73
|
+
"The command `flower-server-app` is deprecated and no longer in use. "
|
|
74
|
+
"Use the `flwr-serverapp` exclusively instead."
|
|
214
75
|
)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
log(
|
|
219
|
-
DEBUG,
|
|
220
|
-
"root_certificates: `%s`",
|
|
221
|
-
root_certificates,
|
|
222
|
-
)
|
|
223
|
-
|
|
224
|
-
# Initialize Context
|
|
225
|
-
context = Context(
|
|
226
|
-
run_id=run_id,
|
|
227
|
-
node_id=0,
|
|
228
|
-
node_config={},
|
|
229
|
-
state=RecordSet(),
|
|
230
|
-
run_config=server_app_run_config,
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
# Run the ServerApp with the Driver
|
|
234
|
-
run(
|
|
235
|
-
driver=driver,
|
|
236
|
-
context=context,
|
|
237
|
-
server_app_dir=app_path,
|
|
238
|
-
server_app_attr=server_app_attr,
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
# Clean up
|
|
242
|
-
driver.close()
|
|
243
|
-
|
|
244
|
-
event(EventType.RUN_SERVER_APP_LEAVE)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def _parse_args_run_server_app() -> argparse.ArgumentParser:
|
|
248
|
-
"""Parse flower-server-app command line arguments."""
|
|
249
|
-
parser = argparse.ArgumentParser(
|
|
250
|
-
description="Start a Flower server app",
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
parser.add_argument(
|
|
254
|
-
"app",
|
|
255
|
-
nargs="?",
|
|
256
|
-
default=None,
|
|
257
|
-
help="Load and run the `ServerApp` from the specified Flower App path. "
|
|
258
|
-
"The `pyproject.toml` file must be located in the root of this path.",
|
|
259
|
-
)
|
|
260
|
-
parser.add_argument(
|
|
261
|
-
"--insecure",
|
|
262
|
-
action="store_true",
|
|
263
|
-
help="Run the `ServerApp` without HTTPS. By default, the app runs with "
|
|
264
|
-
"HTTPS enabled. Use this flag only if you understand the risks.",
|
|
265
|
-
)
|
|
266
|
-
parser.add_argument(
|
|
267
|
-
"--verbose",
|
|
268
|
-
action="store_true",
|
|
269
|
-
help="Set the logging to `DEBUG`.",
|
|
270
|
-
)
|
|
271
|
-
parser.add_argument(
|
|
272
|
-
"--root-certificates",
|
|
273
|
-
metavar="ROOT_CERT",
|
|
274
|
-
type=str,
|
|
275
|
-
help="Specifies the path to the PEM-encoded root certificate file for "
|
|
276
|
-
"establishing secure HTTPS connections.",
|
|
277
|
-
)
|
|
278
|
-
parser.add_argument(
|
|
279
|
-
"--server",
|
|
280
|
-
default=SERVERAPPIO_API_DEFAULT_ADDRESS,
|
|
281
|
-
help="Server address",
|
|
282
|
-
)
|
|
283
|
-
parser.add_argument(
|
|
284
|
-
"--superlink",
|
|
285
|
-
default=SERVERAPPIO_API_DEFAULT_ADDRESS,
|
|
286
|
-
help="SuperLink ServerAppIo API (gRPC-rere) address "
|
|
287
|
-
"(IPv4, IPv6, or a domain name)",
|
|
288
|
-
)
|
|
289
|
-
parser.add_argument(
|
|
290
|
-
"--run-id",
|
|
291
|
-
default=None,
|
|
292
|
-
type=int,
|
|
293
|
-
help="The identifier of the run.",
|
|
294
|
-
)
|
|
295
|
-
parser.add_argument(
|
|
296
|
-
"--flwr-dir",
|
|
297
|
-
default=None,
|
|
298
|
-
help="""The path containing installed Flower Apps.
|
|
299
|
-
By default, this value is equal to:
|
|
300
|
-
|
|
301
|
-
- `$FLWR_HOME/` if `$FLWR_HOME` is defined
|
|
302
|
-
- `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
|
|
303
|
-
- `$HOME/.flwr/` in all other cases
|
|
304
|
-
""",
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
return parser
|
|
76
|
+
log(ERROR, "`flower-server-app` used.")
|
|
77
|
+
sys.exit()
|
flwr/server/serverapp/app.py
CHANGED
|
@@ -15,9 +15,7 @@
|
|
|
15
15
|
"""Flower ServerApp process."""
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
|
-
import
|
|
19
|
-
from logging import DEBUG, ERROR, INFO, WARN
|
|
20
|
-
from os.path import isfile
|
|
18
|
+
from logging import DEBUG, ERROR, INFO
|
|
21
19
|
from pathlib import Path
|
|
22
20
|
from queue import Queue
|
|
23
21
|
from time import sleep
|
|
@@ -25,13 +23,18 @@ from typing import Optional
|
|
|
25
23
|
|
|
26
24
|
from flwr.cli.config_utils import get_fab_metadata
|
|
27
25
|
from flwr.cli.install import install_from_fab
|
|
26
|
+
from flwr.common.args import add_args_flwr_app_common, try_obtain_root_certificates
|
|
28
27
|
from flwr.common.config import (
|
|
29
28
|
get_flwr_dir,
|
|
30
29
|
get_fused_config_from_dir,
|
|
31
30
|
get_project_config,
|
|
32
31
|
get_project_dir,
|
|
33
32
|
)
|
|
34
|
-
from flwr.common.constant import
|
|
33
|
+
from flwr.common.constant import (
|
|
34
|
+
SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
|
|
35
|
+
Status,
|
|
36
|
+
SubStatus,
|
|
37
|
+
)
|
|
35
38
|
from flwr.common.logger import (
|
|
36
39
|
log,
|
|
37
40
|
mirror_output_to_queue,
|
|
@@ -63,60 +66,21 @@ def flwr_serverapp() -> None:
|
|
|
63
66
|
log_queue: Queue[Optional[str]] = Queue()
|
|
64
67
|
mirror_output_to_queue(log_queue)
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
description="Run a Flower ServerApp",
|
|
68
|
-
)
|
|
69
|
-
parser.add_argument(
|
|
70
|
-
"--superlink",
|
|
71
|
-
type=str,
|
|
72
|
-
help="Address of SuperLink's DriverAPI",
|
|
73
|
-
)
|
|
74
|
-
parser.add_argument(
|
|
75
|
-
"--run-once",
|
|
76
|
-
action="store_true",
|
|
77
|
-
help="When set, this process will start a single ServerApp "
|
|
78
|
-
"for a pending Run. If no pending run the process will exit. ",
|
|
79
|
-
)
|
|
80
|
-
parser.add_argument(
|
|
81
|
-
"--flwr-dir",
|
|
82
|
-
default=None,
|
|
83
|
-
help="""The path containing installed Flower Apps.
|
|
84
|
-
By default, this value is equal to:
|
|
85
|
-
|
|
86
|
-
- `$FLWR_HOME/` if `$FLWR_HOME` is defined
|
|
87
|
-
- `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
|
|
88
|
-
- `$HOME/.flwr/` in all other cases
|
|
89
|
-
""",
|
|
90
|
-
)
|
|
91
|
-
parser.add_argument(
|
|
92
|
-
"--insecure",
|
|
93
|
-
action="store_true",
|
|
94
|
-
help="Run the server without HTTPS, regardless of whether certificate "
|
|
95
|
-
"paths are provided. By default, the server runs with HTTPS enabled. "
|
|
96
|
-
"Use this flag only if you understand the risks.",
|
|
97
|
-
)
|
|
98
|
-
parser.add_argument(
|
|
99
|
-
"--root-certificates",
|
|
100
|
-
metavar="ROOT_CERT",
|
|
101
|
-
type=str,
|
|
102
|
-
help="Specifies the path to the PEM-encoded root certificate file for "
|
|
103
|
-
"establishing secure HTTPS connections.",
|
|
104
|
-
)
|
|
105
|
-
args = parser.parse_args()
|
|
69
|
+
args = _parse_args_run_flwr_serverapp().parse_args()
|
|
106
70
|
|
|
107
71
|
log(INFO, "Starting Flower ServerApp")
|
|
108
|
-
certificates =
|
|
72
|
+
certificates = try_obtain_root_certificates(args, args.serverappio_api_address)
|
|
109
73
|
|
|
110
74
|
log(
|
|
111
75
|
DEBUG,
|
|
112
|
-
"
|
|
113
|
-
args.
|
|
76
|
+
"Starting isolated `ServerApp` connected to SuperLink's ServerAppIo API at %s",
|
|
77
|
+
args.serverappio_api_address,
|
|
114
78
|
)
|
|
115
79
|
run_serverapp(
|
|
116
|
-
|
|
80
|
+
serverappio_api_address=args.serverappio_api_address,
|
|
117
81
|
log_queue=log_queue,
|
|
118
82
|
run_once=args.run_once,
|
|
119
|
-
|
|
83
|
+
flwr_dir=args.flwr_dir,
|
|
120
84
|
certificates=certificates,
|
|
121
85
|
)
|
|
122
86
|
|
|
@@ -124,54 +88,21 @@ def flwr_serverapp() -> None:
|
|
|
124
88
|
restore_output()
|
|
125
89
|
|
|
126
90
|
|
|
127
|
-
def _try_obtain_certificates(
|
|
128
|
-
args: argparse.Namespace,
|
|
129
|
-
) -> Optional[bytes]:
|
|
130
|
-
|
|
131
|
-
if args.insecure:
|
|
132
|
-
if args.root_certificates is not None:
|
|
133
|
-
sys.exit(
|
|
134
|
-
"Conflicting options: The '--insecure' flag disables HTTPS, "
|
|
135
|
-
"but '--root-certificates' was also specified. Please remove "
|
|
136
|
-
"the '--root-certificates' option when running in insecure mode, "
|
|
137
|
-
"or omit '--insecure' to use HTTPS."
|
|
138
|
-
)
|
|
139
|
-
log(
|
|
140
|
-
WARN,
|
|
141
|
-
"Option `--insecure` was set. Starting insecure HTTP channel to %s.",
|
|
142
|
-
args.superlink,
|
|
143
|
-
)
|
|
144
|
-
root_certificates = None
|
|
145
|
-
else:
|
|
146
|
-
# Load the certificates if provided, or load the system certificates
|
|
147
|
-
if not isfile(args.root_certificates):
|
|
148
|
-
sys.exit("Path argument `--root-certificates` does not point to a file.")
|
|
149
|
-
root_certificates = Path(args.root_certificates).read_bytes()
|
|
150
|
-
log(
|
|
151
|
-
DEBUG,
|
|
152
|
-
"Starting secure HTTPS channel to %s "
|
|
153
|
-
"with the following certificates: %s.",
|
|
154
|
-
args.superlink,
|
|
155
|
-
args.root_certificates,
|
|
156
|
-
)
|
|
157
|
-
return root_certificates
|
|
158
|
-
|
|
159
|
-
|
|
160
91
|
def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
161
|
-
|
|
92
|
+
serverappio_api_address: str,
|
|
162
93
|
log_queue: Queue[Optional[str]],
|
|
163
94
|
run_once: bool,
|
|
164
|
-
|
|
95
|
+
flwr_dir: Optional[str] = None,
|
|
165
96
|
certificates: Optional[bytes] = None,
|
|
166
97
|
) -> None:
|
|
167
98
|
"""Run Flower ServerApp process."""
|
|
168
99
|
driver = GrpcDriver(
|
|
169
|
-
serverappio_service_address=
|
|
100
|
+
serverappio_service_address=serverappio_api_address,
|
|
170
101
|
root_certificates=certificates,
|
|
171
102
|
)
|
|
172
103
|
|
|
173
104
|
# Resolve directory where FABs are installed
|
|
174
|
-
|
|
105
|
+
flwr_dir_ = get_flwr_dir(flwr_dir)
|
|
175
106
|
log_uploader = None
|
|
176
107
|
|
|
177
108
|
while True:
|
|
@@ -189,7 +120,7 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
|
189
120
|
run = run_from_proto(res.run)
|
|
190
121
|
fab = fab_from_proto(res.fab)
|
|
191
122
|
|
|
192
|
-
driver.
|
|
123
|
+
driver.set_run(run.run_id)
|
|
193
124
|
|
|
194
125
|
# Start log uploader for this run
|
|
195
126
|
log_uploader = start_log_uploader(
|
|
@@ -200,11 +131,13 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
|
200
131
|
)
|
|
201
132
|
|
|
202
133
|
log(DEBUG, "ServerApp process starts FAB installation.")
|
|
203
|
-
install_from_fab(fab.content, flwr_dir=
|
|
134
|
+
install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
|
|
204
135
|
|
|
205
136
|
fab_id, fab_version = get_fab_metadata(fab.content)
|
|
206
137
|
|
|
207
|
-
app_path = str(
|
|
138
|
+
app_path = str(
|
|
139
|
+
get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir_)
|
|
140
|
+
)
|
|
208
141
|
config = get_project_config(app_path)
|
|
209
142
|
|
|
210
143
|
# Obtain server app reference and the run config
|
|
@@ -268,3 +201,25 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
|
268
201
|
# Stop the loop if `flwr-serverapp` is expected to process a single run
|
|
269
202
|
if run_once:
|
|
270
203
|
break
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _parse_args_run_flwr_serverapp() -> argparse.ArgumentParser:
|
|
207
|
+
"""Parse flwr-serverapp command line arguments."""
|
|
208
|
+
parser = argparse.ArgumentParser(
|
|
209
|
+
description="Run a Flower ServerApp",
|
|
210
|
+
)
|
|
211
|
+
parser.add_argument(
|
|
212
|
+
"--serverappio-api-address",
|
|
213
|
+
default=SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
|
|
214
|
+
type=str,
|
|
215
|
+
help="Address of SuperLink's ServerAppIo API (IPv4, IPv6, or a domain name)."
|
|
216
|
+
f"By default, it is set to {SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS}.",
|
|
217
|
+
)
|
|
218
|
+
parser.add_argument(
|
|
219
|
+
"--run-once",
|
|
220
|
+
action="store_true",
|
|
221
|
+
help="When set, this process will start a single ServerApp for a pending Run. "
|
|
222
|
+
"If there is no pending Run, the process will exit.",
|
|
223
|
+
)
|
|
224
|
+
add_args_flwr_app_common(parser=parser)
|
|
225
|
+
return parser
|
|
@@ -48,12 +48,12 @@ def aggregate_inplace(results: list[tuple[ClientProxy, FitRes]]) -> NDArrays:
|
|
|
48
48
|
num_examples_total = sum(fit_res.num_examples for (_, fit_res) in results)
|
|
49
49
|
|
|
50
50
|
# Compute scaling factors for each result
|
|
51
|
-
scaling_factors =
|
|
52
|
-
fit_res.num_examples / num_examples_total for _, fit_res in results
|
|
53
|
-
|
|
51
|
+
scaling_factors = np.asarray(
|
|
52
|
+
[fit_res.num_examples / num_examples_total for _, fit_res in results]
|
|
53
|
+
)
|
|
54
54
|
|
|
55
55
|
def _try_inplace(
|
|
56
|
-
x: NDArray, y: Union[NDArray,
|
|
56
|
+
x: NDArray, y: Union[NDArray, np.float64], np_binary_op: np.ufunc
|
|
57
57
|
) -> NDArray:
|
|
58
58
|
return ( # type: ignore[no-any-return]
|
|
59
59
|
np_binary_op(x, y, out=x)
|
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import sys
|
|
21
21
|
from collections.abc import Awaitable
|
|
22
|
-
from typing import Callable, TypeVar
|
|
22
|
+
from typing import Callable, TypeVar, cast
|
|
23
23
|
|
|
24
24
|
from google.protobuf.message import Message as GrpcMessage
|
|
25
25
|
|
|
@@ -39,8 +39,9 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
|
39
39
|
)
|
|
40
40
|
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
41
41
|
from flwr.server.superlink.ffs.ffs import Ffs
|
|
42
|
+
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
42
43
|
from flwr.server.superlink.fleet.message_handler import message_handler
|
|
43
|
-
from flwr.server.superlink.linkstate import LinkState
|
|
44
|
+
from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
|
|
44
45
|
|
|
45
46
|
try:
|
|
46
47
|
from starlette.applications import Starlette
|
|
@@ -90,7 +91,7 @@ def rest_request_response(
|
|
|
90
91
|
async def create_node(request: CreateNodeRequest) -> CreateNodeResponse:
|
|
91
92
|
"""Create Node."""
|
|
92
93
|
# Get state from app
|
|
93
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
94
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
94
95
|
|
|
95
96
|
# Handle message
|
|
96
97
|
return message_handler.create_node(request=request, state=state)
|
|
@@ -100,7 +101,7 @@ async def create_node(request: CreateNodeRequest) -> CreateNodeResponse:
|
|
|
100
101
|
async def delete_node(request: DeleteNodeRequest) -> DeleteNodeResponse:
|
|
101
102
|
"""Delete Node Id."""
|
|
102
103
|
# Get state from app
|
|
103
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
104
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
104
105
|
|
|
105
106
|
# Handle message
|
|
106
107
|
return message_handler.delete_node(request=request, state=state)
|
|
@@ -110,7 +111,7 @@ async def delete_node(request: DeleteNodeRequest) -> DeleteNodeResponse:
|
|
|
110
111
|
async def pull_task_ins(request: PullTaskInsRequest) -> PullTaskInsResponse:
|
|
111
112
|
"""Pull TaskIns."""
|
|
112
113
|
# Get state from app
|
|
113
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
114
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
114
115
|
|
|
115
116
|
# Handle message
|
|
116
117
|
return message_handler.pull_task_ins(request=request, state=state)
|
|
@@ -121,7 +122,7 @@ async def pull_task_ins(request: PullTaskInsRequest) -> PullTaskInsResponse:
|
|
|
121
122
|
async def push_task_res(request: PushTaskResRequest) -> PushTaskResResponse:
|
|
122
123
|
"""Push TaskRes."""
|
|
123
124
|
# Get state from app
|
|
124
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
125
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
125
126
|
|
|
126
127
|
# Handle message
|
|
127
128
|
return message_handler.push_task_res(request=request, state=state)
|
|
@@ -131,7 +132,7 @@ async def push_task_res(request: PushTaskResRequest) -> PushTaskResResponse:
|
|
|
131
132
|
async def ping(request: PingRequest) -> PingResponse:
|
|
132
133
|
"""Ping."""
|
|
133
134
|
# Get state from app
|
|
134
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
135
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
135
136
|
|
|
136
137
|
# Handle message
|
|
137
138
|
return message_handler.ping(request=request, state=state)
|
|
@@ -141,7 +142,7 @@ async def ping(request: PingRequest) -> PingResponse:
|
|
|
141
142
|
async def get_run(request: GetRunRequest) -> GetRunResponse:
|
|
142
143
|
"""GetRun."""
|
|
143
144
|
# Get state from app
|
|
144
|
-
state: LinkState = app.state.STATE_FACTORY.state()
|
|
145
|
+
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
145
146
|
|
|
146
147
|
# Handle message
|
|
147
148
|
return message_handler.get_run(request=request, state=state)
|
|
@@ -151,7 +152,7 @@ async def get_run(request: GetRunRequest) -> GetRunResponse:
|
|
|
151
152
|
async def get_fab(request: GetFabRequest) -> GetFabResponse:
|
|
152
153
|
"""GetRun."""
|
|
153
154
|
# Get ffs from app
|
|
154
|
-
ffs: Ffs = app.state.FFS_FACTORY.
|
|
155
|
+
ffs: Ffs = cast(FfsFactory, app.state.FFS_FACTORY).ffs()
|
|
155
156
|
|
|
156
157
|
# Handle message
|
|
157
158
|
return message_handler.get_fab(request=request, ffs=ffs)
|