| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- # app/services/docker_remote_service.py
- import json
- from typing import Optional, Dict, Any, List
- from app.services.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()
|