feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
734
docs/WEB_INTERFACE_DETAILS.md
Normal file
734
docs/WEB_INTERFACE_DETAILS.md
Normal file
@@ -0,0 +1,734 @@
|
||||
# Детали работы веб-интерфейса: тестирование и inventory
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 🎯 Обзор
|
||||
|
||||
Этот документ описывает, как пользователь будет работать с тестированием ролей, выбором Docker образов, настройкой inventory и Molecule через веб-интерфейс.
|
||||
|
||||
---
|
||||
|
||||
## 1. 🐳 Выбор Docker образов и количества контейнеров
|
||||
|
||||
### 1.1. Страница создания/редактирования preset'а
|
||||
|
||||
**URL:** `/presets/create` или `/presets/{preset_name}/edit`
|
||||
|
||||
**Интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Создание Preset'а: "my-custom-test" │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Доступные образы: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ☑ Ubuntu 22.04 [inecs/ansible-lab:ubuntu22] │ │
|
||||
│ │ ☐ Ubuntu 20.04 [inecs/ansible-lab:ubuntu20] │ │
|
||||
│ │ ☑ Debian 12 [inecs/ansible-lab:debian12] │ │
|
||||
│ │ ☐ Debian 11 [inecs/ansible-lab:debian11] │ │
|
||||
│ │ ☑ CentOS 9 [inecs/ansible-lab:centos9] │ │
|
||||
│ │ ☐ CentOS 8 [inecs/ansible-lab:centos8] │ │
|
||||
│ │ ☐ RHEL 8 [inecs/ansible-lab:rhel] │ │
|
||||
│ │ ☐ AlmaLinux 8 [inecs/ansible-lab:alma] │ │
|
||||
│ │ ☐ Rocky Linux 8 [inecs/ansible-lab:rocky] │ │
|
||||
│ │ ☐ ALT Linux 9 [inecs/ansible-lab:alt9] │ │
|
||||
│ │ ☐ Astra Linux [inecs/ansible-lab:astra] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ➕ Добавить кастомный образ: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Registry: [docker.io] │ │
|
||||
│ │ Image: [my-custom/image:tag] │ │
|
||||
│ │ [Добавить] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🖥️ Настройка хостов: │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Хост 1 │ │
|
||||
│ │ ├─ Имя: [web1] │ │
|
||||
│ │ ├─ Образ: [Ubuntu 22.04 ▼] │ │
|
||||
│ │ ├─ Группы: [web, frontend] (можно добавить) │ │
|
||||
│ │ └─ [🗑️ Удалить] │ │
|
||||
│ ├─────────────────────────────────────────────────┤ │
|
||||
│ │ Хост 2 │ │
|
||||
│ │ ├─ Имя: [web2] │ │
|
||||
│ │ ├─ Образ: [Debian 12 ▼] │ │
|
||||
│ │ ├─ Группы: [web, backend] │ │
|
||||
│ │ └─ [🗑️ Удалить] │ │
|
||||
│ ├─────────────────────────────────────────────────┤ │
|
||||
│ │ Хост 3 │ │
|
||||
│ │ ├─ Имя: [db1] │ │
|
||||
│ │ ├─ Образ: [CentOS 9 ▼] │ │
|
||||
│ │ ├─ Группы: [database, backend] │ │
|
||||
│ │ └─ [🗑️ Удалить] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [➕ Добавить хост] │
|
||||
│ │
|
||||
│ 📊 Предпросмотр: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Всего хостов: 3 │ │
|
||||
│ │ Ubuntu 22.04: 1 │ │
|
||||
│ │ Debian 12: 1 │ │
|
||||
│ │ CentOS 9: 1 │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [💾 Сохранить preset] [👁️ Предпросмотр YAML] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.2. Быстрое создание preset'а при тестировании
|
||||
|
||||
**URL:** `/roles/{role_name}/test`
|
||||
|
||||
**Интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Тестирование роли: nginx │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Выбор preset'а: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ○ Использовать существующий preset │ │
|
||||
│ │ [default ▼] [minimal] [all-images] │ │
|
||||
│ │ │ │
|
||||
│ │ ● Создать временный preset для этого теста │ │
|
||||
│ │ ┌─────────────────────────────────────────┐ │ │
|
||||
│ │ │ Быстрый выбор: │ │ │
|
||||
│ │ │ ☑ Ubuntu 22.04 [Количество: 2] │ │ │
|
||||
│ │ │ ☑ Debian 12 [Количество: 2] │ │ │
|
||||
│ │ │ ☐ CentOS 9 [Количество: 0] │ │ │
|
||||
│ │ │ ☐ RHEL 8 [Количество: 0] │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Итого: 4 хоста │ │ │
|
||||
│ │ └─────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ Или детальная настройка: │ │
|
||||
│ │ [Открыть редактор preset'а] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ⚙️ Параметры теста: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ☑ Параллельное выполнение [Количество: 2] │ │
|
||||
│ │ ☑ Проверка синтаксиса (lint) │ │
|
||||
│ │ ☑ Проверка идемпотентности │ │
|
||||
│ │ ☐ Verbose режим │ │
|
||||
│ │ ☐ Dry-run (только проверка) │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [🚀 Запустить тест] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.3. Визуальный редактор хостов (Drag & Drop)
|
||||
|
||||
**Интерфейс с возможностью перетаскивания:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Редактор хостов │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📦 Доступные образы (перетащите для добавления): │
|
||||
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
|
||||
│ │Ubuntu│ │Debian│ │CentOS│ │RHEL │ │
|
||||
│ │ 22.04│ │ 12 │ │ 9 │ │ 8 │ │
|
||||
│ └──────┘ └──────┘ └──────┘ └──────┘ │
|
||||
│ │
|
||||
│ 🖥️ Хосты (перетащите для изменения порядка): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ═══ web1 (Ubuntu 22.04) [web, frontend] [✏️][🗑️]│ │
|
||||
│ ├─────────────────────────────────────────────────┤ │
|
||||
│ │ ═══ web2 (Debian 12) [web, backend] [✏️][🗑️] │ │
|
||||
│ ├─────────────────────────────────────────────────┤ │
|
||||
│ │ ═══ db1 (CentOS 9) [database] [✏️][🗑️] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [➕ Добавить хост] [🔄 Сбросить] [💾 Сохранить] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**HTMX реализация:**
|
||||
```html
|
||||
<!-- Drag & Drop через HTMX и Alpine.js -->
|
||||
<div
|
||||
x-data="{ dragged: null }"
|
||||
@dragstart="dragged = $event.target.dataset.image"
|
||||
@drop.prevent="addHost(dragged)"
|
||||
>
|
||||
<!-- Образы для перетаскивания -->
|
||||
<div
|
||||
draggable="true"
|
||||
data-image="ubuntu22"
|
||||
class="draggable-image"
|
||||
>
|
||||
Ubuntu 22.04
|
||||
</div>
|
||||
|
||||
<!-- Список хостов -->
|
||||
<div
|
||||
@drop="addHostFromDrag($event)"
|
||||
class="hosts-list"
|
||||
>
|
||||
<!-- Хосты -->
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 📝 Заполнение Inventory
|
||||
|
||||
### 2.1. Визуальный редактор Inventory
|
||||
|
||||
**URL:** `/inventory/edit` или `/presets/{preset_name}/inventory`
|
||||
|
||||
**Интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Редактор Inventory │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Группы хостов: │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [web_servers] │ │
|
||||
│ │ ├─ web1 │ │
|
||||
│ │ │ ├─ ansible_host: [172.17.0.2] │ │
|
||||
│ │ │ ├─ ansible_user: [ansible] │ │
|
||||
│ │ │ ├─ ansible_ssh_private_key_file: [~/.ssh/id_rsa]│
|
||||
│ │ │ └─ [➕ Добавить переменную] │ │
|
||||
│ │ │ │ │
|
||||
│ │ └─ web2 │ │
|
||||
│ │ ├─ ansible_host: [172.17.0.3] │ │
|
||||
│ │ └─ ... │ │
|
||||
│ │ │ │
|
||||
│ │ [➕ Добавить хост в группу] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [database_servers] │ │
|
||||
│ │ └─ db1 │ │
|
||||
│ │ └─ ... │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [all:vars] (глобальные переменные) │ │
|
||||
│ │ ├─ ansible_user: [ansible] │ │
|
||||
│ │ ├─ ansible_ssh_private_key_file: [~/.ssh/id_rsa]│
|
||||
│ │ ├─ ansible_python_interpreter: [/usr/bin/python3]│
|
||||
│ │ └─ [➕ Добавить переменную] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📄 Предпросмотр INI формата: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [web_servers] │ │
|
||||
│ │ web1 ansible_host=172.17.0.2 │ │
|
||||
│ │ web2 ansible_host=172.17.0.3 │ │
|
||||
│ │ │ │
|
||||
│ │ [database_servers] │ │
|
||||
│ │ db1 ansible_host=172.17.0.4 │ │
|
||||
│ │ │ │
|
||||
│ │ [all:vars] │ │
|
||||
│ │ ansible_user=ansible │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [💾 Сохранить] [📥 Экспорт в файл] [📤 Импорт] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2. Автоматическая генерация Inventory из preset'а
|
||||
|
||||
**При создании preset'а автоматически генерируется inventory:**
|
||||
|
||||
```python
|
||||
# app/services/inventory_service.py
|
||||
class InventoryService:
|
||||
def generate_from_preset(self, preset: dict) -> str:
|
||||
"""Генерация inventory из preset'а"""
|
||||
inventory = []
|
||||
|
||||
# Группировка хостов по группам
|
||||
groups = {}
|
||||
for host in preset['hosts']:
|
||||
for group in host.get('groups', []):
|
||||
if group not in groups:
|
||||
groups[group] = []
|
||||
groups[group].append(host)
|
||||
|
||||
# Формирование INI
|
||||
for group_name, hosts in groups.items():
|
||||
inventory.append(f"[{group_name}]")
|
||||
for host in hosts:
|
||||
# Получение IP из Docker контейнера
|
||||
ip = self.get_container_ip(host['name'])
|
||||
inventory.append(f"{host['name']} ansible_host={ip}")
|
||||
inventory.append("")
|
||||
|
||||
# Глобальные переменные
|
||||
inventory.append("[all:vars]")
|
||||
inventory.append("ansible_user=ansible")
|
||||
inventory.append("ansible_ssh_private_key_file=~/.ssh/id_rsa")
|
||||
|
||||
return "\n".join(inventory)
|
||||
```
|
||||
|
||||
### 2.3. Редактирование Inventory для реальных серверов
|
||||
|
||||
**URL:** `/inventory/production/edit`
|
||||
|
||||
**Интерфейс для продакшн inventory:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Production Inventory │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ⚠️ Это inventory для реальных серверов! │
|
||||
│ │
|
||||
│ 📋 Группы: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [web_servers] │ │
|
||||
│ │ ┌─────────────────────────────────────────────┐ │ │
|
||||
│ │ │ Хост: web1.example.com │ │ │
|
||||
│ │ │ IP: [192.168.1.10] │ │ │
|
||||
│ │ │ Пользователь: [deploy] │ │ │
|
||||
│ │ │ SSH ключ: [~/.ssh/deploy_key] │ │ │
|
||||
│ │ │ Порт: [22] │ │ │
|
||||
│ │ │ Python: [/usr/bin/python3] │ │ │
|
||||
│ │ │ [🔐 Тест подключения] │ │ │
|
||||
│ │ └─────────────────────────────────────────────┘ │ │
|
||||
│ │ [➕ Добавить хост] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🔐 Безопасность: │
|
||||
│ ☑ Использовать Vault для секретов │
|
||||
│ ☑ Шифровать SSH ключи │
|
||||
│ │
|
||||
│ [💾 Сохранить] [🔒 Зашифровать в Vault] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 🧪 Тестирование в Molecule
|
||||
|
||||
### 3.1. Страница тестирования роли
|
||||
|
||||
**URL:** `/roles/{role_name}/test`
|
||||
|
||||
**Полный интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Тестирование роли: nginx │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Шаг 1: Выбор окружения │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ○ Использовать preset │ │
|
||||
│ │ [default ▼] [minimal] [all-images] │ │
|
||||
│ │ │ │
|
||||
│ │ ● Создать кастомное окружение │ │
|
||||
│ │ ┌─────────────────────────────────────────┐ │ │
|
||||
│ │ │ Образы и хосты: │ │ │
|
||||
│ │ │ [См. раздел 1.1] │ │ │
|
||||
│ │ └─────────────────────────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📝 Шаг 2: Настройка переменных роли │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Переменные из defaults/main.yml: │ │
|
||||
│ │ │ │
|
||||
│ │ nginx_version: [1.25.0] │ │
|
||||
│ │ nginx_worker_processes: [auto] │ │
|
||||
│ │ nginx_worker_connections: [1024] │ │
|
||||
│ │ nginx_enabled: ☑ │ │
|
||||
│ │ nginx_sites: │ │
|
||||
│ │ ┌─────────────────────────────────────┐ │ │
|
||||
│ │ │ [➕ Добавить сайт] │ │ │
|
||||
│ │ │ - name: example.com │ │ │
|
||||
│ │ │ root: /var/www/html │ │ │
|
||||
│ │ └─────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ [📥 Загрузить из файла] │ │
|
||||
│ │ [💾 Сохранить как шаблон] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ⚙️ Шаг 3: Параметры Molecule │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Molecule сценарий: [default] │ │
|
||||
│ │ │ │
|
||||
│ │ Этапы тестирования: │ │
|
||||
│ │ ☑ create (создание контейнеров) │ │
|
||||
│ │ ☑ prepare (подготовка) │ │
|
||||
│ │ ☑ converge (применение роли) │ │
|
||||
│ │ ☑ idempotence (проверка идемпотентности) │ │
|
||||
│ │ ☑ verify (проверка через testinfra) │ │
|
||||
│ │ ☑ destroy (удаление контейнеров) │ │
|
||||
│ │ │ │
|
||||
│ │ Дополнительные опции: │ │
|
||||
│ │ ☑ --destroy=never (не удалять после теста) │ │
|
||||
│ │ ☐ --scenario-name=custom (кастомный сценарий) │ │
|
||||
│ │ ☐ --driver-name=docker (драйвер) │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🔍 Шаг 4: Настройка проверок (verify) │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Использовать testinfra: ☑ │ │
|
||||
│ │ │ │
|
||||
│ │ Тесты для проверки: │ │
|
||||
│ │ ☑ nginx установлен │ │
|
||||
│ │ ☑ nginx запущен │ │
|
||||
│ │ ☑ nginx слушает на порту 80 │ │
|
||||
│ │ ☑ конфигурация валидна │ │
|
||||
│ │ │ │
|
||||
│ │ [➕ Добавить кастомный тест] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [🚀 Запустить тест] [💾 Сохранить конфигурацию] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2. Live мониторинг теста
|
||||
|
||||
**После запуска теста открывается страница с live логами:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Тест роли: nginx | Статус: 🟢 Running │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📊 Прогресс: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ████████████░░░░░░░░ 60% │ │
|
||||
│ │ Этап: converge (применение роли) │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📋 Этапы: │
|
||||
│ ✅ create - Создание контейнеров (5s) │
|
||||
│ ✅ prepare - Подготовка (2s) │
|
||||
│ 🟢 converge - Применение роли (в процессе...) │
|
||||
│ ⏳ idempotence - Ожидание... │
|
||||
│ ⏳ verify - Ожидание... │
|
||||
│ ⏳ destroy - Ожидание... │
|
||||
│ │
|
||||
│ 📝 Логи (live): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [2024-01-15 10:30:15] TASK [nginx : Install] │ │
|
||||
│ │ [2024-01-15 10:30:16] changed: [web1] │ │
|
||||
│ │ [2024-01-15 10:30:17] TASK [nginx : Configure] │ │
|
||||
│ │ [2024-01-15 10:30:18] changed: [web1] │ │
|
||||
│ │ ... │ │
|
||||
│ │ │ │
|
||||
│ │ [Автоскролл: ☑] [Очистить] [📥 Скачать] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🖥️ Статус контейнеров: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ web1 (Ubuntu 22.04) 🟢 Running │ │
|
||||
│ │ web2 (Debian 12) 🟢 Running │ │
|
||||
│ │ db1 (CentOS 9) 🟢 Running │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [⏸️ Пауза] [⏹️ Остановить] [🔄 Перезапустить] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**WebSocket реализация:**
|
||||
```python
|
||||
# app/api/v1/endpoints/websocket.py
|
||||
@router.websocket("/ws/test/{test_id}/logs")
|
||||
async def test_logs_websocket(websocket: WebSocket, test_id: str):
|
||||
await websocket.accept()
|
||||
|
||||
# Запуск molecule test с потоковым выводом
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
"molecule", "test", "-s", "default",
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
cwd=f"roles/{test_id}"
|
||||
)
|
||||
|
||||
# Отправка логов в реальном времени
|
||||
async for line in process.stdout:
|
||||
await websocket.send_json({
|
||||
"type": "log",
|
||||
"stage": detect_stage(line), # create, converge, etc.
|
||||
"data": line.decode(),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
|
||||
# Результат
|
||||
await websocket.send_json({
|
||||
"type": "complete",
|
||||
"status": "success" if process.returncode == 0 else "failed"
|
||||
})
|
||||
```
|
||||
|
||||
### 3.3. Редактирование molecule.yml через интерфейс
|
||||
|
||||
**URL:** `/roles/{role_name}/molecule/edit`
|
||||
|
||||
**Интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Редактор molecule.yml для роли: nginx │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Вкладки: │
|
||||
│ [Driver] [Platforms] [Provisioner] [Verifier] │
|
||||
│ │
|
||||
│ 🚗 Driver (Docker): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ driver: │ │
|
||||
│ │ name: [docker ▼] │ │
|
||||
│ │ options: │ │
|
||||
│ │ privileged: ☑ │ │
|
||||
│ │ volumes: │ │
|
||||
│ │ - /sys/fs/cgroup:/sys/fs/cgroup:ro │ │
|
||||
│ │ capabilities: │ │
|
||||
│ │ - SYS_ADMIN │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🖥️ Platforms (контейнеры): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [➕ Добавить платформу] │ │
|
||||
│ │ │ │
|
||||
│ │ Платформа 1: │ │
|
||||
│ │ ├─ name: [web1] │ │
|
||||
│ │ ├─ image: [inecs/ansible-lab:ubuntu22 ▼] │ │
|
||||
│ │ ├─ pre_build_image: ☑ │ │
|
||||
│ │ └─ [🗑️ Удалить] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📝 Предпросмотр YAML: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ driver: │ │
|
||||
│ │ name: docker │ │
|
||||
│ │ platforms: │ │
|
||||
│ │ - name: web1 │ │
|
||||
│ │ image: inecs/ansible-lab:ubuntu22 │ │
|
||||
│ │ pre_build_image: true │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [💾 Сохранить] [✅ Валидация] [🔄 Сбросить] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 🔄 Интеграция с существующими preset'ами
|
||||
|
||||
### 4.1. Использование preset'ов из `molecule/presets/`
|
||||
|
||||
**Автоматическое обнаружение preset'ов:**
|
||||
|
||||
```python
|
||||
# app/services/preset_service.py
|
||||
class PresetService:
|
||||
def list_presets(self) -> List[dict]:
|
||||
"""Список всех preset'ов из molecule/presets/"""
|
||||
presets = []
|
||||
preset_dir = Path("molecule/presets")
|
||||
|
||||
for preset_file in preset_dir.glob("*.yml"):
|
||||
with open(preset_file) as f:
|
||||
preset_data = yaml.safe_load(f)
|
||||
presets.append({
|
||||
"name": preset_file.stem,
|
||||
"description": preset_data.get("description", ""),
|
||||
"hosts_count": len(preset_data.get("hosts", [])),
|
||||
"images": self.extract_images(preset_data),
|
||||
"file": str(preset_file)
|
||||
})
|
||||
|
||||
return presets
|
||||
|
||||
def load_preset(self, name: str) -> dict:
|
||||
"""Загрузка preset'а"""
|
||||
preset_file = Path(f"molecule/presets/{name}.yml")
|
||||
with open(preset_file) as f:
|
||||
return yaml.safe_load(f)
|
||||
```
|
||||
|
||||
### 4.2. Редактирование существующих preset'ов
|
||||
|
||||
**Интерфейс редактирования:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Редактирование preset'а: default │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Информация: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Описание: [Стандартный preset для тестирования] │ │
|
||||
│ │ Файл: molecule/presets/default.yml │ │
|
||||
│ │ Хостов: 2 │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [См. интерфейс из раздела 1.1] │
|
||||
│ │
|
||||
│ ⚠️ Внимание: Изменения сохраняются в файл! │
|
||||
│ │
|
||||
│ [💾 Сохранить] [📋 Создать копию] [🗑️ Удалить] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 🎯 Примеры использования
|
||||
|
||||
### 5.1. Быстрый тест на одном образе
|
||||
|
||||
**Сценарий:** Пользователь хочет быстро протестировать роль на Ubuntu 22.04
|
||||
|
||||
1. Переходит на `/roles/nginx/test`
|
||||
2. Выбирает "Создать временный preset"
|
||||
3. Ставит галочку только на "Ubuntu 22.04", количество: 1
|
||||
4. Нажимает "Запустить тест"
|
||||
5. Смотрит live логи
|
||||
|
||||
### 5.2. Тест на нескольких ОС
|
||||
|
||||
**Сценарий:** Пользователь хочет протестировать на Ubuntu, Debian и CentOS
|
||||
|
||||
1. Переходит на `/roles/nginx/test`
|
||||
2. Выбирает "Создать временный preset"
|
||||
3. Ставит галочки:
|
||||
- Ubuntu 22.04 (2 хоста)
|
||||
- Debian 12 (2 хоста)
|
||||
- CentOS 9 (1 хост)
|
||||
4. Настраивает переменные роли
|
||||
5. Запускает тест
|
||||
6. Смотрит результаты по каждому хосту
|
||||
|
||||
### 5.3. Создание и сохранение кастомного preset'а
|
||||
|
||||
**Сценарий:** Пользователь создает preset для тестирования веб-серверов
|
||||
|
||||
1. Переходит на `/presets/create`
|
||||
2. Называет preset: "web-servers-test"
|
||||
3. Добавляет хосты:
|
||||
- web1 (Ubuntu 22.04) в группы [web, frontend]
|
||||
- web2 (Debian 12) в группы [web, backend]
|
||||
- lb1 (CentOS 9) в группы [web, loadbalancer]
|
||||
4. Сохраняет preset
|
||||
5. Использует его для тестирования: `/roles/nginx/test?preset=web-servers-test`
|
||||
|
||||
### 5.4. Редактирование inventory для продакшн
|
||||
|
||||
**Сценарий:** Пользователь настраивает inventory для реальных серверов
|
||||
|
||||
1. Переходит на `/inventory/production/edit`
|
||||
2. Добавляет группу [web_servers]
|
||||
3. Добавляет хосты с реальными IP
|
||||
4. Настраивает SSH ключи
|
||||
5. Тестирует подключение к каждому хосту
|
||||
6. Сохраняет в Vault для безопасности
|
||||
|
||||
---
|
||||
|
||||
## 6. 🔧 Технические детали реализации
|
||||
|
||||
### 6.1. Генерация molecule.yml из preset'а
|
||||
|
||||
```python
|
||||
# app/services/molecule_service.py
|
||||
class MoleculeService:
|
||||
def generate_molecule_yml(self, preset: dict, role_name: str) -> str:
|
||||
"""Генерация molecule.yml из preset'а"""
|
||||
molecule_config = {
|
||||
"driver": {
|
||||
"name": "docker"
|
||||
},
|
||||
"platforms": [],
|
||||
"provisioner": {
|
||||
"name": "ansible",
|
||||
"inventory": {
|
||||
"hosts": self.generate_inventory_hosts(preset)
|
||||
}
|
||||
},
|
||||
"verifier": {
|
||||
"name": "ansible"
|
||||
}
|
||||
}
|
||||
|
||||
# Преобразование хостов из preset'а в platforms
|
||||
for host in preset['hosts']:
|
||||
molecule_config['platforms'].append({
|
||||
"name": host['name'],
|
||||
"image": preset['images'][host['family']],
|
||||
"pre_build_image": True,
|
||||
**preset.get('systemd_defaults', {})
|
||||
})
|
||||
|
||||
return yaml.dump(molecule_config)
|
||||
```
|
||||
|
||||
### 6.2. Выполнение molecule команд
|
||||
|
||||
```python
|
||||
# app/core/molecule_executor.py
|
||||
class MoleculeExecutor:
|
||||
async def test(
|
||||
self,
|
||||
role_name: str,
|
||||
scenario: str = "default",
|
||||
stream: bool = False
|
||||
):
|
||||
"""Запуск molecule test"""
|
||||
cmd = [
|
||||
"molecule", "test",
|
||||
"-s", scenario,
|
||||
"--destroy", "never" # Не удалять для просмотра
|
||||
]
|
||||
|
||||
if stream:
|
||||
# Для WebSocket
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
cwd=f"roles/{role_name}"
|
||||
)
|
||||
return process
|
||||
else:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=f"roles/{role_name}"
|
||||
)
|
||||
return {
|
||||
"success": result.returncode == 0,
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Резюме
|
||||
|
||||
Все действия по настройке тестирования выполняются через веб-интерфейс:
|
||||
|
||||
1. **Выбор образов и хостов:** Визуальный редактор с drag & drop
|
||||
2. **Настройка inventory:** Автоматическая генерация + ручное редактирование
|
||||
3. **Molecule тестирование:** Полный контроль через интерфейс с live логами
|
||||
4. **Preset'ы:** Создание, редактирование, использование через UI
|
||||
5. **Переменные ролей:** Формы для заполнения с валидацией
|
||||
|
||||
Всё интуитивно, визуально и без необходимости знать команды make или структуру файлов!
|
||||
|
||||
---
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
Reference in New Issue
Block a user