diff --git a/services/agent/src/simcore_service_agent/services/backup.py b/services/agent/src/simcore_service_agent/services/backup.py index 616af7e97f85..0e1a9b00bcac 100644 --- a/services/agent/src/simcore_service_agent/services/backup.py +++ b/services/agent/src/simcore_service_agent/services/backup.py @@ -1,6 +1,7 @@ import asyncio +import json import logging -import os +import socket import tempfile from asyncio.streams import StreamReader from datetime import timedelta @@ -9,6 +10,7 @@ from typing import Final from uuid import uuid4 +import httpx from fastapi import FastAPI from servicelib.container_utils import run_command_in_container from settings_library.utils_r_clone import resolve_provider @@ -112,8 +114,28 @@ def _log_expected_operation( _logger.log(log_level, formatted_message) +def _get_self_container_ip() -> str: + return socket.gethostbyname(socket.gethostname()) + + +async def _get_self_container() -> str: + ip = _get_self_container_ip() + + async with httpx.AsyncClient( + transport=httpx.AsyncHTTPTransport(uds="/var/run/docker.sock") + ) as client: + response = await client.get("http://localhost/containers/json") + for entry in response.json(): + if ip in json.dumps(entry): + container_id: str = entry["Id"] + return container_id + + msg = "Could not determine self container ID" + raise RuntimeError(msg) + + async def _ensure_permissions_on_source_dir(source_dir: Path) -> None: - self_container = os.environ["HOSTNAME"] + self_container = await _get_self_container() await run_command_in_container( self_container, command=f"chmod -R o+rX '{source_dir}'", diff --git a/services/agent/tests/unit/test_services_backup.py b/services/agent/tests/unit/test_services_backup.py index 9b612112c703..2d73dd80fb17 100644 --- a/services/agent/tests/unit/test_services_backup.py +++ b/services/agent/tests/unit/test_services_backup.py @@ -15,6 +15,8 @@ from models_library.projects_nodes_io import NodeID from models_library.services_types import ServiceRunID from pydantic import NonNegativeInt +from pytest_mock import MockerFixture +from servicelib.container_utils import run_command_in_container from simcore_service_agent.core.settings import ApplicationSettings from simcore_service_agent.services.backup import backup_volume from simcore_service_agent.services.docker_utils import get_volume_details @@ -42,7 +44,7 @@ def volume_content(tmpdir: Path) -> Path: @pytest.fixture async def mock_container_with_data( volume_content: Path, monkeypatch: pytest.MonkeyPatch -) -> AsyncIterable[None]: +) -> AsyncIterable[str]: async with aiodocker.Docker() as client: container = await client.containers.run( config={ @@ -56,7 +58,7 @@ async def mock_container_with_data( container_name = container_inspect["Name"][1:] monkeypatch.setenv("HOSTNAME", container_name) - yield None + yield container_inspect["Id"] await container.delete(force=True) @@ -68,8 +70,24 @@ def downlaoded_from_s3(tmpdir: Path) -> Path: return path +@pytest.fixture +async def mock__get_self_container_ip( + mock_container_with_data: str, + mocker: MockerFixture, +) -> None: + container_ip = await run_command_in_container( + mock_container_with_data, command="hostname -i" + ) + + mocker.patch( + "simcore_service_agent.services.backup._get_self_container_ip", + return_value=container_ip.strip(), + ) + + async def test_backup_volume( - mock_container_with_data: None, + mock_container_with_data: str, + mock__get_self_container_ip: None, volume_content: Path, project_id: ProjectID, swarm_stack_name: str,