MindSearch_Duplicate / docker /msdl /docker_manager.py
vansin's picture
feat: update
dc9e27a
raw
history blame
5.9 kB
# msdl/docker_manager.py
import os
import subprocess
import sys
from functools import lru_cache
import yaml
from msdl.config import PROJECT_ROOT, TEMP_DIR
from msdl.i18n import t
@lru_cache(maxsize=1)
def get_docker_command():
try:
subprocess.run(
["docker", "compose", "version"], check=True, capture_output=True
)
return ["docker", "compose"]
except subprocess.CalledProcessError:
try:
subprocess.run(
["docker-compose", "--version"], check=True, capture_output=True
)
return ["docker-compose"]
except subprocess.CalledProcessError:
print(t("DOCKER_COMPOSE_NOT_FOUND"))
sys.exit(1)
@lru_cache(maxsize=1)
def check_docker_install():
try:
subprocess.run(["docker", "--version"], check=True, capture_output=True)
docker_compose_cmd = get_docker_command()
subprocess.run(
docker_compose_cmd + ["version"], check=True, capture_output=True
)
print(t("DOCKER_INSTALLED"))
return True
except subprocess.CalledProcessError as e:
print(t("DOCKER_INSTALL_ERROR", error=str(e)))
return False
except FileNotFoundError:
print(t("DOCKER_NOT_FOUND"))
return False
def stop_and_remove_containers():
docker_compose_cmd = get_docker_command()
compose_file = os.path.join(TEMP_DIR, "docker-compose.yaml")
# Read the docker-compose.yaml file
try:
with open(compose_file, "r") as file:
compose_config = yaml.safe_load(file)
except Exception as e:
print(t("COMPOSE_FILE_READ_ERROR", error=str(e)))
return
# Get project name and service names
project_name = compose_config.get("name", "mindsearch")
service_names = list(compose_config.get("services", {}).keys())
# Use only the project name as the container prefix
container_prefix = f"{project_name}_"
try:
# 1. Try to stop containers using the current docker-compose.yaml
subprocess.run(
docker_compose_cmd + ["-f", compose_file, "down", "-v", "--remove-orphans"],
check=True,
)
except subprocess.CalledProcessError:
print(t("CURRENT_COMPOSE_STOP_FAILED"))
# 2. Attempt to clean up potentially existing containers, regardless of the success of the previous step
try:
# List all containers (including stopped ones)
result = subprocess.run(
["docker", "ps", "-a", "--format", "{{.Names}}"],
check=True,
capture_output=True,
text=True,
)
all_containers = result.stdout.splitlines()
# 3. Filter out containers belonging to our project
project_containers = [
c
for c in all_containers
if c.startswith(container_prefix)
or any(c == f"{project_name}-{service}" for service in service_names)
]
if project_containers:
# 4. Force stop and remove these containers
for container in project_containers:
try:
subprocess.run(["docker", "stop", container], check=True)
subprocess.run(["docker", "rm", "-f", container], check=True)
print(t("CONTAINER_STOPPED_AND_REMOVED", container=container))
except subprocess.CalledProcessError as e:
print(t("CONTAINER_STOP_ERROR", container=container, error=str(e)))
# 5. Clean up potentially leftover networks
try:
subprocess.run(["docker", "network", "prune", "-f"], check=True)
print(t("NETWORKS_PRUNED"))
except subprocess.CalledProcessError as e:
print(t("NETWORK_PRUNE_ERROR", error=str(e)))
except subprocess.CalledProcessError as e:
print(t("DOCKER_LIST_ERROR", error=str(e)))
print(t("CONTAINERS_STOPPED_AND_REMOVED"))
def run_docker_compose():
docker_compose_cmd = get_docker_command()
try:
print(t("STARTING_CONTAINERS_WITH_BUILD"))
subprocess.run(
docker_compose_cmd
+ [
"-f",
os.path.join(TEMP_DIR, "docker-compose.yaml"),
"--env-file",
os.path.join(TEMP_DIR, ".env"),
"up",
"-d",
"--build",
],
check=True,
)
print(t("CONTAINERS_STARTED"))
except subprocess.CalledProcessError as e:
print(t("DOCKER_ERROR", error=str(e)))
print(t("DOCKER_OUTPUT"))
print(e.output.decode() if e.output else "No output")
stop_and_remove_containers()
sys.exit(1)
def update_docker_compose_paths(project_root=PROJECT_ROOT):
docker_compose_path = os.path.join(TEMP_DIR, "docker-compose.yaml")
with open(docker_compose_path, "r") as file:
compose_data = yaml.safe_load(file)
for service in compose_data["services"].values():
if "build" in service:
if "context" in service["build"]:
if service["build"]["context"] == "..":
service["build"]["context"] = project_root
else:
service["build"]["context"] = os.path.join(
project_root, service["build"]["context"]
)
if "dockerfile" in service["build"]:
dockerfile_name = os.path.basename(service["build"]["dockerfile"])
service["build"]["dockerfile"] = os.path.join(TEMP_DIR, dockerfile_name)
with open(docker_compose_path, "w") as file:
yaml.dump(compose_data, file)
print(t("PATHS_UPDATED"))
def main():
if check_docker_install():
update_docker_compose_paths()
run_docker_compose()
else:
sys.exit(1)
if __name__ == "__main__":
main()