flwr 1.22.0__py3-none-any.whl → 1.24.0__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/__init__.py +16 -5
- flwr/app/error.py +2 -2
- flwr/app/exception.py +3 -3
- flwr/cli/app.py +34 -1
- flwr/cli/app_cmd/__init__.py +23 -0
- flwr/cli/app_cmd/publish.py +285 -0
- flwr/cli/app_cmd/review.py +252 -0
- flwr/cli/auth_plugin/__init__.py +15 -6
- flwr/cli/auth_plugin/auth_plugin.py +94 -0
- flwr/cli/auth_plugin/noop_auth_plugin.py +101 -0
- flwr/cli/auth_plugin/oidc_cli_plugin.py +46 -32
- flwr/cli/build.py +166 -53
- flwr/cli/{cli_user_auth_interceptor.py → cli_account_auth_interceptor.py} +29 -11
- flwr/cli/config_utils.py +101 -13
- flwr/cli/federation/__init__.py +24 -0
- flwr/cli/federation/ls.py +140 -0
- flwr/cli/federation/show.py +317 -0
- flwr/cli/install.py +91 -13
- flwr/cli/log.py +54 -11
- flwr/cli/login/login.py +41 -27
- flwr/cli/ls.py +177 -133
- flwr/cli/new/new.py +175 -40
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl +1 -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.pytorch_legacy_api.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
- flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +1 -1
- flwr/cli/pull.py +12 -7
- flwr/cli/run/run.py +82 -31
- flwr/cli/run_utils.py +130 -0
- flwr/cli/stop.py +27 -9
- flwr/cli/supernode/__init__.py +25 -0
- flwr/cli/supernode/ls.py +268 -0
- flwr/cli/supernode/register.py +190 -0
- flwr/cli/supernode/unregister.py +140 -0
- flwr/cli/utils.py +464 -81
- flwr/client/__init__.py +2 -1
- flwr/client/dpfedavg_numpy_client.py +4 -1
- flwr/client/grpc_adapter_client/connection.py +12 -15
- flwr/client/grpc_rere_client/connection.py +68 -41
- flwr/client/grpc_rere_client/grpc_adapter.py +34 -14
- flwr/client/grpc_rere_client/{client_interceptor.py → node_auth_client_interceptor.py} +5 -7
- flwr/client/message_handler/message_handler.py +2 -2
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +10 -8
- flwr/client/numpy_client.py +1 -1
- flwr/client/rest_client/connection.py +94 -51
- flwr/client/run_info_store.py +4 -5
- flwr/client/typing.py +1 -1
- flwr/clientapp/__init__.py +1 -2
- flwr/{client → clientapp}/client_app.py +9 -10
- flwr/clientapp/mod/centraldp_mods.py +16 -17
- flwr/clientapp/mod/localdp_mod.py +8 -9
- flwr/clientapp/typing.py +1 -1
- flwr/{client/clientapp → clientapp}/utils.py +4 -4
- flwr/common/address.py +1 -2
- flwr/common/args.py +3 -4
- flwr/common/config.py +13 -16
- flwr/common/constant.py +56 -13
- flwr/common/differential_privacy.py +3 -4
- flwr/common/event_log_plugin/event_log_plugin.py +3 -4
- flwr/common/exit/exit.py +15 -2
- flwr/common/exit/exit_code.py +39 -10
- flwr/common/exit/exit_handler.py +6 -2
- flwr/common/exit/signal_handler.py +5 -5
- flwr/common/grpc.py +6 -6
- flwr/common/inflatable_protobuf_utils.py +1 -1
- flwr/common/inflatable_utils.py +48 -31
- flwr/common/logger.py +19 -19
- flwr/common/message.py +4 -4
- flwr/common/object_ref.py +7 -7
- flwr/common/record/array.py +6 -6
- flwr/common/record/arrayrecord.py +18 -21
- flwr/common/record/configrecord.py +3 -3
- flwr/common/record/recorddict.py +5 -5
- flwr/common/record/typeddict.py +9 -2
- flwr/common/recorddict_compat.py +7 -10
- flwr/common/retry_invoker.py +20 -20
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +1 -89
- flwr/common/secure_aggregation/ndarrays_arithmetic.py +3 -3
- flwr/common/serde.py +9 -6
- flwr/common/serde_utils.py +2 -2
- flwr/common/telemetry.py +9 -5
- flwr/common/typing.py +59 -43
- flwr/compat/client/app.py +39 -38
- flwr/compat/client/grpc_client/connection.py +13 -13
- flwr/compat/server/app.py +5 -6
- flwr/proto/appio_pb2.py +13 -3
- flwr/proto/appio_pb2.pyi +134 -65
- flwr/proto/appio_pb2_grpc.py +20 -0
- flwr/proto/appio_pb2_grpc.pyi +27 -0
- flwr/proto/clientappio_pb2.py +17 -7
- flwr/proto/clientappio_pb2.pyi +15 -0
- flwr/proto/clientappio_pb2_grpc.py +206 -40
- flwr/proto/clientappio_pb2_grpc.pyi +168 -53
- flwr/proto/control_pb2.py +72 -40
- flwr/proto/control_pb2.pyi +319 -87
- flwr/proto/control_pb2_grpc.py +339 -28
- flwr/proto/control_pb2_grpc.pyi +209 -37
- flwr/proto/error_pb2.py +13 -3
- flwr/proto/error_pb2.pyi +24 -6
- flwr/proto/error_pb2_grpc.py +20 -0
- flwr/proto/error_pb2_grpc.pyi +27 -0
- flwr/proto/fab_pb2.py +24 -10
- flwr/proto/fab_pb2.pyi +68 -20
- flwr/proto/fab_pb2_grpc.py +20 -0
- flwr/proto/fab_pb2_grpc.pyi +27 -0
- flwr/proto/federation_pb2.py +38 -0
- flwr/proto/federation_pb2.pyi +56 -0
- flwr/proto/federation_pb2_grpc.py +24 -0
- flwr/proto/federation_pb2_grpc.pyi +31 -0
- flwr/proto/fleet_pb2.py +45 -27
- flwr/proto/fleet_pb2.pyi +186 -70
- flwr/proto/fleet_pb2_grpc.py +277 -66
- flwr/proto/fleet_pb2_grpc.pyi +201 -55
- flwr/proto/grpcadapter_pb2.py +14 -4
- flwr/proto/grpcadapter_pb2.pyi +38 -16
- flwr/proto/grpcadapter_pb2_grpc.py +35 -4
- flwr/proto/grpcadapter_pb2_grpc.pyi +38 -7
- flwr/proto/heartbeat_pb2.py +17 -7
- flwr/proto/heartbeat_pb2.pyi +51 -22
- flwr/proto/heartbeat_pb2_grpc.py +20 -0
- flwr/proto/heartbeat_pb2_grpc.pyi +27 -0
- flwr/proto/log_pb2.py +13 -3
- flwr/proto/log_pb2.pyi +34 -11
- flwr/proto/log_pb2_grpc.py +20 -0
- flwr/proto/log_pb2_grpc.pyi +27 -0
- flwr/proto/message_pb2.py +15 -5
- flwr/proto/message_pb2.pyi +154 -86
- flwr/proto/message_pb2_grpc.py +20 -0
- flwr/proto/message_pb2_grpc.pyi +27 -0
- flwr/proto/node_pb2.py +16 -4
- flwr/proto/node_pb2.pyi +77 -4
- flwr/proto/node_pb2_grpc.py +20 -0
- flwr/proto/node_pb2_grpc.pyi +27 -0
- flwr/proto/recorddict_pb2.py +13 -3
- flwr/proto/recorddict_pb2.pyi +184 -107
- flwr/proto/recorddict_pb2_grpc.py +20 -0
- flwr/proto/recorddict_pb2_grpc.pyi +27 -0
- flwr/proto/run_pb2.py +40 -31
- flwr/proto/run_pb2.pyi +149 -84
- flwr/proto/run_pb2_grpc.py +20 -0
- flwr/proto/run_pb2_grpc.pyi +27 -0
- flwr/proto/serverappio_pb2.py +13 -3
- flwr/proto/serverappio_pb2.pyi +32 -8
- flwr/proto/serverappio_pb2_grpc.py +246 -65
- flwr/proto/serverappio_pb2_grpc.pyi +221 -85
- flwr/proto/simulationio_pb2.py +16 -8
- flwr/proto/simulationio_pb2.pyi +15 -0
- flwr/proto/simulationio_pb2_grpc.py +162 -41
- flwr/proto/simulationio_pb2_grpc.pyi +149 -55
- flwr/proto/transport_pb2.py +20 -10
- flwr/proto/transport_pb2.pyi +249 -160
- flwr/proto/transport_pb2_grpc.py +35 -4
- flwr/proto/transport_pb2_grpc.pyi +38 -8
- flwr/server/app.py +173 -127
- flwr/server/client_manager.py +4 -5
- flwr/server/client_proxy.py +10 -11
- flwr/server/compat/app.py +4 -5
- flwr/server/compat/app_utils.py +2 -1
- flwr/server/compat/grid_client_proxy.py +10 -12
- flwr/server/compat/legacy_context.py +3 -4
- flwr/server/fleet_event_log_interceptor.py +2 -1
- flwr/server/grid/grid.py +2 -3
- flwr/server/grid/grpc_grid.py +10 -8
- flwr/server/grid/inmemory_grid.py +4 -4
- flwr/server/run_serverapp.py +2 -3
- flwr/server/server.py +34 -39
- flwr/server/server_app.py +7 -8
- flwr/server/server_config.py +1 -2
- flwr/server/serverapp/app.py +34 -28
- flwr/server/serverapp_components.py +4 -5
- flwr/server/strategy/aggregate.py +9 -8
- flwr/server/strategy/bulyan.py +13 -11
- flwr/server/strategy/dp_adaptive_clipping.py +16 -20
- flwr/server/strategy/dp_fixed_clipping.py +12 -17
- flwr/server/strategy/dpfedavg_adaptive.py +3 -4
- flwr/server/strategy/dpfedavg_fixed.py +6 -10
- flwr/server/strategy/fault_tolerant_fedavg.py +14 -13
- flwr/server/strategy/fedadagrad.py +18 -14
- flwr/server/strategy/fedadam.py +16 -14
- flwr/server/strategy/fedavg.py +16 -17
- flwr/server/strategy/fedavg_android.py +15 -15
- flwr/server/strategy/fedavgm.py +21 -18
- flwr/server/strategy/fedmedian.py +2 -3
- flwr/server/strategy/fedopt.py +11 -10
- flwr/server/strategy/fedprox.py +10 -9
- flwr/server/strategy/fedtrimmedavg.py +12 -11
- flwr/server/strategy/fedxgb_bagging.py +13 -11
- flwr/server/strategy/fedxgb_cyclic.py +6 -6
- flwr/server/strategy/fedxgb_nn_avg.py +4 -4
- flwr/server/strategy/fedyogi.py +16 -14
- flwr/server/strategy/krum.py +12 -11
- flwr/server/strategy/qfedavg.py +16 -15
- flwr/server/strategy/strategy.py +6 -9
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +19 -8
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -2
- flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +3 -4
- flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +10 -12
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +1 -3
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +136 -42
- flwr/server/superlink/fleet/grpc_rere/{server_interceptor.py → node_auth_server_interceptor.py} +28 -51
- flwr/server/superlink/fleet/message_handler/message_handler.py +100 -49
- flwr/server/superlink/fleet/rest_rere/rest_api.py +54 -33
- flwr/server/superlink/fleet/vce/backend/backend.py +2 -2
- flwr/server/superlink/fleet/vce/backend/raybackend.py +6 -6
- flwr/server/superlink/fleet/vce/vce_api.py +32 -13
- flwr/server/superlink/linkstate/in_memory_linkstate.py +266 -207
- flwr/server/superlink/linkstate/linkstate.py +161 -62
- flwr/server/superlink/linkstate/linkstate_factory.py +24 -6
- flwr/server/superlink/linkstate/sqlite_linkstate.py +698 -638
- flwr/server/superlink/linkstate/utils.py +9 -60
- flwr/server/superlink/serverappio/serverappio_grpc.py +1 -2
- flwr/server/superlink/serverappio/serverappio_servicer.py +28 -23
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -2
- flwr/server/superlink/simulation/simulationio_servicer.py +19 -14
- flwr/server/superlink/utils.py +4 -6
- flwr/server/typing.py +1 -1
- flwr/server/utils/tensorboard.py +15 -8
- flwr/server/utils/validator.py +2 -3
- flwr/server/workflow/default_workflows.py +5 -5
- flwr/server/workflow/secure_aggregation/secagg_workflow.py +2 -4
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +12 -10
- flwr/serverapp/strategy/bulyan.py +16 -15
- flwr/serverapp/strategy/dp_adaptive_clipping.py +12 -11
- flwr/serverapp/strategy/dp_fixed_clipping.py +11 -14
- flwr/serverapp/strategy/fedadagrad.py +10 -11
- flwr/serverapp/strategy/fedadam.py +10 -11
- flwr/serverapp/strategy/fedavg.py +9 -10
- flwr/serverapp/strategy/fedavgm.py +17 -16
- flwr/serverapp/strategy/fedmedian.py +2 -2
- flwr/serverapp/strategy/fedopt.py +10 -11
- flwr/serverapp/strategy/fedprox.py +7 -8
- flwr/serverapp/strategy/fedtrimmedavg.py +9 -9
- flwr/serverapp/strategy/fedxgb_bagging.py +3 -3
- flwr/serverapp/strategy/fedxgb_cyclic.py +9 -9
- flwr/serverapp/strategy/fedyogi.py +9 -11
- flwr/serverapp/strategy/krum.py +7 -7
- flwr/serverapp/strategy/multikrum.py +9 -9
- flwr/serverapp/strategy/qfedavg.py +17 -16
- flwr/serverapp/strategy/strategy.py +6 -9
- flwr/serverapp/strategy/strategy_utils.py +7 -8
- flwr/simulation/app.py +46 -42
- flwr/simulation/legacy_app.py +12 -12
- flwr/simulation/ray_transport/ray_actor.py +11 -12
- flwr/simulation/ray_transport/ray_client_proxy.py +12 -13
- flwr/simulation/run_simulation.py +44 -43
- flwr/simulation/simulationio_connection.py +4 -4
- flwr/supercore/cli/flower_superexec.py +3 -4
- flwr/supercore/constant.py +52 -0
- flwr/supercore/corestate/corestate.py +24 -3
- flwr/supercore/corestate/in_memory_corestate.py +138 -0
- flwr/supercore/corestate/sqlite_corestate.py +157 -0
- flwr/supercore/ffs/disk_ffs.py +1 -2
- flwr/supercore/ffs/ffs.py +1 -2
- flwr/supercore/ffs/ffs_factory.py +1 -2
- flwr/{common → supercore}/heartbeat.py +20 -25
- flwr/supercore/object_store/in_memory_object_store.py +1 -6
- flwr/supercore/object_store/object_store.py +1 -2
- flwr/supercore/object_store/object_store_factory.py +27 -8
- flwr/supercore/object_store/sqlite_object_store.py +253 -0
- flwr/{client/clientapp → supercore/primitives}/__init__.py +1 -1
- flwr/supercore/primitives/asymmetric.py +117 -0
- flwr/supercore/primitives/asymmetric_ed25519.py +175 -0
- flwr/supercore/sqlite_mixin.py +159 -0
- flwr/supercore/superexec/plugin/base_exec_plugin.py +1 -2
- flwr/supercore/superexec/plugin/exec_plugin.py +3 -3
- flwr/supercore/superexec/run_superexec.py +9 -13
- flwr/supercore/utils.py +20 -0
- flwr/superlink/artifact_provider/artifact_provider.py +1 -2
- flwr/{common → superlink}/auth_plugin/__init__.py +6 -6
- flwr/superlink/auth_plugin/auth_plugin.py +88 -0
- flwr/superlink/auth_plugin/noop_auth_plugin.py +84 -0
- flwr/superlink/federation/__init__.py +24 -0
- flwr/superlink/federation/federation_manager.py +64 -0
- flwr/superlink/federation/noop_federation_manager.py +71 -0
- flwr/superlink/servicer/control/{control_user_auth_interceptor.py → control_account_auth_interceptor.py} +41 -32
- flwr/superlink/servicer/control/control_event_log_interceptor.py +7 -7
- flwr/superlink/servicer/control/control_grpc.py +18 -17
- flwr/superlink/servicer/control/control_license_interceptor.py +3 -3
- flwr/superlink/servicer/control/control_servicer.py +239 -63
- flwr/supernode/cli/flower_supernode.py +74 -26
- flwr/supernode/nodestate/in_memory_nodestate.py +60 -49
- flwr/supernode/nodestate/nodestate.py +7 -8
- flwr/supernode/nodestate/nodestate_factory.py +7 -4
- flwr/supernode/runtime/run_clientapp.py +43 -24
- flwr/supernode/servicer/clientappio/clientappio_servicer.py +40 -10
- flwr/supernode/start_client_internal.py +175 -51
- {flwr-1.22.0.dist-info → flwr-1.24.0.dist-info}/METADATA +8 -8
- flwr-1.24.0.dist-info/RECORD +454 -0
- flwr/common/auth_plugin/auth_plugin.py +0 -149
- flwr/supercore/object_store/utils.py +0 -43
- flwr-1.22.0.dist-info/RECORD +0 -428
- {flwr-1.22.0.dist-info → flwr-1.24.0.dist-info}/WHEEL +0 -0
- {flwr-1.22.0.dist-info → flwr-1.24.0.dist-info}/entry_points.txt +0 -0
flwr/proto/transport_pb2_grpc.py
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
|
2
2
|
"""Client and server classes corresponding to protobuf-defined services."""
|
|
3
3
|
import grpc
|
|
4
|
+
import warnings
|
|
4
5
|
|
|
5
6
|
from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
|
|
6
7
|
|
|
8
|
+
GRPC_GENERATED_VERSION = '1.70.0'
|
|
9
|
+
GRPC_VERSION = grpc.__version__
|
|
10
|
+
_version_not_supported = False
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from grpc._utilities import first_version_is_lower
|
|
14
|
+
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
|
15
|
+
except ImportError:
|
|
16
|
+
_version_not_supported = True
|
|
17
|
+
|
|
18
|
+
if _version_not_supported:
|
|
19
|
+
raise RuntimeError(
|
|
20
|
+
f'The grpc package installed is at version {GRPC_VERSION},'
|
|
21
|
+
+ f' but the generated code in flwr/proto/transport_pb2_grpc.py depends on'
|
|
22
|
+
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
|
23
|
+
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
|
24
|
+
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
|
25
|
+
)
|
|
26
|
+
|
|
7
27
|
|
|
8
28
|
class FlowerServiceStub(object):
|
|
9
29
|
"""Missing associated documentation comment in .proto file."""
|
|
@@ -18,7 +38,7 @@ class FlowerServiceStub(object):
|
|
|
18
38
|
'/flwr.proto.FlowerService/Join',
|
|
19
39
|
request_serializer=flwr_dot_proto_dot_transport__pb2.ClientMessage.SerializeToString,
|
|
20
40
|
response_deserializer=flwr_dot_proto_dot_transport__pb2.ServerMessage.FromString,
|
|
21
|
-
)
|
|
41
|
+
_registered_method=True)
|
|
22
42
|
|
|
23
43
|
|
|
24
44
|
class FlowerServiceServicer(object):
|
|
@@ -42,6 +62,7 @@ def add_FlowerServiceServicer_to_server(servicer, server):
|
|
|
42
62
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
43
63
|
'flwr.proto.FlowerService', rpc_method_handlers)
|
|
44
64
|
server.add_generic_rpc_handlers((generic_handler,))
|
|
65
|
+
server.add_registered_method_handlers('flwr.proto.FlowerService', rpc_method_handlers)
|
|
45
66
|
|
|
46
67
|
|
|
47
68
|
# This class is part of an EXPERIMENTAL API.
|
|
@@ -59,8 +80,18 @@ class FlowerService(object):
|
|
|
59
80
|
wait_for_ready=None,
|
|
60
81
|
timeout=None,
|
|
61
82
|
metadata=None):
|
|
62
|
-
return grpc.experimental.stream_stream(
|
|
83
|
+
return grpc.experimental.stream_stream(
|
|
84
|
+
request_iterator,
|
|
85
|
+
target,
|
|
86
|
+
'/flwr.proto.FlowerService/Join',
|
|
63
87
|
flwr_dot_proto_dot_transport__pb2.ClientMessage.SerializeToString,
|
|
64
88
|
flwr_dot_proto_dot_transport__pb2.ServerMessage.FromString,
|
|
65
|
-
options,
|
|
66
|
-
|
|
89
|
+
options,
|
|
90
|
+
channel_credentials,
|
|
91
|
+
insecure,
|
|
92
|
+
call_credentials,
|
|
93
|
+
compression,
|
|
94
|
+
wait_for_ready,
|
|
95
|
+
timeout,
|
|
96
|
+
metadata,
|
|
97
|
+
_registered_method=True)
|
|
@@ -1,25 +1,55 @@
|
|
|
1
1
|
"""
|
|
2
2
|
@generated by mypy-protobuf. Do not edit manually!
|
|
3
3
|
isort:skip_file
|
|
4
|
+
Copyright 2020 Flower Labs GmbH. All Rights Reserved.
|
|
5
|
+
|
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
you may not use this file except in compliance with the License.
|
|
8
|
+
You may obtain a copy of the License at
|
|
9
|
+
|
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
|
|
12
|
+
Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
See the License for the specific language governing permissions and
|
|
16
|
+
limitations under the License.
|
|
17
|
+
==============================================================================
|
|
4
18
|
"""
|
|
19
|
+
|
|
5
20
|
import abc
|
|
21
|
+
import collections.abc
|
|
6
22
|
import flwr.proto.transport_pb2
|
|
7
23
|
import grpc
|
|
24
|
+
import grpc.aio
|
|
8
25
|
import typing
|
|
9
26
|
|
|
27
|
+
_T = typing.TypeVar("_T")
|
|
28
|
+
|
|
29
|
+
class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ...
|
|
30
|
+
|
|
31
|
+
class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg]
|
|
32
|
+
...
|
|
33
|
+
|
|
10
34
|
class FlowerServiceStub:
|
|
11
|
-
def __init__(self, channel: grpc.Channel) -> None: ...
|
|
35
|
+
def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ...
|
|
12
36
|
Join: grpc.StreamStreamMultiCallable[
|
|
13
37
|
flwr.proto.transport_pb2.ClientMessage,
|
|
14
|
-
flwr.proto.transport_pb2.ServerMessage
|
|
38
|
+
flwr.proto.transport_pb2.ServerMessage,
|
|
39
|
+
]
|
|
15
40
|
|
|
41
|
+
class FlowerServiceAsyncStub:
|
|
42
|
+
Join: grpc.aio.StreamStreamMultiCallable[
|
|
43
|
+
flwr.proto.transport_pb2.ClientMessage,
|
|
44
|
+
flwr.proto.transport_pb2.ServerMessage,
|
|
45
|
+
]
|
|
16
46
|
|
|
17
47
|
class FlowerServiceServicer(metaclass=abc.ABCMeta):
|
|
18
48
|
@abc.abstractmethod
|
|
19
|
-
def Join(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
49
|
+
def Join(
|
|
50
|
+
self,
|
|
51
|
+
request_iterator: _MaybeAsyncIterator[flwr.proto.transport_pb2.ClientMessage],
|
|
52
|
+
context: _ServicerContext,
|
|
53
|
+
) -> typing.Union[collections.abc.Iterator[flwr.proto.transport_pb2.ServerMessage], collections.abc.AsyncIterator[flwr.proto.transport_pb2.ServerMessage]]: ...
|
|
24
54
|
|
|
25
|
-
def add_FlowerServiceServicer_to_server(servicer: FlowerServiceServicer, server: grpc.Server) -> None: ...
|
|
55
|
+
def add_FlowerServiceServicer_to_server(servicer: FlowerServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ...
|
flwr/server/app.py
CHANGED
|
@@ -16,30 +16,26 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import argparse
|
|
19
|
-
import csv
|
|
20
19
|
import importlib.util
|
|
21
20
|
import os
|
|
22
21
|
import subprocess
|
|
23
22
|
import sys
|
|
24
23
|
import threading
|
|
25
|
-
from collections.abc import Sequence
|
|
26
|
-
from logging import
|
|
24
|
+
from collections.abc import Callable, Sequence
|
|
25
|
+
from logging import INFO, WARN
|
|
27
26
|
from pathlib import Path
|
|
28
27
|
from time import sleep
|
|
29
|
-
from typing import
|
|
28
|
+
from typing import TypeVar, cast
|
|
30
29
|
|
|
31
30
|
import grpc
|
|
32
31
|
import yaml
|
|
33
|
-
from cryptography.hazmat.primitives.asymmetric import ec
|
|
34
|
-
from cryptography.hazmat.primitives.serialization import load_ssh_public_key
|
|
35
32
|
|
|
36
33
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
|
|
37
34
|
from flwr.common.address import parse_address
|
|
38
35
|
from flwr.common.args import try_obtain_server_certificates
|
|
39
|
-
from flwr.common.auth_plugin import ControlAuthPlugin, ControlAuthzPlugin
|
|
40
36
|
from flwr.common.config import get_flwr_dir
|
|
41
37
|
from flwr.common.constant import (
|
|
42
|
-
|
|
38
|
+
AUTHN_TYPE_YAML_KEY,
|
|
43
39
|
AUTHZ_TYPE_YAML_KEY,
|
|
44
40
|
CLIENT_OCTET,
|
|
45
41
|
CONTROL_API_DEFAULT_SERVER_ADDRESS,
|
|
@@ -53,6 +49,8 @@ from flwr.common.constant import (
|
|
|
53
49
|
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
54
50
|
TRANSPORT_TYPE_GRPC_RERE,
|
|
55
51
|
TRANSPORT_TYPE_REST,
|
|
52
|
+
AuthnType,
|
|
53
|
+
AuthzType,
|
|
56
54
|
EventLogWriterType,
|
|
57
55
|
ExecPluginType,
|
|
58
56
|
)
|
|
@@ -60,39 +58,47 @@ from flwr.common.event_log_plugin import EventLogWriterPlugin
|
|
|
60
58
|
from flwr.common.exit import ExitCode, flwr_exit, register_signal_handlers
|
|
61
59
|
from flwr.common.grpc import generic_create_grpc_server
|
|
62
60
|
from flwr.common.logger import log
|
|
63
|
-
from flwr.common.
|
|
64
|
-
public_key_to_bytes,
|
|
65
|
-
)
|
|
61
|
+
from flwr.common.version import package_version
|
|
66
62
|
from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
67
63
|
add_FleetServicer_to_server,
|
|
68
64
|
)
|
|
69
65
|
from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
|
|
70
66
|
from flwr.server.fleet_event_log_interceptor import FleetEventLogInterceptor
|
|
67
|
+
from flwr.supercore.constant import FLWR_IN_MEMORY_DB_NAME
|
|
71
68
|
from flwr.supercore.ffs import FfsFactory
|
|
72
69
|
from flwr.supercore.grpc_health import add_args_health, run_health_server_grpc_no_tls
|
|
73
70
|
from flwr.supercore.object_store import ObjectStoreFactory
|
|
74
71
|
from flwr.superlink.artifact_provider import ArtifactProvider
|
|
72
|
+
from flwr.superlink.auth_plugin import (
|
|
73
|
+
ControlAuthnPlugin,
|
|
74
|
+
ControlAuthzPlugin,
|
|
75
|
+
NoOpControlAuthnPlugin,
|
|
76
|
+
NoOpControlAuthzPlugin,
|
|
77
|
+
)
|
|
78
|
+
from flwr.superlink.federation import FederationManager, NoOpFederationManager
|
|
75
79
|
from flwr.superlink.servicer.control import run_control_api_grpc
|
|
76
80
|
|
|
77
81
|
from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
|
|
78
82
|
from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
|
|
79
|
-
from .superlink.fleet.grpc_rere.
|
|
83
|
+
from .superlink.fleet.grpc_rere.node_auth_server_interceptor import (
|
|
84
|
+
NodeAuthServerInterceptor,
|
|
85
|
+
)
|
|
80
86
|
from .superlink.linkstate import LinkStateFactory
|
|
81
87
|
from .superlink.serverappio.serverappio_grpc import run_serverappio_api_grpc
|
|
82
88
|
from .superlink.simulation.simulationio_grpc import run_simulationio_api_grpc
|
|
83
89
|
|
|
84
|
-
DATABASE = ":flwr-in-memory-state:"
|
|
85
90
|
BASE_DIR = get_flwr_dir() / "superlink" / "ffs"
|
|
86
|
-
P = TypeVar("P",
|
|
91
|
+
P = TypeVar("P", ControlAuthnPlugin, ControlAuthzPlugin)
|
|
87
92
|
|
|
88
93
|
|
|
89
94
|
try:
|
|
90
95
|
from flwr.ee import (
|
|
91
96
|
add_ee_args_superlink,
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
get_control_authn_ee_plugins,
|
|
98
|
+
get_control_authz_ee_plugins,
|
|
94
99
|
get_control_event_log_writer_plugins,
|
|
95
100
|
get_ee_artifact_provider,
|
|
101
|
+
get_ee_federation_manager,
|
|
96
102
|
get_fleet_event_log_writer_plugins,
|
|
97
103
|
)
|
|
98
104
|
except ImportError:
|
|
@@ -101,14 +107,6 @@ except ImportError:
|
|
|
101
107
|
def add_ee_args_superlink(parser: argparse.ArgumentParser) -> None:
|
|
102
108
|
"""Add EE-specific arguments to the parser."""
|
|
103
109
|
|
|
104
|
-
def get_control_auth_plugins() -> dict[str, type[ControlAuthPlugin]]:
|
|
105
|
-
"""Return all Control API authentication plugins."""
|
|
106
|
-
raise NotImplementedError("No authentication plugins are currently supported.")
|
|
107
|
-
|
|
108
|
-
def get_control_authz_plugins() -> dict[str, type[ControlAuthzPlugin]]:
|
|
109
|
-
"""Return all Control API authorization plugins."""
|
|
110
|
-
raise NotImplementedError("No authorization plugins are currently supported.")
|
|
111
|
-
|
|
112
110
|
def get_control_event_log_writer_plugins() -> dict[str, type[EventLogWriterPlugin]]:
|
|
113
111
|
"""Return all Control API event log writer plugins."""
|
|
114
112
|
raise NotImplementedError(
|
|
@@ -125,6 +123,39 @@ except ImportError:
|
|
|
125
123
|
"No event log writer plugins are currently supported."
|
|
126
124
|
)
|
|
127
125
|
|
|
126
|
+
def get_control_authn_ee_plugins() -> dict[str, type[ControlAuthnPlugin]]:
|
|
127
|
+
"""Return all Control API authentication plugins for EE."""
|
|
128
|
+
return {}
|
|
129
|
+
|
|
130
|
+
def get_control_authz_ee_plugins() -> dict[str, type[ControlAuthzPlugin]]:
|
|
131
|
+
"""Return all Control API authorization plugins for EE."""
|
|
132
|
+
return {}
|
|
133
|
+
|
|
134
|
+
# pylint: disable-next=unused-argument
|
|
135
|
+
def get_ee_federation_manager(config_path: str) -> FederationManager:
|
|
136
|
+
"""Return the EE FederationManager."""
|
|
137
|
+
raise NotImplementedError("No federation manager is currently supported.")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_control_authn_plugins() -> dict[str, type[ControlAuthnPlugin]]:
|
|
141
|
+
"""Return all Control API authentication plugins."""
|
|
142
|
+
ee_dict: dict[str, type[ControlAuthnPlugin]] = get_control_authn_ee_plugins()
|
|
143
|
+
return ee_dict | {AuthnType.NOOP: NoOpControlAuthnPlugin}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_control_authz_plugins() -> dict[str, type[ControlAuthzPlugin]]:
|
|
147
|
+
"""Return all Control API authorization plugins."""
|
|
148
|
+
ee_dict: dict[str, type[ControlAuthzPlugin]] = get_control_authz_ee_plugins()
|
|
149
|
+
return ee_dict | {AuthzType.NOOP: NoOpControlAuthzPlugin}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_federation_manager(config_path: str | None = None) -> FederationManager:
|
|
153
|
+
"""Return the FederationManager."""
|
|
154
|
+
if config_path is None:
|
|
155
|
+
return NoOpFederationManager()
|
|
156
|
+
federation_manager: FederationManager = get_ee_federation_manager(config_path)
|
|
157
|
+
return federation_manager
|
|
158
|
+
|
|
128
159
|
|
|
129
160
|
# pylint: disable=too-many-branches, too-many-locals, too-many-statements
|
|
130
161
|
def run_superlink() -> None:
|
|
@@ -189,18 +220,24 @@ def run_superlink() -> None:
|
|
|
189
220
|
# Obtain certificates
|
|
190
221
|
certificates = try_obtain_server_certificates(args)
|
|
191
222
|
|
|
192
|
-
# Disable the
|
|
223
|
+
# Disable the account auth TLS check if args.disable_oidc_tls_cert_verification is
|
|
193
224
|
# provided
|
|
194
225
|
verify_tls_cert = not getattr(args, "disable_oidc_tls_cert_verification", None)
|
|
195
226
|
|
|
196
|
-
|
|
197
|
-
authz_plugin:
|
|
198
|
-
event_log_plugin:
|
|
199
|
-
# Load the auth plugin if the args.
|
|
227
|
+
authn_plugin: ControlAuthnPlugin | None = None
|
|
228
|
+
authz_plugin: ControlAuthzPlugin | None = None
|
|
229
|
+
event_log_plugin: EventLogWriterPlugin | None = None
|
|
230
|
+
# Load the auth plugin if the args.account_auth_config is provided
|
|
200
231
|
if cfg_path := getattr(args, "user_auth_config", None):
|
|
201
|
-
|
|
202
|
-
|
|
232
|
+
log(
|
|
233
|
+
WARN,
|
|
234
|
+
"The `--user-auth-config` flag is deprecated and will be removed in a "
|
|
235
|
+
"future release. Please use `--account-auth-config` instead.",
|
|
203
236
|
)
|
|
237
|
+
args.account_auth_config = cfg_path
|
|
238
|
+
cfg_path = getattr(args, "account_auth_config", None)
|
|
239
|
+
authn_plugin, authz_plugin = _load_control_auth_plugins(cfg_path, verify_tls_cert)
|
|
240
|
+
if cfg_path is not None:
|
|
204
241
|
# Enable event logging if the args.enable_event_log is True
|
|
205
242
|
if args.enable_event_log:
|
|
206
243
|
event_log_plugin = _try_obtain_control_event_log_writer_plugin()
|
|
@@ -211,15 +248,69 @@ def run_superlink() -> None:
|
|
|
211
248
|
log(WARN, "The `--artifact-provider-config` flag is highly experimental.")
|
|
212
249
|
artifact_provider = get_ee_artifact_provider(cfg_path)
|
|
213
250
|
|
|
251
|
+
# Check for incompatible args with SuperNode authentication
|
|
252
|
+
enable_supernode_auth: bool = args.enable_supernode_auth
|
|
253
|
+
if enable_supernode_auth:
|
|
254
|
+
if args.insecure:
|
|
255
|
+
url_v = f"https://flower.ai/docs/framework/v{package_version}/en/"
|
|
256
|
+
page = "how-to-authenticate-supernodes.html"
|
|
257
|
+
flwr_exit(
|
|
258
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
|
259
|
+
"The `--enable-supernode-auth` flag requires encrypted TLS "
|
|
260
|
+
"communications. Please provide TLS certificates using the "
|
|
261
|
+
"`--ssl-certfile`, `--ssl-keyfile` and `--ssl-ca-certfile` "
|
|
262
|
+
"arguments to your SuperLink. Please refer to the Flower "
|
|
263
|
+
f"documentation for more information: {url_v}{page}",
|
|
264
|
+
)
|
|
265
|
+
if args.fleet_api_type != TRANSPORT_TYPE_GRPC_RERE:
|
|
266
|
+
flwr_exit(
|
|
267
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
|
268
|
+
"The `--enable-supernode-auth` flag is only supported "
|
|
269
|
+
"with the gRPC-rere Fleet API transport. Please set "
|
|
270
|
+
f"`--fleet-api-type` to `{TRANSPORT_TYPE_GRPC_RERE}`.",
|
|
271
|
+
)
|
|
272
|
+
if args.simulation:
|
|
273
|
+
log(
|
|
274
|
+
WARN,
|
|
275
|
+
"SuperNode authentication is not applicable with the simulation, "
|
|
276
|
+
"runtime as no SuperNodes can connect to this SuperLink. "
|
|
277
|
+
"Proceeding...",
|
|
278
|
+
)
|
|
279
|
+
# If supernode authentication is disabled, warn users
|
|
280
|
+
else:
|
|
281
|
+
log(
|
|
282
|
+
WARN,
|
|
283
|
+
"SuperNode authentication is disabled. The SuperLink will accept "
|
|
284
|
+
"connections from any SuperNode.",
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
if args.auth_list_public_keys:
|
|
288
|
+
url_v = f"https://flower.ai/docs/framework/v{package_version}/en/"
|
|
289
|
+
page = "how-to-authenticate-supernodes.html"
|
|
290
|
+
flwr_exit(
|
|
291
|
+
ExitCode.SUPERLINK_INVALID_ARGS,
|
|
292
|
+
"The `--auth-list-public-keys` "
|
|
293
|
+
"argument is no longer supported. To enable SuperNode authentication, "
|
|
294
|
+
"use the `--enable-supernode-auth` flag and use the Flower CLI to register "
|
|
295
|
+
"SuperNodes by supplying their public keys. Please refer"
|
|
296
|
+
f" to the Flower documentation for more information: {url_v}{page}",
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# Load Federation Manager
|
|
300
|
+
fed_config_path = getattr(args, "federations_config", None)
|
|
301
|
+
federation_manager = get_federation_manager(fed_config_path)
|
|
302
|
+
|
|
303
|
+
# Initialize ObjectStoreFactory
|
|
304
|
+
objectstore_factory = ObjectStoreFactory(args.database)
|
|
305
|
+
|
|
214
306
|
# Initialize StateFactory
|
|
215
|
-
state_factory = LinkStateFactory(
|
|
307
|
+
state_factory = LinkStateFactory(
|
|
308
|
+
args.database, federation_manager, objectstore_factory
|
|
309
|
+
)
|
|
216
310
|
|
|
217
311
|
# Initialize FfsFactory
|
|
218
312
|
ffs_factory = FfsFactory(args.storage_dir)
|
|
219
313
|
|
|
220
|
-
# Initialize ObjectStoreFactory
|
|
221
|
-
objectstore_factory = ObjectStoreFactory()
|
|
222
|
-
|
|
223
314
|
# Start Control API
|
|
224
315
|
is_simulation = args.simulation
|
|
225
316
|
control_server: grpc.Server = run_control_api_grpc(
|
|
@@ -229,7 +320,7 @@ def run_superlink() -> None:
|
|
|
229
320
|
objectstore_factory=objectstore_factory,
|
|
230
321
|
certificates=certificates,
|
|
231
322
|
is_simulation=is_simulation,
|
|
232
|
-
|
|
323
|
+
authn_plugin=authn_plugin,
|
|
233
324
|
authz_plugin=authz_plugin,
|
|
234
325
|
event_log_plugin=event_log_plugin,
|
|
235
326
|
artifact_provider=artifact_provider,
|
|
@@ -306,22 +397,8 @@ def run_superlink() -> None:
|
|
|
306
397
|
fleet_thread.start()
|
|
307
398
|
bckg_threads.append(fleet_thread)
|
|
308
399
|
elif args.fleet_api_type == TRANSPORT_TYPE_GRPC_RERE:
|
|
309
|
-
node_public_keys = _try_load_public_keys_node_authentication(args)
|
|
310
|
-
auto_auth = True
|
|
311
|
-
if node_public_keys is not None:
|
|
312
|
-
auto_auth = False
|
|
313
|
-
state = state_factory.state()
|
|
314
|
-
state.clear_supernode_auth_keys()
|
|
315
|
-
state.store_node_public_keys(node_public_keys)
|
|
316
|
-
log(
|
|
317
|
-
INFO,
|
|
318
|
-
"Node authentication enabled with %d known public keys",
|
|
319
|
-
len(node_public_keys),
|
|
320
|
-
)
|
|
321
|
-
else:
|
|
322
|
-
log(DEBUG, "Automatic node authentication enabled")
|
|
323
400
|
|
|
324
|
-
interceptors = [
|
|
401
|
+
interceptors = [NodeAuthServerInterceptor(state_factory)]
|
|
325
402
|
if getattr(args, "enable_event_log", None):
|
|
326
403
|
fleet_log_plugin = _try_obtain_fleet_event_log_writer_plugin()
|
|
327
404
|
if fleet_log_plugin is not None:
|
|
@@ -333,6 +410,7 @@ def run_superlink() -> None:
|
|
|
333
410
|
state_factory=state_factory,
|
|
334
411
|
ffs_factory=ffs_factory,
|
|
335
412
|
objectstore_factory=objectstore_factory,
|
|
413
|
+
enable_supernode_auth=enable_supernode_auth,
|
|
336
414
|
certificates=certificates,
|
|
337
415
|
interceptors=interceptors,
|
|
338
416
|
)
|
|
@@ -400,55 +478,21 @@ def _format_address(address: str) -> tuple[str, str, int]:
|
|
|
400
478
|
return (f"[{host}]:{port}" if is_v6 else f"{host}:{port}", host, port)
|
|
401
479
|
|
|
402
480
|
|
|
403
|
-
def
|
|
404
|
-
|
|
405
|
-
) ->
|
|
406
|
-
"""Return a set of node public keys."""
|
|
407
|
-
if args.auth_superlink_private_key or args.auth_superlink_public_key:
|
|
408
|
-
log(
|
|
409
|
-
WARN,
|
|
410
|
-
"The `--auth-superlink-private-key` and `--auth-superlink-public-key` "
|
|
411
|
-
"arguments are deprecated and will be removed in a future release. Node "
|
|
412
|
-
"authentication no longer requires these arguments.",
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
if not args.auth_list_public_keys:
|
|
416
|
-
return None
|
|
417
|
-
|
|
418
|
-
node_keys_file_path = Path(args.auth_list_public_keys)
|
|
419
|
-
if not node_keys_file_path.exists():
|
|
420
|
-
sys.exit(
|
|
421
|
-
"The provided path to the known public keys CSV file does not exist: "
|
|
422
|
-
f"{node_keys_file_path}. "
|
|
423
|
-
"Please provide the CSV file path containing known public keys "
|
|
424
|
-
"to '--auth-list-public-keys'."
|
|
425
|
-
)
|
|
426
|
-
|
|
427
|
-
node_public_keys: set[bytes] = set()
|
|
428
|
-
|
|
429
|
-
with open(node_keys_file_path, newline="", encoding="utf-8") as csvfile:
|
|
430
|
-
reader = csv.reader(csvfile)
|
|
431
|
-
for row in reader:
|
|
432
|
-
for element in row:
|
|
433
|
-
public_key = load_ssh_public_key(element.encode())
|
|
434
|
-
if isinstance(public_key, ec.EllipticCurvePublicKey):
|
|
435
|
-
node_public_keys.add(public_key_to_bytes(public_key))
|
|
436
|
-
else:
|
|
437
|
-
sys.exit(
|
|
438
|
-
"Error: Unable to parse the public keys in the CSV "
|
|
439
|
-
"file. Please ensure that the CSV file path points to a valid "
|
|
440
|
-
"known SSH public keys files and try again."
|
|
441
|
-
)
|
|
442
|
-
return node_public_keys
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
def _try_obtain_control_auth_plugins(
|
|
446
|
-
config_path: Path, verify_tls_cert: bool
|
|
447
|
-
) -> tuple[ControlAuthPlugin, ControlAuthzPlugin]:
|
|
481
|
+
def _load_control_auth_plugins(
|
|
482
|
+
config_path: str | None, verify_tls_cert: bool
|
|
483
|
+
) -> tuple[ControlAuthnPlugin, ControlAuthzPlugin]:
|
|
448
484
|
"""Obtain Control API authentication and authorization plugins."""
|
|
485
|
+
# Load NoOp plugins if no config path is provided
|
|
486
|
+
if config_path is None:
|
|
487
|
+
config_path = ""
|
|
488
|
+
config = {
|
|
489
|
+
"authentication": {AUTHN_TYPE_YAML_KEY: AuthnType.NOOP},
|
|
490
|
+
"authorization": {AUTHZ_TYPE_YAML_KEY: AuthzType.NOOP},
|
|
491
|
+
}
|
|
449
492
|
# Load YAML file
|
|
450
|
-
|
|
451
|
-
|
|
493
|
+
else:
|
|
494
|
+
with Path(config_path).open("r", encoding="utf-8") as file:
|
|
495
|
+
config = yaml.safe_load(file)
|
|
452
496
|
|
|
453
497
|
def _load_plugin(
|
|
454
498
|
section: str, yaml_key: str, loader: Callable[[], dict[str, type[P]]]
|
|
@@ -458,9 +502,7 @@ def _try_obtain_control_auth_plugins(
|
|
|
458
502
|
try:
|
|
459
503
|
plugins: dict[str, type[P]] = loader()
|
|
460
504
|
plugin_cls: type[P] = plugins[auth_plugin_name]
|
|
461
|
-
return plugin_cls(
|
|
462
|
-
user_auth_config_path=config_path, verify_tls_cert=verify_tls_cert
|
|
463
|
-
)
|
|
505
|
+
return plugin_cls(Path(cast(str, config_path)), verify_tls_cert)
|
|
464
506
|
except KeyError:
|
|
465
507
|
if auth_plugin_name:
|
|
466
508
|
sys.exit(
|
|
@@ -468,14 +510,22 @@ def _try_obtain_control_auth_plugins(
|
|
|
468
510
|
f"Please provide a valid {section} type in the configuration."
|
|
469
511
|
)
|
|
470
512
|
sys.exit(f"No {section} type is provided in the configuration.")
|
|
471
|
-
|
|
472
|
-
|
|
513
|
+
|
|
514
|
+
# Warn deprecated auth_type key
|
|
515
|
+
if authn_type := config["authentication"].pop("auth_type", None):
|
|
516
|
+
log(
|
|
517
|
+
WARN,
|
|
518
|
+
"The `auth_type` key in the authentication configuration is deprecated. "
|
|
519
|
+
"Use `%s` instead.",
|
|
520
|
+
AUTHN_TYPE_YAML_KEY,
|
|
521
|
+
)
|
|
522
|
+
config["authentication"][AUTHN_TYPE_YAML_KEY] = authn_type
|
|
473
523
|
|
|
474
524
|
# Load authentication plugin
|
|
475
|
-
|
|
525
|
+
authn_plugin = _load_plugin(
|
|
476
526
|
section="authentication",
|
|
477
|
-
yaml_key=
|
|
478
|
-
loader=
|
|
527
|
+
yaml_key=AUTHN_TYPE_YAML_KEY,
|
|
528
|
+
loader=get_control_authn_plugins,
|
|
479
529
|
)
|
|
480
530
|
|
|
481
531
|
# Load authorization plugin
|
|
@@ -485,10 +535,10 @@ def _try_obtain_control_auth_plugins(
|
|
|
485
535
|
loader=get_control_authz_plugins,
|
|
486
536
|
)
|
|
487
537
|
|
|
488
|
-
return
|
|
538
|
+
return authn_plugin, authz_plugin
|
|
489
539
|
|
|
490
540
|
|
|
491
|
-
def _try_obtain_control_event_log_writer_plugin() ->
|
|
541
|
+
def _try_obtain_control_event_log_writer_plugin() -> EventLogWriterPlugin | None:
|
|
492
542
|
"""Return an instance of the event log writer plugin."""
|
|
493
543
|
try:
|
|
494
544
|
all_plugins: dict[str, type[EventLogWriterPlugin]] = (
|
|
@@ -502,7 +552,7 @@ def _try_obtain_control_event_log_writer_plugin() -> Optional[EventLogWriterPlug
|
|
|
502
552
|
sys.exit("No event log writer plugins are currently supported.")
|
|
503
553
|
|
|
504
554
|
|
|
505
|
-
def _try_obtain_fleet_event_log_writer_plugin() ->
|
|
555
|
+
def _try_obtain_fleet_event_log_writer_plugin() -> EventLogWriterPlugin | None:
|
|
506
556
|
"""Return an instance of the Fleet Servicer event log writer plugin."""
|
|
507
557
|
try:
|
|
508
558
|
all_plugins: dict[str, type[EventLogWriterPlugin]] = (
|
|
@@ -521,8 +571,9 @@ def _run_fleet_api_grpc_rere( # pylint: disable=R0913, R0917
|
|
|
521
571
|
state_factory: LinkStateFactory,
|
|
522
572
|
ffs_factory: FfsFactory,
|
|
523
573
|
objectstore_factory: ObjectStoreFactory,
|
|
524
|
-
|
|
525
|
-
|
|
574
|
+
enable_supernode_auth: bool,
|
|
575
|
+
certificates: tuple[bytes, bytes, bytes] | None,
|
|
576
|
+
interceptors: Sequence[grpc.ServerInterceptor] | None = None,
|
|
526
577
|
) -> grpc.Server:
|
|
527
578
|
"""Run Fleet API (gRPC, request-response)."""
|
|
528
579
|
# Create Fleet API gRPC server
|
|
@@ -530,6 +581,7 @@ def _run_fleet_api_grpc_rere( # pylint: disable=R0913, R0917
|
|
|
530
581
|
state_factory=state_factory,
|
|
531
582
|
ffs_factory=ffs_factory,
|
|
532
583
|
objectstore_factory=objectstore_factory,
|
|
584
|
+
enable_supernode_auth=enable_supernode_auth,
|
|
533
585
|
)
|
|
534
586
|
fleet_add_servicer_to_server_fn = add_FleetServicer_to_server
|
|
535
587
|
fleet_grpc_server = generic_create_grpc_server(
|
|
@@ -548,12 +600,13 @@ def _run_fleet_api_grpc_rere( # pylint: disable=R0913, R0917
|
|
|
548
600
|
return fleet_grpc_server
|
|
549
601
|
|
|
550
602
|
|
|
603
|
+
# pylint: disable=R0913, R0917
|
|
551
604
|
def _run_fleet_api_grpc_adapter(
|
|
552
605
|
address: str,
|
|
553
606
|
state_factory: LinkStateFactory,
|
|
554
607
|
ffs_factory: FfsFactory,
|
|
555
608
|
objectstore_factory: ObjectStoreFactory,
|
|
556
|
-
certificates:
|
|
609
|
+
certificates: tuple[bytes, bytes, bytes] | None,
|
|
557
610
|
) -> grpc.Server:
|
|
558
611
|
"""Run Fleet API (GrpcAdapter)."""
|
|
559
612
|
# Create Fleet API gRPC server
|
|
@@ -561,6 +614,7 @@ def _run_fleet_api_grpc_adapter(
|
|
|
561
614
|
state_factory=state_factory,
|
|
562
615
|
ffs_factory=ffs_factory,
|
|
563
616
|
objectstore_factory=objectstore_factory,
|
|
617
|
+
enable_supernode_auth=False,
|
|
564
618
|
)
|
|
565
619
|
fleet_add_servicer_to_server_fn = add_GrpcAdapterServicer_to_server
|
|
566
620
|
fleet_grpc_server = generic_create_grpc_server(
|
|
@@ -585,8 +639,8 @@ def _run_fleet_api_grpc_adapter(
|
|
|
585
639
|
def _run_fleet_api_rest(
|
|
586
640
|
host: str,
|
|
587
641
|
port: int,
|
|
588
|
-
ssl_keyfile:
|
|
589
|
-
ssl_certfile:
|
|
642
|
+
ssl_keyfile: str | None,
|
|
643
|
+
ssl_certfile: str | None,
|
|
590
644
|
state_factory: LinkStateFactory,
|
|
591
645
|
ffs_factory: FfsFactory,
|
|
592
646
|
objectstore_factory: ObjectStoreFactory,
|
|
@@ -691,11 +745,9 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
691
745
|
parser.add_argument(
|
|
692
746
|
"--database",
|
|
693
747
|
help="A string representing the path to the database "
|
|
694
|
-
"file that will be opened.
|
|
695
|
-
"will open a connection to a database that is in RAM, "
|
|
696
|
-
"instead of on disk. If nothing is provided, "
|
|
748
|
+
"file that will be opened. If nothing is provided, "
|
|
697
749
|
"Flower will just create a state in memory.",
|
|
698
|
-
default=
|
|
750
|
+
default=FLWR_IN_MEMORY_DB_NAME,
|
|
699
751
|
)
|
|
700
752
|
parser.add_argument(
|
|
701
753
|
"--storage-dir",
|
|
@@ -705,18 +757,12 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
705
757
|
parser.add_argument(
|
|
706
758
|
"--auth-list-public-keys",
|
|
707
759
|
type=str,
|
|
708
|
-
help="A CSV file (as a path str) containing a list of known public "
|
|
709
|
-
"keys to enable authentication.",
|
|
710
|
-
)
|
|
711
|
-
parser.add_argument(
|
|
712
|
-
"--auth-superlink-private-key",
|
|
713
|
-
type=str,
|
|
714
760
|
help="This argument is deprecated and will be removed in a future release.",
|
|
715
761
|
)
|
|
716
762
|
parser.add_argument(
|
|
717
|
-
"--
|
|
718
|
-
|
|
719
|
-
help="
|
|
763
|
+
"--enable-supernode-auth",
|
|
764
|
+
action="store_true",
|
|
765
|
+
help="Enable supernode authentication.",
|
|
720
766
|
)
|
|
721
767
|
|
|
722
768
|
|
flwr/server/client_manager.py
CHANGED
|
@@ -19,7 +19,6 @@ import random
|
|
|
19
19
|
import threading
|
|
20
20
|
from abc import ABC, abstractmethod
|
|
21
21
|
from logging import INFO
|
|
22
|
-
from typing import Optional
|
|
23
22
|
|
|
24
23
|
from flwr.common.logger import log
|
|
25
24
|
|
|
@@ -80,8 +79,8 @@ class ClientManager(ABC):
|
|
|
80
79
|
def sample(
|
|
81
80
|
self,
|
|
82
81
|
num_clients: int,
|
|
83
|
-
min_num_clients:
|
|
84
|
-
criterion:
|
|
82
|
+
min_num_clients: int | None = None,
|
|
83
|
+
criterion: Criterion | None = None,
|
|
85
84
|
) -> list[ClientProxy]:
|
|
86
85
|
"""Sample a number of Flower ClientProxy instances."""
|
|
87
86
|
|
|
@@ -179,8 +178,8 @@ class SimpleClientManager(ClientManager):
|
|
|
179
178
|
def sample(
|
|
180
179
|
self,
|
|
181
180
|
num_clients: int,
|
|
182
|
-
min_num_clients:
|
|
183
|
-
criterion:
|
|
181
|
+
min_num_clients: int | None = None,
|
|
182
|
+
criterion: Criterion | None = None,
|
|
184
183
|
) -> list[ClientProxy]:
|
|
185
184
|
"""Sample a number of Flower ClientProxy instances."""
|
|
186
185
|
# Block until at least num_clients are connected.
|