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/proto/run_pb2.pyi
CHANGED
|
@@ -5,6 +5,7 @@ isort:skip_file
|
|
|
5
5
|
import builtins
|
|
6
6
|
import flwr.proto.fab_pb2
|
|
7
7
|
import flwr.proto.node_pb2
|
|
8
|
+
import flwr.proto.recordset_pb2
|
|
8
9
|
import flwr.proto.transport_pb2
|
|
9
10
|
import google.protobuf.descriptor
|
|
10
11
|
import google.protobuf.internal.containers
|
|
@@ -36,12 +37,23 @@ class Run(google.protobuf.message.Message):
|
|
|
36
37
|
FAB_VERSION_FIELD_NUMBER: builtins.int
|
|
37
38
|
OVERRIDE_CONFIG_FIELD_NUMBER: builtins.int
|
|
38
39
|
FAB_HASH_FIELD_NUMBER: builtins.int
|
|
40
|
+
PENDING_AT_FIELD_NUMBER: builtins.int
|
|
41
|
+
STARTING_AT_FIELD_NUMBER: builtins.int
|
|
42
|
+
RUNNING_AT_FIELD_NUMBER: builtins.int
|
|
43
|
+
FINISHED_AT_FIELD_NUMBER: builtins.int
|
|
44
|
+
STATUS_FIELD_NUMBER: builtins.int
|
|
39
45
|
run_id: builtins.int
|
|
40
46
|
fab_id: typing.Text
|
|
41
47
|
fab_version: typing.Text
|
|
42
48
|
@property
|
|
43
49
|
def override_config(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.transport_pb2.Scalar]: ...
|
|
44
50
|
fab_hash: typing.Text
|
|
51
|
+
pending_at: typing.Text
|
|
52
|
+
starting_at: typing.Text
|
|
53
|
+
running_at: typing.Text
|
|
54
|
+
finished_at: typing.Text
|
|
55
|
+
@property
|
|
56
|
+
def status(self) -> global___RunStatus: ...
|
|
45
57
|
def __init__(self,
|
|
46
58
|
*,
|
|
47
59
|
run_id: builtins.int = ...,
|
|
@@ -49,8 +61,14 @@ class Run(google.protobuf.message.Message):
|
|
|
49
61
|
fab_version: typing.Text = ...,
|
|
50
62
|
override_config: typing.Optional[typing.Mapping[typing.Text, flwr.proto.transport_pb2.Scalar]] = ...,
|
|
51
63
|
fab_hash: typing.Text = ...,
|
|
64
|
+
pending_at: typing.Text = ...,
|
|
65
|
+
starting_at: typing.Text = ...,
|
|
66
|
+
running_at: typing.Text = ...,
|
|
67
|
+
finished_at: typing.Text = ...,
|
|
68
|
+
status: typing.Optional[global___RunStatus] = ...,
|
|
52
69
|
) -> None: ...
|
|
53
|
-
def
|
|
70
|
+
def HasField(self, field_name: typing_extensions.Literal["status",b"status"]) -> builtins.bool: ...
|
|
71
|
+
def ClearField(self, field_name: typing_extensions.Literal["fab_hash",b"fab_hash","fab_id",b"fab_id","fab_version",b"fab_version","finished_at",b"finished_at","override_config",b"override_config","pending_at",b"pending_at","run_id",b"run_id","running_at",b"running_at","starting_at",b"starting_at","status",b"status"]) -> None: ...
|
|
54
72
|
global___Run = Run
|
|
55
73
|
|
|
56
74
|
class RunStatus(google.protobuf.message.Message):
|
|
@@ -223,3 +241,28 @@ class GetRunStatusResponse(google.protobuf.message.Message):
|
|
|
223
241
|
) -> None: ...
|
|
224
242
|
def ClearField(self, field_name: typing_extensions.Literal["run_status_dict",b"run_status_dict"]) -> None: ...
|
|
225
243
|
global___GetRunStatusResponse = GetRunStatusResponse
|
|
244
|
+
|
|
245
|
+
class GetFederationOptionsRequest(google.protobuf.message.Message):
|
|
246
|
+
"""Get Federation Options associated with run"""
|
|
247
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
248
|
+
RUN_ID_FIELD_NUMBER: builtins.int
|
|
249
|
+
run_id: builtins.int
|
|
250
|
+
def __init__(self,
|
|
251
|
+
*,
|
|
252
|
+
run_id: builtins.int = ...,
|
|
253
|
+
) -> None: ...
|
|
254
|
+
def ClearField(self, field_name: typing_extensions.Literal["run_id",b"run_id"]) -> None: ...
|
|
255
|
+
global___GetFederationOptionsRequest = GetFederationOptionsRequest
|
|
256
|
+
|
|
257
|
+
class GetFederationOptionsResponse(google.protobuf.message.Message):
|
|
258
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
259
|
+
FEDERATION_OPTIONS_FIELD_NUMBER: builtins.int
|
|
260
|
+
@property
|
|
261
|
+
def federation_options(self) -> flwr.proto.recordset_pb2.ConfigsRecord: ...
|
|
262
|
+
def __init__(self,
|
|
263
|
+
*,
|
|
264
|
+
federation_options: typing.Optional[flwr.proto.recordset_pb2.ConfigsRecord] = ...,
|
|
265
|
+
) -> None: ...
|
|
266
|
+
def HasField(self, field_name: typing_extensions.Literal["federation_options",b"federation_options"]) -> builtins.bool: ...
|
|
267
|
+
def ClearField(self, field_name: typing_extensions.Literal["federation_options",b"federation_options"]) -> None: ...
|
|
268
|
+
global___GetFederationOptionsResponse = GetFederationOptionsResponse
|
flwr/proto/simulationio_pb2.py
CHANGED
|
@@ -18,7 +18,7 @@ from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
|
|
|
18
18
|
from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x66lwr/proto/simulationio.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/log.proto\x1a\x18\x66lwr/proto/message.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\"\x1d\n\x1bPullSimulationInputsRequest\"\x80\x01\n\x1cPullSimulationInputsResponse\x12$\n\x07\x63ontext\x18\x01 \x01(\x0b\x32\x13.flwr.proto.Context\x12\x1c\n\x03run\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run\x12\x1c\n\x03\x66\x61\x62\x18\x03 \x01(\x0b\x32\x0f.flwr.proto.Fab\"T\n\x1cPushSimulationOutputsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12$\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Context\"\x1f\n\x1dPushSimulationOutputsResponse2\
|
|
21
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x66lwr/proto/simulationio.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/log.proto\x1a\x18\x66lwr/proto/message.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\"\x1d\n\x1bPullSimulationInputsRequest\"\x80\x01\n\x1cPullSimulationInputsResponse\x12$\n\x07\x63ontext\x18\x01 \x01(\x0b\x32\x13.flwr.proto.Context\x12\x1c\n\x03run\x18\x02 \x01(\x0b\x32\x0f.flwr.proto.Run\x12\x1c\n\x03\x66\x61\x62\x18\x03 \x01(\x0b\x32\x0f.flwr.proto.Fab\"T\n\x1cPushSimulationOutputsRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12$\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Context\"\x1f\n\x1dPushSimulationOutputsResponse2\xff\x03\n\x0cSimulationIo\x12k\n\x14PullSimulationInputs\x12\'.flwr.proto.PullSimulationInputsRequest\x1a(.flwr.proto.PullSimulationInputsResponse\"\x00\x12n\n\x15PushSimulationOutputs\x12(.flwr.proto.PushSimulationOutputsRequest\x1a).flwr.proto.PushSimulationOutputsResponse\"\x00\x12\\\n\x0fUpdateRunStatus\x12\".flwr.proto.UpdateRunStatusRequest\x1a#.flwr.proto.UpdateRunStatusResponse\"\x00\x12G\n\x08PushLogs\x12\x1b.flwr.proto.PushLogsRequest\x1a\x1c.flwr.proto.PushLogsResponse\"\x00\x12k\n\x14GetFederationOptions\x12\'.flwr.proto.GetFederationOptionsRequest\x1a(.flwr.proto.GetFederationOptionsResponse\"\x00\x62\x06proto3')
|
|
22
22
|
|
|
23
23
|
_globals = globals()
|
|
24
24
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -34,5 +34,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
34
34
|
_globals['_PUSHSIMULATIONOUTPUTSRESPONSE']._serialized_start=385
|
|
35
35
|
_globals['_PUSHSIMULATIONOUTPUTSRESPONSE']._serialized_end=416
|
|
36
36
|
_globals['_SIMULATIONIO']._serialized_start=419
|
|
37
|
-
_globals['_SIMULATIONIO']._serialized_end=
|
|
37
|
+
_globals['_SIMULATIONIO']._serialized_end=930
|
|
38
38
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -36,6 +36,11 @@ class SimulationIoStub(object):
|
|
|
36
36
|
request_serializer=flwr_dot_proto_dot_log__pb2.PushLogsRequest.SerializeToString,
|
|
37
37
|
response_deserializer=flwr_dot_proto_dot_log__pb2.PushLogsResponse.FromString,
|
|
38
38
|
)
|
|
39
|
+
self.GetFederationOptions = channel.unary_unary(
|
|
40
|
+
'/flwr.proto.SimulationIo/GetFederationOptions',
|
|
41
|
+
request_serializer=flwr_dot_proto_dot_run__pb2.GetFederationOptionsRequest.SerializeToString,
|
|
42
|
+
response_deserializer=flwr_dot_proto_dot_run__pb2.GetFederationOptionsResponse.FromString,
|
|
43
|
+
)
|
|
39
44
|
|
|
40
45
|
|
|
41
46
|
class SimulationIoServicer(object):
|
|
@@ -69,6 +74,13 @@ class SimulationIoServicer(object):
|
|
|
69
74
|
context.set_details('Method not implemented!')
|
|
70
75
|
raise NotImplementedError('Method not implemented!')
|
|
71
76
|
|
|
77
|
+
def GetFederationOptions(self, request, context):
|
|
78
|
+
"""Get Federation Options
|
|
79
|
+
"""
|
|
80
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
81
|
+
context.set_details('Method not implemented!')
|
|
82
|
+
raise NotImplementedError('Method not implemented!')
|
|
83
|
+
|
|
72
84
|
|
|
73
85
|
def add_SimulationIoServicer_to_server(servicer, server):
|
|
74
86
|
rpc_method_handlers = {
|
|
@@ -92,6 +104,11 @@ def add_SimulationIoServicer_to_server(servicer, server):
|
|
|
92
104
|
request_deserializer=flwr_dot_proto_dot_log__pb2.PushLogsRequest.FromString,
|
|
93
105
|
response_serializer=flwr_dot_proto_dot_log__pb2.PushLogsResponse.SerializeToString,
|
|
94
106
|
),
|
|
107
|
+
'GetFederationOptions': grpc.unary_unary_rpc_method_handler(
|
|
108
|
+
servicer.GetFederationOptions,
|
|
109
|
+
request_deserializer=flwr_dot_proto_dot_run__pb2.GetFederationOptionsRequest.FromString,
|
|
110
|
+
response_serializer=flwr_dot_proto_dot_run__pb2.GetFederationOptionsResponse.SerializeToString,
|
|
111
|
+
),
|
|
95
112
|
}
|
|
96
113
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
97
114
|
'flwr.proto.SimulationIo', rpc_method_handlers)
|
|
@@ -169,3 +186,20 @@ class SimulationIo(object):
|
|
|
169
186
|
flwr_dot_proto_dot_log__pb2.PushLogsResponse.FromString,
|
|
170
187
|
options, channel_credentials,
|
|
171
188
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
189
|
+
|
|
190
|
+
@staticmethod
|
|
191
|
+
def GetFederationOptions(request,
|
|
192
|
+
target,
|
|
193
|
+
options=(),
|
|
194
|
+
channel_credentials=None,
|
|
195
|
+
call_credentials=None,
|
|
196
|
+
insecure=False,
|
|
197
|
+
compression=None,
|
|
198
|
+
wait_for_ready=None,
|
|
199
|
+
timeout=None,
|
|
200
|
+
metadata=None):
|
|
201
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.SimulationIo/GetFederationOptions',
|
|
202
|
+
flwr_dot_proto_dot_run__pb2.GetFederationOptionsRequest.SerializeToString,
|
|
203
|
+
flwr_dot_proto_dot_run__pb2.GetFederationOptionsResponse.FromString,
|
|
204
|
+
options, channel_credentials,
|
|
205
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
@@ -30,6 +30,11 @@ class SimulationIoStub:
|
|
|
30
30
|
flwr.proto.log_pb2.PushLogsResponse]
|
|
31
31
|
"""Push ServerApp logs"""
|
|
32
32
|
|
|
33
|
+
GetFederationOptions: grpc.UnaryUnaryMultiCallable[
|
|
34
|
+
flwr.proto.run_pb2.GetFederationOptionsRequest,
|
|
35
|
+
flwr.proto.run_pb2.GetFederationOptionsResponse]
|
|
36
|
+
"""Get Federation Options"""
|
|
37
|
+
|
|
33
38
|
|
|
34
39
|
class SimulationIoServicer(metaclass=abc.ABCMeta):
|
|
35
40
|
@abc.abstractmethod
|
|
@@ -64,5 +69,13 @@ class SimulationIoServicer(metaclass=abc.ABCMeta):
|
|
|
64
69
|
"""Push ServerApp logs"""
|
|
65
70
|
pass
|
|
66
71
|
|
|
72
|
+
@abc.abstractmethod
|
|
73
|
+
def GetFederationOptions(self,
|
|
74
|
+
request: flwr.proto.run_pb2.GetFederationOptionsRequest,
|
|
75
|
+
context: grpc.ServicerContext,
|
|
76
|
+
) -> flwr.proto.run_pb2.GetFederationOptionsResponse:
|
|
77
|
+
"""Get Federation Options"""
|
|
78
|
+
pass
|
|
79
|
+
|
|
67
80
|
|
|
68
81
|
def add_SimulationIoServicer_to_server(servicer: SimulationIoServicer, server: grpc.Server) -> None: ...
|
flwr/server/app.py
CHANGED
|
@@ -22,7 +22,6 @@ import sys
|
|
|
22
22
|
import threading
|
|
23
23
|
from collections.abc import Sequence
|
|
24
24
|
from logging import DEBUG, INFO, WARN
|
|
25
|
-
from os.path import isfile
|
|
26
25
|
from pathlib import Path
|
|
27
26
|
from time import sleep
|
|
28
27
|
from typing import Optional
|
|
@@ -37,23 +36,26 @@ from cryptography.hazmat.primitives.serialization import (
|
|
|
37
36
|
|
|
38
37
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
|
|
39
38
|
from flwr.common.address import parse_address
|
|
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
|
|
@@ -215,13 +233,19 @@ def run_superlink() -> None:
|
|
|
215
233
|
|
|
216
234
|
event(EventType.RUN_SUPERLINK_ENTER)
|
|
217
235
|
|
|
236
|
+
# Warn unused options
|
|
237
|
+
if args.flwr_dir is not None:
|
|
238
|
+
log(
|
|
239
|
+
WARN, "The `--flwr-dir` option is currently not in use and will be ignored."
|
|
240
|
+
)
|
|
241
|
+
|
|
218
242
|
# Parse IP addresses
|
|
219
243
|
serverappio_address, _, _ = _format_address(args.serverappio_api_address)
|
|
220
244
|
exec_address, _, _ = _format_address(args.exec_api_address)
|
|
221
245
|
simulationio_address, _, _ = _format_address(args.simulationio_api_address)
|
|
222
246
|
|
|
223
247
|
# Obtain certificates
|
|
224
|
-
certificates =
|
|
248
|
+
certificates = try_obtain_server_certificates(args, args.fleet_api_type)
|
|
225
249
|
|
|
226
250
|
# Initialize StateFactory
|
|
227
251
|
state_factory = LinkStateFactory(args.database)
|
|
@@ -359,18 +383,27 @@ def run_superlink() -> None:
|
|
|
359
383
|
else:
|
|
360
384
|
raise ValueError(f"Unknown fleet_api_type: {args.fleet_api_type}")
|
|
361
385
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
386
|
+
if args.isolation == ISOLATION_MODE_SUBPROCESS:
|
|
387
|
+
|
|
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
|
|
393
|
+
cmd = "flwr-simulation" if sim_exec else "flwr-serverapp"
|
|
394
|
+
|
|
395
|
+
# Scheduler thread
|
|
396
|
+
scheduler_th = threading.Thread(
|
|
397
|
+
target=_flwr_scheduler,
|
|
398
|
+
args=(
|
|
399
|
+
state_factory,
|
|
400
|
+
address,
|
|
401
|
+
args.ssl_ca_certfile,
|
|
402
|
+
cmd,
|
|
403
|
+
),
|
|
404
|
+
)
|
|
405
|
+
scheduler_th.start()
|
|
406
|
+
bckg_threads.append(scheduler_th)
|
|
374
407
|
|
|
375
408
|
# Graceful shutdown
|
|
376
409
|
register_exit_handlers(
|
|
@@ -388,12 +421,13 @@ def run_superlink() -> None:
|
|
|
388
421
|
exec_server.wait_for_termination(timeout=1)
|
|
389
422
|
|
|
390
423
|
|
|
391
|
-
def
|
|
424
|
+
def _flwr_scheduler(
|
|
392
425
|
state_factory: LinkStateFactory,
|
|
393
|
-
|
|
426
|
+
io_api_address: str,
|
|
394
427
|
ssl_ca_certfile: Optional[str],
|
|
428
|
+
cmd: str,
|
|
395
429
|
) -> None:
|
|
396
|
-
log(DEBUG, "Started
|
|
430
|
+
log(DEBUG, "Started %s scheduler thread.", cmd)
|
|
397
431
|
|
|
398
432
|
state = state_factory.state()
|
|
399
433
|
|
|
@@ -406,14 +440,16 @@ def _flwr_serverapp_scheduler(
|
|
|
406
440
|
|
|
407
441
|
log(
|
|
408
442
|
INFO,
|
|
409
|
-
"Launching
|
|
410
|
-
|
|
443
|
+
"Launching %s subprocess. Connects to SuperLink on %s",
|
|
444
|
+
cmd,
|
|
445
|
+
io_api_address,
|
|
411
446
|
)
|
|
412
|
-
# Start
|
|
447
|
+
# Start subprocess
|
|
413
448
|
command = [
|
|
414
|
-
|
|
415
|
-
"--
|
|
416
|
-
|
|
449
|
+
cmd,
|
|
450
|
+
"--run-once",
|
|
451
|
+
"--serverappio-api-address",
|
|
452
|
+
io_api_address,
|
|
417
453
|
]
|
|
418
454
|
if ssl_ca_certfile:
|
|
419
455
|
command.append("--root-certificates")
|
|
@@ -526,60 +562,6 @@ def _try_setup_node_authentication(
|
|
|
526
562
|
)
|
|
527
563
|
|
|
528
564
|
|
|
529
|
-
def _try_obtain_certificates(
|
|
530
|
-
args: argparse.Namespace,
|
|
531
|
-
) -> Optional[tuple[bytes, bytes, bytes]]:
|
|
532
|
-
# Obtain certificates
|
|
533
|
-
if args.insecure:
|
|
534
|
-
log(WARN, "Option `--insecure` was set. Starting insecure HTTP server.")
|
|
535
|
-
return None
|
|
536
|
-
# Check if certificates are provided
|
|
537
|
-
if args.fleet_api_type in [TRANSPORT_TYPE_GRPC_RERE, TRANSPORT_TYPE_GRPC_ADAPTER]:
|
|
538
|
-
if args.ssl_certfile and args.ssl_keyfile and args.ssl_ca_certfile:
|
|
539
|
-
if not isfile(args.ssl_ca_certfile):
|
|
540
|
-
sys.exit("Path argument `--ssl-ca-certfile` does not point to a file.")
|
|
541
|
-
if not isfile(args.ssl_certfile):
|
|
542
|
-
sys.exit("Path argument `--ssl-certfile` does not point to a file.")
|
|
543
|
-
if not isfile(args.ssl_keyfile):
|
|
544
|
-
sys.exit("Path argument `--ssl-keyfile` does not point to a file.")
|
|
545
|
-
certificates = (
|
|
546
|
-
Path(args.ssl_ca_certfile).read_bytes(), # CA certificate
|
|
547
|
-
Path(args.ssl_certfile).read_bytes(), # server certificate
|
|
548
|
-
Path(args.ssl_keyfile).read_bytes(), # server private key
|
|
549
|
-
)
|
|
550
|
-
return certificates
|
|
551
|
-
if args.ssl_certfile or args.ssl_keyfile or args.ssl_ca_certfile:
|
|
552
|
-
sys.exit(
|
|
553
|
-
"You need to provide valid file paths to `--ssl-certfile`, "
|
|
554
|
-
"`--ssl-keyfile`, and `—-ssl-ca-certfile` to create a secure "
|
|
555
|
-
"connection in Fleet API server (gRPC-rere)."
|
|
556
|
-
)
|
|
557
|
-
if args.fleet_api_type == TRANSPORT_TYPE_REST:
|
|
558
|
-
if args.ssl_certfile and args.ssl_keyfile:
|
|
559
|
-
if not isfile(args.ssl_certfile):
|
|
560
|
-
sys.exit("Path argument `--ssl-certfile` does not point to a file.")
|
|
561
|
-
if not isfile(args.ssl_keyfile):
|
|
562
|
-
sys.exit("Path argument `--ssl-keyfile` does not point to a file.")
|
|
563
|
-
certificates = (
|
|
564
|
-
b"",
|
|
565
|
-
Path(args.ssl_certfile).read_bytes(), # server certificate
|
|
566
|
-
Path(args.ssl_keyfile).read_bytes(), # server private key
|
|
567
|
-
)
|
|
568
|
-
return certificates
|
|
569
|
-
if args.ssl_certfile or args.ssl_keyfile:
|
|
570
|
-
sys.exit(
|
|
571
|
-
"You need to provide valid file paths to `--ssl-certfile` "
|
|
572
|
-
"and `--ssl-keyfile` to create a secure connection "
|
|
573
|
-
"in Fleet API server (REST, experimental)."
|
|
574
|
-
)
|
|
575
|
-
sys.exit(
|
|
576
|
-
"Certificates are required unless running in insecure mode. "
|
|
577
|
-
"Please provide certificate paths to `--ssl-certfile`, "
|
|
578
|
-
"`--ssl-keyfile`, and `—-ssl-ca-certfile` or run the server "
|
|
579
|
-
"in insecure mode using '--insecure' if you understand the risks."
|
|
580
|
-
)
|
|
581
|
-
|
|
582
|
-
|
|
583
565
|
def _run_fleet_api_grpc_rere(
|
|
584
566
|
address: str,
|
|
585
567
|
state_factory: LinkStateFactory,
|
|
@@ -694,6 +676,17 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
694
676
|
"paths are provided. By default, the server runs with HTTPS enabled. "
|
|
695
677
|
"Use this flag only if you understand the risks.",
|
|
696
678
|
)
|
|
679
|
+
parser.add_argument(
|
|
680
|
+
"--flwr-dir",
|
|
681
|
+
default=None,
|
|
682
|
+
help="""The path containing installed Flower Apps.
|
|
683
|
+
The default directory is:
|
|
684
|
+
|
|
685
|
+
- `$FLWR_HOME/` if `$FLWR_HOME` is defined
|
|
686
|
+
- `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
|
|
687
|
+
- `$HOME/.flwr/` in all other cases
|
|
688
|
+
""",
|
|
689
|
+
)
|
|
697
690
|
parser.add_argument(
|
|
698
691
|
"--ssl-certfile",
|
|
699
692
|
help="Fleet API server SSL certificate file (as a path str) "
|
|
@@ -761,8 +754,9 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
761
754
|
def _add_args_serverappio_api(parser: argparse.ArgumentParser) -> None:
|
|
762
755
|
parser.add_argument(
|
|
763
756
|
"--serverappio-api-address",
|
|
764
|
-
|
|
765
|
-
|
|
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}.",
|
|
766
760
|
)
|
|
767
761
|
|
|
768
762
|
|
|
@@ -795,8 +789,9 @@ def _add_args_exec_api(parser: argparse.ArgumentParser) -> None:
|
|
|
795
789
|
"""Add command line arguments for Exec API."""
|
|
796
790
|
parser.add_argument(
|
|
797
791
|
"--exec-api-address",
|
|
798
|
-
help="Exec API server address (IPv4, IPv6, or a domain name)"
|
|
799
|
-
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,
|
|
800
795
|
)
|
|
801
796
|
parser.add_argument(
|
|
802
797
|
"--executor",
|
|
@@ -820,6 +815,7 @@ def _add_args_exec_api(parser: argparse.ArgumentParser) -> None:
|
|
|
820
815
|
def _add_args_simulationio_api(parser: argparse.ArgumentParser) -> None:
|
|
821
816
|
parser.add_argument(
|
|
822
817
|
"--simulationio-api-address",
|
|
823
|
-
|
|
824
|
-
|
|
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}.",
|
|
825
821
|
)
|
flwr/server/driver/driver.py
CHANGED
|
@@ -27,7 +27,7 @@ class Driver(ABC):
|
|
|
27
27
|
"""Abstract base Driver class for the ServerAppIo API."""
|
|
28
28
|
|
|
29
29
|
@abstractmethod
|
|
30
|
-
def
|
|
30
|
+
def set_run(self, run_id: int) -> None:
|
|
31
31
|
"""Request a run to the SuperLink with a given `run_id`.
|
|
32
32
|
|
|
33
33
|
If a Run with the specified `run_id` exists, a local Run
|
|
@@ -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
|
|
@@ -112,24 +108,14 @@ class GrpcDriver(Driver):
|
|
|
112
108
|
channel.close()
|
|
113
109
|
log(DEBUG, "[Driver] Disconnected")
|
|
114
110
|
|
|
115
|
-
def
|
|
116
|
-
"""
|
|
117
|
-
# Check if is initialized
|
|
118
|
-
if self._run is not None:
|
|
119
|
-
return
|
|
120
|
-
|
|
111
|
+
def set_run(self, run_id: int) -> None:
|
|
112
|
+
"""Set the run."""
|
|
121
113
|
# Get the run info
|
|
122
114
|
req = GetRunRequest(run_id=run_id)
|
|
123
115
|
res: GetRunResponse = self._stub.GetRun(req)
|
|
124
116
|
if not res.HasField("run"):
|
|
125
117
|
raise RuntimeError(f"Cannot find the run with ID: {run_id}")
|
|
126
|
-
self._run =
|
|
127
|
-
run_id=res.run.run_id,
|
|
128
|
-
fab_id=res.run.fab_id,
|
|
129
|
-
fab_version=res.run.fab_version,
|
|
130
|
-
fab_hash=res.run.fab_hash,
|
|
131
|
-
override_config=user_config_from_proto(res.run.override_config),
|
|
132
|
-
)
|
|
118
|
+
self._run = run_from_proto(res.run)
|
|
133
119
|
|
|
134
120
|
@property
|
|
135
121
|
def run(self) -> Run:
|
|
@@ -62,10 +62,8 @@ class InMemoryDriver(Driver):
|
|
|
62
62
|
):
|
|
63
63
|
raise ValueError(f"Invalid message: {message}")
|
|
64
64
|
|
|
65
|
-
def
|
|
65
|
+
def set_run(self, run_id: int) -> None:
|
|
66
66
|
"""Initialize the run."""
|
|
67
|
-
if self._run is not None:
|
|
68
|
-
return
|
|
69
67
|
run = self.state.get_run(run_id)
|
|
70
68
|
if run is None:
|
|
71
69
|
raise RuntimeError(f"Cannot find the run with ID: {run_id}")
|