flwr-nightly 1.13.0.dev20241113__py3-none-any.whl → 1.13.0.dev20241115__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/ls.py +228 -0
- flwr/client/app.py +58 -13
- flwr/client/clientapp/app.py +34 -23
- flwr/client/grpc_rere_client/connection.py +2 -12
- flwr/client/rest_client/connection.py +4 -14
- flwr/client/supernode/app.py +56 -18
- flwr/common/constant.py +21 -6
- flwr/common/serde.py +10 -0
- flwr/common/typing.py +31 -10
- flwr/proto/exec_pb2.py +22 -13
- flwr/proto/exec_pb2.pyi +44 -0
- flwr/proto/exec_pb2_grpc.py +34 -0
- flwr/proto/exec_pb2_grpc.pyi +13 -0
- flwr/proto/run_pb2.py +30 -30
- flwr/proto/run_pb2.pyi +18 -1
- flwr/server/app.py +37 -12
- flwr/server/driver/grpc_driver.py +4 -14
- flwr/server/run_serverapp.py +8 -238
- flwr/server/serverapp/app.py +33 -22
- flwr/server/superlink/fleet/rest_rere/rest_api.py +10 -9
- flwr/server/superlink/linkstate/in_memory_linkstate.py +71 -46
- flwr/server/superlink/linkstate/linkstate.py +19 -5
- flwr/server/superlink/linkstate/sqlite_linkstate.py +79 -111
- flwr/server/superlink/linkstate/utils.py +182 -3
- flwr/simulation/app.py +3 -3
- flwr/simulation/legacy_app.py +21 -1
- flwr/simulation/run_simulation.py +7 -18
- flwr/simulation/simulationio_connection.py +2 -2
- flwr/superexec/deployment.py +9 -5
- flwr/superexec/exec_servicer.py +31 -2
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241115.dist-info}/METADATA +2 -1
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241115.dist-info}/RECORD +36 -35
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241115.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241115.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.13.0.dev20241113.dist-info → flwr_nightly-1.13.0.dev20241115.dist-info}/entry_points.txt +0 -0
flwr/server/app.py
CHANGED
|
@@ -39,21 +39,23 @@ from flwr.common.address import parse_address
|
|
|
39
39
|
from flwr.common.args import try_obtain_server_certificates
|
|
40
40
|
from flwr.common.config import get_flwr_dir, parse_config_args
|
|
41
41
|
from flwr.common.constant import (
|
|
42
|
-
|
|
42
|
+
CLIENT_OCTET,
|
|
43
|
+
EXEC_API_DEFAULT_SERVER_ADDRESS,
|
|
43
44
|
FLEET_API_GRPC_BIDI_DEFAULT_ADDRESS,
|
|
44
45
|
FLEET_API_GRPC_RERE_DEFAULT_ADDRESS,
|
|
45
46
|
FLEET_API_REST_DEFAULT_ADDRESS,
|
|
46
47
|
ISOLATION_MODE_PROCESS,
|
|
47
48
|
ISOLATION_MODE_SUBPROCESS,
|
|
48
49
|
MISSING_EXTRA_REST,
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
SERVER_OCTET,
|
|
51
|
+
SERVERAPPIO_API_DEFAULT_SERVER_ADDRESS,
|
|
52
|
+
SIMULATIONIO_API_DEFAULT_SERVER_ADDRESS,
|
|
51
53
|
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
52
54
|
TRANSPORT_TYPE_GRPC_RERE,
|
|
53
55
|
TRANSPORT_TYPE_REST,
|
|
54
56
|
)
|
|
55
57
|
from flwr.common.exit_handlers import register_exit_handlers
|
|
56
|
-
from flwr.common.logger import log
|
|
58
|
+
from flwr.common.logger import log, warn_deprecated_feature
|
|
57
59
|
from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
|
|
58
60
|
private_key_to_bytes,
|
|
59
61
|
public_key_to_bytes,
|
|
@@ -99,6 +101,11 @@ def start_server( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
99
101
|
) -> History:
|
|
100
102
|
"""Start a Flower server using the gRPC transport layer.
|
|
101
103
|
|
|
104
|
+
Warning
|
|
105
|
+
-------
|
|
106
|
+
This function is deprecated since 1.13.0. Use the :code:`flower-superlink` command
|
|
107
|
+
instead to start a SuperLink.
|
|
108
|
+
|
|
102
109
|
Parameters
|
|
103
110
|
----------
|
|
104
111
|
server_address : Optional[str]
|
|
@@ -156,6 +163,17 @@ def start_server( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
156
163
|
>>> )
|
|
157
164
|
>>> )
|
|
158
165
|
"""
|
|
166
|
+
msg = (
|
|
167
|
+
"flwr.server.start_server() is deprecated."
|
|
168
|
+
"\n\tInstead, use the `flower-superlink` CLI command to start a SuperLink "
|
|
169
|
+
"as shown below:"
|
|
170
|
+
"\n\n\t\t$ flower-superlink --insecure"
|
|
171
|
+
"\n\n\tTo view usage and all available options, run:"
|
|
172
|
+
"\n\n\t\t$ flower-superlink --help"
|
|
173
|
+
"\n\n\tUsing `start_server()` is deprecated."
|
|
174
|
+
)
|
|
175
|
+
warn_deprecated_feature(name=msg)
|
|
176
|
+
|
|
159
177
|
event(EventType.START_SERVER_ENTER)
|
|
160
178
|
|
|
161
179
|
# Parse IP address
|
|
@@ -367,7 +385,11 @@ def run_superlink() -> None:
|
|
|
367
385
|
|
|
368
386
|
if args.isolation == ISOLATION_MODE_SUBPROCESS:
|
|
369
387
|
|
|
370
|
-
|
|
388
|
+
_octet, _colon, _port = serverappio_address.rpartition(":")
|
|
389
|
+
io_address = (
|
|
390
|
+
f"{CLIENT_OCTET}:{_port}" if _octet == SERVER_OCTET else serverappio_address
|
|
391
|
+
)
|
|
392
|
+
address = simulationio_address if sim_exec else io_address
|
|
371
393
|
cmd = "flwr-simulation" if sim_exec else "flwr-serverapp"
|
|
372
394
|
|
|
373
395
|
# Scheduler thread
|
|
@@ -426,7 +448,7 @@ def _flwr_scheduler(
|
|
|
426
448
|
command = [
|
|
427
449
|
cmd,
|
|
428
450
|
"--run-once",
|
|
429
|
-
"--
|
|
451
|
+
"--serverappio-api-address",
|
|
430
452
|
io_api_address,
|
|
431
453
|
]
|
|
432
454
|
if ssl_ca_certfile:
|
|
@@ -732,8 +754,9 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
732
754
|
def _add_args_serverappio_api(parser: argparse.ArgumentParser) -> None:
|
|
733
755
|
parser.add_argument(
|
|
734
756
|
"--serverappio-api-address",
|
|
735
|
-
|
|
736
|
-
|
|
757
|
+
default=SERVERAPPIO_API_DEFAULT_SERVER_ADDRESS,
|
|
758
|
+
help="ServerAppIo API (gRPC) server address (IPv4, IPv6, or a domain name). "
|
|
759
|
+
f"By default, it is set to {SERVERAPPIO_API_DEFAULT_SERVER_ADDRESS}.",
|
|
737
760
|
)
|
|
738
761
|
|
|
739
762
|
|
|
@@ -766,8 +789,9 @@ def _add_args_exec_api(parser: argparse.ArgumentParser) -> None:
|
|
|
766
789
|
"""Add command line arguments for Exec API."""
|
|
767
790
|
parser.add_argument(
|
|
768
791
|
"--exec-api-address",
|
|
769
|
-
help="Exec API server address (IPv4, IPv6, or a domain name)"
|
|
770
|
-
default
|
|
792
|
+
help="Exec API server address (IPv4, IPv6, or a domain name) "
|
|
793
|
+
f"By default, it is set to {EXEC_API_DEFAULT_SERVER_ADDRESS}.",
|
|
794
|
+
default=EXEC_API_DEFAULT_SERVER_ADDRESS,
|
|
771
795
|
)
|
|
772
796
|
parser.add_argument(
|
|
773
797
|
"--executor",
|
|
@@ -791,6 +815,7 @@ def _add_args_exec_api(parser: argparse.ArgumentParser) -> None:
|
|
|
791
815
|
def _add_args_simulationio_api(parser: argparse.ArgumentParser) -> None:
|
|
792
816
|
parser.add_argument(
|
|
793
817
|
"--simulationio-api-address",
|
|
794
|
-
|
|
795
|
-
|
|
818
|
+
default=SIMULATIONIO_API_DEFAULT_SERVER_ADDRESS,
|
|
819
|
+
help="SimulationIo API (gRPC) server address (IPv4, IPv6, or a domain name)."
|
|
820
|
+
f"By default, it is set to {SIMULATIONIO_API_DEFAULT_SERVER_ADDRESS}.",
|
|
796
821
|
)
|
|
@@ -23,14 +23,10 @@ from typing import Optional, cast
|
|
|
23
23
|
import grpc
|
|
24
24
|
|
|
25
25
|
from flwr.common import DEFAULT_TTL, Message, Metadata, RecordSet
|
|
26
|
-
from flwr.common.constant import
|
|
26
|
+
from flwr.common.constant import SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS
|
|
27
27
|
from flwr.common.grpc import create_channel
|
|
28
28
|
from flwr.common.logger import log
|
|
29
|
-
from flwr.common.serde import
|
|
30
|
-
message_from_taskres,
|
|
31
|
-
message_to_taskins,
|
|
32
|
-
user_config_from_proto,
|
|
33
|
-
)
|
|
29
|
+
from flwr.common.serde import message_from_taskres, message_to_taskins, run_from_proto
|
|
34
30
|
from flwr.common.typing import Run
|
|
35
31
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
36
32
|
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
@@ -70,7 +66,7 @@ class GrpcDriver(Driver):
|
|
|
70
66
|
|
|
71
67
|
def __init__( # pylint: disable=too-many-arguments
|
|
72
68
|
self,
|
|
73
|
-
serverappio_service_address: str =
|
|
69
|
+
serverappio_service_address: str = SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
|
|
74
70
|
root_certificates: Optional[bytes] = None,
|
|
75
71
|
) -> None:
|
|
76
72
|
self._addr = serverappio_service_address
|
|
@@ -119,13 +115,7 @@ class GrpcDriver(Driver):
|
|
|
119
115
|
res: GetRunResponse = self._stub.GetRun(req)
|
|
120
116
|
if not res.HasField("run"):
|
|
121
117
|
raise RuntimeError(f"Cannot find the run with ID: {run_id}")
|
|
122
|
-
self._run =
|
|
123
|
-
run_id=res.run.run_id,
|
|
124
|
-
fab_id=res.run.fab_id,
|
|
125
|
-
fab_version=res.run.fab_version,
|
|
126
|
-
fab_hash=res.run.fab_hash,
|
|
127
|
-
override_config=user_config_from_proto(res.run.override_config),
|
|
128
|
-
)
|
|
118
|
+
self._run = run_from_proto(res.run)
|
|
129
119
|
|
|
130
120
|
@property
|
|
131
121
|
def run(self) -> Run:
|
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.set_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.set_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
|
@@ -30,7 +30,11 @@ from flwr.common.config import (
|
|
|
30
30
|
get_project_config,
|
|
31
31
|
get_project_dir,
|
|
32
32
|
)
|
|
33
|
-
from flwr.common.constant import
|
|
33
|
+
from flwr.common.constant import (
|
|
34
|
+
SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
|
|
35
|
+
Status,
|
|
36
|
+
SubStatus,
|
|
37
|
+
)
|
|
34
38
|
from flwr.common.logger import (
|
|
35
39
|
log,
|
|
36
40
|
mirror_output_to_queue,
|
|
@@ -62,33 +66,18 @@ def flwr_serverapp() -> None:
|
|
|
62
66
|
log_queue: Queue[Optional[str]] = Queue()
|
|
63
67
|
mirror_output_to_queue(log_queue)
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
description="Run a Flower ServerApp",
|
|
67
|
-
)
|
|
68
|
-
parser.add_argument(
|
|
69
|
-
"--superlink",
|
|
70
|
-
type=str,
|
|
71
|
-
help="Address of SuperLink's ServerAppIo API",
|
|
72
|
-
)
|
|
73
|
-
parser.add_argument(
|
|
74
|
-
"--run-once",
|
|
75
|
-
action="store_true",
|
|
76
|
-
help="When set, this process will start a single ServerApp for a pending Run. "
|
|
77
|
-
"If there is no pending Run, the process will exit.",
|
|
78
|
-
)
|
|
79
|
-
add_args_flwr_app_common(parser=parser)
|
|
80
|
-
args = parser.parse_args()
|
|
69
|
+
args = _parse_args_run_flwr_serverapp().parse_args()
|
|
81
70
|
|
|
82
71
|
log(INFO, "Starting Flower ServerApp")
|
|
83
|
-
certificates = try_obtain_root_certificates(args, args.
|
|
72
|
+
certificates = try_obtain_root_certificates(args, args.serverappio_api_address)
|
|
84
73
|
|
|
85
74
|
log(
|
|
86
75
|
DEBUG,
|
|
87
76
|
"Starting isolated `ServerApp` connected to SuperLink's ServerAppIo API at %s",
|
|
88
|
-
args.
|
|
77
|
+
args.serverappio_api_address,
|
|
89
78
|
)
|
|
90
79
|
run_serverapp(
|
|
91
|
-
|
|
80
|
+
serverappio_api_address=args.serverappio_api_address,
|
|
92
81
|
log_queue=log_queue,
|
|
93
82
|
run_once=args.run_once,
|
|
94
83
|
flwr_dir=args.flwr_dir,
|
|
@@ -100,7 +89,7 @@ def flwr_serverapp() -> None:
|
|
|
100
89
|
|
|
101
90
|
|
|
102
91
|
def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
103
|
-
|
|
92
|
+
serverappio_api_address: str,
|
|
104
93
|
log_queue: Queue[Optional[str]],
|
|
105
94
|
run_once: bool,
|
|
106
95
|
flwr_dir: Optional[str] = None,
|
|
@@ -108,7 +97,7 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
|
108
97
|
) -> None:
|
|
109
98
|
"""Run Flower ServerApp process."""
|
|
110
99
|
driver = GrpcDriver(
|
|
111
|
-
serverappio_service_address=
|
|
100
|
+
serverappio_service_address=serverappio_api_address,
|
|
112
101
|
root_certificates=certificates,
|
|
113
102
|
)
|
|
114
103
|
|
|
@@ -212,3 +201,25 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
|
212
201
|
# Stop the loop if `flwr-serverapp` is expected to process a single run
|
|
213
202
|
if run_once:
|
|
214
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
|
|
@@ -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)
|