Skip to content

Commit fd9e0ed

Browse files
Merge branch 'master' into is8027/exclude-conversations-ui-when-copying-projects
2 parents 72b3eca + 61a124a commit fd9e0ed

File tree

10 files changed

+300
-42
lines changed

10 files changed

+300
-42
lines changed

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from simcore_postgres_database.models.comp_pipeline import StateType, comp_pipeline
1616
from simcore_postgres_database.models.comp_tasks import comp_tasks
1717
from simcore_postgres_database.models.projects import ProjectType, projects
18+
from simcore_postgres_database.models.services import services_access_rights
1819
from simcore_postgres_database.models.users import UserRole, UserStatus, users
1920
from simcore_postgres_database.utils_projects_nodes import (
2021
ProjectNodeCreate,
@@ -183,3 +184,74 @@ def creator(project_id: ProjectID, **task_kwargs) -> dict[str, Any]:
183184
conn.execute(
184185
comp_tasks.delete().where(comp_tasks.c.task_id.in_(created_task_ids))
185186
)
187+
188+
189+
@pytest.fixture
190+
def grant_service_access_rights(
191+
postgres_db: sa.engine.Engine,
192+
) -> Iterator[Callable[..., dict[str, Any]]]:
193+
"""Fixture to grant access rights on a service for a given group.
194+
195+
Creates a row in the services_access_rights table with the provided parameters and cleans up after the test.
196+
"""
197+
created_entries: list[tuple[str, str, int, str]] = []
198+
199+
def creator(
200+
*,
201+
service_key: str,
202+
service_version: str,
203+
group_id: int = 1,
204+
product_name: str = "osparc",
205+
execute_access: bool = True,
206+
write_access: bool = False,
207+
) -> dict[str, Any]:
208+
values = {
209+
"key": service_key,
210+
"version": service_version,
211+
"gid": group_id,
212+
"product_name": product_name,
213+
"execute_access": execute_access,
214+
"write_access": write_access,
215+
}
216+
217+
# Directly use SQLAlchemy to insert and retrieve the row
218+
with postgres_db.begin() as conn:
219+
# Insert the row
220+
conn.execute(services_access_rights.insert().values(**values))
221+
222+
# Retrieve the inserted row
223+
result = conn.execute(
224+
sa.select(services_access_rights).where(
225+
sa.and_(
226+
services_access_rights.c.key == service_key,
227+
services_access_rights.c.version == service_version,
228+
services_access_rights.c.gid == group_id,
229+
services_access_rights.c.product_name == product_name,
230+
)
231+
)
232+
)
233+
row = result.one()
234+
235+
# Track the entry for cleanup
236+
created_entries.append(
237+
(service_key, service_version, group_id, product_name)
238+
)
239+
240+
# Convert row to dict
241+
return dict(row._asdict())
242+
243+
yield creator
244+
245+
# Cleanup all created entries
246+
with postgres_db.begin() as conn:
247+
for key, version, gid, product in created_entries:
248+
conn.execute(
249+
services_access_rights.delete().where(
250+
sa.and_(
251+
services_access_rights.c.key == key,
252+
services_access_rights.c.version == version,
253+
services_access_rights.c.gid == gid,
254+
services_access_rights.c.product_name == product,
255+
)
256+
)
257+
)

packages/service-library/src/servicelib/fastapi/http_error.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,35 @@ async def _http_error_handler(request: Request, exc: Exception) -> JSONResponse:
4848
"errors": error_extractor(exc) if error_extractor else [f"{exc}"]
4949
}
5050

51+
response = JSONResponse(
52+
content=jsonable_encoder(
53+
{"error": error_content} if envelope_error else error_content
54+
),
55+
status_code=status_code,
56+
)
57+
5158
if is_5xx_server_error(status_code):
5259
_logger.exception(
5360
create_troubleshootting_log_kwargs(
54-
"Unexpected error happened in the Resource Usage Tracker. Please contact support.",
61+
f"A 5XX server error happened in current service. Responding with {error_content} and {status_code} status code",
5562
error=exc,
5663
error_context={
5764
"request": request,
58-
"request.method": f"{request.method}",
65+
"request.client_host": (
66+
request.client.host if request.client else "unknown"
67+
),
68+
"request.method": request.method,
69+
"request.url_path": request.url.path,
70+
"request.query_params": dict(request.query_params),
71+
"request.headers": dict(request.headers),
72+
"response": response,
73+
"response.error_content": error_content,
74+
"response.status_code": status_code,
5975
},
6076
)
6177
)
6278

63-
return JSONResponse(
64-
content=jsonable_encoder(
65-
{"error": error_content} if envelope_error else error_content
66-
),
67-
status_code=status_code,
68-
)
79+
return response
6980

7081
return _http_error_handler
7182

services/catalog/src/simcore_service_catalog/clients/director.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,13 @@ async def get_service_extras(
277277
)
278278

279279
# get org labels
280-
result.update(
281-
{
282-
sl: labels[dl]
283-
for dl, sl in _ORG_LABELS_TO_SCHEMA_LABELS.items()
284-
if dl in labels
285-
}
286-
)
280+
if service_build_details := {
281+
sl: labels[dl]
282+
for dl, sl in _ORG_LABELS_TO_SCHEMA_LABELS.items()
283+
if dl in labels
284+
}:
287285

288-
_logger.debug("Following service extras were compiled: %s", pformat(result))
286+
result.update({"service_build_details": service_build_details})
289287

290288
return TypeAdapter(ServiceExtras).validate_python(result)
291289

services/catalog/src/simcore_service_catalog/service/access_rights.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424

2525
_logger = logging.getLogger(__name__)
2626

