wip docker module

This commit is contained in:
Niels Geens
2024-10-24 17:26:34 +02:00
parent 4bbe636f0e
commit a2f9e9c1c5
5 changed files with 139 additions and 111 deletions

View File

@@ -1,19 +1,30 @@
from docker.models.containers import Container
from typing import Dict, List, Optional, Tuple
import docker
from docker.models.containers import Container
import logging
import subprocess
import time
class DockerModule:
"""
Module for handling Docker container operations in SIA.
Manages container lifecycle, I/O operations, and status monitoring.
"""
def _start_docker_engine():
"""
Start the Docker engine
"""
subprocess.run(['/etc/init.d/docker', 'start'])
time.sleep(1)
def __init__(self):
self.client = docker.from_env()
DockerModule._start_docker_engine()
self.client = docker.DockerClient(base_url='unix://var/run/docker.sock')
self.containers: Dict[str, Container] = {}
self.container_sockets: Dict[str, docker.APIClient.AttachSocket] = {}
self.logger = logging.getLogger(__name__)
def start_container(
self,
image: str,
@@ -69,7 +80,9 @@ class DockerModule:
port_bindings[container_port] = host_port
try:
container = self.client.containers.run(
self.client.images.pull('busybox:latest')
# Create container with tty and open stdin
container = self.client.containers.create(
image,
command=cmd if cmd else None,
name=name,
@@ -77,21 +90,36 @@ class DockerModule:
volumes=volume_binds,
ports=port_bindings,
environment=environment,
tty=True,
stdin_open=True
)
# Attach socket before starting container
socket = container.attach_socket(params={
'stdin': 1,
'stdout': 1,
'stderr': 1,
'stream': 1
})
# Start the container
container.start()
if timeout >= 0:
# For short-lived containers, wait for completion
try:
container.wait(timeout=timeout/1000) # Convert ms to seconds
output = container.logs().decode('utf-8')
socket.close()
container.remove(force=True)
return output
except docker.errors.NotFound:
self.logger.warning(f"Container was removed before timeout")
return ""
else:
# For long-running containers, store reference
# For long-running containers, store references
self.containers[name] = container
self.container_sockets[name] = socket
return name
except Exception as e:
@@ -112,6 +140,12 @@ class DockerModule:
raise KeyError(f"Container {name} not found")
try:
# Close socket if it exists
if name in self.container_sockets:
self.container_sockets[name].close()
del self.container_sockets[name]
# Stop and remove container
container = self.containers[name]
container.stop()
container.remove()
@@ -131,14 +165,12 @@ class DockerModule:
KeyError: If container name not found
docker.errors.APIError: If write operation fails
"""
if name not in self.containers:
raise KeyError(f"Container {name} not found")
if name not in self.containers or name not in self.container_sockets:
raise KeyError(f"Container {name} not found or socket not initialized")
try:
container = self.containers[name]
socket = container.attach_socket(params={'stdin': 1, 'stream': 1})
socket = self.container_sockets[name]
socket._sock.send(data.encode('utf-8'))
socket.close()
except Exception as e:
self.logger.error(f"Error writing to container {name} stdin: {str(e)}")
raise
@@ -251,4 +283,4 @@ class DockerModule:
}
except Exception as e:
self.logger.error(f"Error getting status for container {name}: {str(e)}")
raise
raise