flwr-nightly 1.8.0.dev20240315__py3-none-any.whl → 1.11.0.dev20240813__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/cli/app.py +7 -0
- flwr/cli/build.py +150 -0
- flwr/cli/config_utils.py +219 -0
- flwr/cli/example.py +3 -1
- flwr/cli/install.py +227 -0
- flwr/cli/new/new.py +179 -48
- flwr/cli/new/templates/app/.gitignore.tpl +160 -0
- flwr/cli/new/templates/app/README.flowertune.md.tpl +56 -0
- flwr/cli/new/templates/app/README.md.tpl +1 -5
- flwr/cli/new/templates/app/code/__init__.py.tpl +1 -1
- flwr/cli/new/templates/app/code/client.huggingface.py.tpl +65 -0
- flwr/cli/new/templates/app/code/client.jax.py.tpl +56 -0
- flwr/cli/new/templates/app/code/client.mlx.py.tpl +93 -0
- flwr/cli/new/templates/app/code/client.numpy.py.tpl +3 -2
- flwr/cli/new/templates/app/code/client.pytorch.py.tpl +23 -11
- flwr/cli/new/templates/app/code/client.sklearn.py.tpl +97 -0
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +60 -1
- flwr/cli/new/templates/app/code/flwr_tune/__init__.py +15 -0
- flwr/cli/new/templates/app/code/flwr_tune/app.py.tpl +89 -0
- flwr/cli/new/templates/app/code/flwr_tune/client.py.tpl +126 -0
- flwr/cli/new/templates/app/code/flwr_tune/config.yaml.tpl +34 -0
- flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +57 -0
- flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +59 -0
- flwr/cli/new/templates/app/code/flwr_tune/server.py.tpl +48 -0
- flwr/cli/new/templates/app/code/flwr_tune/static_config.yaml.tpl +11 -0
- flwr/cli/new/templates/app/code/server.huggingface.py.tpl +23 -0
- flwr/cli/new/templates/app/code/server.jax.py.tpl +20 -0
- flwr/cli/new/templates/app/code/server.mlx.py.tpl +20 -0
- flwr/cli/new/templates/app/code/server.numpy.py.tpl +17 -9
- flwr/cli/new/templates/app/code/server.pytorch.py.tpl +21 -18
- flwr/cli/new/templates/app/code/server.sklearn.py.tpl +24 -0
- flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +29 -1
- flwr/cli/new/templates/app/code/task.huggingface.py.tpl +99 -0
- flwr/cli/new/templates/app/code/task.jax.py.tpl +57 -0
- flwr/cli/new/templates/app/code/task.mlx.py.tpl +102 -0
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl +28 -23
- flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +53 -0
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +39 -0
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +38 -0
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +34 -0
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +39 -0
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +25 -12
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +29 -14
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +33 -0
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +29 -14
- flwr/cli/run/run.py +168 -17
- flwr/cli/utils.py +75 -4
- flwr/client/__init__.py +6 -1
- flwr/client/app.py +239 -248
- flwr/client/client_app.py +70 -9
- flwr/client/dpfedavg_numpy_client.py +1 -1
- flwr/client/grpc_adapter_client/__init__.py +15 -0
- flwr/client/grpc_adapter_client/connection.py +97 -0
- flwr/client/grpc_client/connection.py +18 -5
- flwr/client/grpc_rere_client/__init__.py +1 -1
- flwr/client/grpc_rere_client/client_interceptor.py +158 -0
- flwr/client/grpc_rere_client/connection.py +127 -33
- flwr/client/grpc_rere_client/grpc_adapter.py +140 -0
- flwr/client/heartbeat.py +74 -0
- flwr/client/message_handler/__init__.py +1 -1
- flwr/client/message_handler/message_handler.py +7 -7
- flwr/client/mod/__init__.py +5 -5
- flwr/client/mod/centraldp_mods.py +4 -2
- flwr/client/mod/comms_mods.py +4 -4
- flwr/client/mod/localdp_mod.py +9 -4
- flwr/client/mod/secure_aggregation/__init__.py +1 -1
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +1 -1
- flwr/client/mod/utils.py +1 -1
- flwr/client/node_state.py +60 -10
- flwr/client/node_state_tests.py +4 -3
- flwr/client/rest_client/__init__.py +1 -1
- flwr/client/rest_client/connection.py +177 -157
- flwr/client/supernode/__init__.py +26 -0
- flwr/client/supernode/app.py +464 -0
- flwr/client/typing.py +1 -0
- flwr/common/__init__.py +13 -11
- flwr/common/address.py +1 -1
- flwr/common/config.py +193 -0
- flwr/common/constant.py +42 -1
- flwr/common/context.py +26 -1
- flwr/common/date.py +1 -1
- flwr/common/dp.py +1 -1
- flwr/common/grpc.py +6 -2
- flwr/common/logger.py +79 -8
- flwr/common/message.py +167 -105
- flwr/common/object_ref.py +126 -25
- flwr/common/record/__init__.py +1 -1
- flwr/common/record/parametersrecord.py +0 -1
- flwr/common/record/recordset.py +78 -27
- flwr/common/recordset_compat.py +8 -1
- flwr/common/retry_invoker.py +25 -13
- flwr/common/secure_aggregation/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/shamir.py +1 -1
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +21 -2
- flwr/common/secure_aggregation/ndarrays_arithmetic.py +1 -1
- flwr/common/secure_aggregation/quantization.py +1 -1
- flwr/common/secure_aggregation/secaggplus_constants.py +1 -1
- flwr/common/secure_aggregation/secaggplus_utils.py +1 -1
- flwr/common/serde.py +209 -3
- flwr/common/telemetry.py +25 -0
- flwr/common/typing.py +38 -0
- flwr/common/version.py +14 -0
- flwr/proto/clientappio_pb2.py +41 -0
- flwr/proto/clientappio_pb2.pyi +110 -0
- flwr/proto/clientappio_pb2_grpc.py +101 -0
- flwr/proto/clientappio_pb2_grpc.pyi +40 -0
- flwr/proto/common_pb2.py +36 -0
- flwr/proto/common_pb2.pyi +121 -0
- flwr/proto/common_pb2_grpc.py +4 -0
- flwr/proto/common_pb2_grpc.pyi +4 -0
- flwr/proto/driver_pb2.py +26 -19
- flwr/proto/driver_pb2.pyi +34 -0
- flwr/proto/driver_pb2_grpc.py +70 -0
- flwr/proto/driver_pb2_grpc.pyi +28 -0
- flwr/proto/exec_pb2.py +43 -0
- flwr/proto/exec_pb2.pyi +95 -0
- flwr/proto/exec_pb2_grpc.py +101 -0
- flwr/proto/exec_pb2_grpc.pyi +41 -0
- flwr/proto/fab_pb2.py +30 -0
- flwr/proto/fab_pb2.pyi +56 -0
- flwr/proto/fab_pb2_grpc.py +4 -0
- flwr/proto/fab_pb2_grpc.pyi +4 -0
- flwr/proto/fleet_pb2.py +29 -23
- flwr/proto/fleet_pb2.pyi +33 -0
- flwr/proto/fleet_pb2_grpc.py +102 -0
- flwr/proto/fleet_pb2_grpc.pyi +35 -0
- flwr/proto/grpcadapter_pb2.py +32 -0
- flwr/proto/grpcadapter_pb2.pyi +43 -0
- flwr/proto/grpcadapter_pb2_grpc.py +66 -0
- flwr/proto/grpcadapter_pb2_grpc.pyi +24 -0
- flwr/proto/message_pb2.py +41 -0
- flwr/proto/message_pb2.pyi +122 -0
- flwr/proto/message_pb2_grpc.py +4 -0
- flwr/proto/message_pb2_grpc.pyi +4 -0
- flwr/proto/run_pb2.py +35 -0
- flwr/proto/run_pb2.pyi +76 -0
- flwr/proto/run_pb2_grpc.py +4 -0
- flwr/proto/run_pb2_grpc.pyi +4 -0
- flwr/proto/task_pb2.py +7 -8
- flwr/proto/task_pb2.pyi +8 -5
- flwr/server/__init__.py +4 -8
- flwr/server/app.py +298 -350
- flwr/server/compat/app.py +6 -57
- flwr/server/compat/app_utils.py +5 -4
- flwr/server/compat/driver_client_proxy.py +29 -48
- flwr/server/compat/legacy_context.py +5 -4
- flwr/server/driver/__init__.py +2 -0
- flwr/server/driver/driver.py +22 -132
- flwr/server/driver/grpc_driver.py +224 -74
- flwr/server/driver/inmemory_driver.py +183 -0
- flwr/server/history.py +20 -20
- flwr/server/run_serverapp.py +121 -34
- flwr/server/server.py +11 -7
- flwr/server/server_app.py +59 -10
- flwr/server/serverapp_components.py +52 -0
- flwr/server/strategy/__init__.py +2 -2
- flwr/server/strategy/bulyan.py +1 -1
- flwr/server/strategy/dp_adaptive_clipping.py +3 -3
- flwr/server/strategy/dp_fixed_clipping.py +4 -3
- flwr/server/strategy/dpfedavg_adaptive.py +1 -1
- flwr/server/strategy/dpfedavg_fixed.py +1 -1
- flwr/server/strategy/fedadagrad.py +1 -1
- flwr/server/strategy/fedadam.py +1 -1
- flwr/server/strategy/fedavg_android.py +1 -1
- flwr/server/strategy/fedavgm.py +1 -1
- flwr/server/strategy/fedmedian.py +1 -1
- flwr/server/strategy/fedopt.py +1 -1
- flwr/server/strategy/fedprox.py +1 -1
- flwr/server/strategy/fedxgb_bagging.py +1 -1
- flwr/server/strategy/fedxgb_cyclic.py +1 -1
- flwr/server/strategy/fedxgb_nn_avg.py +1 -1
- flwr/server/strategy/fedyogi.py +1 -1
- flwr/server/strategy/krum.py +1 -1
- flwr/server/strategy/qfedavg.py +1 -1
- flwr/server/superlink/driver/__init__.py +1 -1
- flwr/server/superlink/driver/driver_grpc.py +1 -1
- flwr/server/superlink/driver/driver_servicer.py +51 -4
- flwr/server/superlink/ffs/__init__.py +24 -0
- flwr/server/superlink/ffs/disk_ffs.py +104 -0
- flwr/server/superlink/ffs/ffs.py +79 -0
- flwr/server/superlink/fleet/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_adapter/__init__.py +15 -0
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +131 -0
- flwr/server/superlink/fleet/grpc_bidi/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +8 -2
- flwr/server/superlink/fleet/grpc_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +30 -2
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +214 -0
- flwr/server/superlink/fleet/message_handler/__init__.py +1 -1
- flwr/server/superlink/fleet/message_handler/message_handler.py +42 -2
- flwr/server/superlink/fleet/rest_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/rest_rere/rest_api.py +59 -1
- flwr/server/superlink/fleet/vce/backend/__init__.py +1 -1
- flwr/server/superlink/fleet/vce/backend/backend.py +5 -5
- flwr/server/superlink/fleet/vce/backend/raybackend.py +53 -56
- flwr/server/superlink/fleet/vce/vce_api.py +190 -127
- flwr/server/superlink/state/__init__.py +1 -1
- flwr/server/superlink/state/in_memory_state.py +159 -42
- flwr/server/superlink/state/sqlite_state.py +243 -39
- flwr/server/superlink/state/state.py +81 -6
- flwr/server/superlink/state/state_factory.py +11 -2
- flwr/server/superlink/state/utils.py +62 -0
- flwr/server/typing.py +2 -0
- flwr/server/utils/__init__.py +1 -1
- flwr/server/utils/tensorboard.py +1 -1
- flwr/server/utils/validator.py +23 -9
- flwr/server/workflow/default_workflows.py +67 -25
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +18 -6
- flwr/simulation/__init__.py +7 -4
- flwr/simulation/app.py +67 -36
- flwr/simulation/ray_transport/__init__.py +1 -1
- flwr/simulation/ray_transport/ray_actor.py +20 -46
- flwr/simulation/ray_transport/ray_client_proxy.py +36 -16
- flwr/simulation/run_simulation.py +308 -92
- flwr/superexec/__init__.py +21 -0
- flwr/superexec/app.py +184 -0
- flwr/superexec/deployment.py +185 -0
- flwr/superexec/exec_grpc.py +55 -0
- flwr/superexec/exec_servicer.py +70 -0
- flwr/superexec/executor.py +75 -0
- flwr/superexec/simulation.py +193 -0
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/METADATA +10 -6
- flwr_nightly-1.11.0.dev20240813.dist-info/RECORD +288 -0
- flwr_nightly-1.11.0.dev20240813.dist-info/entry_points.txt +10 -0
- flwr/cli/flower_toml.py +0 -140
- flwr/cli/new/templates/app/flower.toml.tpl +0 -13
- flwr/cli/new/templates/app/requirements.numpy.txt.tpl +0 -2
- flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +0 -4
- flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -4
- flwr_nightly-1.8.0.dev20240315.dist-info/RECORD +0 -211
- flwr_nightly-1.8.0.dev20240315.dist-info/entry_points.txt +0 -9
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/WHEEL +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -15,13 +15,15 @@
|
|
|
15
15
|
"""Driver API servicer."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
import time
|
|
19
|
+
from logging import DEBUG
|
|
19
20
|
from typing import List, Optional, Set
|
|
20
21
|
from uuid import UUID
|
|
21
22
|
|
|
22
23
|
import grpc
|
|
23
24
|
|
|
24
25
|
from flwr.common.logger import log
|
|
26
|
+
from flwr.common.serde import user_config_from_proto, user_config_to_proto
|
|
25
27
|
from flwr.proto import driver_pb2_grpc # pylint: disable=E0611
|
|
26
28
|
from flwr.proto.driver_pb2 import ( # pylint: disable=E0611
|
|
27
29
|
CreateRunRequest,
|
|
@@ -33,7 +35,13 @@ from flwr.proto.driver_pb2 import ( # pylint: disable=E0611
|
|
|
33
35
|
PushTaskInsRequest,
|
|
34
36
|
PushTaskInsResponse,
|
|
35
37
|
)
|
|
38
|
+
from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=E0611
|
|
36
39
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
40
|
+
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
|
41
|
+
GetRunRequest,
|
|
42
|
+
GetRunResponse,
|
|
43
|
+
Run,
|
|
44
|
+
)
|
|
37
45
|
from flwr.proto.task_pb2 import TaskRes # pylint: disable=E0611
|
|
38
46
|
from flwr.server.superlink.state import State, StateFactory
|
|
39
47
|
from flwr.server.utils.validator import validate_task_ins_or_res
|
|
@@ -61,9 +69,13 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
|
|
|
61
69
|
self, request: CreateRunRequest, context: grpc.ServicerContext
|
|
62
70
|
) -> CreateRunResponse:
|
|
63
71
|
"""Create run ID."""
|
|
64
|
-
log(
|
|
72
|
+
log(DEBUG, "DriverServicer.CreateRun")
|
|
65
73
|
state: State = self.state_factory.state()
|
|
66
|
-
run_id = state.create_run(
|
|
74
|
+
run_id = state.create_run(
|
|
75
|
+
request.fab_id,
|
|
76
|
+
request.fab_version,
|
|
77
|
+
user_config_from_proto(request.override_config),
|
|
78
|
+
)
|
|
67
79
|
return CreateRunResponse(run_id=run_id)
|
|
68
80
|
|
|
69
81
|
def PushTaskIns(
|
|
@@ -72,6 +84,11 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
|
|
|
72
84
|
"""Push a set of TaskIns."""
|
|
73
85
|
log(DEBUG, "DriverServicer.PushTaskIns")
|
|
74
86
|
|
|
87
|
+
# Set pushed_at (timestamp in seconds)
|
|
88
|
+
pushed_at = time.time()
|
|
89
|
+
for task_ins in request.task_ins_list:
|
|
90
|
+
task_ins.task.pushed_at = pushed_at
|
|
91
|
+
|
|
75
92
|
# Validate request
|
|
76
93
|
_raise_if(len(request.task_ins_list) == 0, "`task_ins_list` must not be empty")
|
|
77
94
|
for task_ins in request.task_ins_list:
|
|
@@ -123,6 +140,36 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
|
|
|
123
140
|
context.set_code(grpc.StatusCode.OK)
|
|
124
141
|
return PullTaskResResponse(task_res_list=task_res_list)
|
|
125
142
|
|
|
143
|
+
def GetRun(
|
|
144
|
+
self, request: GetRunRequest, context: grpc.ServicerContext
|
|
145
|
+
) -> GetRunResponse:
|
|
146
|
+
"""Get run information."""
|
|
147
|
+
log(DEBUG, "DriverServicer.GetRun")
|
|
148
|
+
|
|
149
|
+
# Init state
|
|
150
|
+
state: State = self.state_factory.state()
|
|
151
|
+
|
|
152
|
+
# Retrieve run information
|
|
153
|
+
run = state.get_run(request.run_id)
|
|
154
|
+
|
|
155
|
+
if run is None:
|
|
156
|
+
return GetRunResponse()
|
|
157
|
+
|
|
158
|
+
return GetRunResponse(
|
|
159
|
+
run=Run(
|
|
160
|
+
run_id=run.run_id,
|
|
161
|
+
fab_id=run.fab_id,
|
|
162
|
+
fab_version=run.fab_version,
|
|
163
|
+
override_config=user_config_to_proto(run.override_config),
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def GetFab(
|
|
168
|
+
self, request: GetFabRequest, context: grpc.ServicerContext
|
|
169
|
+
) -> GetFabResponse:
|
|
170
|
+
"""Will be implemented later."""
|
|
171
|
+
raise NotImplementedError
|
|
172
|
+
|
|
126
173
|
|
|
127
174
|
def _raise_if(validation_error: bool, detail: str) -> None:
|
|
128
175
|
if validation_error:
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Flower File Storage for large objects."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from .disk_ffs import DiskFfs as DiskFfs
|
|
19
|
+
from .ffs import Ffs as Ffs
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"DiskFfs",
|
|
23
|
+
"Ffs",
|
|
24
|
+
]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Disk based Flower File Storage."""
|
|
16
|
+
|
|
17
|
+
import hashlib
|
|
18
|
+
import json
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Dict, List, Tuple
|
|
21
|
+
|
|
22
|
+
from flwr.server.superlink.ffs.ffs import Ffs
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DiskFfs(Ffs): # pylint: disable=R0904
|
|
26
|
+
"""Disk-based Flower File Storage interface for large objects."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, base_dir: str) -> None:
|
|
29
|
+
"""Create a new DiskFfs instance.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
base_dir : str
|
|
34
|
+
The base directory to store the objects.
|
|
35
|
+
"""
|
|
36
|
+
self.base_dir = Path(base_dir)
|
|
37
|
+
|
|
38
|
+
def put(self, content: bytes, meta: Dict[str, str]) -> str:
|
|
39
|
+
"""Store bytes and metadata and return key (hash of content).
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
content : bytes
|
|
44
|
+
The content to be stored.
|
|
45
|
+
meta : Dict[str, str]
|
|
46
|
+
The metadata to be stored.
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
key : str
|
|
51
|
+
The key (sha256hex hash) of the content.
|
|
52
|
+
"""
|
|
53
|
+
content_hash = hashlib.sha256(content).hexdigest()
|
|
54
|
+
|
|
55
|
+
self.base_dir.mkdir(exist_ok=True, parents=True)
|
|
56
|
+
(self.base_dir / content_hash).write_bytes(content)
|
|
57
|
+
(self.base_dir / f"{content_hash}.META").write_text(json.dumps(meta))
|
|
58
|
+
|
|
59
|
+
return content_hash
|
|
60
|
+
|
|
61
|
+
def get(self, key: str) -> Tuple[bytes, Dict[str, str]]:
|
|
62
|
+
"""Return tuple containing the object content and metadata.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
key : str
|
|
67
|
+
The sha256hex hash of the object to be retrieved.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
Tuple[bytes, Dict[str, str]]
|
|
72
|
+
A tuple containing the object content and metadata.
|
|
73
|
+
"""
|
|
74
|
+
content = (self.base_dir / key).read_bytes()
|
|
75
|
+
meta = json.loads((self.base_dir / f"{key}.META").read_text())
|
|
76
|
+
|
|
77
|
+
return content, meta
|
|
78
|
+
|
|
79
|
+
def delete(self, key: str) -> None:
|
|
80
|
+
"""Delete object with hash.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
key : str
|
|
85
|
+
The sha256hex hash of the object to be deleted.
|
|
86
|
+
"""
|
|
87
|
+
(self.base_dir / key).unlink()
|
|
88
|
+
(self.base_dir / f"{key}.META").unlink()
|
|
89
|
+
|
|
90
|
+
def list(self) -> List[str]:
|
|
91
|
+
"""List all keys.
|
|
92
|
+
|
|
93
|
+
Return all available keys in this `Ffs` instance.
|
|
94
|
+
This can be combined with, for example,
|
|
95
|
+
the `delete` method to delete objects.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
List[str]
|
|
100
|
+
A list of all available keys.
|
|
101
|
+
"""
|
|
102
|
+
return [
|
|
103
|
+
item.name for item in self.base_dir.iterdir() if not item.suffix == ".META"
|
|
104
|
+
]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Abstract base class for Flower File Storage interface."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import abc
|
|
19
|
+
from typing import Dict, List, Tuple
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Ffs(abc.ABC): # pylint: disable=R0904
|
|
23
|
+
"""Abstract Flower File Storage interface for large objects."""
|
|
24
|
+
|
|
25
|
+
@abc.abstractmethod
|
|
26
|
+
def put(self, content: bytes, meta: Dict[str, str]) -> str:
|
|
27
|
+
"""Store bytes and metadata and return sha256hex hash of data as str.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
content : bytes
|
|
32
|
+
The content to be stored.
|
|
33
|
+
meta : Dict[str, str]
|
|
34
|
+
The metadata to be stored.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
key : str
|
|
39
|
+
The key (sha256hex hash) of the content.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@abc.abstractmethod
|
|
43
|
+
def get(self, key: str) -> Tuple[bytes, Dict[str, str]]:
|
|
44
|
+
"""Return tuple containing the object content and metadata.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
key : str
|
|
49
|
+
The key (sha256hex hash) of the object to be retrieved.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
Tuple[bytes, Dict[str, str]]
|
|
54
|
+
A tuple containing the object content and metadata.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
@abc.abstractmethod
|
|
58
|
+
def delete(self, key: str) -> None:
|
|
59
|
+
"""Delete object with hash.
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
key : str
|
|
64
|
+
The key (sha256hex hash) of the object to be deleted.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
@abc.abstractmethod
|
|
68
|
+
def list(self) -> List[str]:
|
|
69
|
+
"""List keys of all stored objects.
|
|
70
|
+
|
|
71
|
+
Return all available keys in this `Ffs` instance.
|
|
72
|
+
This can be combined with, for example,
|
|
73
|
+
the `delete` method to delete objects.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
List[str]
|
|
78
|
+
A list of all available keys.
|
|
79
|
+
"""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Server-side part of the GrpcAdapter transport layer."""
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Fleet API gRPC adapter servicer."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from logging import DEBUG, INFO
|
|
19
|
+
from typing import Callable, Type, TypeVar
|
|
20
|
+
|
|
21
|
+
import grpc
|
|
22
|
+
from google.protobuf.message import Message as GrpcMessage
|
|
23
|
+
|
|
24
|
+
from flwr.common.logger import log
|
|
25
|
+
from flwr.proto import grpcadapter_pb2_grpc # pylint: disable=E0611
|
|
26
|
+
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
27
|
+
CreateNodeRequest,
|
|
28
|
+
CreateNodeResponse,
|
|
29
|
+
DeleteNodeRequest,
|
|
30
|
+
DeleteNodeResponse,
|
|
31
|
+
PingRequest,
|
|
32
|
+
PingResponse,
|
|
33
|
+
PullTaskInsRequest,
|
|
34
|
+
PullTaskInsResponse,
|
|
35
|
+
PushTaskResRequest,
|
|
36
|
+
PushTaskResResponse,
|
|
37
|
+
)
|
|
38
|
+
from flwr.proto.grpcadapter_pb2 import MessageContainer # pylint: disable=E0611
|
|
39
|
+
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
40
|
+
from flwr.server.superlink.fleet.message_handler import message_handler
|
|
41
|
+
from flwr.server.superlink.state import StateFactory
|
|
42
|
+
|
|
43
|
+
T = TypeVar("T", bound=GrpcMessage)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _handle(
|
|
47
|
+
msg_container: MessageContainer,
|
|
48
|
+
request_type: Type[T],
|
|
49
|
+
handler: Callable[[T], GrpcMessage],
|
|
50
|
+
) -> MessageContainer:
|
|
51
|
+
req = request_type.FromString(msg_container.grpc_message_content)
|
|
52
|
+
res = handler(req)
|
|
53
|
+
return MessageContainer(
|
|
54
|
+
metadata={},
|
|
55
|
+
grpc_message_name=res.__class__.__qualname__,
|
|
56
|
+
grpc_message_content=res.SerializeToString(),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class GrpcAdapterServicer(grpcadapter_pb2_grpc.GrpcAdapterServicer):
|
|
61
|
+
"""Fleet API via GrpcAdapter servicer."""
|
|
62
|
+
|
|
63
|
+
def __init__(self, state_factory: StateFactory) -> None:
|
|
64
|
+
self.state_factory = state_factory
|
|
65
|
+
|
|
66
|
+
def SendReceive(
|
|
67
|
+
self, request: MessageContainer, context: grpc.ServicerContext
|
|
68
|
+
) -> MessageContainer:
|
|
69
|
+
"""."""
|
|
70
|
+
log(DEBUG, "GrpcAdapterServicer.SendReceive")
|
|
71
|
+
if request.grpc_message_name == CreateNodeRequest.__qualname__:
|
|
72
|
+
return _handle(request, CreateNodeRequest, self._create_node)
|
|
73
|
+
if request.grpc_message_name == DeleteNodeRequest.__qualname__:
|
|
74
|
+
return _handle(request, DeleteNodeRequest, self._delete_node)
|
|
75
|
+
if request.grpc_message_name == PingRequest.__qualname__:
|
|
76
|
+
return _handle(request, PingRequest, self._ping)
|
|
77
|
+
if request.grpc_message_name == PullTaskInsRequest.__qualname__:
|
|
78
|
+
return _handle(request, PullTaskInsRequest, self._pull_task_ins)
|
|
79
|
+
if request.grpc_message_name == PushTaskResRequest.__qualname__:
|
|
80
|
+
return _handle(request, PushTaskResRequest, self._push_task_res)
|
|
81
|
+
if request.grpc_message_name == GetRunRequest.__qualname__:
|
|
82
|
+
return _handle(request, GetRunRequest, self._get_run)
|
|
83
|
+
raise ValueError(f"Invalid grpc_message_name: {request.grpc_message_name}")
|
|
84
|
+
|
|
85
|
+
def _create_node(self, request: CreateNodeRequest) -> CreateNodeResponse:
|
|
86
|
+
"""."""
|
|
87
|
+
log(INFO, "GrpcAdapter.CreateNode")
|
|
88
|
+
return message_handler.create_node(
|
|
89
|
+
request=request,
|
|
90
|
+
state=self.state_factory.state(),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def _delete_node(self, request: DeleteNodeRequest) -> DeleteNodeResponse:
|
|
94
|
+
"""."""
|
|
95
|
+
log(INFO, "GrpcAdapter.DeleteNode")
|
|
96
|
+
return message_handler.delete_node(
|
|
97
|
+
request=request,
|
|
98
|
+
state=self.state_factory.state(),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def _ping(self, request: PingRequest) -> PingResponse:
|
|
102
|
+
"""."""
|
|
103
|
+
log(DEBUG, "GrpcAdapter.Ping")
|
|
104
|
+
return message_handler.ping(
|
|
105
|
+
request=request,
|
|
106
|
+
state=self.state_factory.state(),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def _pull_task_ins(self, request: PullTaskInsRequest) -> PullTaskInsResponse:
|
|
110
|
+
"""Pull TaskIns."""
|
|
111
|
+
log(INFO, "GrpcAdapter.PullTaskIns")
|
|
112
|
+
return message_handler.pull_task_ins(
|
|
113
|
+
request=request,
|
|
114
|
+
state=self.state_factory.state(),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def _push_task_res(self, request: PushTaskResRequest) -> PushTaskResResponse:
|
|
118
|
+
"""Push TaskRes."""
|
|
119
|
+
log(INFO, "GrpcAdapter.PushTaskRes")
|
|
120
|
+
return message_handler.push_task_res(
|
|
121
|
+
request=request,
|
|
122
|
+
state=self.state_factory.state(),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def _get_run(self, request: GetRunRequest) -> GetRunResponse:
|
|
126
|
+
"""Get run information."""
|
|
127
|
+
log(INFO, "GrpcAdapter.GetRun")
|
|
128
|
+
return message_handler.get_run(
|
|
129
|
+
request=request,
|
|
130
|
+
state=self.state_factory.state(),
|
|
131
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import concurrent.futures
|
|
19
19
|
import sys
|
|
20
20
|
from logging import ERROR
|
|
21
|
-
from typing import Any, Callable, Optional, Tuple, Union
|
|
21
|
+
from typing import Any, Callable, Optional, Sequence, Tuple, Union
|
|
22
22
|
|
|
23
23
|
import grpc
|
|
24
24
|
|
|
@@ -29,6 +29,9 @@ from flwr.proto.transport_pb2_grpc import ( # pylint: disable=E0611
|
|
|
29
29
|
)
|
|
30
30
|
from flwr.server.client_manager import ClientManager
|
|
31
31
|
from flwr.server.superlink.driver.driver_servicer import DriverServicer
|
|
32
|
+
from flwr.server.superlink.fleet.grpc_adapter.grpc_adapter_servicer import (
|
|
33
|
+
GrpcAdapterServicer,
|
|
34
|
+
)
|
|
32
35
|
from flwr.server.superlink.fleet.grpc_bidi.flower_service_servicer import (
|
|
33
36
|
FlowerServiceServicer,
|
|
34
37
|
)
|
|
@@ -154,6 +157,7 @@ def start_grpc_server( # pylint: disable=too-many-arguments
|
|
|
154
157
|
def generic_create_grpc_server( # pylint: disable=too-many-arguments
|
|
155
158
|
servicer_and_add_fn: Union[
|
|
156
159
|
Tuple[FleetServicer, AddServicerToServerFn],
|
|
160
|
+
Tuple[GrpcAdapterServicer, AddServicerToServerFn],
|
|
157
161
|
Tuple[FlowerServiceServicer, AddServicerToServerFn],
|
|
158
162
|
Tuple[DriverServicer, AddServicerToServerFn],
|
|
159
163
|
],
|
|
@@ -162,6 +166,7 @@ def generic_create_grpc_server( # pylint: disable=too-many-arguments
|
|
|
162
166
|
max_message_length: int = GRPC_MAX_MESSAGE_LENGTH,
|
|
163
167
|
keepalive_time_ms: int = 210000,
|
|
164
168
|
certificates: Optional[Tuple[bytes, bytes, bytes]] = None,
|
|
169
|
+
interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
|
|
165
170
|
) -> grpc.Server:
|
|
166
171
|
"""Create a gRPC server with a single servicer.
|
|
167
172
|
|
|
@@ -249,6 +254,7 @@ def generic_create_grpc_server( # pylint: disable=too-many-arguments
|
|
|
249
254
|
# returning RESOURCE_EXHAUSTED status, or None to indicate no limit.
|
|
250
255
|
maximum_concurrent_rpcs=max_concurrent_workers,
|
|
251
256
|
options=options,
|
|
257
|
+
interceptors=interceptors,
|
|
252
258
|
)
|
|
253
259
|
add_servicer_to_server_fn(servicer, server)
|
|
254
260
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -15,22 +15,26 @@
|
|
|
15
15
|
"""Fleet API gRPC request-response servicer."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from logging import INFO
|
|
18
|
+
from logging import DEBUG, INFO
|
|
19
19
|
|
|
20
20
|
import grpc
|
|
21
21
|
|
|
22
22
|
from flwr.common.logger import log
|
|
23
23
|
from flwr.proto import fleet_pb2_grpc # pylint: disable=E0611
|
|
24
|
+
from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=E0611
|
|
24
25
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
25
26
|
CreateNodeRequest,
|
|
26
27
|
CreateNodeResponse,
|
|
27
28
|
DeleteNodeRequest,
|
|
28
29
|
DeleteNodeResponse,
|
|
30
|
+
PingRequest,
|
|
31
|
+
PingResponse,
|
|
29
32
|
PullTaskInsRequest,
|
|
30
33
|
PullTaskInsResponse,
|
|
31
34
|
PushTaskResRequest,
|
|
32
35
|
PushTaskResResponse,
|
|
33
36
|
)
|
|
37
|
+
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
34
38
|
from flwr.server.superlink.fleet.message_handler import message_handler
|
|
35
39
|
from flwr.server.superlink.state import StateFactory
|
|
36
40
|
|
|
@@ -61,6 +65,14 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
|
61
65
|
state=self.state_factory.state(),
|
|
62
66
|
)
|
|
63
67
|
|
|
68
|
+
def Ping(self, request: PingRequest, context: grpc.ServicerContext) -> PingResponse:
|
|
69
|
+
"""."""
|
|
70
|
+
log(DEBUG, "FleetServicer.Ping")
|
|
71
|
+
return message_handler.ping(
|
|
72
|
+
request=request,
|
|
73
|
+
state=self.state_factory.state(),
|
|
74
|
+
)
|
|
75
|
+
|
|
64
76
|
def PullTaskIns(
|
|
65
77
|
self, request: PullTaskInsRequest, context: grpc.ServicerContext
|
|
66
78
|
) -> PullTaskInsResponse:
|
|
@@ -80,3 +92,19 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
|
|
|
80
92
|
request=request,
|
|
81
93
|
state=self.state_factory.state(),
|
|
82
94
|
)
|
|
95
|
+
|
|
96
|
+
def GetRun(
|
|
97
|
+
self, request: GetRunRequest, context: grpc.ServicerContext
|
|
98
|
+
) -> GetRunResponse:
|
|
99
|
+
"""Get run information."""
|
|
100
|
+
log(INFO, "FleetServicer.GetRun")
|
|
101
|
+
return message_handler.get_run(
|
|
102
|
+
request=request,
|
|
103
|
+
state=self.state_factory.state(),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def GetFab(
|
|
107
|
+
self, request: GetFabRequest, context: grpc.ServicerContext
|
|
108
|
+
) -> GetFabResponse:
|
|
109
|
+
"""Will be implemented later."""
|
|
110
|
+
raise NotImplementedError
|