Files
DevOpsLab/app/services/playbook_service.py
Сергей Антропов 1fbf9185a2 feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок
- Для push операций отображается registry вместо платформ
- Сохранение пользователя при создании push лога
- Исправлена ошибка с logger в push_docker_image endpoint
- Улучшено отображение истории сборок с визуальными индикаторами
2026-02-15 22:59:02 +03:00

188 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Сервис для работы с 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