Skip to content

Commit bd5eb5e

Browse files
review @pcrespov
1 parent 94952b9 commit bd5eb5e

File tree

9 files changed

+77
-73
lines changed

9 files changed

+77
-73
lines changed

services/efs-guardian/src/simcore_service_efs_guardian/services/background_tasks.py

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

99

1010
async def removal_policy_task(app: FastAPI) -> None:
11-
_logger.info("Removal policy task started")
11+
_logger.info("FAKE Removal policy task started (not yet implemented)")
1212

1313
# After X days of inactivity remove data from EFS
1414
# Probably use `last_modified_data` in the project DB table

services/efs-guardian/src/simcore_service_efs_guardian/services/background_tasks_setup.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class EfsGuardianBackgroundTask(TypedDict):
2727
]
2828

2929

30-
def on_app_startup(app: FastAPI) -> Callable[[], Awaitable[None]]:
30+
def _on_app_startup(app: FastAPI) -> Callable[[], Awaitable[None]]:
3131
async def _startup() -> None:
3232
with log_context(
3333
_logger, logging.INFO, msg="Efs Guardian startup.."
@@ -49,7 +49,7 @@ async def _startup() -> None:
4949
return _startup
5050

5151

52-
def on_app_shutdown(
52+
def _on_app_shutdown(
5353
_app: FastAPI,
5454
) -> Callable[[], Awaitable[None]]:
5555
async def _stop() -> None:
@@ -69,5 +69,5 @@ async def _stop() -> None:
6969

7070

7171
def setup(app: FastAPI) -> None:
72-
app.add_event_handler("startup", on_app_startup(app))
73-
app.add_event_handler("shutdown", on_app_shutdown(app))
72+
app.add_event_handler("startup", _on_app_startup(app))
73+
app.add_event_handler("shutdown", _on_app_shutdown(app))

services/efs-guardian/src/simcore_service_efs_guardian/services/efs_manager.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ async def get_project_node_data_size(
7777
/ f"{node_id}"
7878
)
7979

80-
service_size = await efs_manager_utils.get_size_bash_async(_dir_path)
81-
return service_size
80+
return await efs_manager_utils.get_size_bash_async(_dir_path)
8281

8382
async def remove_project_node_data_write_permissions(
8483
self, project_id: ProjectID, node_id: NodeID

services/efs-guardian/src/simcore_service_efs_guardian/services/process_messages.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from fastapi import FastAPI
44
from models_library.rabbitmq_messages import DynamicServiceRunningMessage
55
from pydantic import parse_raw_as
6+
from servicelib.logging_utils import log_context
67
from simcore_service_efs_guardian.services.modules.redis import get_redis_lock_client
78

89
from ..core.settings import get_application_settings
@@ -50,22 +51,16 @@ async def process_dynamic_service_running_message(app: FastAPI, data: bytes) ->
5051
)
5152

5253
if size > settings.EFS_DEFAULT_USER_SERVICE_SIZE_BYTES:
53-
_logger.warning(
54-
"Removing write permissions inside of EFS starts for project ID: %s, node ID: %s, current user: %s, size: %s, upper limit: %s",
55-
rabbit_message.project_id,
56-
rabbit_message.node_id,
57-
rabbit_message.user_id,
58-
size,
59-
settings.EFS_DEFAULT_USER_SERVICE_SIZE_BYTES,
60-
)
61-
redis = get_redis_lock_client(app)
62-
async with redis.lock_context(
63-
f"efs_remove_write_permissions-{rabbit_message.project_id=}-{rabbit_message.node_id=}",
64-
blocking=True,
65-
blocking_timeout_s=10,
66-
):
67-
await efs_manager.remove_project_node_data_write_permissions(
68-
project_id=rabbit_message.project_id, node_id=rabbit_message.node_id
69-
)
54+
msg = f"Removing write permissions inside of EFS starts for project ID: {rabbit_message.project_id}, node ID: {rabbit_message.node_id}, current user: {rabbit_message.user_id}, size: {size}, upper limit: {settings.EFS_DEFAULT_USER_SERVICE_SIZE_BYTES}"
55+
with log_context(_logger, logging.WARNING, msg=msg):
56+
redis = get_redis_lock_client(app)
57+
async with redis.lock_context(
58+
f"efs_remove_write_permissions-{rabbit_message.project_id=}-{rabbit_message.node_id=}",
59+
blocking=True,
60+
blocking_timeout_s=10,
61+
):
62+
await efs_manager.remove_project_node_data_write_permissions(
63+
project_id=rabbit_message.project_id, node_id=rabbit_message.node_id
64+
)
7065

7166
return True

services/efs-guardian/src/simcore_service_efs_guardian/services/process_messages_setup.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
_logger = logging.getLogger(__name__)
1616

1717

18-
_RUT_MESSAGE_TTL_IN_MS = 2 * 60 * 60 * 1000 # 2 hours
18+
_SEC = 1000 # in ms
19+
_MIN = 60 * _SEC # in ms
20+
_HOUR = 60 * _MIN # in ms
21+
22+
_EFS_MESSAGE_TTL_IN_MS = 2 * _HOUR
1923

2024

2125
async def _subscribe_to_rabbitmq(app) -> str:
@@ -27,12 +31,12 @@ async def _subscribe_to_rabbitmq(app) -> str:
2731
process_dynamic_service_running_message, app
2832
),
2933
exclusive_queue=False,
30-
message_ttl=_RUT_MESSAGE_TTL_IN_MS,
34+
message_ttl=_EFS_MESSAGE_TTL_IN_MS,
3135
)
3236
return subscribed_queue
3337

