isolated-sandbox / sandbox /container_builder.py
ChefAdorous's picture
Deploy Code Execution Sandbox with FastAPI and Docker
a89f25d
import docker
from docker.errors import DockerException, ImageNotFound
import logging
from pathlib import Path
logger = logging.getLogger(__name__)
class ContainerBuilder:
"""Builds and manages the development environment Docker image"""
IMAGE_NAME = "sandbox-devenv"
IMAGE_TAG = "latest"
def __init__(self):
try:
self.client = docker.from_env()
logger.info("Container builder initialized")
except DockerException as e:
logger.error(f"Failed to initialize Docker client: {e}")
raise RuntimeError("Docker is not available") from e
def image_exists(self) -> bool:
"""Check if devenv image exists"""
try:
self.client.images.get(f"{self.IMAGE_NAME}:{self.IMAGE_TAG}")
return True
except ImageNotFound:
return False
def build_devenv_image(self) -> bool:
"""
Build the development environment image.
Returns:
True if successful, False otherwise
"""
try:
dockerfile_path = Path(__file__).parent / "images" / "devenv.Dockerfile"
if not dockerfile_path.exists():
logger.error(f"Dockerfile not found: {dockerfile_path}")
return False
logger.info("Building development environment image (this may take several minutes)...")
# Build image
image, build_logs = self.client.images.build(
path=str(dockerfile_path.parent),
dockerfile=str(dockerfile_path.name),
tag=f"{self.IMAGE_NAME}:{self.IMAGE_TAG}",
rm=True, # Remove intermediate containers
pull=True, # Pull base image
decode=True # Decode build logs
)
# Print build progress
for log in build_logs:
if 'stream' in log:
print(log['stream'], end='')
elif 'error' in log:
logger.error(f"Build error: {log['error']}")
return False
logger.info(f"Successfully built {self.IMAGE_NAME}:{self.IMAGE_TAG}")
return True
except Exception as e:
logger.error(f"Failed to build image: {e}", exc_info=True)
return False
def ensure_devenv_image(self) -> bool:
"""
Ensure devenv image exists, build if necessary.
Returns:
True if image is available, False otherwise
"""
if self.image_exists():
logger.info(f"Image {self.IMAGE_NAME}:{self.IMAGE_TAG} already exists")
return True
logger.info(f"Image {self.IMAGE_NAME}:{self.IMAGE_TAG} not found, building...")
return self.build_devenv_image()