karl/app/services/containers.py
2025-11-29 01:25:50 +01:00

59 lines
1.9 KiB
Python

import logging
from pathlib import Path
import docker
from docker.models.containers import Container
from injectable import injectable
from app.model.containers import Tree, Compose, SimpleContainer
logger = logging.getLogger(__name__)
@injectable(singleton=True)
class DockerService:
def __init__(self):
self._client = docker.from_env()
# logger.info(f"Docker client initialized. Plugins: {self._client.plugins()}")
self._tree = self._init_tree()
def _init_tree(self) -> Tree:
tree = Tree()
container: Container
for container in self._client.containers.list():
labels = container.labels
working_dir = labels.get("com.docker.compose.project.working_dir")
if working_dir:
if tree.composes.get(working_dir) is None:
tree.composes[working_dir] = Compose(working_dir)
tree.composes[working_dir].containers.append(SimpleContainer.from_container(container))
else:
tree.containers.append(SimpleContainer.from_container(container))
return tree
@property
def tree(self) -> Tree:
return self._tree
def reload(self, compose_path: Path):
# TODO: Won't work in docker container
cmd = ["sudo", "docker", "compose", "-f", str(compose_path), "up", "-d"]
import subprocess
try:
process = subprocess.run(
cmd,
capture_output=True,
text=True,
check=False
)
if process.returncode != 0:
logger.error(f"Docker compose failed with code {process.returncode}")
logger.error(f"stderr: {process.stderr}")
raise Exception(f"Docker compose failed: {process.stderr}")
logger.info(f"Docker compose executed successfully")
logger.debug(f"stdout: {process.stdout}")
return process.stdout, process.stderr, process.returncode
except Exception as e:
logger.error(f"Failed to execute docker compose command: {e}")
raise e