flwr-nightly 1.23.0.dev20251030__py3-none-any.whl → 1.23.0.dev20251031__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/new/new.py +187 -35
- flwr/client/grpc_adapter_client/connection.py +4 -6
- flwr/client/grpc_rere_client/connection.py +47 -24
- flwr/client/grpc_rere_client/grpc_adapter.py +0 -16
- flwr/client/rest_client/connection.py +70 -33
- flwr/proto/fleet_pb2.py +31 -39
- flwr/proto/fleet_pb2.pyi +0 -48
- flwr/proto/fleet_pb2_grpc.py +0 -66
- flwr/proto/fleet_pb2_grpc.pyi +0 -20
- flwr/server/app.py +30 -16
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +0 -6
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +1 -98
- flwr/server/superlink/fleet/grpc_rere/node_auth_server_interceptor.py +14 -5
- flwr/server/superlink/fleet/message_handler/message_handler.py +0 -28
- flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -24
- flwr/server/superlink/linkstate/in_memory_linkstate.py +2 -1
- flwr/server/superlink/linkstate/sqlite_linkstate.py +2 -2
- flwr/supercore/constant.py +4 -0
- flwr/supernode/cli/flower_supernode.py +7 -0
- flwr/supernode/start_client_internal.py +3 -9
- {flwr_nightly-1.23.0.dev20251030.dist-info → flwr_nightly-1.23.0.dev20251031.dist-info}/METADATA +1 -1
- {flwr_nightly-1.23.0.dev20251030.dist-info → flwr_nightly-1.23.0.dev20251031.dist-info}/RECORD +24 -24
- {flwr_nightly-1.23.0.dev20251030.dist-info → flwr_nightly-1.23.0.dev20251031.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.23.0.dev20251030.dist-info → flwr_nightly-1.23.0.dev20251031.dist-info}/entry_points.txt +0 -0
flwr/proto/fleet_pb2.py
CHANGED
|
@@ -19,7 +19,7 @@ from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
|
|
|
19
19
|
from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"
|
|
22
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\".\n\x18RegisterNodeFleetRequest\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\"\x1b\n\x19RegisterNodeFleetResponse\"E\n\x13\x41\x63tivateNodeRequest\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x1a\n\x12heartbeat_interval\x18\x02 \x01(\x01\"\'\n\x14\x41\x63tivateNodeResponse\x12\x0f\n\x07node_id\x18\x01 \x01(\x04\"(\n\x15\x44\x65\x61\x63tivateNodeRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x04\"\x18\n\x16\x44\x65\x61\x63tivateNodeResponse\"-\n\x1aUnregisterNodeFleetRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x04\"\x1d\n\x1bUnregisterNodeFleetResponse\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"\xa2\x01\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12\x34\n\x14message_object_trees\x18\x03 \x03(\x0b\x32\x16.flwr.proto.ObjectTree\"\x97\x01\n\x13PushMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12\x34\n\x14message_object_trees\x18\x03 \x03(\x0b\x32\x16.flwr.proto.ObjectTree\"\xc9\x01\n\x14PushMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12>\n\x07results\x18\x02 \x03(\x0b\x32-.flwr.proto.PushMessagesResponse.ResultsEntry\x12\x17\n\x0fobjects_to_push\x18\x03 \x03(\t\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xa0\x08\n\x05\x46leet\x12]\n\x0cRegisterNode\x12$.flwr.proto.RegisterNodeFleetRequest\x1a%.flwr.proto.RegisterNodeFleetResponse\"\x00\x12S\n\x0c\x41\x63tivateNode\x12\x1f.flwr.proto.ActivateNodeRequest\x1a .flwr.proto.ActivateNodeResponse\"\x00\x12Y\n\x0e\x44\x65\x61\x63tivateNode\x12!.flwr.proto.DeactivateNodeRequest\x1a\".flwr.proto.DeactivateNodeResponse\"\x00\x12\x63\n\x0eUnregisterNode\x12&.flwr.proto.UnregisterNodeFleetRequest\x1a\'.flwr.proto.UnregisterNodeFleetResponse\"\x00\x12\x62\n\x11SendNodeHeartbeat\x12$.flwr.proto.SendNodeHeartbeatRequest\x1a%.flwr.proto.SendNodeHeartbeatResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12S\n\x0cPushMessages\x12\x1f.flwr.proto.PushMessagesRequest\x1a .flwr.proto.PushMessagesResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12\x41\n\x06GetFab\x12\x19.flwr.proto.GetFabRequest\x1a\x1a.flwr.proto.GetFabResponse\"\x00\x12M\n\nPushObject\x12\x1d.flwr.proto.PushObjectRequest\x1a\x1e.flwr.proto.PushObjectResponse\"\x00\x12M\n\nPullObject\x12\x1d.flwr.proto.PullObjectRequest\x1a\x1e.flwr.proto.PullObjectResponse\"\x00\x12q\n\x16\x43onfirmMessageReceived\x12).flwr.proto.ConfirmMessageReceivedRequest\x1a*.flwr.proto.ConfirmMessageReceivedResponse\"\x00\x62\x06proto3')
|
|
23
23
|
|
|
24
24
|
_globals = globals()
|
|
25
25
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -28,42 +28,34 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
28
28
|
DESCRIPTOR._options = None
|
|
29
29
|
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._options = None
|
|
30
30
|
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
|
|
31
|
-
_globals['
|
|
32
|
-
_globals['
|
|
33
|
-
_globals['
|
|
34
|
-
_globals['
|
|
35
|
-
_globals['
|
|
36
|
-
_globals['
|
|
37
|
-
_globals['
|
|
38
|
-
_globals['
|
|
39
|
-
_globals['
|
|
40
|
-
_globals['
|
|
41
|
-
_globals['
|
|
42
|
-
_globals['
|
|
43
|
-
_globals['
|
|
44
|
-
_globals['
|
|
45
|
-
_globals['
|
|
46
|
-
_globals['
|
|
47
|
-
_globals['
|
|
48
|
-
_globals['
|
|
49
|
-
_globals['
|
|
50
|
-
_globals['
|
|
51
|
-
_globals['
|
|
52
|
-
_globals['
|
|
53
|
-
_globals['
|
|
54
|
-
_globals['
|
|
55
|
-
_globals['
|
|
56
|
-
_globals['
|
|
57
|
-
_globals['
|
|
58
|
-
_globals['
|
|
59
|
-
_globals['
|
|
60
|
-
_globals['
|
|
61
|
-
_globals['_PUSHMESSAGESRESPONSE']._serialized_start=1088
|
|
62
|
-
_globals['_PUSHMESSAGESRESPONSE']._serialized_end=1289
|
|
63
|
-
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=1243
|
|
64
|
-
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=1289
|
|
65
|
-
_globals['_RECONNECT']._serialized_start=1291
|
|
66
|
-
_globals['_RECONNECT']._serialized_end=1321
|
|
67
|
-
_globals['_FLEET']._serialized_start=1324
|
|
68
|
-
_globals['_FLEET']._serialized_end=2538
|
|
31
|
+
_globals['_REGISTERNODEFLEETREQUEST']._serialized_start=159
|
|
32
|
+
_globals['_REGISTERNODEFLEETREQUEST']._serialized_end=205
|
|
33
|
+
_globals['_REGISTERNODEFLEETRESPONSE']._serialized_start=207
|
|
34
|
+
_globals['_REGISTERNODEFLEETRESPONSE']._serialized_end=234
|
|
35
|
+
_globals['_ACTIVATENODEREQUEST']._serialized_start=236
|
|
36
|
+
_globals['_ACTIVATENODEREQUEST']._serialized_end=305
|
|
37
|
+
_globals['_ACTIVATENODERESPONSE']._serialized_start=307
|
|
38
|
+
_globals['_ACTIVATENODERESPONSE']._serialized_end=346
|
|
39
|
+
_globals['_DEACTIVATENODEREQUEST']._serialized_start=348
|
|
40
|
+
_globals['_DEACTIVATENODEREQUEST']._serialized_end=388
|
|
41
|
+
_globals['_DEACTIVATENODERESPONSE']._serialized_start=390
|
|
42
|
+
_globals['_DEACTIVATENODERESPONSE']._serialized_end=414
|
|
43
|
+
_globals['_UNREGISTERNODEFLEETREQUEST']._serialized_start=416
|
|
44
|
+
_globals['_UNREGISTERNODEFLEETREQUEST']._serialized_end=461
|
|
45
|
+
_globals['_UNREGISTERNODEFLEETRESPONSE']._serialized_start=463
|
|
46
|
+
_globals['_UNREGISTERNODEFLEETRESPONSE']._serialized_end=492
|
|
47
|
+
_globals['_PULLMESSAGESREQUEST']._serialized_start=494
|
|
48
|
+
_globals['_PULLMESSAGESREQUEST']._serialized_end=568
|
|
49
|
+
_globals['_PULLMESSAGESRESPONSE']._serialized_start=571
|
|
50
|
+
_globals['_PULLMESSAGESRESPONSE']._serialized_end=733
|
|
51
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_start=736
|
|
52
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_end=887
|
|
53
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_start=890
|
|
54
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_end=1091
|
|
55
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=1045
|
|
56
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=1091
|
|
57
|
+
_globals['_RECONNECT']._serialized_start=1093
|
|
58
|
+
_globals['_RECONNECT']._serialized_end=1123
|
|
59
|
+
_globals['_FLEET']._serialized_start=1126
|
|
60
|
+
_globals['_FLEET']._serialized_end=2182
|
|
69
61
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/fleet_pb2.pyi
CHANGED
|
@@ -13,54 +13,6 @@ import typing_extensions
|
|
|
13
13
|
|
|
14
14
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
|
15
15
|
|
|
16
|
-
class CreateNodeRequest(google.protobuf.message.Message):
|
|
17
|
-
"""CreateNode messages"""
|
|
18
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
19
|
-
PUBLIC_KEY_FIELD_NUMBER: builtins.int
|
|
20
|
-
HEARTBEAT_INTERVAL_FIELD_NUMBER: builtins.int
|
|
21
|
-
public_key: builtins.bytes
|
|
22
|
-
heartbeat_interval: builtins.float
|
|
23
|
-
def __init__(self,
|
|
24
|
-
*,
|
|
25
|
-
public_key: builtins.bytes = ...,
|
|
26
|
-
heartbeat_interval: builtins.float = ...,
|
|
27
|
-
) -> None: ...
|
|
28
|
-
def ClearField(self, field_name: typing_extensions.Literal["heartbeat_interval",b"heartbeat_interval","public_key",b"public_key"]) -> None: ...
|
|
29
|
-
global___CreateNodeRequest = CreateNodeRequest
|
|
30
|
-
|
|
31
|
-
class CreateNodeResponse(google.protobuf.message.Message):
|
|
32
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
33
|
-
NODE_FIELD_NUMBER: builtins.int
|
|
34
|
-
@property
|
|
35
|
-
def node(self) -> flwr.proto.node_pb2.Node: ...
|
|
36
|
-
def __init__(self,
|
|
37
|
-
*,
|
|
38
|
-
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
|
39
|
-
) -> None: ...
|
|
40
|
-
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
|
41
|
-
def ClearField(self, field_name: typing_extensions.Literal["node",b"node"]) -> None: ...
|
|
42
|
-
global___CreateNodeResponse = CreateNodeResponse
|
|
43
|
-
|
|
44
|
-
class DeleteNodeRequest(google.protobuf.message.Message):
|
|
45
|
-
"""DeleteNode messages"""
|
|
46
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
47
|
-
NODE_FIELD_NUMBER: builtins.int
|
|
48
|
-
@property
|
|
49
|
-
def node(self) -> flwr.proto.node_pb2.Node: ...
|
|
50
|
-
def __init__(self,
|
|
51
|
-
*,
|
|
52
|
-
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
|
53
|
-
) -> None: ...
|
|
54
|
-
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
|
55
|
-
def ClearField(self, field_name: typing_extensions.Literal["node",b"node"]) -> None: ...
|
|
56
|
-
global___DeleteNodeRequest = DeleteNodeRequest
|
|
57
|
-
|
|
58
|
-
class DeleteNodeResponse(google.protobuf.message.Message):
|
|
59
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
|
60
|
-
def __init__(self,
|
|
61
|
-
) -> None: ...
|
|
62
|
-
global___DeleteNodeResponse = DeleteNodeResponse
|
|
63
|
-
|
|
64
16
|
class RegisterNodeFleetRequest(google.protobuf.message.Message):
|
|
65
17
|
"""RegisterNode messages (add prefix to avoid name clash)"""
|
|
66
18
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
flwr/proto/fleet_pb2_grpc.py
CHANGED
|
@@ -18,16 +18,6 @@ class FleetStub(object):
|
|
|
18
18
|
Args:
|
|
19
19
|
channel: A grpc.Channel.
|
|
20
20
|
"""
|
|
21
|
-
self.CreateNode = channel.unary_unary(
|
|
22
|
-
'/flwr.proto.Fleet/CreateNode',
|
|
23
|
-
request_serializer=flwr_dot_proto_dot_fleet__pb2.CreateNodeRequest.SerializeToString,
|
|
24
|
-
response_deserializer=flwr_dot_proto_dot_fleet__pb2.CreateNodeResponse.FromString,
|
|
25
|
-
)
|
|
26
|
-
self.DeleteNode = channel.unary_unary(
|
|
27
|
-
'/flwr.proto.Fleet/DeleteNode',
|
|
28
|
-
request_serializer=flwr_dot_proto_dot_fleet__pb2.DeleteNodeRequest.SerializeToString,
|
|
29
|
-
response_deserializer=flwr_dot_proto_dot_fleet__pb2.DeleteNodeResponse.FromString,
|
|
30
|
-
)
|
|
31
21
|
self.RegisterNode = channel.unary_unary(
|
|
32
22
|
'/flwr.proto.Fleet/RegisterNode',
|
|
33
23
|
request_serializer=flwr_dot_proto_dot_fleet__pb2.RegisterNodeFleetRequest.SerializeToString,
|
|
@@ -93,18 +83,6 @@ class FleetStub(object):
|
|
|
93
83
|
class FleetServicer(object):
|
|
94
84
|
"""Missing associated documentation comment in .proto file."""
|
|
95
85
|
|
|
96
|
-
def CreateNode(self, request, context):
|
|
97
|
-
"""Missing associated documentation comment in .proto file."""
|
|
98
|
-
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
99
|
-
context.set_details('Method not implemented!')
|
|
100
|
-
raise NotImplementedError('Method not implemented!')
|
|
101
|
-
|
|
102
|
-
def DeleteNode(self, request, context):
|
|
103
|
-
"""Missing associated documentation comment in .proto file."""
|
|
104
|
-
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
105
|
-
context.set_details('Method not implemented!')
|
|
106
|
-
raise NotImplementedError('Method not implemented!')
|
|
107
|
-
|
|
108
86
|
def RegisterNode(self, request, context):
|
|
109
87
|
"""Register Node
|
|
110
88
|
"""
|
|
@@ -194,16 +172,6 @@ class FleetServicer(object):
|
|
|
194
172
|
|
|
195
173
|
def add_FleetServicer_to_server(servicer, server):
|
|
196
174
|
rpc_method_handlers = {
|
|
197
|
-
'CreateNode': grpc.unary_unary_rpc_method_handler(
|
|
198
|
-
servicer.CreateNode,
|
|
199
|
-
request_deserializer=flwr_dot_proto_dot_fleet__pb2.CreateNodeRequest.FromString,
|
|
200
|
-
response_serializer=flwr_dot_proto_dot_fleet__pb2.CreateNodeResponse.SerializeToString,
|
|
201
|
-
),
|
|
202
|
-
'DeleteNode': grpc.unary_unary_rpc_method_handler(
|
|
203
|
-
servicer.DeleteNode,
|
|
204
|
-
request_deserializer=flwr_dot_proto_dot_fleet__pb2.DeleteNodeRequest.FromString,
|
|
205
|
-
response_serializer=flwr_dot_proto_dot_fleet__pb2.DeleteNodeResponse.SerializeToString,
|
|
206
|
-
),
|
|
207
175
|
'RegisterNode': grpc.unary_unary_rpc_method_handler(
|
|
208
176
|
servicer.RegisterNode,
|
|
209
177
|
request_deserializer=flwr_dot_proto_dot_fleet__pb2.RegisterNodeFleetRequest.FromString,
|
|
@@ -274,40 +242,6 @@ def add_FleetServicer_to_server(servicer, server):
|
|
|
274
242
|
class Fleet(object):
|
|
275
243
|
"""Missing associated documentation comment in .proto file."""
|
|
276
244
|
|
|
277
|
-
@staticmethod
|
|
278
|
-
def CreateNode(request,
|
|
279
|
-
target,
|
|
280
|
-
options=(),
|
|
281
|
-
channel_credentials=None,
|
|
282
|
-
call_credentials=None,
|
|
283
|
-
insecure=False,
|
|
284
|
-
compression=None,
|
|
285
|
-
wait_for_ready=None,
|
|
286
|
-
timeout=None,
|
|
287
|
-
metadata=None):
|
|
288
|
-
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/CreateNode',
|
|
289
|
-
flwr_dot_proto_dot_fleet__pb2.CreateNodeRequest.SerializeToString,
|
|
290
|
-
flwr_dot_proto_dot_fleet__pb2.CreateNodeResponse.FromString,
|
|
291
|
-
options, channel_credentials,
|
|
292
|
-
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
293
|
-
|
|
294
|
-
@staticmethod
|
|
295
|
-
def DeleteNode(request,
|
|
296
|
-
target,
|
|
297
|
-
options=(),
|
|
298
|
-
channel_credentials=None,
|
|
299
|
-
call_credentials=None,
|
|
300
|
-
insecure=False,
|
|
301
|
-
compression=None,
|
|
302
|
-
wait_for_ready=None,
|
|
303
|
-
timeout=None,
|
|
304
|
-
metadata=None):
|
|
305
|
-
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/DeleteNode',
|
|
306
|
-
flwr_dot_proto_dot_fleet__pb2.DeleteNodeRequest.SerializeToString,
|
|
307
|
-
flwr_dot_proto_dot_fleet__pb2.DeleteNodeResponse.FromString,
|
|
308
|
-
options, channel_credentials,
|
|
309
|
-
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
310
|
-
|
|
311
245
|
@staticmethod
|
|
312
246
|
def RegisterNode(request,
|
|
313
247
|
target,
|
flwr/proto/fleet_pb2_grpc.pyi
CHANGED
|
@@ -12,14 +12,6 @@ import grpc
|
|
|
12
12
|
|
|
13
13
|
class FleetStub:
|
|
14
14
|
def __init__(self, channel: grpc.Channel) -> None: ...
|
|
15
|
-
CreateNode: grpc.UnaryUnaryMultiCallable[
|
|
16
|
-
flwr.proto.fleet_pb2.CreateNodeRequest,
|
|
17
|
-
flwr.proto.fleet_pb2.CreateNodeResponse]
|
|
18
|
-
|
|
19
|
-
DeleteNode: grpc.UnaryUnaryMultiCallable[
|
|
20
|
-
flwr.proto.fleet_pb2.DeleteNodeRequest,
|
|
21
|
-
flwr.proto.fleet_pb2.DeleteNodeResponse]
|
|
22
|
-
|
|
23
15
|
RegisterNode: grpc.UnaryUnaryMultiCallable[
|
|
24
16
|
flwr.proto.fleet_pb2.RegisterNodeFleetRequest,
|
|
25
17
|
flwr.proto.fleet_pb2.RegisterNodeFleetResponse]
|
|
@@ -86,18 +78,6 @@ class FleetStub:
|
|
|
86
78
|
|
|
87
79
|
|
|
88
80
|
class FleetServicer(metaclass=abc.ABCMeta):
|
|
89
|
-
@abc.abstractmethod
|
|
90
|
-
def CreateNode(self,
|
|
91
|
-
request: flwr.proto.fleet_pb2.CreateNodeRequest,
|
|
92
|
-
context: grpc.ServicerContext,
|
|
93
|
-
) -> flwr.proto.fleet_pb2.CreateNodeResponse: ...
|
|
94
|
-
|
|
95
|
-
@abc.abstractmethod
|
|
96
|
-
def DeleteNode(self,
|
|
97
|
-
request: flwr.proto.fleet_pb2.DeleteNodeRequest,
|
|
98
|
-
context: grpc.ServicerContext,
|
|
99
|
-
) -> flwr.proto.fleet_pb2.DeleteNodeResponse: ...
|
|
100
|
-
|
|
101
81
|
@abc.abstractmethod
|
|
102
82
|
def RegisterNode(self,
|
|
103
83
|
request: flwr.proto.fleet_pb2.RegisterNodeFleetRequest,
|
flwr/server/app.py
CHANGED
|
@@ -233,20 +233,36 @@ def run_superlink() -> None:
|
|
|
233
233
|
log(WARN, "The `--artifact-provider-config` flag is highly experimental.")
|
|
234
234
|
artifact_provider = get_ee_artifact_provider(cfg_path)
|
|
235
235
|
|
|
236
|
-
#
|
|
236
|
+
# Check for incompatible args with SuperNode authentication
|
|
237
237
|
enable_supernode_auth: bool = args.enable_supernode_auth
|
|
238
|
-
if enable_supernode_auth
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
238
|
+
if enable_supernode_auth:
|
|
239
|
+
if args.insecure:
|
|
240
|
+
url_v = f"https://flower.ai/docs/framework/v{package_version}/en/"
|
|
241
|
+
page = "how-to-authenticate-supernodes.html"
|
|
242
|
+
flwr_exit(
|
|
243
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
|
244
|
+
"The `--enable-supernode-auth` flag requires encrypted TLS "
|
|
245
|
+
"communications. Please provide TLS certificates using the "
|
|
246
|
+
"`--ssl-certfile`, `--ssl-keyfile` and `--ssl-ca-certfile` "
|
|
247
|
+
"arguments to your SuperLink. Please refer to the Flower "
|
|
248
|
+
f"documentation for more information: {url_v}{page}",
|
|
249
|
+
)
|
|
250
|
+
if args.fleet_api_type != TRANSPORT_TYPE_GRPC_RERE:
|
|
251
|
+
flwr_exit(
|
|
252
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
|
253
|
+
"The `--enable-supernode-auth` flag is only supported "
|
|
254
|
+
"with the gRPC-rere Fleet API transport. Please set "
|
|
255
|
+
f"`--fleet-api-type` to `{TRANSPORT_TYPE_GRPC_RERE}`.",
|
|
256
|
+
)
|
|
257
|
+
if args.simulation:
|
|
258
|
+
log(
|
|
259
|
+
WARN,
|
|
260
|
+
"SuperNode authentication is not applicable with the simulation, "
|
|
261
|
+
"runtime as no SuperNodes can connect to this SuperLink. "
|
|
262
|
+
"Proceeding...",
|
|
263
|
+
)
|
|
264
|
+
# If supernode authentication is disabled, warn users
|
|
265
|
+
else:
|
|
250
266
|
log(
|
|
251
267
|
WARN,
|
|
252
268
|
"SuperNode authentication is disabled. The SuperLink will accept "
|
|
@@ -384,7 +400,6 @@ def run_superlink() -> None:
|
|
|
384
400
|
state_factory=state_factory,
|
|
385
401
|
ffs_factory=ffs_factory,
|
|
386
402
|
objectstore_factory=objectstore_factory,
|
|
387
|
-
enable_supernode_auth=enable_supernode_auth,
|
|
388
403
|
certificates=certificates,
|
|
389
404
|
)
|
|
390
405
|
grpc_servers.append(fleet_server)
|
|
@@ -570,7 +585,6 @@ def _run_fleet_api_grpc_adapter(
|
|
|
570
585
|
state_factory: LinkStateFactory,
|
|
571
586
|
ffs_factory: FfsFactory,
|
|
572
587
|
objectstore_factory: ObjectStoreFactory,
|
|
573
|
-
enable_supernode_auth: bool,
|
|
574
588
|
certificates: Optional[tuple[bytes, bytes, bytes]],
|
|
575
589
|
) -> grpc.Server:
|
|
576
590
|
"""Run Fleet API (GrpcAdapter)."""
|
|
@@ -579,7 +593,7 @@ def _run_fleet_api_grpc_adapter(
|
|
|
579
593
|
state_factory=state_factory,
|
|
580
594
|
ffs_factory=ffs_factory,
|
|
581
595
|
objectstore_factory=objectstore_factory,
|
|
582
|
-
enable_supernode_auth=
|
|
596
|
+
enable_supernode_auth=False,
|
|
583
597
|
)
|
|
584
598
|
fleet_add_servicer_to_server_fn = add_GrpcAdapterServicer_to_server
|
|
585
599
|
fleet_grpc_server = generic_create_grpc_server(
|
|
@@ -34,9 +34,7 @@ from flwr.proto import grpcadapter_pb2_grpc # pylint: disable=E0611
|
|
|
34
34
|
from flwr.proto.fab_pb2 import GetFabRequest # pylint: disable=E0611
|
|
35
35
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
36
36
|
ActivateNodeRequest,
|
|
37
|
-
CreateNodeRequest,
|
|
38
37
|
DeactivateNodeRequest,
|
|
39
|
-
DeleteNodeRequest,
|
|
40
38
|
PullMessagesRequest,
|
|
41
39
|
PushMessagesRequest,
|
|
42
40
|
RegisterNodeFleetRequest,
|
|
@@ -86,10 +84,6 @@ class GrpcAdapterServicer(grpcadapter_pb2_grpc.GrpcAdapterServicer, FleetService
|
|
|
86
84
|
) -> MessageContainer:
|
|
87
85
|
"""."""
|
|
88
86
|
log(DEBUG, "GrpcAdapterServicer.SendReceive")
|
|
89
|
-
if request.grpc_message_name == CreateNodeRequest.__qualname__:
|
|
90
|
-
return _handle(request, context, CreateNodeRequest, self.CreateNode)
|
|
91
|
-
if request.grpc_message_name == DeleteNodeRequest.__qualname__:
|
|
92
|
-
return _handle(request, context, DeleteNodeRequest, self.DeleteNode)
|
|
93
87
|
if request.grpc_message_name == RegisterNodeFleetRequest.__qualname__:
|
|
94
88
|
return _handle(
|
|
95
89
|
request, context, RegisterNodeFleetRequest, self.RegisterNode
|
|
@@ -21,10 +21,7 @@ from logging import DEBUG, ERROR, INFO
|
|
|
21
21
|
import grpc
|
|
22
22
|
from google.protobuf.json_format import MessageToDict
|
|
23
23
|
|
|
24
|
-
from flwr.common.constant import
|
|
25
|
-
PUBLIC_KEY_ALREADY_IN_USE_MESSAGE,
|
|
26
|
-
SUPERNODE_NOT_CREATED_FROM_CLI_MESSAGE,
|
|
27
|
-
)
|
|
24
|
+
from flwr.common.constant import PUBLIC_KEY_ALREADY_IN_USE_MESSAGE
|
|
28
25
|
from flwr.common.inflatable import UnexpectedObjectContentError
|
|
29
26
|
from flwr.common.logger import log
|
|
30
27
|
from flwr.common.typing import InvalidRunStatusException
|
|
@@ -33,12 +30,8 @@ from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=
|
|
|
33
30
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
34
31
|
ActivateNodeRequest,
|
|
35
32
|
ActivateNodeResponse,
|
|
36
|
-
CreateNodeRequest,
|
|
37
|
-
CreateNodeResponse,
|
|
38
33
|
DeactivateNodeRequest,
|
|
39
34
|
DeactivateNodeResponse,
|
|
40
|
-
DeleteNodeRequest,
|
|
41
|
-
DeleteNodeResponse,
|
|
42
35
|
PullMessagesRequest,
|
|
43
36
|
PullMessagesResponse,
|
|
44
37
|
PushMessagesRequest,
|
|
@@ -60,12 +53,10 @@ from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
|
|
60
53
|
PushObjectRequest,
|
|
61
54
|
PushObjectResponse,
|
|
62
55
|
)
|
|
63
|
-
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
64
56
|
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
65
57
|
from flwr.server.superlink.fleet.message_handler import message_handler
|
|
66
58
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
67
59
|
from flwr.server.superlink.utils import abort_grpc_context
|
|
68
|
-
from flwr.supercore.constant import NodeStatus
|
|
69
60
|
from flwr.supercore.ffs import FfsFactory
|
|
70
61
|
from flwr.supercore.object_store import ObjectStoreFactory
|
|
71
62
|
|
|
@@ -86,71 +77,6 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
|
86
77
|
self.enable_supernode_auth = enable_supernode_auth
|
|
87
78
|
self.lock = threading.Lock()
|
|
88
79
|
|
|
89
|
-
def CreateNode(
|
|
90
|
-
self, request: CreateNodeRequest, context: grpc.ServicerContext
|
|
91
|
-
) -> CreateNodeResponse:
|
|
92
|
-
"""."""
|
|
93
|
-
log(
|
|
94
|
-
INFO,
|
|
95
|
-
"[Fleet.CreateNode] Request heartbeat_interval=%s",
|
|
96
|
-
request.heartbeat_interval,
|
|
97
|
-
)
|
|
98
|
-
log(DEBUG, "[Fleet.CreateNode] Request: %s", MessageToDict(request))
|
|
99
|
-
try:
|
|
100
|
-
|
|
101
|
-
state = self.state_factory.state()
|
|
102
|
-
|
|
103
|
-
# Check if public key is already in use
|
|
104
|
-
if node_id := state.get_node_id_by_public_key(request.public_key):
|
|
105
|
-
|
|
106
|
-
# Ensure only one request that requires checking the node state
|
|
107
|
-
# is processed at a time. This avoids race conditions when two
|
|
108
|
-
# SuperNodes try to connect at the same time with the same
|
|
109
|
-
# public key.
|
|
110
|
-
with self.lock:
|
|
111
|
-
node_info = state.get_node_info(node_ids=[node_id])[0]
|
|
112
|
-
if node_info.status == NodeStatus.ONLINE:
|
|
113
|
-
# Node is already active
|
|
114
|
-
log(
|
|
115
|
-
ERROR,
|
|
116
|
-
"Public key already in use (node_id=%s)",
|
|
117
|
-
node_id,
|
|
118
|
-
)
|
|
119
|
-
raise ValueError(
|
|
120
|
-
"Public key already in use by an active SuperNode"
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
# Prepare response with existing node_id
|
|
124
|
-
response = CreateNodeResponse(node=Node(node_id=node_id))
|
|
125
|
-
# Awknowledge heartbeat to mark node as online
|
|
126
|
-
state.acknowledge_node_heartbeat(
|
|
127
|
-
node_id=node_id,
|
|
128
|
-
heartbeat_interval=request.heartbeat_interval,
|
|
129
|
-
)
|
|
130
|
-
else:
|
|
131
|
-
if self.enable_supernode_auth:
|
|
132
|
-
# When SuperNode authentication is enabled,
|
|
133
|
-
# only SuperNodes created from the CLI are allowed to
|
|
134
|
-
# stablish a connection with the Fleet API
|
|
135
|
-
log(ERROR, SUPERNODE_NOT_CREATED_FROM_CLI_MESSAGE)
|
|
136
|
-
raise ValueError(SUPERNODE_NOT_CREATED_FROM_CLI_MESSAGE)
|
|
137
|
-
|
|
138
|
-
# When SuperNode authentication is disabled, auto-auth
|
|
139
|
-
# allows creating a new node
|
|
140
|
-
response = message_handler.create_node(
|
|
141
|
-
request=request,
|
|
142
|
-
state=state,
|
|
143
|
-
)
|
|
144
|
-
log(
|
|
145
|
-
INFO, "[Fleet.CreateNode] Created node_id=%s", response.node.node_id
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
except ValueError as e:
|
|
149
|
-
# Public key already in use
|
|
150
|
-
context.abort(grpc.StatusCode.FAILED_PRECONDITION, str(e))
|
|
151
|
-
log(DEBUG, "[Fleet.CreateNode] Response: %s", MessageToDict(response))
|
|
152
|
-
return response
|
|
153
|
-
|
|
154
80
|
def RegisterNode(
|
|
155
81
|
self, request: RegisterNodeFleetRequest, context: grpc.ServicerContext
|
|
156
82
|
) -> RegisterNodeFleetResponse:
|
|
@@ -249,29 +175,6 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
|
249
175
|
context.abort(grpc.StatusCode.FAILED_PRECONDITION, str(e))
|
|
250
176
|
raise RuntimeError from None # Make mypy happy
|
|
251
177
|
|
|
252
|
-
def DeleteNode(
|
|
253
|
-
self, request: DeleteNodeRequest, context: grpc.ServicerContext
|
|
254
|
-
) -> DeleteNodeResponse:
|
|
255
|
-
"""."""
|
|
256
|
-
log(INFO, "[Fleet.DeleteNode] Delete node_id=%s", request.node.node_id)
|
|
257
|
-
log(DEBUG, "[Fleet.DeleteNode] Request: %s", MessageToDict(request))
|
|
258
|
-
# This shall be refactored when renaming `Fleet.Create/DeleteNode`
|
|
259
|
-
# to `Fleet.Activate/DeactivateNode`
|
|
260
|
-
if self.enable_supernode_auth:
|
|
261
|
-
# SuperNodes can only be deleted from the CLI
|
|
262
|
-
# We simply acknowledge the heartbeat with interval 0
|
|
263
|
-
# to mark the node as offline
|
|
264
|
-
state = self.state_factory.state()
|
|
265
|
-
state.acknowledge_node_heartbeat(
|
|
266
|
-
node_id=request.node.node_id, heartbeat_interval=0
|
|
267
|
-
)
|
|
268
|
-
return DeleteNodeResponse()
|
|
269
|
-
|
|
270
|
-
return message_handler.delete_node(
|
|
271
|
-
request=request,
|
|
272
|
-
state=self.state_factory.state(),
|
|
273
|
-
)
|
|
274
|
-
|
|
275
178
|
def SendNodeHeartbeat(
|
|
276
179
|
self, request: SendNodeHeartbeatRequest, context: grpc.ServicerContext
|
|
277
180
|
) -> SendNodeHeartbeatResponse:
|
|
@@ -29,7 +29,10 @@ from flwr.common.constant import (
|
|
|
29
29
|
TIMESTAMP_HEADER,
|
|
30
30
|
TIMESTAMP_TOLERANCE,
|
|
31
31
|
)
|
|
32
|
-
from flwr.proto.fleet_pb2 import
|
|
32
|
+
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
33
|
+
ActivateNodeRequest,
|
|
34
|
+
RegisterNodeFleetRequest,
|
|
35
|
+
)
|
|
33
36
|
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
34
37
|
from flwr.supercore.primitives.asymmetric import bytes_to_public_key, verify_signature
|
|
35
38
|
|
|
@@ -110,15 +113,21 @@ class NodeAuthServerInterceptor(grpc.ServerInterceptor): # type: ignore
|
|
|
110
113
|
request: GrpcMessage,
|
|
111
114
|
context: grpc.ServicerContext,
|
|
112
115
|
) -> GrpcMessage:
|
|
116
|
+
# Note: This function runs in a different thread
|
|
117
|
+
# than the `intercept_service` function.
|
|
118
|
+
|
|
113
119
|
# Retrieve the public key
|
|
114
|
-
if isinstance(request,
|
|
120
|
+
if isinstance(request, (RegisterNodeFleetRequest, ActivateNodeRequest)):
|
|
115
121
|
actual_public_key = request.public_key
|
|
116
122
|
else:
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
if hasattr(request, "node"):
|
|
124
|
+
node_id = request.node.node_id
|
|
125
|
+
else:
|
|
126
|
+
node_id = request.node_id # type: ignore[attr-defined]
|
|
119
127
|
actual_public_key = self.state_factory.state().get_node_public_key(
|
|
120
|
-
|
|
128
|
+
node_id
|
|
121
129
|
)
|
|
130
|
+
|
|
122
131
|
# Verify the public key
|
|
123
132
|
if actual_public_key != expected_public_key:
|
|
124
133
|
context.abort(grpc.StatusCode.UNAUTHENTICATED, "Invalid node ID")
|
|
@@ -36,12 +36,8 @@ from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=
|
|
|
36
36
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
37
37
|
ActivateNodeRequest,
|
|
38
38
|
ActivateNodeResponse,
|
|
39
|
-
CreateNodeRequest,
|
|
40
|
-
CreateNodeResponse,
|
|
41
39
|
DeactivateNodeRequest,
|
|
42
40
|
DeactivateNodeResponse,
|
|
43
|
-
DeleteNodeRequest,
|
|
44
|
-
DeleteNodeResponse,
|
|
45
41
|
PullMessagesRequest,
|
|
46
42
|
PullMessagesResponse,
|
|
47
43
|
PushMessagesRequest,
|
|
@@ -64,7 +60,6 @@ from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
|
|
64
60
|
PushObjectRequest,
|
|
65
61
|
PushObjectResponse,
|
|
66
62
|
)
|
|
67
|
-
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
68
63
|
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
|
69
64
|
GetRunRequest,
|
|
70
65
|
GetRunResponse,
|
|
@@ -81,29 +76,6 @@ class InvalidHeartbeatIntervalError(Exception):
|
|
|
81
76
|
"""Invalid heartbeat interval exception."""
|
|
82
77
|
|
|
83
78
|
|
|
84
|
-
def create_node(
|
|
85
|
-
request: CreateNodeRequest, # pylint: disable=unused-argument
|
|
86
|
-
state: LinkState,
|
|
87
|
-
) -> CreateNodeResponse:
|
|
88
|
-
"""."""
|
|
89
|
-
# Create node
|
|
90
|
-
node_id = state.create_node(
|
|
91
|
-
NOOP_FLWR_AID, request.public_key, request.heartbeat_interval
|
|
92
|
-
)
|
|
93
|
-
return CreateNodeResponse(node=Node(node_id=node_id))
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def delete_node(request: DeleteNodeRequest, state: LinkState) -> DeleteNodeResponse:
|
|
97
|
-
"""."""
|
|
98
|
-
# Validate node_id
|
|
99
|
-
if request.node.node_id == 0: # i.e. unset `node_id`
|
|
100
|
-
return DeleteNodeResponse()
|
|
101
|
-
|
|
102
|
-
# Update state
|
|
103
|
-
state.delete_node(NOOP_FLWR_AID, node_id=request.node.node_id)
|
|
104
|
-
return DeleteNodeResponse()
|
|
105
|
-
|
|
106
|
-
|
|
107
79
|
def register_node(
|
|
108
80
|
request: RegisterNodeFleetRequest,
|
|
109
81
|
state: LinkState,
|
|
@@ -27,12 +27,8 @@ from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=
|
|
|
27
27
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
28
28
|
ActivateNodeRequest,
|
|
29
29
|
ActivateNodeResponse,
|
|
30
|
-
CreateNodeRequest,
|
|
31
|
-
CreateNodeResponse,
|
|
32
30
|
DeactivateNodeRequest,
|
|
33
31
|
DeactivateNodeResponse,
|
|
34
|
-
DeleteNodeRequest,
|
|
35
|
-
DeleteNodeResponse,
|
|
36
32
|
PullMessagesRequest,
|
|
37
33
|
PullMessagesResponse,
|
|
38
34
|
PushMessagesRequest,
|
|
@@ -110,26 +106,6 @@ def rest_request_response(
|
|
|
110
106
|
return decorator
|
|
111
107
|
|
|
112
108
|
|
|
113
|
-
@rest_request_response(CreateNodeRequest)
|
|
114
|
-
async def create_node(request: CreateNodeRequest) -> CreateNodeResponse:
|
|
115
|
-
"""Create Node."""
|
|
116
|
-
# Get state from app
|
|
117
|
-
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
118
|
-
|
|
119
|
-
# Handle message
|
|
120
|
-
return message_handler.create_node(request=request, state=state)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@rest_request_response(DeleteNodeRequest)
|
|
124
|
-
async def delete_node(request: DeleteNodeRequest) -> DeleteNodeResponse:
|
|
125
|
-
"""Delete Node Id."""
|
|
126
|
-
# Get state from app
|
|
127
|
-
state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
|
|
128
|
-
|
|
129
|
-
# Handle message
|
|
130
|
-
return message_handler.delete_node(request=request, state=state)
|
|
131
|
-
|
|
132
|
-
|
|
133
109
|
@rest_request_response(RegisterNodeFleetRequest)
|
|
134
110
|
async def register_node(
|
|
135
111
|
request: RegisterNodeFleetRequest,
|
|
@@ -117,7 +117,8 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
117
117
|
)
|
|
118
118
|
return None
|
|
119
119
|
# Validate destination node ID
|
|
120
|
-
|
|
120
|
+
dst_node = self.nodes.get(message.metadata.dst_node_id)
|
|
121
|
+
if dst_node is None or dst_node.status == NodeStatus.UNREGISTERED:
|
|
121
122
|
log(
|
|
122
123
|
ERROR,
|
|
123
124
|
"Invalid destination node ID for Message: %s",
|