- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
46 KiB
Детали работы веб-интерфейса: тестирование и 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 реализация:
<!-- 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:
# 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 реализация:
# 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'ов:
# 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
- Переходит на
/roles/nginx/test - Выбирает "Создать временный preset"
- Ставит галочку только на "Ubuntu 22.04", количество: 1
- Нажимает "Запустить тест"
- Смотрит live логи
5.2. Тест на нескольких ОС
Сценарий: Пользователь хочет протестировать на Ubuntu, Debian и CentOS
- Переходит на
/roles/nginx/test - Выбирает "Создать временный preset"
- Ставит галочки:
- Ubuntu 22.04 (2 хоста)
- Debian 12 (2 хоста)
- CentOS 9 (1 хост)
- Настраивает переменные роли
- Запускает тест
- Смотрит результаты по каждому хосту
5.3. Создание и сохранение кастомного preset'а
Сценарий: Пользователь создает preset для тестирования веб-серверов
- Переходит на
/presets/create - Называет preset: "web-servers-test"
- Добавляет хосты:
- web1 (Ubuntu 22.04) в группы [web, frontend]
- web2 (Debian 12) в группы [web, backend]
- lb1 (CentOS 9) в группы [web, loadbalancer]
- Сохраняет preset
- Использует его для тестирования:
/roles/nginx/test?preset=web-servers-test
5.4. Редактирование inventory для продакшн
Сценарий: Пользователь настраивает inventory для реальных серверов
- Переходит на
/inventory/production/edit - Добавляет группу [web_servers]
- Добавляет хосты с реальными IP
- Настраивает SSH ключи
- Тестирует подключение к каждому хосту
- Сохраняет в Vault для безопасности
6. 🔧 Технические детали реализации
6.1. Генерация molecule.yml из preset'а
# 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 команд
# 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
}
📝 Резюме
Все действия по настройке тестирования выполняются через веб-интерфейс:
- Выбор образов и хостов: Визуальный редактор с drag & drop
- Настройка inventory: Автоматическая генерация + ручное редактирование
- Molecule тестирование: Полный контроль через интерфейс с live логами
- Preset'ы: Создание, редактирование, использование через UI
- Переменные ролей: Формы для заполнения с валидацией
Всё интуитивно, визуально и без необходимости знать команды make или структуру файлов!
Автор: Сергей Антропов
Сайт: https://devops.org.ru