27-
_LEGACY_SERVICES_DATE: datetime = datetime(year=2020, month=8, day=19, tzinfo=UTC)
27+
_OLD_SERVICES_CUTOFF_DATETIME: datetime = datetime(
28+
year=2020, month=8, day=19, tzinfo=UTC
29+
)
2830

2931

3032
class InheritedData(TypedDict):
@@ -37,15 +39,42 @@ def _is_frontend_service(service: ServiceMetaDataPublished) -> bool:
3739

3840

3941
async def _is_old_service(app: FastAPI, service: ServiceMetaDataPublished) -> bool:
42+
#
4043
# NOTE: https://github.com/ITISFoundation/osparc-simcore/pull/6003#discussion_r1658200909
41-
# get service build date
42-
client = get_director_client(app)
44+
#
45+
service_extras = await get_director_client(app).get_service_extras(
46+
service.key, service.version
47+
)
48+
49+
# 1. w/o build details
50+
has_no_build_data = (
51+
not service_extras or service_extras.service_build_details is None
52+
)
53+
if has_no_build_data:
54+
_logger.debug(
55+
"Service %s:%s is considered legacy because it has no build details",
56+
service.key,
57+
service.version,
58+
)
59+
return True
60+
61+
# 2. check if built before cutoff date
62+
assert service_extras.service_build_details
63+
service_build_datetime = arrow.get(
64+
service_extras.service_build_details.build_date
65+
).datetime
4366

44-
data = await client.get_service_extras(service.key, service.version)
45-
if not data or data.service_build_details is None:
67+
is_older_than_cutoff = service_build_datetime < _OLD_SERVICES_CUTOFF_DATETIME
68+
if is_older_than_cutoff:
69+
_logger.debug(
70+
"Service %s:%s is considered legacy because it was built before %s",
71+
service.key,
72+
service.version,
73+
_OLD_SERVICES_CUTOFF_DATETIME,
74+
)
4675
return True
47-
service_build_data = arrow.get(data.service_build_details.build_date).datetime
48-
return bool(service_build_data < _LEGACY_SERVICES_DATE)
76+
77+
return False
4978

5079

5180
async def evaluate_default_service_ownership_and_rights(

services/catalog/tests/unit/conftest.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@
2121
from faker import Faker
2222
from fastapi import FastAPI, status
2323
from fastapi.testclient import TestClient
24-
from models_library.api_schemas_directorv2.services import ServiceExtras
24+
from models_library.api_schemas_directorv2.services import (
25+
NodeRequirements,
26+
ServiceBuildDetails,
27+
ServiceExtras,
28+
)
2529
from packaging.version import Version
26-
from pydantic import EmailStr, TypeAdapter
30+
from pydantic import EmailStr
2731
from pytest_mock import MockerFixture, MockType
2832
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
2933
from pytest_simcore.helpers.typing_env import EnvVarsDict
@@ -407,8 +411,10 @@ def mocked_director_rest_api_base(
407411

408412
@pytest.fixture
409413
def get_mocked_service_labels() -> Callable[[str, str], dict]:
410-
def _(service_key: str, service_version: str) -> dict:
411-
return {
414+
def _(
415+
service_key: str, service_version: str, *, include_org_labels: bool = True
416+
) -> dict:
417+
base_labels = {
412418
"io.simcore.authors": '{"authors": [{"name": "John Smith", "email": "[email protected]", "affiliation": "ACME\'IS Foundation"}]}',
413419
"io.simcore.contact": '{"contact": "[email protected]"}',
414420
"io.simcore.description": '{"description": "Autonomous Nervous System Network model"}',
@@ -423,21 +429,35 @@ def _(service_key: str, service_version: str) -> dict:
423429
"xxxxx", service_version
424430
),
425431
"maintainer": "johnsmith",
426-
"org.label-schema.build-date": "2023-04-17T08:04:15Z",
427-
"org.label-schema.schema-version": "1.0",
428-
"org.label-schema.vcs-ref": "4d79449a2e79f8a3b3b2e1dd0290af9f3d1a8792",
429-
"org.label-schema.vcs-url": "https://github.com/ITISFoundation/jupyter-math.git",
430432
"simcore.service.restart-policy": "no-restart",
431433
"simcore.service.settings": '[{"name": "Resources", "type": "Resources", "value": {"Limits": {"NanoCPUs": 1000000000, "MemoryBytes": 4194304}, "Reservations": {"NanoCPUs": 4000000000, "MemoryBytes": 2147483648}}}]',
432434
}
433435

436+
if include_org_labels:
437+
base_labels.update(
438+
{
439+
"org.label-schema.build-date": "2023-04-17T08:04:15Z",
440+
"org.label-schema.schema-version": "1.0",
441+
"org.label-schema.vcs-ref": "4d79449a2e79f8a3b3b2e1dd0290af9f3d1a8792",
442+
"org.label-schema.vcs-url": "https://github.com/ITISFoundation/jupyter-math.git",
443+
}
444+
)
445+
446+
return base_labels
447+
434448
return _
435449

436450

437451
@pytest.fixture
438452
def mock_service_extras() -> ServiceExtras:
439-
return TypeAdapter(ServiceExtras).validate_python(
440-
ServiceExtras.model_json_schema()["examples"][0]
453+
return ServiceExtras(
454+
node_requirements=NodeRequirements(CPU=1.0, GPU=None, RAM=4194304, VRAM=None),
455+
service_build_details=ServiceBuildDetails(
456+
build_date="2023-04-17T08:04:15Z",
457+
vcs_ref="4d79449a2e79f8a3b3b2e1dd0290af9f3d1a8792",
458+
vcs_url="https://github.com/ITISFoundation/jupyter-math.git",
459+
),
460+
container_spec=None,
441461
)
442462

443463

0 commit comments

Comments
 (0)