Skip to content

Commit f1ab2d7

Browse files
authored
✨Allow computational sidecar to understand S3 links for download/upload (ITISFoundation#2997)
1 parent 42811c8 commit f1ab2d7

File tree

26 files changed

+682
-263
lines changed

26 files changed

+682
-263
lines changed

packages/dask-task-models-library/src/dask_task_models_library/container_tasks/events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class BaseTaskEvent(BaseModel, ABC):
1010
job_id: str
11-
msg: Optional[str]
11+
msg: Optional[str] = None
1212

1313
@staticmethod
1414
@abstractmethod

packages/pytest-simcore/src/pytest_simcore/minio_service.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
from typing import Dict, Iterator
77

88
import pytest
9-
import tenacity
109
from _pytest.monkeypatch import MonkeyPatch
1110
from minio import Minio
1211
from minio.datatypes import Object
1312
from minio.deleteobjects import DeleteError, DeleteObject
1413
from pydantic import parse_obj_as
1514
from tenacity import Retrying
15+
from tenacity.before_sleep import before_sleep_log
16+
from tenacity.stop import stop_after_attempt
17+
from tenacity.wait import wait_fixed
1618

1719
from .helpers.utils_docker import get_localhost_ip, get_service_published_port
1820

@@ -71,9 +73,9 @@ def minio_service(minio_config: Dict[str, str]) -> Iterator[Minio]:
7173
client = Minio(**minio_config["client"])
7274

7375
for attempt in Retrying(
74-
wait=tenacity.wait_fixed(5),
75-
stop=tenacity.stop_after_attempt(60),
76-
before_sleep=tenacity.before_sleep_log(log, logging.WARNING),
76+
wait=wait_fixed(5),
77+
stop=stop_after_attempt(60),
78+
before_sleep=before_sleep_log(log, logging.WARNING),
7779
reraise=True,
7880
):
7981
with attempt:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
from typing import Optional
2+
13
from .base import BaseCustomSettings
24

35

46
class S3Settings(BaseCustomSettings):
57
S3_ENDPOINT: str = "minio:9000"
68
S3_ACCESS_KEY: str = "12345678"
79
S3_SECRET_KEY: str = "12345678"
10+
S3_ACCESS_TOKEN: Optional[str] = None
811
S3_BUCKET_NAME: str = "simcore"
912
S3_SECURE: bool = False

packages/simcore-sdk/src/simcore_sdk/node_data/data_manager.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ async def _push_file(
3333
await filemanager.upload_file(
3434
user_id=user_id,
3535
store_id=store_id,
36+
store_name=None,
3637
s3_object=s3_object,
3738
local_file_path=file_path,
3839
)
@@ -79,6 +80,7 @@ async def _pull_file(
7980
downloaded_file = await filemanager.download_file_from_s3(
8081
user_id=user_id,
8182
store_id="0",
83+
store_name=None,
8284
s3_object=s3_object,
8385
local_folder=destination_path.parent,
8486
)

packages/simcore-sdk/src/simcore_sdk/node_ports/_item.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ async def set(self, value: ItemConcreteValue):
177177
)
178178
store_id, _ = await filemanager.upload_file(
179179
user_id=self._user_id,
180+
store_id=None,
180181
store_name=config.STORE,
181182
s3_object=s3_object,
182183
local_file_path=file_path,
@@ -216,6 +217,7 @@ async def __get_value_from_store(self, user_id: int, value: StoreLink) -> Path:
216217
downloaded_file = await filemanager.download_file_from_s3(
217218
user_id=user_id,
218219
store_id=store_id,
220+
store_name=None,
219221
s3_object=s3_path,
220222
local_folder=local_path,
221223
)

packages/simcore-sdk/src/simcore_sdk/node_ports_common/filemanager.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ async def file_sender(file_name: Path):
137137
async def get_download_link_from_s3(
138138
*,
139139
user_id: int,
140-
store_name: str = None,
141-
store_id: str = None,
140+
store_name: Optional[str],
141+
store_id: Optional[str],
142142
s3_object: str,
143143
client_session: Optional[ClientSession] = None,
144144
) -> Optional[URL]:
@@ -157,8 +157,8 @@ async def get_download_link_from_s3(
157157
async def get_upload_link_from_s3(
158158
*,
159159
user_id: int,
160-
store_name: str = None,
161-
store_id: str = None,
160+
store_name: Optional[str],
161+
store_id: Optional[str],
162162
s3_object: str,
163163
client_session: Optional[ClientSession] = None,
164164
) -> Tuple[str, URL]:
@@ -180,8 +180,8 @@ async def get_upload_link_from_s3(
180180
async def download_file_from_s3(
181181
*,
182182
user_id: int,
183-
store_name: str = None,
184-
store_id: str = None,
183+
store_name: Optional[str],
184+
store_id: Optional[str],
185185
s3_object: str,
186186
local_folder: Path,
187187
client_session: Optional[ClientSession] = None,
@@ -246,8 +246,8 @@ async def download_file_from_link(
246246
async def upload_file(
247247
*,
248248
user_id: int,
249-
store_id: Optional[str] = None,
250-
store_name: Optional[str] = None,
249+
store_id: Optional[str],
250+
store_name: Optional[str],
251251
s3_object: str,
252252
local_file_path: Path,
253253
client_session: Optional[ClientSession] = None,

packages/simcore-sdk/src/simcore_sdk/node_ports_v2/port_utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ async def get_download_link_from_storage(
7070
link = await filemanager.get_download_link_from_s3(
7171
user_id=user_id,
7272
store_id=f"{value.store}",
73+
store_name=None,
7374
s3_object=value.path,
7475
)
7576
return parse_obj_as(AnyUrl, f"{link}") if link else None
@@ -85,6 +86,7 @@ async def get_upload_link_from_storage(
8586
s3_object = data_items_utils.encode_file_id(Path(file_name), project_id, node_id)
8687
_, link = await filemanager.get_upload_link_from_s3(
8788
user_id=user_id,
89+
store_id=None,
8890
store_name=config.STORE,
8991
s3_object=s3_object,
9092
)
@@ -125,6 +127,7 @@ async def pull_file_from_store(
125127
downloaded_file = await filemanager.download_file_from_s3(
126128
user_id=user_id,
127129
store_id=f"{value.store}",
130+
store_name=None,
128131
s3_object=value.path,
129132
local_folder=local_path,
130133
)
@@ -150,6 +153,7 @@ async def push_file_to_store(
150153
s3_object = data_items_utils.encode_file_id(file, project_id, node_id)
151154
store_id, e_tag = await filemanager.upload_file(
152155
user_id=user_id,
156+
store_id=None,
153157
store_name=config.STORE,
154158
s3_object=s3_object,
155159
local_file_path=file,
@@ -198,6 +202,7 @@ async def get_file_link_from_url(
198202
node_id: str,
199203
) -> FileLink:
200204
log.debug("url %s will now be converted to a file link", new_value)
205+
assert new_value.path # nosec
201206
s3_object = data_items_utils.encode_file_id(
202207
Path(new_value.path), project_id, node_id
203208
)

packages/simcore-sdk/tests/integration/test_node_ports_common_filemanager.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ async def test_valid_upload_download(
3737
store_id, e_tag = await filemanager.upload_file(
3838
user_id=user_id,
3939
store_id=s3_simcore_location,
40+
store_name=None,
4041
s3_object=file_id,
4142
local_file_path=file_path,
4243
)
@@ -53,6 +54,7 @@ async def test_valid_upload_download(
5354
download_file_path = await filemanager.download_file_from_s3(
5455
user_id=user_id,
5556
store_id=s3_simcore_location,
57+
store_name=None,
5658
s3_object=file_id,
5759
local_folder=download_folder,
5860
)
@@ -79,6 +81,7 @@ async def test_invalid_file_path(
7981
await filemanager.upload_file(
8082
user_id=user_id,
8183
store_id=store,
84+
store_name=None,
8285
s3_object=file_id,
8386
local_file_path=Path(tmpdir) / "some other file.txt",
8487
)
@@ -88,6 +91,7 @@ async def test_invalid_file_path(
8891
await filemanager.download_file_from_s3(
8992
user_id=user_id,
9093
store_id=store,
94+
store_name=None,
9195
s3_object=file_id,
9296
local_folder=download_folder,
9397
)
@@ -108,27 +112,37 @@ async def test_errors_upon_invalid_file_identifiers(
108112
store = s3_simcore_location
109113
with pytest.raises(exceptions.StorageInvalidCall):
110114
await filemanager.upload_file(
111-
user_id=user_id, store_id=store, s3_object="", local_file_path=file_path
115+
user_id=user_id,
116+
store_id=store,
117+
store_name=None,
118+
s3_object="",
119+
local_file_path=file_path,
112120
)
113121

114122
with pytest.raises(exceptions.StorageInvalidCall):
115123
await filemanager.upload_file(
116124
user_id=user_id,
117125
store_id=store,
126+
store_name=None,
118127
s3_object="file_id",
119128
local_file_path=file_path,
120129
)
121130

122131
download_folder = Path(tmpdir) / "downloads"
123132
with pytest.raises(exceptions.StorageInvalidCall):
124133
await filemanager.download_file_from_s3(
125-
user_id=user_id, store_id=store, s3_object="", local_folder=download_folder
134+
user_id=user_id,
135+
store_id=store,
136+
store_name=None,
137+
s3_object="",
138+
local_folder=download_folder,
126139
)
127140

128141
with pytest.raises(exceptions.StorageInvalidCall):
129142
await filemanager.download_file_from_s3(
130143
user_id=user_id,
131144
store_id=store,
145+
store_name=None,
132146
s3_object=np_helpers.file_uuid(
133147
Path("invisible.txt"), project_id, f"{uuid4()}"
134148
),
@@ -153,6 +167,7 @@ async def test_invalid_store(
153167
with pytest.raises(exceptions.S3InvalidStore):
154168
await filemanager.upload_file(
155169
user_id=user_id,
170+
store_id=None,
156171
store_name=store,
157172
s3_object=file_id,
158173
local_file_path=file_path,
@@ -162,6 +177,7 @@ async def test_invalid_store(
162177
with pytest.raises(exceptions.S3InvalidStore):
163178
await filemanager.download_file_from_s3(
164179
user_id=user_id,
180+
store_id=None,
165181
store_name=store,
166182
s3_object=file_id,
167183
local_folder=download_folder,
@@ -194,6 +210,7 @@ async def test_valid_metadata(
194210
store_id, e_tag = await filemanager.upload_file(
195211
user_id=user_id,
196212
store_id=s3_simcore_location,
213+
store_name=None,
197214
s3_object=file_id,
198215
local_file_path=file_path,
199216
)
@@ -252,6 +269,7 @@ async def test_delete_File(
252269
store_id, e_tag = await filemanager.upload_file(
253270
user_id=user_id,
254271
store_id=s3_simcore_location,
272+
store_name=None,
255273
s3_object=file_id,
256274
local_file_path=file_path,
257275
)

packages/simcore-sdk/tests/unit/test_node_data_data_manager.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
from filecmp import cmpfiles
66
from pathlib import Path
77
from shutil import copy, make_archive, unpack_archive
8-
from typing import Callable, List
8+
from typing import Callable, Iterator, List
99

1010
import pytest
1111
from simcore_sdk.node_data import data_manager
1212

1313

1414
@pytest.fixture
15-
def create_files() -> Callable:
15+
def create_files() -> Iterator[Callable[..., List[Path]]]:
1616
created_files = []
1717

1818
def _create_files(number: int, folder: Path) -> List[Path]:
@@ -76,6 +76,7 @@ async def test_push_folder(
7676
local_file_path=(test_compression_folder / "{}.zip".format(test_folder.stem)),
7777
s3_object=f"{project_id}/{node_uuid}/{test_folder.stem}.zip",
7878
store_id="0",
79+
store_name=None,
7980
user_id=user_id,
8081
)
8182

@@ -121,6 +122,7 @@ async def test_push_file(
121122
local_file_path=file_path,
122123
s3_object=f"{project_id}/{node_uuid}/{file_path.name}",
123124
store_id="0",
125+
store_name=None,
124126
user_id=user_id,
125127
)
126128
mock_filemanager.reset_mock()
@@ -152,7 +154,7 @@ async def test_pull_folder(
152154
create_files(files_number, test_control_folder)
153155
compressed_file_name = test_compression_folder / test_folder.stem
154156
archive_file = make_archive(
155-
compressed_file_name, "zip", root_dir=test_control_folder
157+
f"{compressed_file_name}", "zip", root_dir=test_control_folder
156158
)
157159
assert Path(archive_file).exists()
158160
# create mock downloaded folder
@@ -179,6 +181,7 @@ async def test_pull_folder(
179181
local_folder=test_compression_folder,
180182
s3_object=f"{project_id}/{node_uuid}/{test_folder.stem}.zip",
181183
store_id="0",
184+
store_name=None,
182185
user_id=user_id,
183186
)
184187

@@ -223,5 +226,6 @@ async def test_pull_file(
223226
local_folder=file_path.parent,
224227
s3_object=f"{project_id}/{node_uuid}/{file_path.name}",
225228
store_id="0",
229+
store_name=None,
226230
user_id=user_id,
227231
)

services/dask-sidecar/requirements/_base.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ requests
2424
dask[complete]
2525
dask-gateway
2626
pydantic[email,dotenv]
27-
27+
# s3 access
28+
s3fs
2829
# compression
2930
blosc
3031
lz4

0 commit comments

Comments
 (0)