feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
168
app/services/dockerfile_service.py
Normal file
168
app/services/dockerfile_service.py
Normal file
@@ -0,0 +1,168 @@
|
||||
"""
|
||||
Сервис для работы с Dockerfile
|
||||
Автор: Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
"""
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from app.models.database import Dockerfile
|
||||
from typing import Optional, List
|
||||
from pathlib import Path
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DockerfileService:
|
||||
"""Сервис для работы с Dockerfile"""
|
||||
|
||||
@staticmethod
|
||||
async def get_dockerfile(db: AsyncSession, dockerfile_id: int) -> Optional[Dockerfile]:
|
||||
"""Получение Dockerfile по ID"""
|
||||
result = await db.execute(select(Dockerfile).where(Dockerfile.id == dockerfile_id))
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
@staticmethod
|
||||
async def get_dockerfile_by_name(db: AsyncSession, name: str) -> Optional[Dockerfile]:
|
||||
"""Получение Dockerfile по имени"""
|
||||
result = await db.execute(select(Dockerfile).where(Dockerfile.name == name))
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
@staticmethod
|
||||
async def list_dockerfiles(db: AsyncSession, status: Optional[str] = None) -> List[Dockerfile]:
|
||||
"""Список всех Dockerfile"""
|
||||
query = select(Dockerfile)
|
||||
if status:
|
||||
query = query.where(Dockerfile.status == status)
|
||||
result = await db.execute(query.order_by(Dockerfile.name))
|
||||
return result.scalars().all()
|
||||
|
||||
@staticmethod
|
||||
async def create_dockerfile(
|
||||
db: AsyncSession,
|
||||
name: str,
|
||||
content: str,
|
||||
description: Optional[str] = None,
|
||||
base_image: Optional[str] = None,
|
||||
tags: Optional[List[str]] = None,
|
||||
platforms: Optional[List[str]] = None,
|
||||
created_by: Optional[str] = None
|
||||
) -> Dockerfile:
|
||||
"""Создание нового Dockerfile"""
|
||||
# Платформы по умолчанию: linux/amd64 (x86_64), linux/386 (x86) и linux/arm64 (macOS M1)
|
||||
if platforms is None:
|
||||
platforms = ["linux/amd64", "linux/386", "linux/arm64"]
|
||||
|
||||
dockerfile = Dockerfile(
|
||||
name=name,
|
||||
description=description,
|
||||
content=content,
|
||||
base_image=base_image,
|
||||
tags=tags or [],
|
||||
platforms=platforms,
|
||||
created_by=created_by
|
||||
)
|
||||
db.add(dockerfile)
|
||||
await db.commit()
|
||||
await db.refresh(dockerfile)
|
||||
return dockerfile
|
||||
|
||||
@staticmethod
|
||||
async def update_dockerfile(
|
||||
db: AsyncSession,
|
||||
dockerfile_id: int,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
content: Optional[str] = None,
|
||||
base_image: Optional[str] = None,
|
||||
tags: Optional[List[str]] = None,
|
||||
platforms: Optional[List[str]] = None,
|
||||
updated_by: Optional[str] = None
|
||||
) -> Optional[Dockerfile]:
|
||||
"""Обновление Dockerfile"""
|
||||
dockerfile = await DockerfileService.get_dockerfile(db, dockerfile_id)
|
||||
if not dockerfile:
|
||||
return None
|
||||
|
||||
if name:
|
||||
dockerfile.name = name
|
||||
if description is not None:
|
||||
dockerfile.description = description
|
||||
if content is not None:
|
||||
dockerfile.content = content
|
||||
if base_image is not None:
|
||||
dockerfile.base_image = base_image
|
||||
if tags is not None:
|
||||
dockerfile.tags = tags
|
||||
if platforms is not None:
|
||||
dockerfile.platforms = platforms
|
||||
if updated_by:
|
||||
dockerfile.updated_by = updated_by
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(dockerfile)
|
||||
return dockerfile
|
||||
|
||||
@staticmethod
|
||||
async def delete_dockerfile(db: AsyncSession, dockerfile_id: int) -> bool:
|
||||
"""Удаление Dockerfile"""
|
||||
dockerfile = await DockerfileService.get_dockerfile(db, dockerfile_id)
|
||||
if not dockerfile:
|
||||
return False
|
||||
|
||||
await db.delete(dockerfile)
|
||||
await db.commit()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
async def load_from_filesystem(
|
||||
db: AsyncSession,
|
||||
project_root: Path,
|
||||
created_by: Optional[str] = None
|
||||
) -> List[Dockerfile]:
|
||||
"""Загрузка Dockerfile из файловой системы в БД"""
|
||||
# Dockerfiles теперь находятся в alembic/dockerfiles
|
||||
alembic_dir = project_root / "app" / "alembic"
|
||||
dockerfiles_dir = alembic_dir / "dockerfiles"
|
||||
loaded = []
|
||||
|
||||
if not dockerfiles_dir.exists():
|
||||
logger.warning(f"Dockerfiles directory not found: {dockerfiles_dir}")
|
||||
return loaded
|
||||
|
||||
for dockerfile_path in dockerfiles_dir.rglob("Dockerfile*"):
|
||||
if dockerfile_path.is_file():
|
||||
# Имя из пути (например, ubuntu22/Dockerfile -> ubuntu22)
|
||||
relative_path = dockerfile_path.relative_to(dockerfiles_dir)
|
||||
name = str(relative_path.parent) if relative_path.parent != Path('.') else relative_path.stem
|
||||
|
||||
# Проверяем, существует ли уже в БД
|
||||
existing = await DockerfileService.get_dockerfile_by_name(db, name)
|
||||
if existing:
|
||||
continue
|
||||
|
||||
content = dockerfile_path.read_text(encoding='utf-8')
|
||||
|
||||
# Определяем базовый образ из содержимого
|
||||
base_image = None
|
||||
for line in content.split('\n'):
|
||||
if line.strip().startswith('FROM'):
|
||||
base_image = line.strip().replace('FROM', '').strip().split()[0]
|
||||
break
|
||||
|
||||
# Платформы по умолчанию: linux/amd64 (x86_64), linux/386 (x86) и linux/arm64 (macOS M1)
|
||||
default_platforms = ["linux/amd64", "linux/386", "linux/arm64"]
|
||||
|
||||
dockerfile = await DockerfileService.create_dockerfile(
|
||||
db=db,
|
||||
name=name,
|
||||
content=content,
|
||||
base_image=base_image,
|
||||
platforms=default_platforms,
|
||||
created_by=created_by
|
||||
)
|
||||
loaded.append(dockerfile)
|
||||
logger.info(f"Loaded Dockerfile: {name}")
|
||||
|
||||
return loaded
|
||||
Reference in New Issue
Block a user