Skip to content

Commit f90a680

Browse files
authored
🐛 Fix/storage API backwards compatibility with deprecated storage client sdk (ITISFoundation#3198)
1 parent 67beca2 commit f90a680

File tree

8 files changed

+216
-5
lines changed

8 files changed

+216
-5
lines changed

api/specs/storage/openapi.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
openapi: 3.0.0
22
info:
33
description: API definition for simcore-service-storage service
4-
version: 0.2.1
4+
version: 0.3.0
55
title: simcore-service-storage API
66
contact:
77
name: IT'IS Foundation

services/storage/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.1
1+
0.3.0

services/storage/requirements/_test.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
--constraint ../../../requirements/constraints.txt
66
--constraint _base.txt
77

8+
# to test backwards compatibility against deprecated client-sdk (used still in old versions of simcore-sdk)
9+
simcore-service-storage-sdk @ git+https://github.com/ITISFoundation/osparc-simcore.git@cfdf4f86d844ebb362f4f39e9c6571d561b72897#subdirectory=services/storage/client-sdk/python
810

911
aioresponses
1012
codecov

services/storage/requirements/_test.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ aiohttp==3.8.1
1010
# -c requirements/_base.txt
1111
# aioresponses
1212
# pytest-aiohttp
13+
# simcore-service-storage-sdk
1314
aioresponses==0.7.3
1415
# via -r requirements/_test.in
1516
aiosignal==1.2.0
@@ -47,7 +48,9 @@ botocore==1.24.21
4748
# moto
4849
# s3transfer
4950
certifi==2022.5.18.1
50-
# via requests
51+
# via
52+
# requests
53+
# simcore-service-storage-sdk
5154
cffi==1.15.0
5255
# via cryptography
5356
cfn-lint==0.61.1
@@ -250,6 +253,7 @@ python-dateutil==2.8.2
250253
# faker
251254
# moto
252255
# pandas
256+
# simcore-service-storage-sdk
253257
python-dotenv==0.20.0
254258
# via -r requirements/_test.in
255259
python-jose==3.3.0
@@ -284,6 +288,8 @@ s3transfer==0.5.2
284288
# boto3
285289
sarif-om==1.0.4
286290
# via cfn-lint
291+
simcore-service-storage-sdk @ git+https://github.com/ITISFoundation/osparc-simcore.git@cfdf4f86d844ebb362f4f39e9c6571d561b72897#subdirectory=services/storage/client-sdk/python
292+
# via -r requirements/_test.in
287293
six==1.16.0
288294
# via
289295
# -c requirements/_base.txt
@@ -292,6 +298,7 @@ six==1.16.0
292298
# jsonschema
293299
# junit-xml
294300
# python-dateutil
301+
# simcore-service-storage-sdk
295302
sshpubkeys==3.3.1
296303
# via moto
297304
termcolor==1.1.0
@@ -313,6 +320,7 @@ urllib3==1.26.9
313320
# botocore
314321
# requests
315322
# responses
323+
# simcore-service-storage-sdk
316324
websocket-client==1.3.2
317325
# via docker
318326
werkzeug==2.0.3

services/storage/setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.2.1
2+
current_version = 0.3.0
33
commit = True
44
message = services/storage api version: {current_version} → {new_version}
55
tag = False

services/storage/src/simcore_service_storage/api/v0/openapi.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
openapi: 3.0.0
22
info:
33
description: API definition for simcore-service-storage service
4-
version: 0.2.1
4+
version: 0.3.0
55
title: simcore-service-storage API
66
contact:
77
name: IT'IS Foundation

services/storage/src/simcore_service_storage/handlers_files.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,29 @@ async def get_file_metadata(request: web.Request):
9191
# TODO: once all legacy services are gone, remove the try except, it will default to 404
9292
return {"error": "No result found", "data": {}}
9393

94+
if request.headers.get("User-Agent") == "OpenAPI-Generator/0.1.0/python":
95+
# LEGACY compatiblity with API v0.1.0
96+
# SEE models used in sdk in:
97+
# https://github.com/ITISFoundation/osparc-simcore/blob/cfdf4f86d844ebb362f4f39e9c6571d561b72897/services/storage/client-sdk/python/simcore_service_storage_sdk/models/file_meta_data_enveloped.py#L34
98+
# https://github.com/ITISFoundation/osparc-simcore/blob/cfdf4f86d844ebb362f4f39e9c6571d561b72897/services/storage/client-sdk/python/simcore_service_storage_sdk/models/file_meta_data_type.py#L34
99+
return {
100+
"data": {
101+
"file_uuid": data.file_uuid,
102+
"location_id": data.location_id,
103+
"location": data.location,
104+
"bucket_name": data.bucket_name,
105+
"object_name": data.object_name,
106+
"project_id": data.project_id,
107+
"project_name": data.project_name,
108+
"node_id": data.node_id,
109+
"node_name": data.node_name,
110+
"file_name": data.file_name,
111+
"user_id": data.user_id,
112+
"user_name": None,
113+
},
114+
"error": None,
115+
}
116+
94117
return jsonable_encoder(FileMetaDataGet.from_orm(data))
95118

96119

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# pylint: disable=redefined-outer-name
2+
# pylint: disable=unused-argument
3+
# pylint: disable=unused-variable
4+
5+
"""
6+
Tests compatibility of old services/storage/client-sdk/python client ('simcore_service_storage_sdk')
7+
against current storage OAS
8+
9+
10+
NOTE: this test coverage is intentionally limited to the functions of 'simcore_service_storage_sdk'
11+
used in simcore_sdk since legacy services are planned to be deprecated.
12+
"""
13+
14+
from pathlib import Path
15+
16+
import aiohttp
17+
import pytest
18+
from aiohttp.test_utils import TestClient
19+
from faker import Faker
20+
from models_library.projects_nodes_io import LocationID, SimcoreS3FileID
21+
from models_library.users import UserID
22+
from simcore_service_storage.simcore_s3_dsm import SimcoreS3DataManager
23+
from simcore_service_storage_sdk import ApiClient, Configuration, UsersApi
24+
25+
pytest_simcore_core_services_selection = [
26+
"postgres",
27+
]
28+
pytest_simcore_ops_services_selection = [
29+
"adminer",
30+
]
31+
32+
33+
#
34+
# FIXTURES: produces values to be used as arguments in the simcore_service_storage_sdk API
35+
#
36+
37+
38+
@pytest.fixture
39+
def user_id(user_id: UserID) -> str:
40+
"""overrides tests/fixtures/data_models.py::user_id
41+
and adapts to simcore_service_storage_sdk API
42+
"""
43+
return str(user_id)
44+
45+
46+
@pytest.fixture
47+
def file_id(simcore_file_id: SimcoreS3FileID) -> str:
48+
"""overrides tests/conftest.py::simcore_file_id
49+
and adapts to simcore_service_storage_sdk API
50+
"""
51+
return str(simcore_file_id)
52+
53+
54+
@pytest.fixture
55+
def location_id() -> LocationID:
56+
return SimcoreS3DataManager.get_location_id()
57+
58+
59+
@pytest.fixture
60+
def location_name() -> str:
61+
return SimcoreS3DataManager.get_location_name()
62+
63+
64+
async def test_storage_client_used_in_simcore_sdk_0_3_2(
65+
client: TestClient,
66+
file_id: str,
67+
user_id: str,
68+
location_id: int,
69+
location_name: str,
70+
tmp_path: Path,
71+
faker: Faker,
72+
):
73+
"""
74+
This test reproduces the failure described in https://github.com/ITISFoundation/osparc-simcore/pull/3198
75+
where a legacy service could not download data from s3.
76+
77+
Here we test the calls from 'simcore_service_storage_sdk' used in simcore_sdk.node_ports.filemanage (v0.3.2)
78+
SEE https://github.com/ITISFoundation/osparc-simcore/blob/cfdf4f86d844ebb362f4f39e9c6571d561b72897/packages/simcore-sdk/src/simcore_sdk/node_ports/filemanager.py
79+
80+
NOTICE that 'simcore_service_storage_sdk' was automatically built using OAS v0.1.0 despite the fact that at that time
81+
the OAS had already change!!!
82+
"""
83+
84+
assert client.app
85+
assert client.server
86+
# --------
87+
cfg = Configuration()
88+
cfg.host = f"http://{client.host}:{client.port}/v0"
89+
cfg.debug = True
90+
91+
assert cfg.host == f'{client.make_url("/v0")}'
92+
print(f"{cfg=}")
93+
print(f"{cfg.to_debug_report()=}")
94+
95+
# --------
96+
api_client = ApiClient(cfg)
97+
print(f"{api_client=}")
98+
print(f"{api_client.default_headers=}")
99+
100+
# --------
101+
try:
102+
api = UsersApi(api_client)
103+
print(f"{api=}")
104+
105+
(
106+
response_payload,
107+
status_code,
108+
response_headers,
109+
) = await api.get_storage_locations_with_http_info(user_id)
110+
print(f"{response_payload=}")
111+
print(f"{status_code=}")
112+
print(f"{response_headers=}")
113+
114+
assert status_code == 200
115+
116+
# _get_upload_link
117+
# https://github.com/ITISFoundation/osparc-simcore/blob/cfdf4f86d844ebb362f4f39e9c6571d561b72897/packages/simcore-sdk/src/simcore_sdk/node_ports/filemanager.py#L132
118+
resp_model = await api.upload_file(
119+
location_id=location_id,
120+
user_id=user_id,
121+
file_id=file_id,
122+
_request_timeout=1000,
123+
)
124+
assert resp_model.error is None
125+
assert resp_model.data.link is not None
126+
127+
# dumps file & upload
128+
file = tmp_path / Path(file_id).name
129+
uploaded_content = faker.text()
130+
file.write_text(uploaded_content)
131+
132+
async with aiohttp.ClientSession() as session:
133+
with file.open("rb") as fh:
134+
async with session.put(resp_model.data.link, data=fh) as r:
135+
assert r.status == 200, await r.text()
136+
print(await r.text())
137+
138+
# entry_exists
139+
# https://github.com/ITISFoundation/osparc-simcore/blob/cfdf4f86d844ebb362f4f39e9c6571d561b72897/packages/simcore-sdk/src/simcore_sdk/node_ports/filemanager.py#L322
140+
#
141+
# NOTE: jupyter-smash 2.5.9 was failing to download because
142+
# this call was not returning any 'object_name'
143+
# A bug in the response of this call was preventing downloading data
144+
# with the new storage API
145+
#
146+
resp_model = await api.get_file_metadata(file_id, location_id, user_id)
147+
print(type(resp_model), ":\n", resp_model)
148+
assert resp_model.data.object_name is not None
149+
assert resp_model.error is None
150+
151+
# _get_location_id_from_location_name
152+
# https://github.com/ITISFoundation/osparc-simcore/blob/cfdf4f86d844ebb362f4f39e9c6571d561b72897/packages/simcore-sdk/src/simcore_sdk/node_ports/filemanager.py#L89
153+
resp_model = await api.get_storage_locations(user_id=user_id)
154+
print(f"{resp_model=}")
155+
for location in resp_model.data:
156+
assert location["name"] == location_name
157+
assert location["id"] == location_id
158+
159+
# _get_download_link
160+
# https://github.com/ITISFoundation/osparc-simcore/blob/cfdf4f86d844ebb362f4f39e9c6571d561b72897/packages/simcore-sdk/src/simcore_sdk/node_ports/filemanager.py#L123
161+
resp_model = await api.download_file(
162+
location_id=location_id,
163+
user_id=user_id,
164+
file_id=file_id,
165+
_request_timeout=1000,
166+
)
167+
print(f"{resp_model=}")
168+
assert resp_model.error is None
169+
170+
async with aiohttp.ClientSession() as session:
171+
async with session.get(resp_model.data.link) as r:
172+
print(r.status)
173+
downloaded_content = await r.text()
174+
assert r.status == 200, downloaded_content
175+
assert uploaded_content == downloaded_content
176+
177+
finally:
178+
del api_client

0 commit comments

Comments
 (0)