3438

35-
def on_app_startup(app: FastAPI) -> Callable[[], Awaitable[None]]:
39+
def _on_app_startup(app: FastAPI) -> Callable[[], Awaitable[None]]:
3640
async def _startup() -> None:
3741
with log_context(
3842
_logger, logging.INFO, msg="setup resource tracker"
@@ -48,7 +52,7 @@ async def _startup() -> None:
4852
return _startup
4953

5054

51-
def on_app_shutdown(
55+
def _on_app_shutdown(
5256
_app: FastAPI,
5357
) -> Callable[[], Awaitable[None]]:
5458
async def _stop() -> None:
@@ -58,5 +62,5 @@ async def _stop() -> None:
5862

5963

6064
def setup(app: FastAPI) -> None:
61-
app.add_event_handler("startup", on_app_startup(app))
62-
app.add_event_handler("shutdown", on_app_shutdown(app))
65+
app.add_event_handler("startup", _on_app_startup(app))
66+
app.add_event_handler("shutdown", _on_app_shutdown(app))

services/efs-guardian/tests/unit/conftest.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
# pylint:disable=unused-argument
33
# pylint:disable=redefined-outer-name
44

5+
import os
56
import re
7+
import shutil
8+
import stat
69
from collections.abc import AsyncIterator, Callable
710
from pathlib import Path
811
from typing import Awaitable
@@ -18,6 +21,7 @@
1821
from pytest_mock import MockerFixture
1922
from pytest_simcore.helpers.monkeypatch_envs import EnvVarsDict, setenvs_from_dict
2023
from servicelib.rabbitmq import RabbitMQRPCClient
24+
from settings_library.efs import AwsEfsSettings
2125
from settings_library.rabbit import RabbitSettings
2226
from simcore_service_efs_guardian.core.application import create_app
2327
from simcore_service_efs_guardian.core.settings import ApplicationSettings
@@ -28,6 +32,7 @@
2832
"pytest_simcore.docker_registry",
2933
"pytest_simcore.docker_swarm",
3034
"pytest_simcore.environment_configs",
35+
"pytest_simcore.faker_projects_data",
3136
"pytest_simcore.pydantic_models",
3237
"pytest_simcore.pytest_global_environs",
3338
"pytest_simcore.rabbit_service",
@@ -148,3 +153,22 @@ async def rpc_client(
148153
async def mocked_redis_server(mocker: MockerFixture) -> None:
149154
mock_redis = FakeRedis()
150155
mocker.patch("redis.asyncio.from_url", return_value=mock_redis)
156+
157+
158+
@pytest.fixture
159+
async def cleanup(app: FastAPI):
160+
161+
yield
162+
163+
aws_efs_settings: AwsEfsSettings = app.state.settings.EFS_GUARDIAN_AWS_EFS_SETTINGS
164+
_dir_path = Path(aws_efs_settings.EFS_MOUNTED_PATH)
165+
if _dir_path.exists():
166+
for root, dirs, files in os.walk(_dir_path):
167+
for name in dirs + files:
168+
file_path = Path(root, name)
169+
# Get the current permissions of the file or directory
170+
current_permissions = Path.stat(file_path).st_mode
171+
# Add write permission for the owner (user)
172+
Path.chmod(file_path, current_permissions | stat.S_IWUSR)
173+
174+
shutil.rmtree(_dir_path)

services/efs-guardian/tests/unit/test_api_health.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def app_environment(
3030

3131
async def test_healthcheck(
3232
rabbit_service: RabbitSettings,
33-
mocked_redis_server,
33+
mocked_redis_server: None,
3434
client: httpx.AsyncClient,
3535
):
3636
response = await client.get("/")

services/efs-guardian/tests/unit/test_efs_guardian_rpc.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import pytest
1111
from faker import Faker
1212
from fastapi import FastAPI
13+
from models_library.projects import ProjectID
14+
from models_library.projects_nodes import NodeID
1315
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
1416
from pytest_simcore.helpers.typing_env import EnvVarsDict
1517
from servicelib.rabbitmq import RabbitMQRPCClient
@@ -40,20 +42,21 @@ async def test_rpc_create_project_specific_data_dir(
4042
rpc_client: RabbitMQRPCClient,
4143
faker: Faker,
4244
app: FastAPI,
45+
project_id: ProjectID,
46+
node_id: NodeID,
47+
cleanup: None,
4348
):
4449
aws_efs_settings: AwsEfsSettings = app.state.settings.EFS_GUARDIAN_AWS_EFS_SETTINGS
4550

46-
_project_id = faker.uuid4()
47-
_node_id = faker.uuid4()
48-
_storage_directory_name = faker.name()
51+
_storage_directory_name = faker.word()
4952

5053
with patch(
5154
"simcore_service_efs_guardian.services.efs_manager.os.chown"
5255
) as mocked_chown:
5356
result = await efs_manager.create_project_specific_data_dir(
5457
rpc_client,
55-
project_id=_project_id,
56-
node_id=_node_id,
58+
project_id=project_id,
59+
node_id=node_id,
5760
storage_directory_name=_storage_directory_name,
5861
)
5962
mocked_chown.assert_called_once()
@@ -62,8 +65,8 @@ async def test_rpc_create_project_specific_data_dir(
6265
_expected_path = (
6366
aws_efs_settings.EFS_MOUNTED_PATH
6467
/ aws_efs_settings.EFS_PROJECT_SPECIFIC_DATA_DIRECTORY
65-
/ _project_id
66-
/ _node_id
68+
/ f"{project_id}"
69+
/ f"{node_id}"
6770
/ _storage_directory_name
6871
)
6972
assert _expected_path == result

services/efs-guardian/tests/unit/test_efs_manager.py

Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
# pylint: disable=unused-argument
55
# pylint: disable=unused-variable
66

7-
import os
8-
import shutil
97
import stat
108
from pathlib import Path
119
from unittest.mock import patch
@@ -41,32 +39,13 @@ def app_environment(
4139
)
4240

4341

44-
@pytest.fixture
45-
async def cleanup(app: FastAPI):
46-
47-
yield
48-
49-
aws_efs_settings: AwsEfsSettings = app.state.settings.EFS_GUARDIAN_AWS_EFS_SETTINGS
50-
_dir_path = Path(aws_efs_settings.EFS_MOUNTED_PATH)
51-
if Path.exists(_dir_path):
52-
for root, dirs, files in os.walk(_dir_path):
53-
for name in dirs + files:
54-
file_path = os.path.join(root, name)
55-
# Get the current permissions of the file or directory
56-
current_permissions = os.stat(file_path).st_mode
57-
# Add write permission for the owner (user)
58-
os.chmod(file_path, current_permissions | stat.S_IWUSR)
59-
60-
shutil.rmtree(_dir_path)
61-
62-
6342
def assert_permissions(
6443
file_path: Path,
6544
expected_readable: bool,
6645
expected_writable: bool,
6746
expected_executable: bool,
6847
):
69-
file_stat = os.stat(file_path)
48+
file_stat = Path.stat(file_path)
7049
file_permissions = file_stat.st_mode
7150
is_readable = bool(file_permissions & stat.S_IRUSR)
7251
is_writable = bool(file_permissions & stat.S_IWUSR)
@@ -88,25 +67,25 @@ async def test_remove_write_access_rights(
8867
mocked_redis_server: None,
8968
app: FastAPI,
9069
cleanup: None,
70+
project_id: ProjectID,
71+
node_id: NodeID,
9172
):
9273
aws_efs_settings: AwsEfsSettings = app.state.settings.EFS_GUARDIAN_AWS_EFS_SETTINGS
9374

94-
_project_id = ProjectID(faker.uuid4())
95-
_node_id = NodeID(faker.uuid4())
9675
_storage_directory_name = faker.word()
9776
_dir_path = (
9877
aws_efs_settings.EFS_MOUNTED_PATH
9978
/ aws_efs_settings.EFS_PROJECT_SPECIFIC_DATA_DIRECTORY
100-
/ f"{_project_id}"
101-
/ f"{_node_id}"
79+
/ f"{project_id}"
80+
/ f"{node_id}"
10281
/ f"{_storage_directory_name}"
10382
)
10483

10584
efs_manager: EfsManager = app.state.efs_manager
10685

10786
assert (
10887
await efs_manager.check_project_node_data_directory_exits(
109-
project_id=_project_id, node_id=_node_id
88+
project_id=project_id, node_id=node_id
11089
)
11190
is False
11291
)
@@ -115,31 +94,31 @@ async def test_remove_write_access_rights(
11594
"simcore_service_efs_guardian.services.efs_manager.os.chown"
11695
) as mocked_chown:
11796
await efs_manager.create_project_specific_data_dir(
118-
project_id=_project_id,
119-
node_id=_node_id,
97+
project_id=project_id,
98+
node_id=node_id,
12099
storage_directory_name=_storage_directory_name,
121100
)
101+
assert mocked_chown.called
122102

123103
assert (
124104
await efs_manager.check_project_node_data_directory_exits(
125-
project_id=_project_id, node_id=_node_id
105+
project_id=project_id, node_id=node_id
126106
)
127107
is True
128108
)
129109

130110
size_before = await efs_manager.get_project_node_data_size(
131-
project_id=_project_id, node_id=_node_id
111+
project_id=project_id, node_id=node_id
132112
)
133113

134114
file_paths = []
135115
for i in range(3): # Let's create 3 small files for testing
136116
file_path = Path(_dir_path, f"test_file_{i}.txt")
137-
with open(file_path, "w") as f:
138-
f.write(f"This is file {i}")
117+
file_path.write_text(f"This is file {i}")
139118
file_paths.append(file_path)
140119

141120
size_after = await efs_manager.get_project_node_data_size(
142-
project_id=_project_id, node_id=_node_id
121+
project_id=project_id, node_id=node_id
143122
)
144123
assert size_after > size_before
145124

@@ -153,7 +132,7 @@ async def test_remove_write_access_rights(
153132
)
154133

155134
await efs_manager.remove_project_node_data_write_permissions(
156-
project_id=_project_id, node_id=_node_id
135+
project_id=project_id, node_id=node_id
157136
)
158137

159138
for file_path in file_paths:

0 commit comments

Comments
 (0)