feat: Make user configurable
This commit is contained in:
@@ -4,20 +4,16 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import io
|
import io
|
||||||
import select as _select
|
import select as _select
|
||||||
import socket as _socket
|
|
||||||
import tarfile
|
import tarfile
|
||||||
from contextlib import ExitStack
|
|
||||||
from select import select as _original_select
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from unittest.mock import patch
|
import docker
|
||||||
|
import docker.errors
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
_original_poll = getattr(_select, "poll", None)
|
_original_poll = getattr(_select, "poll", None)
|
||||||
|
|
||||||
import docker
|
|
||||||
import docker.errors
|
|
||||||
from docker.utils.socket import consume_socket_output, demux_adaptor, frames_iter
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import docker.models.containers
|
import docker.models.containers
|
||||||
@@ -50,6 +46,8 @@ class DockerSandbox:
|
|||||||
cpu_limit: float = 8,
|
cpu_limit: float = 8,
|
||||||
memory_limit: str = "16g",
|
memory_limit: str = "16g",
|
||||||
command: str | None = None,
|
command: str | None = None,
|
||||||
|
uid: int | None = None,
|
||||||
|
gid: int | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.container_name = container_name
|
self.container_name = container_name
|
||||||
self._image = image
|
self._image = image
|
||||||
@@ -65,9 +63,21 @@ class DockerSandbox:
|
|||||||
self._nano_cpus = int(cpu_limit * 1e9)
|
self._nano_cpus = int(cpu_limit * 1e9)
|
||||||
self._memory_limit = memory_limit
|
self._memory_limit = memory_limit
|
||||||
self._command = command
|
self._command = command
|
||||||
|
self._uid = uid
|
||||||
|
self._gid = gid
|
||||||
self._client: docker.DockerClient = docker.from_env()
|
self._client: docker.DockerClient = docker.from_env()
|
||||||
self._container: docker.models.containers.Container | None = None
|
self._container: docker.models.containers.Container | None = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _user(self) -> str | None:
|
||||||
|
"""Docker ``user`` spec ("uid" or "uid:gid"), or None to use the image default."""
|
||||||
|
if self._uid is None and self._gid is None:
|
||||||
|
return None
|
||||||
|
uid = "" if self._uid is None else str(self._uid)
|
||||||
|
if self._gid is None:
|
||||||
|
return uid
|
||||||
|
return f"{uid}:{self._gid}"
|
||||||
|
|
||||||
def __enter__(self) -> "DockerSandbox":
|
def __enter__(self) -> "DockerSandbox":
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -135,9 +145,13 @@ class DockerSandbox:
|
|||||||
run_kwargs["security_opt"] = self._security_opt
|
run_kwargs["security_opt"] = self._security_opt
|
||||||
run_kwargs["nano_cpus"] = self._nano_cpus
|
run_kwargs["nano_cpus"] = self._nano_cpus
|
||||||
run_kwargs["mem_limit"] = self._memory_limit
|
run_kwargs["mem_limit"] = self._memory_limit
|
||||||
|
if self._user is not None:
|
||||||
|
run_kwargs["user"] = self._user
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._container = self._client.containers.run(self._image, self._command, **run_kwargs)
|
self._container = self._client.containers.run(
|
||||||
|
self._image, self._command, **run_kwargs
|
||||||
|
)
|
||||||
except docker.errors.ImageNotFound:
|
except docker.errors.ImageNotFound:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Image {self._image!r} not found locally. "
|
f"Image {self._image!r} not found locally. "
|
||||||
@@ -247,13 +261,20 @@ class DockerSandbox:
|
|||||||
# Command execution
|
# Command execution
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
def exec(self, command: str, timeout: int = 120, kill_grace: int = 5) -> tuple[int, str]:
|
def exec(
|
||||||
|
self, command: str, timeout: int = 120, kill_grace: int = 5
|
||||||
|
) -> tuple[int, str]:
|
||||||
if self._container is None:
|
if self._container is None:
|
||||||
return 1, "Sandbox container is not running."
|
return 1, "Sandbox container is not running."
|
||||||
|
|
||||||
wrapped = [
|
wrapped = [
|
||||||
"timeout", "--kill-after", f"{kill_grace}s", f"{timeout}s",
|
"timeout",
|
||||||
"bash", "-c", command,
|
"--kill-after",
|
||||||
|
f"{kill_grace}s",
|
||||||
|
f"{timeout}s",
|
||||||
|
"bash",
|
||||||
|
"-c",
|
||||||
|
command,
|
||||||
]
|
]
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if self._working_dir is not None:
|
if self._working_dir is not None:
|
||||||
|
|||||||
Reference in New Issue
Block a user