- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
134 lines
5.1 KiB
Python
134 lines
5.1 KiB
Python
"""
|
||
Сервис для развертывания ролей на реальные серверы
|
||
Автор: Сергей Антропов
|
||
Сайт: https://devops.org.ru
|
||
"""
|
||
|
||
import asyncio
|
||
from pathlib import Path
|
||
from typing import Optional, AsyncGenerator, Dict, List
|
||
from datetime import datetime
|
||
from app.core.config import settings
|
||
from app.core.ansible_executor import AnsibleExecutor
|
||
|
||
|
||
class DeploymentService:
|
||
"""Развертывание ролей на реальные серверы"""
|
||
|
||
def __init__(self):
|
||
self.project_root = settings.PROJECT_ROOT
|
||
self.inventory_file = self.project_root / "inventory" / "hosts.ini"
|
||
self.deploy_playbook = self.project_root / "roles" / "deploy.yml"
|
||
self.ansible_executor = AnsibleExecutor()
|
||
|
||
async def deploy_role(
|
||
self,
|
||
role_name: str,
|
||
inventory: Optional[str] = None,
|
||
limit: Optional[str] = None,
|
||
tags: Optional[List[str]] = None,
|
||
check: bool = False,
|
||
extra_vars: Optional[Dict] = None,
|
||
stream: bool = False
|
||
) -> AsyncGenerator[str, None]:
|
||
"""
|
||
Развертывание роли на реальные серверы
|
||
|
||
Args:
|
||
role_name: Имя роли для развертывания
|
||
inventory: Путь к inventory файлу (по умолчанию inventory/hosts.ini)
|
||
limit: Ограничение на хосты
|
||
tags: Список тегов для фильтрации
|
||
check: Режим dry-run (--check)
|
||
extra_vars: Дополнительные переменные
|
||
stream: Если True, возвращает генератор строк
|
||
|
||
Yields:
|
||
Строки вывода команды
|
||
"""
|
||
# Проверка существования роли
|
||
role_path = self.project_root / "roles" / role_name
|
||
if not role_path.exists():
|
||
yield f"❌ Роль '{role_name}' не найдена\n"
|
||
return
|
||
|
||
# Определение inventory файла
|
||
if inventory:
|
||
inventory_path = Path(inventory)
|
||
if not inventory_path.is_absolute():
|
||
inventory_path = self.project_root / inventory_path
|
||
else:
|
||
inventory_path = self.inventory_file
|
||
|
||
if not inventory_path.exists():
|
||
yield f"❌ Inventory файл '{inventory_path}' не найден\n"
|
||
yield "💡 Создайте файл inventory/hosts.ini с вашими серверами\n"
|
||
return
|
||
|
||
# Проверка deploy.yml
|
||
if not self.deploy_playbook.exists():
|
||
yield f"❌ Playbook '{self.deploy_playbook}' не найден\n"
|
||
return
|
||
|
||
# Формирование тегов
|
||
deploy_tags = [role_name]
|
||
if tags:
|
||
deploy_tags.extend(tags)
|
||
|
||
yield f"🚀 Развертывание роли '{role_name}' на реальные серверы...\n"
|
||
if check:
|
||
yield "⚠️ Режим dry-run (--check) - изменения не будут применены\n"
|
||
yield f"📋 Inventory: {inventory_path}\n"
|
||
if limit:
|
||
yield f"📋 Limit: {limit}\n"
|
||
yield f"📋 Tags: {', '.join(deploy_tags)}\n\n"
|
||
|
||
# Запуск ansible-playbook
|
||
async for line in self.ansible_executor.run_playbook(
|
||
playbook_path=str(self.deploy_playbook),
|
||
inventory=str(inventory_path),
|
||
tags=deploy_tags,
|
||
limit=limit,
|
||
check=check,
|
||
extra_vars=extra_vars,
|
||
stream=True
|
||
):
|
||
yield line
|
||
|
||
yield "\n✅ Развертывание завершено\n"
|
||
|
||
async def dry_run_role(
|
||
self,
|
||
role_name: str,
|
||
inventory: Optional[str] = None,
|
||
limit: Optional[str] = None,
|
||
stream: bool = False
|
||
) -> AsyncGenerator[str, None]:
|
||
"""
|
||
Dry-run проверка роли на реальных серверах (без изменений)
|
||
|
||
Args:
|
||
role_name: Имя роли
|
||
inventory: Путь к inventory файлу
|
||
limit: Ограничение на хосты
|
||
stream: Если True, возвращает генератор строк
|
||
|
||
Yields:
|
||
Строки вывода команды
|
||
"""
|
||
yield f"🔍 Dry-run проверка роли '{role_name}' на реальных серверах...\n"
|
||
yield "⚠️ Безопасно: не изменяет серверы, только проверяет\n\n"
|
||
|
||
async for line in self.deploy_role(
|
||
role_name=role_name,
|
||
inventory=inventory,
|
||
limit=limit,
|
||
check=True,
|
||
stream=True
|
||
):
|
||
yield line
|
||
|
||
def detect_log_level(self, line: str) -> str:
|
||
"""Определение уровня лога из строки"""
|
||
return self.ansible_executor.detect_log_level(line)
|