""" Сервис для работы с playbook Автор: Сергей Антропов Сайт: https://devops.org.ru """ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, update, delete from app.models.database import Playbook, PlaybookTestRun, PlaybookDeployment from typing import Optional, List, Dict import yaml import logging logger = logging.getLogger(__name__) class PlaybookService: """Сервис для работы с playbook""" @staticmethod async def create_playbook( db: AsyncSession, name: str, roles: List[str], description: Optional[str] = None, variables: Optional[Dict] = None, inventory: Optional[str] = None, created_by: Optional[str] = None ) -> Playbook: """Создание нового playbook""" # Генерация YAML содержимого playbook playbook_content = PlaybookService._generate_playbook_yaml(roles, variables) playbook = Playbook( name=name, description=description, content=playbook_content, roles=roles, variables=variables or {}, inventory=inventory, created_by=created_by ) db.add(playbook) await db.commit() await db.refresh(playbook) return playbook @staticmethod async def get_playbook(db: AsyncSession, playbook_id: int) -> Optional[Playbook]: """Получение playbook по ID""" result = await db.execute(select(Playbook).where(Playbook.id == playbook_id)) return result.scalar_one_or_none() @staticmethod async def get_playbook_by_name(db: AsyncSession, name: str) -> Optional[Playbook]: """Получение playbook по имени""" result = await db.execute(select(Playbook).where(Playbook.name == name)) return result.scalar_one_or_none() @staticmethod async def list_playbooks(db: AsyncSession, status: Optional[str] = None) -> List[Playbook]: """Список всех playbook""" query = select(Playbook) if status: query = query.where(Playbook.status == status) result = await db.execute(query.order_by(Playbook.created_at.desc())) return result.scalars().all() @staticmethod async def update_playbook( db: AsyncSession, playbook_id: int, name: Optional[str] = None, description: Optional[str] = None, roles: Optional[List[str]] = None, variables: Optional[Dict] = None, inventory: Optional[str] = None, content: Optional[str] = None, updated_by: Optional[str] = None ) -> Optional[Playbook]: """Обновление playbook""" playbook = await PlaybookService.get_playbook(db, playbook_id) if not playbook: return None if name: playbook.name = name if description is not None: playbook.description = description if roles is not None: playbook.roles = roles # Перегенерируем content если изменились роли playbook.content = PlaybookService._generate_playbook_yaml(roles, variables or playbook.variables) if variables is not None: playbook.variables = variables # Перегенерируем content если изменились переменные playbook.content = PlaybookService._generate_playbook_yaml(playbook.roles, variables) if inventory is not None: playbook.inventory = inventory if content is not None: playbook.content = content if updated_by: playbook.updated_by = updated_by await db.commit() await db.refresh(playbook) return playbook @staticmethod async def delete_playbook(db: AsyncSession, playbook_id: int) -> bool: """Удаление playbook""" playbook = await PlaybookService.get_playbook(db, playbook_id) if not playbook: return False await db.delete(playbook) await db.commit() return True @staticmethod def _generate_playbook_yaml(roles: List[str], variables: Optional[Dict] = None) -> str: """Генерация YAML содержимого playbook""" playbook_data = { 'name': 'Playbook', 'hosts': 'all', 'become': True, 'roles': roles } if variables: playbook_data['vars'] = variables return yaml.dump([playbook_data], default_flow_style=False, allow_unicode=True) @staticmethod async def save_test_run( db: AsyncSession, playbook_id: int, preset_name: Optional[str], status: str, user: Optional[str] = None, output: Optional[str] = None, error: Optional[str] = None, returncode: Optional[int] = None ) -> PlaybookTestRun: """Сохранение результата тестирования playbook""" test_run = PlaybookTestRun( playbook_id=playbook_id, preset_name=preset_name, status=status, output=output, error=error, returncode=returncode, user=user ) db.add(test_run) await db.commit() await db.refresh(test_run) return test_run @staticmethod async def save_deployment( db: AsyncSession, playbook_id: int, inventory: Optional[str], hosts: Optional[List[str]], status: str, user: Optional[str] = None, output: Optional[str] = None, error: Optional[str] = None, returncode: Optional[int] = None ) -> PlaybookDeployment: """Сохранение результата деплоя playbook""" deployment = PlaybookDeployment( playbook_id=playbook_id, inventory=inventory, hosts=hosts or [], status=status, output=output, error=error, returncode=returncode, user=user ) db.add(deployment) await db.commit() await db.refresh(deployment) return deployment