# app/services/docker_remote_service.py import json from typing import Optional, Dict, Any, List from app.utils.docker_remote_control import DockerRemoteController from app.schemas.docker_remote import ( RemoteServerConfig, DockerContainerStatus, DockerLogsRequest, ConfigUpdateRequest, LogReadRequest, ) from app.core.logger import logger from app.core.config import settings from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.models.remote_server import RemoteServer class DockerRemoteService: """Docker远程控制服务""" @staticmethod async def get_server_config(db: AsyncSession, server_id: str) -> RemoteServerConfig: """从数据库中获取服务器连接信息""" result = await db.execute(select(RemoteServer).filter(RemoteServer.server_id == server_id)) server = result.scalar_one_or_none() if not server: raise HTTPException(status_code=404, detail=f"Server {server_id} not found in database") return RemoteServerConfig( host=server.host, port=server.port, username=server.username, password=server.password, key_file=server.key_file, project_path=server.project_path ) @staticmethod async def get_container_status(config: RemoteServerConfig) -> Dict[str, DockerContainerStatus]: """获取容器状态""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") containers = controller.docker_status() result = {} for name, info in containers.items(): result[name] = DockerContainerStatus( name=name, status=info['status'], image=info['image'] ) return result except Exception as e: logger.error(f"获取容器状态失败: {e}") raise finally: controller.disconnect() @staticmethod async def docker_compose_up(config: RemoteServerConfig, services: Optional[List[str]] = None) -> bool: """启动Docker Compose服务""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.docker_compose_up(services) except Exception as e: logger.error(f"启动Docker服务失败: {e}") raise finally: controller.disconnect() @staticmethod async def docker_compose_down(config: RemoteServerConfig, services: Optional[List[str]] = None) -> bool: """停止Docker Compose服务""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.docker_compose_down(services) except Exception as e: logger.error(f"停止Docker服务失败: {e}") raise finally: controller.disconnect() @staticmethod async def docker_restart(config: RemoteServerConfig, container_name: str) -> bool: """重启容器""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.docker_restart(container_name) except Exception as e: logger.error(f"重启容器失败: {e}") raise finally: controller.disconnect() @staticmethod async def docker_start(config: RemoteServerConfig, container_name: str) -> bool: """启动容器""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.docker_start(container_name) except Exception as e: logger.error(f"启动容器失败: {e}") raise finally: controller.disconnect() @staticmethod async def docker_stop(config: RemoteServerConfig, container_name: str) -> bool: """停止容器""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.docker_stop(container_name) except Exception as e: logger.error(f"停止容器失败: {e}") raise finally: controller.disconnect() @staticmethod async def docker_logs(config: RemoteServerConfig, request: DockerLogsRequest) -> str: """查看容器日志""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.docker_logs(request.container_name, request.lines, request.follow) except Exception as e: logger.error(f"查看容器日志失败: {e}") raise finally: controller.disconnect() @staticmethod async def read_config(config: RemoteServerConfig, config_file: str) -> Dict[str, Any]: """读取配置文件""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") result = controller.read_config(config_file) if result is None: raise Exception("配置文件不存在或读取失败") return result except Exception as e: logger.error(f"读取配置文件失败: {e}") raise finally: controller.disconnect() @staticmethod async def update_config(config: RemoteServerConfig, request: ConfigUpdateRequest) -> bool: """更新配置文件""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.update_config(request.config_file, request.key_path, request.value) except Exception as e: logger.error(f"更新配置文件失败: {e}") raise finally: controller.disconnect() @staticmethod async def read_log(config: RemoteServerConfig, request: LogReadRequest) -> str: """读取日志文件""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.read_log( request.log_file, lines=request.lines, from_head=request.from_head, full=request.full ) except Exception as e: logger.error(f"读取日志文件失败: {e}") raise finally: controller.disconnect() @staticmethod async def list_logs(config: RemoteServerConfig) -> List[str]: """列出所有日志文件""" controller = DockerRemoteController( host=config.host, port=config.port, username=config.username, password=config.password, key_file=config.key_file, project_path=config.project_path ) try: if not controller.connect(): raise Exception("连接失败") return controller.list_logs() except Exception as e: logger.error(f"列出日志文件失败: {e}") raise finally: controller.disconnect()