feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
116
app/api/v1/endpoints/docker.py
Normal file
116
app/api/v1/endpoints/docker.py
Normal file
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
API endpoints для управления Docker образами
|
||||
Автор: Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Request, HTTPException
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from pathlib import Path
|
||||
from typing import List, Dict
|
||||
from app.core.config import settings
|
||||
from app.core.docker_client import DockerClient
|
||||
|
||||
router = APIRouter()
|
||||
templates_path = Path(__file__).parent.parent.parent.parent / "templates"
|
||||
templates = Jinja2Templates(directory=str(templates_path))
|
||||
|
||||
|
||||
def get_docker_client():
|
||||
"""Получение Docker клиента с обработкой ошибок"""
|
||||
try:
|
||||
return DockerClient()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
@router.get("/docker", response_class=HTMLResponse)
|
||||
async def docker_page(request: Request):
|
||||
"""Страница управления Docker образами"""
|
||||
docker_client = get_docker_client()
|
||||
images = []
|
||||
|
||||
if docker_client:
|
||||
try:
|
||||
images = docker_client.list_images()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return templates.TemplateResponse(
|
||||
"pages/docker/index.html",
|
||||
{
|
||||
"request": request,
|
||||
"images": images
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/v1/docker/images", response_class=HTMLResponse)
|
||||
async def get_docker_images():
|
||||
"""API endpoint для получения списка Docker образов"""
|
||||
docker_client = get_docker_client()
|
||||
|
||||
if not docker_client:
|
||||
return """
|
||||
<div class="alert alert-warning">
|
||||
<i class="fas fa-exclamation-triangle me-2"></i>
|
||||
<strong>Docker недоступен</strong>
|
||||
<br><small class="text-muted">Убедитесь, что Docker запущен и доступен. Проверьте, что Docker socket доступен: <code>/var/run/docker.sock</code></small>
|
||||
</div>
|
||||
"""
|
||||
|
||||
try:
|
||||
images = docker_client.list_images()
|
||||
if not images:
|
||||
return """
|
||||
<div class="text-center py-5">
|
||||
<i class="fab fa-docker fa-3x text-muted mb-3"></i>
|
||||
<p class="text-muted">Docker образы не найдены</p>
|
||||
</div>
|
||||
"""
|
||||
|
||||
html = '<div class="table-responsive"><table class="table table-hover"><thead><tr><th>ID</th><th>Теги</th><th>Размер</th><th>Создан</th></tr></thead><tbody>'
|
||||
for img in images:
|
||||
size_mb = (img.get("size", 0) / 1024 / 1024) if img.get("size") else 0
|
||||
size_str = f"{size_mb:.2f} MB" if size_mb > 0 else "N/A"
|
||||
tags_list = img.get("tags", [])
|
||||
if tags_list:
|
||||
tags = " ".join([f'<span class="badge bg-info me-1">{tag}</span>' for tag in tags_list])
|
||||
else:
|
||||
tags = '<span class="text-muted">нет тегов</span>'
|
||||
img_id = img.get("id", "")[:12] if img.get("id") else "N/A"
|
||||
created = img.get("created", "")
|
||||
if created:
|
||||
try:
|
||||
# Парсим ISO формат даты или timestamp
|
||||
from datetime import datetime
|
||||
if isinstance(created, (int, float)):
|
||||
# Unix timestamp
|
||||
dt = datetime.fromtimestamp(created)
|
||||
created_str = dt.strftime('%d.%m.%Y %H:%M')
|
||||
elif isinstance(created, str):
|
||||
# ISO формат
|
||||
try:
|
||||
dt = datetime.fromisoformat(created.replace('Z', '+00:00'))
|
||||
except:
|
||||
# Пробуем другой формат
|
||||
dt = datetime.strptime(created.split('.')[0], '%Y-%m-%dT%H:%M:%S')
|
||||
created_str = dt.strftime('%d.%m.%Y %H:%M')
|
||||
else:
|
||||
created_str = str(created)
|
||||
except Exception as e:
|
||||
created_str = str(created)
|
||||
else:
|
||||
created_str = "N/A"
|
||||
|
||||
html += f'<tr><td><code>{img_id}</code></td><td>{tags}</td><td>{size_str}</td><td>{created_str}</td></tr>'
|
||||
html += '</tbody></table></div>'
|
||||
return html
|
||||
except Exception as e:
|
||||
return f"""
|
||||
<div class="alert alert-danger">
|
||||
<i class="fas fa-exclamation-circle me-2"></i>
|
||||
<strong>Ошибка при получении списка образов:</strong> {str(e)}
|
||||
</div>
|
||||
"""
|
||||
Reference in New Issue
Block a user