Skip to content

Commit

Permalink
Fix: The home bind mount detection on Linux.
Browse files Browse the repository at this point in the history
  • Loading branch information
csadorf committed Feb 8, 2022
1 parent 4fc07f9 commit 9f1e5ea
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 40 deletions.
39 changes: 6 additions & 33 deletions aiidalab_launch/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from contextlib import contextmanager
from dataclasses import asdict, dataclass, field
from enum import Enum, auto
from pathlib import Path, PosixPath, PurePosixPath, WindowsPath
from pathlib import Path, PurePosixPath
from secrets import token_hex
from typing import Any, AsyncGenerator, Generator
from urllib.parse import quote_plus
Expand All @@ -19,7 +19,7 @@
from docker.models.containers import Container
from packaging.version import parse as parse_version

from .util import _async_wrap_iter, get_docker_env
from .util import _async_wrap_iter, docker_mount_for, get_docker_env
from .version import __version__

MAIN_PROFILE_NAME = "default"
Expand Down Expand Up @@ -69,35 +69,6 @@ def _get_aiidalab_default_apps(container: Container) -> list:
return []


def _find_docker_home_mount(container: Container, system_user: str) -> Path | None:
# Find the specified home bind mount path for the existing container.
try:
home_mount = [
mount
for mount in container.attrs["Mounts"]
if mount["Destination"] == f"/home/{system_user}"
][0]
except IndexError:
return None
if home_mount["Type"] == "bind":
docker_root = PurePosixPath("/host_mnt")
docker_path = PurePosixPath(home_mount["Source"])
try:
# Try Windows
drive = docker_path.relative_to(docker_root).parts[0]
return WindowsPath(
f"{drive}:",
docker_path.root,
docker_path.relative_to(docker_root, drive),
)
except NotImplementedError:
return PosixPath(docker_root.root, docker_path.relative_to(docker_root))
elif home_mount["Type"] == "volume":
return home_mount["Name"]
else:
raise RuntimeError("Unexpected mount type.")


@dataclass
class Profile:
name: str = MAIN_PROFILE_NAME
Expand Down Expand Up @@ -147,13 +118,15 @@ def from_container(cls, container: Container) -> Profile:
raise RuntimeError(
f"Container {container.id} does not appear to be an AiiDAlab container."
)
system_user = _get_system_user(container)

system_user = _get_system_user(container)
return Profile(
name=profile_name,
port=_get_host_port(container),
default_apps=_get_aiidalab_default_apps(container),
home_mount=str(_find_docker_home_mount(container, system_user)),
home_mount=str(
docker_mount_for(container, PurePosixPath("/", "home", system_user))
),
image=container.image.tags[0],
system_user=system_user,
)
Expand Down
39 changes: 32 additions & 7 deletions aiidalab_launch/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import re
import webbrowser
from contextlib import contextmanager
from pathlib import Path, PurePosixPath
from pathlib import Path, PosixPath, PurePosixPath, WindowsPath
from textwrap import wrap
from threading import Event, Thread, Timer
from typing import Any, AsyncGenerator, Generator, Iterable, Optional
from typing import Any, AsyncGenerator, Generator, Iterable, Optional, Union

import click
import click_spinner
Expand Down Expand Up @@ -159,11 +159,36 @@ def confirm_with_value(value: str, text: str, abort: bool = False) -> bool:
return False


def docker_bind_mount_path(path: Path) -> PurePosixPath:
"Construct the expected docker bind mount path (platform independent)."
return PurePosixPath(
"/host_mnt/", path.drive.strip(":"), path.relative_to(path.drive, path.root)
)
def docker_mount_for(
container: docker.models.containers.Container, destination: PurePosixPath
) -> Union[Path, str]:
"""Identify the Docker mount bind path or volume for a given destination."""
try:
mount = [
mount
for mount in container.attrs["Mounts"]
if mount["Destination"] == str(destination)
][0]
except IndexError:
raise ValueError(f"No mount point for {destination}.")
if mount["Type"] == "bind":
docker_root = PurePosixPath("/host_mnt")
docker_path = PurePosixPath(mount["Source"])
try: # Windows
drive = docker_path.relative_to(docker_root).parts[0]
return WindowsPath(
f"{drive}:",
docker_path.root,
docker_path.relative_to(docker_root, drive),
)
except ValueError: # Linux
return PosixPath(docker_path)
except NotImplementedError: # OS-X
return PosixPath(docker_root.root, docker_path.relative_to(docker_root))
elif mount["Type"] == "volume":
return mount["Name"]
else:
raise RuntimeError("Unexpected mount type.")


def get_docker_env(container: docker.models.containers.Container, env_name: str) -> str:
Expand Down

0 comments on commit 9f1e5ea

Please sign in to comment.