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

735 lines
46 KiB
Markdown
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.

# Детали работы веб-интерфейса: тестирование и 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