flwr-nightly 1.14.0.dev20241216__py3-none-any.whl → 1.15.0.dev20250112__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flwr/cli/cli_user_auth_interceptor.py +6 -2
- flwr/cli/log.py +8 -6
- flwr/cli/login/login.py +11 -4
- flwr/cli/ls.py +7 -4
- flwr/cli/new/templates/app/.gitignore.tpl +3 -0
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +3 -3
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
- flwr/cli/run/run.py +7 -2
- flwr/cli/stop.py +3 -2
- flwr/cli/utils.py +83 -14
- flwr/client/app.py +17 -9
- flwr/client/client.py +0 -32
- flwr/client/grpc_rere_client/client_interceptor.py +6 -0
- flwr/client/grpc_rere_client/grpc_adapter.py +16 -0
- flwr/client/message_handler/message_handler.py +0 -2
- flwr/client/numpy_client.py +0 -44
- flwr/client/supernode/app.py +1 -2
- flwr/common/auth_plugin/auth_plugin.py +33 -23
- flwr/common/constant.py +2 -0
- flwr/common/grpc.py +154 -3
- flwr/common/record/recordset.py +1 -1
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +45 -0
- flwr/common/telemetry.py +13 -3
- flwr/common/typing.py +20 -0
- flwr/proto/exec_pb2.py +12 -24
- flwr/proto/exec_pb2.pyi +27 -54
- flwr/proto/fleet_pb2.py +40 -27
- flwr/proto/fleet_pb2.pyi +84 -0
- flwr/proto/fleet_pb2_grpc.py +66 -0
- flwr/proto/fleet_pb2_grpc.pyi +20 -0
- flwr/server/app.py +54 -33
- flwr/server/run_serverapp.py +8 -9
- flwr/server/serverapp/app.py +17 -2
- flwr/server/superlink/driver/serverappio_grpc.py +1 -1
- flwr/server/superlink/driver/serverappio_servicer.py +29 -6
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -165
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +16 -0
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -1
- flwr/server/superlink/fleet/vce/vce_api.py +2 -2
- flwr/server/superlink/linkstate/in_memory_linkstate.py +36 -24
- flwr/server/superlink/linkstate/linkstate.py +14 -4
- flwr/server/superlink/linkstate/sqlite_linkstate.py +56 -31
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
- flwr/server/superlink/simulation/simulationio_servicer.py +13 -0
- flwr/simulation/app.py +15 -4
- flwr/simulation/run_simulation.py +35 -7
- flwr/superexec/exec_grpc.py +1 -1
- flwr/superexec/exec_servicer.py +23 -2
- {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/METADATA +5 -5
- {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/RECORD +60 -60
- {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.14.0.dev20241216.dist-info → flwr_nightly-1.15.0.dev20250112.dist-info}/entry_points.txt +0 -0
flwr/proto/exec_pb2.pyi
CHANGED
@@ -143,77 +143,50 @@ global___GetLoginDetailsRequest = GetLoginDetailsRequest
|
|
143
143
|
|
144
144
|
class GetLoginDetailsResponse(google.protobuf.message.Message):
|
145
145
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
) -> None: ...
|
157
|
-
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
158
|
-
|
159
|
-
LOGIN_DETAILS_FIELD_NUMBER: builtins.int
|
160
|
-
@property
|
161
|
-
def login_details(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, typing.Text]: ...
|
146
|
+
AUTH_TYPE_FIELD_NUMBER: builtins.int
|
147
|
+
DEVICE_CODE_FIELD_NUMBER: builtins.int
|
148
|
+
VERIFICATION_URI_COMPLETE_FIELD_NUMBER: builtins.int
|
149
|
+
EXPIRES_IN_FIELD_NUMBER: builtins.int
|
150
|
+
INTERVAL_FIELD_NUMBER: builtins.int
|
151
|
+
auth_type: typing.Text
|
152
|
+
device_code: typing.Text
|
153
|
+
verification_uri_complete: typing.Text
|
154
|
+
expires_in: builtins.int
|
155
|
+
interval: builtins.int
|
162
156
|
def __init__(self,
|
163
157
|
*,
|
164
|
-
|
158
|
+
auth_type: typing.Text = ...,
|
159
|
+
device_code: typing.Text = ...,
|
160
|
+
verification_uri_complete: typing.Text = ...,
|
161
|
+
expires_in: builtins.int = ...,
|
162
|
+
interval: builtins.int = ...,
|
165
163
|
) -> None: ...
|
166
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
164
|
+
def ClearField(self, field_name: typing_extensions.Literal["auth_type",b"auth_type","device_code",b"device_code","expires_in",b"expires_in","interval",b"interval","verification_uri_complete",b"verification_uri_complete"]) -> None: ...
|
167
165
|
global___GetLoginDetailsResponse = GetLoginDetailsResponse
|
168
166
|
|
169
167
|
class GetAuthTokensRequest(google.protobuf.message.Message):
|
170
168
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
171
|
-
|
172
|
-
|
173
|
-
KEY_FIELD_NUMBER: builtins.int
|
174
|
-
VALUE_FIELD_NUMBER: builtins.int
|
175
|
-
key: typing.Text
|
176
|
-
value: typing.Text
|
177
|
-
def __init__(self,
|
178
|
-
*,
|
179
|
-
key: typing.Text = ...,
|
180
|
-
value: typing.Text = ...,
|
181
|
-
) -> None: ...
|
182
|
-
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
183
|
-
|
184
|
-
AUTH_DETAILS_FIELD_NUMBER: builtins.int
|
185
|
-
@property
|
186
|
-
def auth_details(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, typing.Text]: ...
|
169
|
+
DEVICE_CODE_FIELD_NUMBER: builtins.int
|
170
|
+
device_code: typing.Text
|
187
171
|
def __init__(self,
|
188
172
|
*,
|
189
|
-
|
173
|
+
device_code: typing.Text = ...,
|
190
174
|
) -> None: ...
|
191
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
175
|
+
def ClearField(self, field_name: typing_extensions.Literal["device_code",b"device_code"]) -> None: ...
|
192
176
|
global___GetAuthTokensRequest = GetAuthTokensRequest
|
193
177
|
|
194
178
|
class GetAuthTokensResponse(google.protobuf.message.Message):
|
195
179
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
key: typing.Text
|
201
|
-
value: typing.Text
|
202
|
-
def __init__(self,
|
203
|
-
*,
|
204
|
-
key: typing.Text = ...,
|
205
|
-
value: typing.Text = ...,
|
206
|
-
) -> None: ...
|
207
|
-
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
208
|
-
|
209
|
-
AUTH_TOKENS_FIELD_NUMBER: builtins.int
|
210
|
-
@property
|
211
|
-
def auth_tokens(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, typing.Text]: ...
|
180
|
+
ACCESS_TOKEN_FIELD_NUMBER: builtins.int
|
181
|
+
REFRESH_TOKEN_FIELD_NUMBER: builtins.int
|
182
|
+
access_token: typing.Text
|
183
|
+
refresh_token: typing.Text
|
212
184
|
def __init__(self,
|
213
185
|
*,
|
214
|
-
|
186
|
+
access_token: typing.Text = ...,
|
187
|
+
refresh_token: typing.Text = ...,
|
215
188
|
) -> None: ...
|
216
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
189
|
+
def ClearField(self, field_name: typing_extensions.Literal["access_token",b"access_token","refresh_token",b"refresh_token"]) -> None: ...
|
217
190
|
global___GetAuthTokensResponse = GetAuthTokensResponse
|
218
191
|
|
219
192
|
class StopRunRequest(google.protobuf.message.Message):
|
flwr/proto/fleet_pb2.py
CHANGED
@@ -16,9 +16,10 @@ from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
|
|
16
16
|
from flwr.proto import task_pb2 as flwr_dot_proto_dot_task__pb2
|
17
17
|
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
|
+
from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
|
19
20
|
|
20
21
|
|
21
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x15\x66lwr/proto/task.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\"*\n\x11\x43reateNodeRequest\x12\x15\n\rping_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"D\n\x0bPingRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x15\n\rping_interval\x18\x02 \x01(\x01\"\x1f\n\x0cPingResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"F\n\x12PullTaskInsRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x10\n\x08task_ids\x18\x02 \x03(\t\"k\n\x13PullTaskInsResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rtask_ins_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskIns\"`\n\x12PushTaskResRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rtask_res_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskRes\"\xae\x01\n\x13PushTaskResResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12=\n\x07results\x18\x02 \x03(\x0b\x32,.flwr.proto.PushTaskResResponse.ResultsEntry\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\
|
22
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x15\x66lwr/proto/task.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"*\n\x11\x43reateNodeRequest\x12\x15\n\rping_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"D\n\x0bPingRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x15\n\rping_interval\x18\x02 \x01(\x01\"\x1f\n\x0cPingResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"F\n\x12PullTaskInsRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x10\n\x08task_ids\x18\x02 \x03(\t\"k\n\x13PullTaskInsResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rtask_ins_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskIns\"`\n\x12PushTaskResRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rtask_res_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskRes\"\xae\x01\n\x13PushTaskResResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12=\n\x07results\x18\x02 \x03(\x0b\x32,.flwr.proto.PushTaskResResponse.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"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\"l\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\"a\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\"\xb0\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\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\xb6\x05\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12;\n\x04Ping\x12\x17.flwr.proto.PingRequest\x1a\x18.flwr.proto.PingResponse\"\x00\x12P\n\x0bPullTaskIns\x12\x1e.flwr.proto.PullTaskInsRequest\x1a\x1f.flwr.proto.PullTaskInsResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12P\n\x0bPushTaskRes\x12\x1e.flwr.proto.PushTaskResRequest\x1a\x1f.flwr.proto.PushTaskResResponse\"\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\x62\x06proto3')
|
22
23
|
|
23
24
|
_globals = globals()
|
24
25
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -27,30 +28,42 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
27
28
|
DESCRIPTOR._options = None
|
28
29
|
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._options = None
|
29
30
|
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
|
30
|
-
_globals['
|
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['
|
31
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._options = None
|
32
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
|
33
|
+
_globals['_CREATENODEREQUEST']._serialized_start=154
|
34
|
+
_globals['_CREATENODEREQUEST']._serialized_end=196
|
35
|
+
_globals['_CREATENODERESPONSE']._serialized_start=198
|
36
|
+
_globals['_CREATENODERESPONSE']._serialized_end=250
|
37
|
+
_globals['_DELETENODEREQUEST']._serialized_start=252
|
38
|
+
_globals['_DELETENODEREQUEST']._serialized_end=303
|
39
|
+
_globals['_DELETENODERESPONSE']._serialized_start=305
|
40
|
+
_globals['_DELETENODERESPONSE']._serialized_end=325
|
41
|
+
_globals['_PINGREQUEST']._serialized_start=327
|
42
|
+
_globals['_PINGREQUEST']._serialized_end=395
|
43
|
+
_globals['_PINGRESPONSE']._serialized_start=397
|
44
|
+
_globals['_PINGRESPONSE']._serialized_end=428
|
45
|
+
_globals['_PULLTASKINSREQUEST']._serialized_start=430
|
46
|
+
_globals['_PULLTASKINSREQUEST']._serialized_end=500
|
47
|
+
_globals['_PULLTASKINSRESPONSE']._serialized_start=502
|
48
|
+
_globals['_PULLTASKINSRESPONSE']._serialized_end=609
|
49
|
+
_globals['_PUSHTASKRESREQUEST']._serialized_start=611
|
50
|
+
_globals['_PUSHTASKRESREQUEST']._serialized_end=707
|
51
|
+
_globals['_PUSHTASKRESRESPONSE']._serialized_start=710
|
52
|
+
_globals['_PUSHTASKRESRESPONSE']._serialized_end=884
|
53
|
+
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_start=838
|
54
|
+
_globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_end=884
|
55
|
+
_globals['_PULLMESSAGESREQUEST']._serialized_start=886
|
56
|
+
_globals['_PULLMESSAGESREQUEST']._serialized_end=960
|
57
|
+
_globals['_PULLMESSAGESRESPONSE']._serialized_start=962
|
58
|
+
_globals['_PULLMESSAGESRESPONSE']._serialized_end=1070
|
59
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_start=1072
|
60
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_end=1169
|
61
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_start=1172
|
62
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_end=1348
|
63
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=838
|
64
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=884
|
65
|
+
_globals['_RECONNECT']._serialized_start=1350
|
66
|
+
_globals['_RECONNECT']._serialized_end=1380
|
67
|
+
_globals['_FLEET']._serialized_start=1383
|
68
|
+
_globals['_FLEET']._serialized_end=2077
|
56
69
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/fleet_pb2.pyi
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
isort:skip_file
|
4
4
|
"""
|
5
5
|
import builtins
|
6
|
+
import flwr.proto.message_pb2
|
6
7
|
import flwr.proto.node_pb2
|
7
8
|
import flwr.proto.task_pb2
|
8
9
|
import google.protobuf.descriptor
|
@@ -169,6 +170,89 @@ class PushTaskResResponse(google.protobuf.message.Message):
|
|
169
170
|
def ClearField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect","results",b"results"]) -> None: ...
|
170
171
|
global___PushTaskResResponse = PushTaskResResponse
|
171
172
|
|
173
|
+
class PullMessagesRequest(google.protobuf.message.Message):
|
174
|
+
"""PullMessages messages"""
|
175
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
176
|
+
NODE_FIELD_NUMBER: builtins.int
|
177
|
+
MESSAGE_IDS_FIELD_NUMBER: builtins.int
|
178
|
+
@property
|
179
|
+
def node(self) -> flwr.proto.node_pb2.Node: ...
|
180
|
+
@property
|
181
|
+
def message_ids(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]: ...
|
182
|
+
def __init__(self,
|
183
|
+
*,
|
184
|
+
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
185
|
+
message_ids: typing.Optional[typing.Iterable[typing.Text]] = ...,
|
186
|
+
) -> None: ...
|
187
|
+
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
188
|
+
def ClearField(self, field_name: typing_extensions.Literal["message_ids",b"message_ids","node",b"node"]) -> None: ...
|
189
|
+
global___PullMessagesRequest = PullMessagesRequest
|
190
|
+
|
191
|
+
class PullMessagesResponse(google.protobuf.message.Message):
|
192
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
193
|
+
RECONNECT_FIELD_NUMBER: builtins.int
|
194
|
+
MESSAGES_LIST_FIELD_NUMBER: builtins.int
|
195
|
+
@property
|
196
|
+
def reconnect(self) -> global___Reconnect: ...
|
197
|
+
@property
|
198
|
+
def messages_list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.Message]: ...
|
199
|
+
def __init__(self,
|
200
|
+
*,
|
201
|
+
reconnect: typing.Optional[global___Reconnect] = ...,
|
202
|
+
messages_list: typing.Optional[typing.Iterable[flwr.proto.message_pb2.Message]] = ...,
|
203
|
+
) -> None: ...
|
204
|
+
def HasField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect"]) -> builtins.bool: ...
|
205
|
+
def ClearField(self, field_name: typing_extensions.Literal["messages_list",b"messages_list","reconnect",b"reconnect"]) -> None: ...
|
206
|
+
global___PullMessagesResponse = PullMessagesResponse
|
207
|
+
|
208
|
+
class PushMessagesRequest(google.protobuf.message.Message):
|
209
|
+
"""PushMessages messages"""
|
210
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
211
|
+
NODE_FIELD_NUMBER: builtins.int
|
212
|
+
MESSAGES_LIST_FIELD_NUMBER: builtins.int
|
213
|
+
@property
|
214
|
+
def node(self) -> flwr.proto.node_pb2.Node: ...
|
215
|
+
@property
|
216
|
+
def messages_list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.Message]: ...
|
217
|
+
def __init__(self,
|
218
|
+
*,
|
219
|
+
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
220
|
+
messages_list: typing.Optional[typing.Iterable[flwr.proto.message_pb2.Message]] = ...,
|
221
|
+
) -> None: ...
|
222
|
+
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
223
|
+
def ClearField(self, field_name: typing_extensions.Literal["messages_list",b"messages_list","node",b"node"]) -> None: ...
|
224
|
+
global___PushMessagesRequest = PushMessagesRequest
|
225
|
+
|
226
|
+
class PushMessagesResponse(google.protobuf.message.Message):
|
227
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
228
|
+
class ResultsEntry(google.protobuf.message.Message):
|
229
|
+
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
230
|
+
KEY_FIELD_NUMBER: builtins.int
|
231
|
+
VALUE_FIELD_NUMBER: builtins.int
|
232
|
+
key: typing.Text
|
233
|
+
value: builtins.int
|
234
|
+
def __init__(self,
|
235
|
+
*,
|
236
|
+
key: typing.Text = ...,
|
237
|
+
value: builtins.int = ...,
|
238
|
+
) -> None: ...
|
239
|
+
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
240
|
+
|
241
|
+
RECONNECT_FIELD_NUMBER: builtins.int
|
242
|
+
RESULTS_FIELD_NUMBER: builtins.int
|
243
|
+
@property
|
244
|
+
def reconnect(self) -> global___Reconnect: ...
|
245
|
+
@property
|
246
|
+
def results(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, builtins.int]: ...
|
247
|
+
def __init__(self,
|
248
|
+
*,
|
249
|
+
reconnect: typing.Optional[global___Reconnect] = ...,
|
250
|
+
results: typing.Optional[typing.Mapping[typing.Text, builtins.int]] = ...,
|
251
|
+
) -> None: ...
|
252
|
+
def HasField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect"]) -> builtins.bool: ...
|
253
|
+
def ClearField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect","results",b"results"]) -> None: ...
|
254
|
+
global___PushMessagesResponse = PushMessagesResponse
|
255
|
+
|
172
256
|
class Reconnect(google.protobuf.message.Message):
|
173
257
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
174
258
|
RECONNECT_FIELD_NUMBER: builtins.int
|
flwr/proto/fleet_pb2_grpc.py
CHANGED
@@ -36,11 +36,21 @@ class FleetStub(object):
|
|
36
36
|
request_serializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsRequest.SerializeToString,
|
37
37
|
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsResponse.FromString,
|
38
38
|
)
|
39
|
+
self.PullMessages = channel.unary_unary(
|
40
|
+
'/flwr.proto.Fleet/PullMessages',
|
41
|
+
request_serializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesRequest.SerializeToString,
|
42
|
+
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesResponse.FromString,
|
43
|
+
)
|
39
44
|
self.PushTaskRes = channel.unary_unary(
|
40
45
|
'/flwr.proto.Fleet/PushTaskRes',
|
41
46
|
request_serializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResRequest.SerializeToString,
|
42
47
|
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResResponse.FromString,
|
43
48
|
)
|
49
|
+
self.PushMessages = channel.unary_unary(
|
50
|
+
'/flwr.proto.Fleet/PushMessages',
|
51
|
+
request_serializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesRequest.SerializeToString,
|
52
|
+
response_deserializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesResponse.FromString,
|
53
|
+
)
|
44
54
|
self.GetRun = channel.unary_unary(
|
45
55
|
'/flwr.proto.Fleet/GetRun',
|
46
56
|
request_serializer=flwr_dot_proto_dot_run__pb2.GetRunRequest.SerializeToString,
|
@@ -83,6 +93,12 @@ class FleetServicer(object):
|
|
83
93
|
context.set_details('Method not implemented!')
|
84
94
|
raise NotImplementedError('Method not implemented!')
|
85
95
|
|
96
|
+
def PullMessages(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
|
+
|
86
102
|
def PushTaskRes(self, request, context):
|
87
103
|
"""Complete one or more tasks, if possible
|
88
104
|
|
@@ -92,6 +108,12 @@ class FleetServicer(object):
|
|
92
108
|
context.set_details('Method not implemented!')
|
93
109
|
raise NotImplementedError('Method not implemented!')
|
94
110
|
|
111
|
+
def PushMessages(self, request, context):
|
112
|
+
"""Missing associated documentation comment in .proto file."""
|
113
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
114
|
+
context.set_details('Method not implemented!')
|
115
|
+
raise NotImplementedError('Method not implemented!')
|
116
|
+
|
95
117
|
def GetRun(self, request, context):
|
96
118
|
"""Missing associated documentation comment in .proto file."""
|
97
119
|
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
@@ -128,11 +150,21 @@ def add_FleetServicer_to_server(servicer, server):
|
|
128
150
|
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsRequest.FromString,
|
129
151
|
response_serializer=flwr_dot_proto_dot_fleet__pb2.PullTaskInsResponse.SerializeToString,
|
130
152
|
),
|
153
|
+
'PullMessages': grpc.unary_unary_rpc_method_handler(
|
154
|
+
servicer.PullMessages,
|
155
|
+
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesRequest.FromString,
|
156
|
+
response_serializer=flwr_dot_proto_dot_fleet__pb2.PullMessagesResponse.SerializeToString,
|
157
|
+
),
|
131
158
|
'PushTaskRes': grpc.unary_unary_rpc_method_handler(
|
132
159
|
servicer.PushTaskRes,
|
133
160
|
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResRequest.FromString,
|
134
161
|
response_serializer=flwr_dot_proto_dot_fleet__pb2.PushTaskResResponse.SerializeToString,
|
135
162
|
),
|
163
|
+
'PushMessages': grpc.unary_unary_rpc_method_handler(
|
164
|
+
servicer.PushMessages,
|
165
|
+
request_deserializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesRequest.FromString,
|
166
|
+
response_serializer=flwr_dot_proto_dot_fleet__pb2.PushMessagesResponse.SerializeToString,
|
167
|
+
),
|
136
168
|
'GetRun': grpc.unary_unary_rpc_method_handler(
|
137
169
|
servicer.GetRun,
|
138
170
|
request_deserializer=flwr_dot_proto_dot_run__pb2.GetRunRequest.FromString,
|
@@ -221,6 +253,23 @@ class Fleet(object):
|
|
221
253
|
options, channel_credentials,
|
222
254
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
223
255
|
|
256
|
+
@staticmethod
|
257
|
+
def PullMessages(request,
|
258
|
+
target,
|
259
|
+
options=(),
|
260
|
+
channel_credentials=None,
|
261
|
+
call_credentials=None,
|
262
|
+
insecure=False,
|
263
|
+
compression=None,
|
264
|
+
wait_for_ready=None,
|
265
|
+
timeout=None,
|
266
|
+
metadata=None):
|
267
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/PullMessages',
|
268
|
+
flwr_dot_proto_dot_fleet__pb2.PullMessagesRequest.SerializeToString,
|
269
|
+
flwr_dot_proto_dot_fleet__pb2.PullMessagesResponse.FromString,
|
270
|
+
options, channel_credentials,
|
271
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
272
|
+
|
224
273
|
@staticmethod
|
225
274
|
def PushTaskRes(request,
|
226
275
|
target,
|
@@ -238,6 +287,23 @@ class Fleet(object):
|
|
238
287
|
options, channel_credentials,
|
239
288
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
240
289
|
|
290
|
+
@staticmethod
|
291
|
+
def PushMessages(request,
|
292
|
+
target,
|
293
|
+
options=(),
|
294
|
+
channel_credentials=None,
|
295
|
+
call_credentials=None,
|
296
|
+
insecure=False,
|
297
|
+
compression=None,
|
298
|
+
wait_for_ready=None,
|
299
|
+
timeout=None,
|
300
|
+
metadata=None):
|
301
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/PushMessages',
|
302
|
+
flwr_dot_proto_dot_fleet__pb2.PushMessagesRequest.SerializeToString,
|
303
|
+
flwr_dot_proto_dot_fleet__pb2.PushMessagesResponse.FromString,
|
304
|
+
options, channel_credentials,
|
305
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
306
|
+
|
241
307
|
@staticmethod
|
242
308
|
def GetRun(request,
|
243
309
|
target,
|
flwr/proto/fleet_pb2_grpc.pyi
CHANGED
@@ -30,6 +30,10 @@ class FleetStub:
|
|
30
30
|
HTTP API path: /api/v1/fleet/pull-task-ins
|
31
31
|
"""
|
32
32
|
|
33
|
+
PullMessages: grpc.UnaryUnaryMultiCallable[
|
34
|
+
flwr.proto.fleet_pb2.PullMessagesRequest,
|
35
|
+
flwr.proto.fleet_pb2.PullMessagesResponse]
|
36
|
+
|
33
37
|
PushTaskRes: grpc.UnaryUnaryMultiCallable[
|
34
38
|
flwr.proto.fleet_pb2.PushTaskResRequest,
|
35
39
|
flwr.proto.fleet_pb2.PushTaskResResponse]
|
@@ -38,6 +42,10 @@ class FleetStub:
|
|
38
42
|
HTTP API path: /api/v1/fleet/push-task-res
|
39
43
|
"""
|
40
44
|
|
45
|
+
PushMessages: grpc.UnaryUnaryMultiCallable[
|
46
|
+
flwr.proto.fleet_pb2.PushMessagesRequest,
|
47
|
+
flwr.proto.fleet_pb2.PushMessagesResponse]
|
48
|
+
|
41
49
|
GetRun: grpc.UnaryUnaryMultiCallable[
|
42
50
|
flwr.proto.run_pb2.GetRunRequest,
|
43
51
|
flwr.proto.run_pb2.GetRunResponse]
|
@@ -78,6 +86,12 @@ class FleetServicer(metaclass=abc.ABCMeta):
|
|
78
86
|
"""
|
79
87
|
pass
|
80
88
|
|
89
|
+
@abc.abstractmethod
|
90
|
+
def PullMessages(self,
|
91
|
+
request: flwr.proto.fleet_pb2.PullMessagesRequest,
|
92
|
+
context: grpc.ServicerContext,
|
93
|
+
) -> flwr.proto.fleet_pb2.PullMessagesResponse: ...
|
94
|
+
|
81
95
|
@abc.abstractmethod
|
82
96
|
def PushTaskRes(self,
|
83
97
|
request: flwr.proto.fleet_pb2.PushTaskResRequest,
|
@@ -89,6 +103,12 @@ class FleetServicer(metaclass=abc.ABCMeta):
|
|
89
103
|
"""
|
90
104
|
pass
|
91
105
|
|
106
|
+
@abc.abstractmethod
|
107
|
+
def PushMessages(self,
|
108
|
+
request: flwr.proto.fleet_pb2.PushMessagesRequest,
|
109
|
+
context: grpc.ServicerContext,
|
110
|
+
) -> flwr.proto.fleet_pb2.PushMessagesResponse: ...
|
111
|
+
|
92
112
|
@abc.abstractmethod
|
93
113
|
def GetRun(self,
|
94
114
|
request: flwr.proto.run_pb2.GetRunRequest,
|
flwr/server/app.py
CHANGED
@@ -18,7 +18,8 @@
|
|
18
18
|
import argparse
|
19
19
|
import csv
|
20
20
|
import importlib.util
|
21
|
-
import
|
21
|
+
import multiprocessing
|
22
|
+
import multiprocessing.context
|
22
23
|
import sys
|
23
24
|
import threading
|
24
25
|
from collections.abc import Sequence
|
@@ -59,6 +60,7 @@ from flwr.common.constant import (
|
|
59
60
|
TRANSPORT_TYPE_REST,
|
60
61
|
)
|
61
62
|
from flwr.common.exit_handlers import register_exit_handlers
|
63
|
+
from flwr.common.grpc import generic_create_grpc_server
|
62
64
|
from flwr.common.logger import log, warn_deprecated_feature
|
63
65
|
from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
|
64
66
|
private_key_to_bytes,
|
@@ -68,6 +70,8 @@ from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
68
70
|
add_FleetServicer_to_server,
|
69
71
|
)
|
70
72
|
from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
73
|
+
from flwr.server.serverapp.app import flwr_serverapp
|
74
|
+
from flwr.simulation.app import flwr_simulation
|
71
75
|
from flwr.superexec.app import load_executor
|
72
76
|
from flwr.superexec.exec_grpc import run_exec_api_grpc
|
73
77
|
|
@@ -79,10 +83,7 @@ from .strategy import Strategy
|
|
79
83
|
from .superlink.driver.serverappio_grpc import run_serverappio_api_grpc
|
80
84
|
from .superlink.ffs.ffs_factory import FfsFactory
|
81
85
|
from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
|
82
|
-
from .superlink.fleet.grpc_bidi.grpc_server import
|
83
|
-
generic_create_grpc_server,
|
84
|
-
start_grpc_server,
|
85
|
-
)
|
86
|
+
from .superlink.fleet.grpc_bidi.grpc_server import start_grpc_server
|
86
87
|
from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
|
87
88
|
from .superlink.fleet.grpc_rere.server_interceptor import AuthenticateServerInterceptor
|
88
89
|
from .superlink.linkstate import LinkStateFactory
|
@@ -263,11 +264,10 @@ def run_superlink() -> None:
|
|
263
264
|
# Obtain certificates
|
264
265
|
certificates = try_obtain_server_certificates(args, args.fleet_api_type)
|
265
266
|
|
266
|
-
user_auth_config = _try_obtain_user_auth_config(args)
|
267
267
|
auth_plugin: Optional[ExecAuthPlugin] = None
|
268
|
-
#
|
269
|
-
if
|
270
|
-
auth_plugin = _try_obtain_exec_auth_plugin(
|
268
|
+
# Load the auth plugin if the args.user_auth_config is provided
|
269
|
+
if cfg_path := getattr(args, "user_auth_config", None):
|
270
|
+
auth_plugin = _try_obtain_exec_auth_plugin(Path(cfg_path))
|
271
271
|
|
272
272
|
# Initialize StateFactory
|
273
273
|
state_factory = LinkStateFactory(args.database)
|
@@ -293,7 +293,7 @@ def run_superlink() -> None:
|
|
293
293
|
# Determine Exec plugin
|
294
294
|
# If simulation is used, don't start ServerAppIo and Fleet APIs
|
295
295
|
sim_exec = executor.__class__.__qualname__ == "SimulationEngine"
|
296
|
-
bckg_threads = []
|
296
|
+
bckg_threads: list[threading.Thread] = []
|
297
297
|
|
298
298
|
if sim_exec:
|
299
299
|
simulationio_server: grpc.Server = run_simulationio_api_grpc(
|
@@ -361,6 +361,7 @@ def run_superlink() -> None:
|
|
361
361
|
ffs_factory,
|
362
362
|
num_workers,
|
363
363
|
),
|
364
|
+
daemon=True,
|
364
365
|
)
|
365
366
|
fleet_thread.start()
|
366
367
|
bckg_threads.append(fleet_thread)
|
@@ -374,6 +375,7 @@ def run_superlink() -> None:
|
|
374
375
|
server_public_key,
|
375
376
|
) = maybe_keys
|
376
377
|
state = state_factory.state()
|
378
|
+
state.clear_supernode_auth_keys_and_credentials()
|
377
379
|
state.store_node_public_keys(node_public_keys)
|
378
380
|
state.store_server_private_public_key(
|
379
381
|
private_key_to_bytes(server_private_key),
|
@@ -426,6 +428,7 @@ def run_superlink() -> None:
|
|
426
428
|
address,
|
427
429
|
cmd,
|
428
430
|
),
|
431
|
+
daemon=True,
|
429
432
|
)
|
430
433
|
scheduler_th.start()
|
431
434
|
bckg_threads.append(scheduler_th)
|
@@ -434,16 +437,24 @@ def run_superlink() -> None:
|
|
434
437
|
register_exit_handlers(
|
435
438
|
event_type=EventType.RUN_SUPERLINK_LEAVE,
|
436
439
|
grpc_servers=grpc_servers,
|
437
|
-
bckg_threads=bckg_threads,
|
438
440
|
)
|
439
441
|
|
440
|
-
# Block
|
441
|
-
while
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
442
|
+
# Block until a thread exits prematurely
|
443
|
+
while all(thread.is_alive() for thread in bckg_threads):
|
444
|
+
sleep(0.1)
|
445
|
+
|
446
|
+
# Exit if any thread has exited prematurely
|
447
|
+
sys.exit(1)
|
448
|
+
|
449
|
+
|
450
|
+
def _run_flwr_command(args: list[str]) -> None:
|
451
|
+
sys.argv = args
|
452
|
+
if args[0] == "flwr-serverapp":
|
453
|
+
flwr_serverapp()
|
454
|
+
elif args[0] == "flwr-simulation":
|
455
|
+
flwr_simulation()
|
456
|
+
else:
|
457
|
+
raise ValueError(f"Unknown command: {args[0]}")
|
447
458
|
|
448
459
|
|
449
460
|
def _flwr_scheduler(
|
@@ -453,15 +464,18 @@ def _flwr_scheduler(
|
|
453
464
|
cmd: str,
|
454
465
|
) -> None:
|
455
466
|
log(DEBUG, "Started %s scheduler thread.", cmd)
|
456
|
-
|
457
467
|
state = state_factory.state()
|
468
|
+
run_id_to_proc: dict[int, multiprocessing.context.SpawnProcess] = {}
|
469
|
+
|
470
|
+
# Use the "spawn" start method for multiprocessing.
|
471
|
+
mp_spawn_context = multiprocessing.get_context("spawn")
|
458
472
|
|
459
473
|
# Periodically check for a pending run in the LinkState
|
460
474
|
while True:
|
461
|
-
sleep(
|
475
|
+
sleep(0.1)
|
462
476
|
pending_run_id = state.get_pending_run_id()
|
463
477
|
|
464
|
-
if pending_run_id:
|
478
|
+
if pending_run_id and pending_run_id not in run_id_to_proc:
|
465
479
|
|
466
480
|
log(
|
467
481
|
INFO,
|
@@ -478,10 +492,18 @@ def _flwr_scheduler(
|
|
478
492
|
"--insecure",
|
479
493
|
]
|
480
494
|
|
481
|
-
|
482
|
-
command,
|
483
|
-
text=True,
|
495
|
+
proc = mp_spawn_context.Process(
|
496
|
+
target=_run_flwr_command, args=(command,), daemon=True
|
484
497
|
)
|
498
|
+
proc.start()
|
499
|
+
|
500
|
+
# Store the process
|
501
|
+
run_id_to_proc[pending_run_id] = proc
|
502
|
+
|
503
|
+
# Clean up finished processes
|
504
|
+
for run_id, proc in list(run_id_to_proc.items()):
|
505
|
+
if not proc.is_alive():
|
506
|
+
del run_id_to_proc[run_id]
|
485
507
|
|
486
508
|
|
487
509
|
def _format_address(address: str) -> tuple[str, str, int]:
|
@@ -583,21 +605,20 @@ def _try_setup_node_authentication(
|
|
583
605
|
)
|
584
606
|
|
585
607
|
|
586
|
-
def
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
return config
|
591
|
-
return None
|
592
|
-
|
608
|
+
def _try_obtain_exec_auth_plugin(config_path: Path) -> Optional[ExecAuthPlugin]:
|
609
|
+
# Load YAML file
|
610
|
+
with config_path.open("r", encoding="utf-8") as file:
|
611
|
+
config: dict[str, Any] = yaml.safe_load(file)
|
593
612
|
|
594
|
-
|
613
|
+
# Load authentication configuration
|
595
614
|
auth_config: dict[str, Any] = config.get("authentication", {})
|
596
615
|
auth_type: str = auth_config.get(AUTH_TYPE, "")
|
616
|
+
|
617
|
+
# Load authentication plugin
|
597
618
|
try:
|
598
619
|
all_plugins: dict[str, type[ExecAuthPlugin]] = get_exec_auth_plugins()
|
599
620
|
auth_plugin_class = all_plugins[auth_type]
|
600
|
-
return auth_plugin_class(
|
621
|
+
return auth_plugin_class(user_auth_config_path=config_path)
|
601
622
|
except KeyError:
|
602
623
|
if auth_type != "":
|
603
624
|
sys.exit(
|