feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile
- Добавлена колонка 'Тип' во все таблицы истории сборок - Для push операций отображается registry вместо платформ - Сохранение пользователя при создании push лога - Исправлена ошибка с logger в push_docker_image endpoint - Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
871
docs/IMPROVEMENTS.md
Normal file
871
docs/IMPROVEMENTS.md
Normal file
@@ -0,0 +1,871 @@
|
||||
# Предложения по улучшению DevOpsLab
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
**Дата:** 2024
|
||||
|
||||
## 📋 Обзор
|
||||
|
||||
Этот документ содержит предложения по улучшению проекта DevOpsLab для превращения его в универсальную платформу для локального создания и тестирования Ansible ролей в любых средах.
|
||||
|
||||
## 🎯 Цели улучшений
|
||||
|
||||
1. **Упрощение создания новых ролей** - максимальная автоматизация и шаблонизация
|
||||
2. **Улучшение системы тестирования** - более гибкие и мощные preset'ы
|
||||
3. **Автоматизация CI/CD** - полная интеграция с популярными системами
|
||||
4. **Улучшение документации** - больше примеров и руководств
|
||||
5. **Мониторинг и отчетность** - визуализация результатов тестирования
|
||||
6. **Производительность** - оптимизация времени тестирования
|
||||
7. **Расширяемость** - плагины и интеграции
|
||||
|
||||
---
|
||||
|
||||
## 1. 🎨 Система шаблонов ролей
|
||||
|
||||
### 1.1. Шаблоны для разных типов ролей
|
||||
|
||||
**Проблема:** Сейчас все роли создаются с одинаковой базовой структурой, но разные типы ролей требуют разных подходов.
|
||||
|
||||
**Решение:** Создать систему шаблонов ролей с предустановленными структурами для разных типов:
|
||||
|
||||
```
|
||||
templates/
|
||||
├── role-types/
|
||||
│ ├── service/ # Роль для установки сервиса (nginx, apache)
|
||||
│ │ ├── tasks/
|
||||
│ │ │ ├── install.yml
|
||||
│ │ │ ├── configure.yml
|
||||
│ │ │ ├── service.yml
|
||||
│ │ │ └── main.yml
|
||||
│ │ ├── handlers/
|
||||
│ │ │ └── main.yml
|
||||
│ │ ├── templates/
|
||||
│ │ │ └── service.conf.j2
|
||||
│ │ └── defaults/
|
||||
│ │ └── main.yml
|
||||
│ ├── package/ # Роль для установки пакетов
|
||||
│ ├── config/ # Роль для конфигурации
|
||||
│ ├── database/ # Роль для работы с БД
|
||||
│ ├── monitoring/ # Роль для мониторинга
|
||||
│ ├── security/ # Роль для безопасности
|
||||
│ └── custom/ # Кастомный шаблон
|
||||
```
|
||||
|
||||
**Команда:**
|
||||
```bash
|
||||
make role create --template=service --name=nginx
|
||||
make role create --template=package --name=python-packages
|
||||
make role create --template=custom --name=my-custom-role
|
||||
```
|
||||
|
||||
### 1.2. Интерактивный мастер создания роли
|
||||
|
||||
**Проблема:** Создание роли требует знания структуры и ручного редактирования.
|
||||
|
||||
**Решение:** Интерактивный мастер с вопросами:
|
||||
- Тип роли (service, package, config, etc.)
|
||||
- Поддерживаемые ОС
|
||||
- Необходимые зависимости
|
||||
- Переменные по умолчанию
|
||||
- Тесты для роли
|
||||
|
||||
**Пример:**
|
||||
```bash
|
||||
make role create-wizard
|
||||
# Вопросы:
|
||||
# 1. Выберите тип роли: [service/package/config/database/monitoring/security/custom]
|
||||
# 2. Введите имя роли: nginx
|
||||
# 3. Выберите поддерживаемые ОС: [Ubuntu/Debian/CentOS/RHEL/AlmaLinux/Rocky/Alt/Astra]
|
||||
# 4. Нужны ли handlers? [y/n]
|
||||
# 5. Нужны ли templates? [y/n]
|
||||
# 6. Нужны ли files? [y/n]
|
||||
# 7. Какие переменные нужны? (интерактивно)
|
||||
```
|
||||
|
||||
### 1.3. Генератор документации из кода
|
||||
|
||||
**Проблема:** Документация роли часто устаревает или неполная.
|
||||
|
||||
**Решение:** Автоматическая генерация документации из:
|
||||
- Переменных в `defaults/main.yml`
|
||||
- Комментариев в tasks
|
||||
- Метаданных в `meta/main.yml`
|
||||
|
||||
**Команда:**
|
||||
```bash
|
||||
make role docs-generate nginx
|
||||
# Генерирует:
|
||||
# - README.md с таблицей переменных
|
||||
# - EXAMPLES.md с примерами использования
|
||||
# - CHANGELOG.md (если есть)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 🔧 Улучшение системы preset'ов
|
||||
|
||||
### 2.1. Динамические preset'ы
|
||||
|
||||
**Проблема:** Preset'ы статичны и требуют ручного редактирования.
|
||||
|
||||
**Решение:** Создание preset'ов на лету через CLI:
|
||||
|
||||
```bash
|
||||
# Создание preset'а для конкретной роли
|
||||
make preset create --name=nginx-test \
|
||||
--os=ubuntu22,debian12,centos9 \
|
||||
--count=3 \
|
||||
--network=nginx-net
|
||||
|
||||
# Создание preset'а для тестирования зависимостей
|
||||
make preset create --name=deps-test \
|
||||
--include-roles=docker,python,repo \
|
||||
--os=all
|
||||
```
|
||||
|
||||
### 2.2. Preset'ы на основе тегов ролей
|
||||
|
||||
**Проблема:** Нет возможности автоматически выбрать preset для тестирования роли с определенными тегами.
|
||||
|
||||
**Решение:** Автоматическое создание preset'ов на основе тегов:
|
||||
|
||||
```yaml
|
||||
# roles/nginx/meta/main.yml
|
||||
galaxy_tags:
|
||||
- web
|
||||
- service
|
||||
- nginx
|
||||
|
||||
# Автоматически создается preset: web-service.yml
|
||||
```
|
||||
|
||||
### 2.3. Preset'ы для разных сценариев
|
||||
|
||||
**Проблема:** Ограниченный набор preset'ов для разных сценариев тестирования.
|
||||
|
||||
**Решение:** Расширенный набор preset'ов:
|
||||
|
||||
```
|
||||
molecule/presets/
|
||||
├── scenarios/
|
||||
│ ├── single-os/ # Тестирование на одной ОС
|
||||
│ ├── multi-os/ # Тестирование на нескольких ОС
|
||||
│ ├── upgrade/ # Тестирование обновлений
|
||||
│ ├── rollback/ # Тестирование откатов
|
||||
│ ├── idempotency/ # Тестирование идемпотентности
|
||||
│ ├── performance/ # Тестирование производительности
|
||||
│ ├── security/ # Тестирование безопасности
|
||||
│ └── integration/ # Интеграционное тестирование
|
||||
```
|
||||
|
||||
### 2.4. Preset'ы с условиями
|
||||
|
||||
**Проблема:** Нет возможности условного запуска тестов.
|
||||
|
||||
**Решение:** Preset'ы с условиями:
|
||||
|
||||
```yaml
|
||||
# molecule/presets/conditional.yml
|
||||
hosts:
|
||||
- name: ubuntu-test
|
||||
family: ubuntu22
|
||||
when: ansible_distribution == "Ubuntu"
|
||||
- name: debian-test
|
||||
family: debian12
|
||||
when: ansible_distribution == "Debian"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 🤖 Автоматизация и CI/CD
|
||||
|
||||
### 3.1. Автоматическое тестирование при коммите
|
||||
|
||||
**Проблема:** Нужно вручную запускать тесты после изменений.
|
||||
|
||||
**Решение:** Git hooks для автоматического тестирования:
|
||||
|
||||
```bash
|
||||
# .git/hooks/pre-commit
|
||||
#!/bin/bash
|
||||
make role lint
|
||||
make role test minimal
|
||||
|
||||
# .git/hooks/post-merge
|
||||
#!/bin/bash
|
||||
make role test default
|
||||
```
|
||||
|
||||
**Команда:**
|
||||
```bash
|
||||
make setup-git-hooks
|
||||
# Устанавливает pre-commit и post-merge hooks
|
||||
```
|
||||
|
||||
### 3.2. Интеграция с GitHub Actions
|
||||
|
||||
**Проблема:** CI/CD конфигурации есть, но можно улучшить.
|
||||
|
||||
**Решение:** Расширенные workflow'ы:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/test-roles.yml
|
||||
name: Test Ansible Roles
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'roles/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'roles/**'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
preset: [minimal, default, all-images]
|
||||
role: ${{ github.event.changed_files }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test role
|
||||
run: make role test ${{ matrix.preset }} ${{ matrix.role }}
|
||||
```
|
||||
|
||||
### 3.3. Автоматическое обновление зависимостей
|
||||
|
||||
**Проблема:** Зависимости ролей могут устаревать.
|
||||
|
||||
**Решение:** Автоматическая проверка и обновление:
|
||||
|
||||
```bash
|
||||
make deps check # Проверка устаревших зависимостей
|
||||
make deps update # Обновление зависимостей
|
||||
make deps audit # Аудит безопасности зависимостей
|
||||
```
|
||||
|
||||
### 3.4. Автоматическая публикация в Ansible Galaxy
|
||||
|
||||
**Проблема:** Роли нужно вручную публиковать в Galaxy.
|
||||
|
||||
**Решение:** Автоматическая публикация:
|
||||
|
||||
```bash
|
||||
make galaxy publish nginx
|
||||
# Автоматически:
|
||||
# - Проверяет синтаксис
|
||||
# - Запускает тесты
|
||||
# - Генерирует документацию
|
||||
# - Публикует в Galaxy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 📊 Мониторинг и отчетность
|
||||
|
||||
### 4.1. Dashboard для результатов тестирования
|
||||
|
||||
**Проблема:** Результаты тестирования разбросаны по логам.
|
||||
|
||||
**Решение:** Web-дашборд для визуализации:
|
||||
|
||||
```bash
|
||||
make dashboard start
|
||||
# Запускает веб-интерфейс на http://localhost:8080
|
||||
# Показывает:
|
||||
# - История тестов
|
||||
# - Статистика успешности
|
||||
# - Время выполнения
|
||||
# - Графики покрытия ОС
|
||||
```
|
||||
|
||||
### 4.2. Отчеты в разных форматах
|
||||
|
||||
**Проблема:** Результаты тестов только в консоли.
|
||||
|
||||
**Решение:** Генерация отчетов:
|
||||
|
||||
```bash
|
||||
make report generate --format=html,json,xml,junit
|
||||
# Генерирует:
|
||||
# - reports/test-report.html
|
||||
# - reports/test-report.json
|
||||
# - reports/test-report.xml
|
||||
# - reports/junit.xml
|
||||
```
|
||||
|
||||
### 4.3. История тестирования
|
||||
|
||||
**Проблема:** Нет истории результатов тестирования.
|
||||
|
||||
**Решение:** Сохранение истории:
|
||||
|
||||
```bash
|
||||
make test history show --role=nginx --limit=10
|
||||
make test history compare --role=nginx --from=v1.0.0 --to=v1.1.0
|
||||
```
|
||||
|
||||
### 4.4. Уведомления о результатах
|
||||
|
||||
**Проблема:** Нужно вручную проверять результаты.
|
||||
|
||||
**Решение:** Уведомления:
|
||||
|
||||
```bash
|
||||
make notify setup --slack,email,telegram
|
||||
# Настройка уведомлений:
|
||||
# - Slack webhook
|
||||
# - Email
|
||||
# - Telegram bot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. ⚡ Производительность
|
||||
|
||||
### 5.1. Параллельное тестирование
|
||||
|
||||
**Проблема:** Тесты запускаются последовательно.
|
||||
|
||||
**Решение:** Параллельное выполнение:
|
||||
|
||||
```bash
|
||||
make role test --parallel=4 --preset=all-images
|
||||
# Запускает 4 теста одновременно
|
||||
```
|
||||
|
||||
### 5.2. Кеширование результатов
|
||||
|
||||
**Проблема:** Повторные тесты выполняют одни и те же действия.
|
||||
|
||||
**Решение:** Кеширование:
|
||||
|
||||
```bash
|
||||
make cache enable
|
||||
# Кеширует:
|
||||
# - Установленные пакеты
|
||||
# - Скачанные файлы
|
||||
# - Результаты проверок
|
||||
```
|
||||
|
||||
### 5.3. Инкрементальное тестирование
|
||||
|
||||
**Проблема:** Тестируются все роли, даже если изменилась только одна.
|
||||
|
||||
**Решение:** Тестирование только измененных ролей:
|
||||
|
||||
```bash
|
||||
make role test --changed-only
|
||||
# Тестирует только роли, измененные в последнем коммите
|
||||
```
|
||||
|
||||
### 5.4. Оптимизация Docker образов
|
||||
|
||||
**Проблема:** Образы могут быть большими и медленными.
|
||||
|
||||
**Решение:** Оптимизация:
|
||||
|
||||
```bash
|
||||
make docker optimize
|
||||
# Оптимизирует:
|
||||
# - Размер образов
|
||||
# - Время сборки
|
||||
# - Кеширование слоев
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 🔌 Расширяемость
|
||||
|
||||
### 6.1. Система плагинов
|
||||
|
||||
**Проблема:** Сложно добавить новую функциональность.
|
||||
|
||||
**Решение:** Плагинная архитектура:
|
||||
|
||||
```
|
||||
plugins/
|
||||
├── verifiers/
|
||||
│ ├── testinfra/
|
||||
│ ├── goss/
|
||||
│ └── serverspec/
|
||||
├── drivers/
|
||||
│ ├── docker/
|
||||
│ ├── vagrant/
|
||||
│ └── cloud/
|
||||
└── reporters/
|
||||
├── html/
|
||||
├── json/
|
||||
└── junit/
|
||||
```
|
||||
|
||||
### 6.2. Интеграция с внешними инструментами
|
||||
|
||||
**Проблема:** Нет интеграции с популярными инструментами.
|
||||
|
||||
**Решение:** Интеграции:
|
||||
|
||||
```bash
|
||||
# Terraform
|
||||
make terraform init
|
||||
make terraform test
|
||||
|
||||
# Vagrant
|
||||
make vagrant up
|
||||
make vagrant test
|
||||
|
||||
# Cloud providers
|
||||
make cloud test --provider=aws,azure,gcp
|
||||
```
|
||||
|
||||
### 6.3. API для автоматизации
|
||||
|
||||
**Проблема:** Нет программного доступа к функциональности.
|
||||
|
||||
**Решение:** REST API:
|
||||
|
||||
```bash
|
||||
# Запуск API сервера
|
||||
make api start
|
||||
|
||||
# Примеры использования:
|
||||
curl http://localhost:8080/api/v1/roles
|
||||
curl -X POST http://localhost:8080/api/v1/roles/nginx/test
|
||||
curl http://localhost:8080/api/v1/test-results/nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 🔐 Безопасность
|
||||
|
||||
### 7.1. Сканирование уязвимостей
|
||||
|
||||
**Проблема:** Нет автоматической проверки безопасности.
|
||||
|
||||
**Решение:** Интеграция сканеров:
|
||||
|
||||
```bash
|
||||
make security scan --role=nginx
|
||||
# Использует:
|
||||
# - ansible-lint security rules
|
||||
# - Bandit для Python кода
|
||||
# - Trivy для Docker образов
|
||||
# - Snyk для зависимостей
|
||||
```
|
||||
|
||||
### 7.2. Проверка секретов
|
||||
|
||||
**Проблема:** Секреты могут попасть в код.
|
||||
|
||||
**Решение:** Автоматическая проверка:
|
||||
|
||||
```bash
|
||||
make security check-secrets
|
||||
# Проверяет:
|
||||
# - Хардкод паролей
|
||||
# - API ключи
|
||||
# - Токены
|
||||
# - Сертификаты
|
||||
```
|
||||
|
||||
### 7.3. Подписывание ролей
|
||||
|
||||
**Проблема:** Нет гарантии целостности ролей.
|
||||
|
||||
**Решение:** GPG подписи:
|
||||
|
||||
```bash
|
||||
make role sign nginx
|
||||
make role verify nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 📚 Документация и примеры
|
||||
|
||||
### 8.1. Интерактивные туториалы
|
||||
|
||||
**Проблема:** Документация статична.
|
||||
|
||||
**Решение:** Интерактивные туториалы:
|
||||
|
||||
```bash
|
||||
make tutorial start --topic=creating-roles
|
||||
# Пошаговый интерактивный туториал
|
||||
```
|
||||
|
||||
### 8.2. Примеры для каждого типа роли
|
||||
|
||||
**Проблема:** Недостаточно примеров.
|
||||
|
||||
**Решение:** Расширенная библиотека примеров:
|
||||
|
||||
```
|
||||
examples/
|
||||
├── roles/
|
||||
│ ├── service/
|
||||
│ │ ├── nginx/
|
||||
│ │ ├── apache/
|
||||
│ │ └── haproxy/
|
||||
│ ├── database/
|
||||
│ │ ├── postgresql/
|
||||
│ │ ├── mysql/
|
||||
│ │ └── mongodb/
|
||||
│ └── monitoring/
|
||||
│ ├── prometheus/
|
||||
│ └── grafana/
|
||||
```
|
||||
|
||||
### 8.3. Видео-руководства
|
||||
|
||||
**Проблема:** Текстовые руководства могут быть непонятны.
|
||||
|
||||
**Решение:** Видео-руководства в документации.
|
||||
|
||||
### 8.4. Чек-листы для разработки
|
||||
|
||||
**Проблема:** Легко забыть важные шаги.
|
||||
|
||||
**Решение:** Чек-листы:
|
||||
|
||||
```bash
|
||||
make checklist show --type=role-development
|
||||
# Показывает чек-лист для разработки роли
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 🎯 Улучшение UX
|
||||
|
||||
### 9.1. Интерактивный режим
|
||||
|
||||
**Проблема:** Много команд для запоминания.
|
||||
|
||||
**Решение:** Интерактивный режим:
|
||||
|
||||
```bash
|
||||
make interactive
|
||||
# Запускает интерактивное меню:
|
||||
# 1. Создать роль
|
||||
# 2. Протестировать роль
|
||||
# 3. Просмотреть результаты
|
||||
# 4. Управление preset'ами
|
||||
# ...
|
||||
```
|
||||
|
||||
### 9.2. Автодополнение команд
|
||||
|
||||
**Проблема:** Нужно помнить все команды.
|
||||
|
||||
**Решение:** Bash/Zsh автодополнение:
|
||||
|
||||
```bash
|
||||
make setup-completion
|
||||
# Устанавливает автодополнение для:
|
||||
# - make команды
|
||||
# - Имена ролей
|
||||
# - Preset'ы
|
||||
```
|
||||
|
||||
### 9.3. Цветной вывод и прогресс-бары
|
||||
|
||||
**Проблема:** Сложно отслеживать прогресс длительных операций.
|
||||
|
||||
**Решение:** Улучшенный вывод:
|
||||
|
||||
```bash
|
||||
make role test --progress
|
||||
# Показывает:
|
||||
# - Прогресс-бары
|
||||
# - Цветной вывод
|
||||
# - ETA для операций
|
||||
```
|
||||
|
||||
### 9.4. Подсказки и советы
|
||||
|
||||
**Проблема:** Нет подсказок при ошибках.
|
||||
|
||||
**Решение:** Умные подсказки:
|
||||
|
||||
```bash
|
||||
# При ошибке теста:
|
||||
❌ Тест не прошел
|
||||
💡 Возможные причины:
|
||||
- Проверьте синтаксис: make role lint
|
||||
- Проверьте переменные: make role vars-show
|
||||
- Посмотрите логи: make logs show
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 🔄 Управление версиями
|
||||
|
||||
### 10.1. Семантическое версионирование
|
||||
|
||||
**Проблема:** Версии ролей не структурированы.
|
||||
|
||||
**Решение:** Автоматическое версионирование:
|
||||
|
||||
```bash
|
||||
make version bump --role=nginx --type=major,minor,patch
|
||||
# Автоматически:
|
||||
# - Обновляет версию в meta/main.yml
|
||||
# - Создает тег в git
|
||||
# - Обновляет CHANGELOG.md
|
||||
```
|
||||
|
||||
### 10.2. Changelog генерация
|
||||
|
||||
**Проблема:** CHANGELOG нужно вести вручную.
|
||||
|
||||
**Решение:** Автоматическая генерация:
|
||||
|
||||
```bash
|
||||
make changelog generate --role=nginx
|
||||
# Генерирует CHANGELOG.md из:
|
||||
# - Git коммитов
|
||||
# - Pull requests
|
||||
# - Issues
|
||||
```
|
||||
|
||||
### 10.3. Тегирование ролей
|
||||
|
||||
**Проблема:** Нет связи между версиями ролей и git тегами.
|
||||
|
||||
**Решение:** Автоматическое тегирование:
|
||||
|
||||
```bash
|
||||
make tag create --role=nginx --version=1.0.0
|
||||
# Создает git тег: roles/nginx/v1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 🧪 Расширенное тестирование
|
||||
|
||||
### 11.1. Тестирование идемпотентности
|
||||
|
||||
**Проблема:** Нет автоматической проверки идемпотентности.
|
||||
|
||||
**Решение:** Автоматическое тестирование:
|
||||
|
||||
```bash
|
||||
make role test --idempotency --role=nginx
|
||||
# Запускает роль дважды и проверяет, что изменений нет
|
||||
```
|
||||
|
||||
### 11.2. Тестирование откатов
|
||||
|
||||
**Проблема:** Нет проверки возможности отката изменений.
|
||||
|
||||
**Решение:** Тестирование откатов:
|
||||
|
||||
```bash
|
||||
make role test --rollback --role=nginx
|
||||
# Применяет роль, затем откатывает и проверяет
|
||||
```
|
||||
|
||||
### 11.3. Нагрузочное тестирование
|
||||
|
||||
**Проблема:** Нет проверки производительности ролей.
|
||||
|
||||
**Решение:** Нагрузочное тестирование:
|
||||
|
||||
```bash
|
||||
make role test --load --role=nginx --concurrent=10
|
||||
# Запускает роль на 10 хостах одновременно
|
||||
```
|
||||
|
||||
### 11.4. Тестирование совместимости
|
||||
|
||||
**Проблема:** Нет проверки совместимости версий.
|
||||
|
||||
**Решение:** Матричное тестирование:
|
||||
|
||||
```bash
|
||||
make role test --matrix --role=nginx
|
||||
# Тестирует на всех комбинациях:
|
||||
# - ОС × версии Ansible × версии Python
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 📦 Управление зависимостями
|
||||
|
||||
### 12.1. Визуализация зависимостей
|
||||
|
||||
**Проблема:** Сложно понять зависимости между ролями.
|
||||
|
||||
**Решение:** Граф зависимостей:
|
||||
|
||||
```bash
|
||||
make deps graph --role=nginx
|
||||
# Генерирует граф зависимостей в формате:
|
||||
# - PNG изображение
|
||||
# - Graphviz DOT
|
||||
# - Интерактивный HTML
|
||||
```
|
||||
|
||||
### 12.2. Проверка циклических зависимостей
|
||||
|
||||
**Проблема:** Могут быть циклические зависимости.
|
||||
|
||||
**Решение:** Автоматическая проверка:
|
||||
|
||||
```bash
|
||||
make deps check-cycles
|
||||
# Проверяет наличие циклов в зависимостях
|
||||
```
|
||||
|
||||
### 12.3. Автоматическое разрешение конфликтов
|
||||
|
||||
**Проблема:** Конфликты версий зависимостей.
|
||||
|
||||
**Решение:** Автоматическое разрешение:
|
||||
|
||||
```bash
|
||||
make deps resolve --role=nginx
|
||||
# Автоматически разрешает конфликты версий
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. 🌐 Мультиоблачные тесты
|
||||
|
||||
### 13.1. Тестирование в облаках
|
||||
|
||||
**Проблема:** Тестирование только локально в Docker.
|
||||
|
||||
**Решение:** Поддержка облачных провайдеров:
|
||||
|
||||
```bash
|
||||
make cloud test --provider=aws --role=nginx
|
||||
make cloud test --provider=azure --role=nginx
|
||||
make cloud test --provider=gcp --role=nginx
|
||||
```
|
||||
|
||||
### 13.2. Унифицированный интерфейс
|
||||
|
||||
**Проблема:** Разные API для разных облаков.
|
||||
|
||||
**Решение:** Единый интерфейс:
|
||||
|
||||
```bash
|
||||
make cloud create --provider=aws,azure,gcp --count=3
|
||||
make cloud test --provider=all
|
||||
make cloud destroy --provider=all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. 🔍 Поиск и фильтрация
|
||||
|
||||
### 14.1. Поиск по ролям
|
||||
|
||||
**Проблема:** Сложно найти нужную роль.
|
||||
|
||||
**Решение:** Поиск:
|
||||
|
||||
```bash
|
||||
make search role --query=nginx
|
||||
# Ищет по:
|
||||
# - Имени роли
|
||||
# - Описанию
|
||||
# - Тегам
|
||||
# - Переменным
|
||||
```
|
||||
|
||||
### 14.2. Фильтрация preset'ов
|
||||
|
||||
**Проблема:** Много preset'ов, сложно выбрать.
|
||||
|
||||
**Решение:** Фильтрация:
|
||||
|
||||
```bash
|
||||
make presets list --filter=os:ubuntu,count:2-5
|
||||
# Фильтрует по:
|
||||
# - ОС
|
||||
# - Количеству хостов
|
||||
# - Тегам
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 15. 📈 Метрики и аналитика
|
||||
|
||||
### 15.1. Метрики ролей
|
||||
|
||||
**Проблема:** Нет статистики по ролям.
|
||||
|
||||
**Решение:** Сбор метрик:
|
||||
|
||||
```bash
|
||||
make metrics show --role=nginx
|
||||
# Показывает:
|
||||
# - Время выполнения
|
||||
# - Успешность тестов
|
||||
# - Покрытие ОС
|
||||
# - Использование переменных
|
||||
```
|
||||
|
||||
### 15.2. Сравнение версий
|
||||
|
||||
**Проблема:** Сложно сравнить версии роли.
|
||||
|
||||
**Решение:** Сравнение:
|
||||
|
||||
```bash
|
||||
make compare versions --role=nginx --from=v1.0.0 --to=v1.1.0
|
||||
# Сравнивает:
|
||||
# - Изменения в коде
|
||||
# - Новые переменные
|
||||
# - Изменения в тестах
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Приоритизация улучшений
|
||||
|
||||
### Высокий приоритет (быстрая реализация, большой эффект)
|
||||
|
||||
1. ✅ Система шаблонов ролей (раздел 1.1, 1.2)
|
||||
2. ✅ Интерактивный мастер создания роли (раздел 1.2)
|
||||
3. ✅ Автоматическое тестирование при коммите (раздел 3.1)
|
||||
4. ✅ Отчеты в разных форматах (раздел 4.2)
|
||||
5. ✅ Параллельное тестирование (раздел 5.1)
|
||||
6. ✅ Интерактивный режим (раздел 9.1)
|
||||
|
||||
### Средний приоритет (средняя сложность, хороший эффект)
|
||||
|
||||
1. ✅ Динамические preset'ы (раздел 2.1)
|
||||
2. ✅ Dashboard для результатов (раздел 4.1)
|
||||
3. ✅ Кеширование результатов (раздел 5.2)
|
||||
4. ✅ Сканирование уязвимостей (раздел 7.1)
|
||||
5. ✅ Интерактивные туториалы (раздел 8.1)
|
||||
6. ✅ Семантическое версионирование (раздел 10.1)
|
||||
|
||||
### Низкий приоритет (сложная реализация, дополнительный функционал)
|
||||
|
||||
1. ✅ API для автоматизации (раздел 6.3)
|
||||
2. ✅ Мультиоблачные тесты (раздел 13)
|
||||
3. ✅ Система плагинов (раздел 6.1)
|
||||
4. ✅ Нагрузочное тестирование (раздел 11.3)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Заключение
|
||||
|
||||
Эти улучшения превратят DevOpsLab в полноценную платформу для разработки и тестирования Ansible ролей. Рекомендуется начать с высокоприоритетных улучшений и постепенно добавлять остальные.
|
||||
|
||||
**Следующие шаги:**
|
||||
1. Выбрать приоритетные улучшения
|
||||
2. Создать issues в репозитории
|
||||
3. Разбить на задачи
|
||||
4. Реализовать по очереди
|
||||
5. Собрать обратную связь от пользователей
|
||||
|
||||
---
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
92
docs/IMPROVEMENTS_SUMMARY.md
Normal file
92
docs/IMPROVEMENTS_SUMMARY.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Краткое резюме предложений по улучшению DevOpsLab
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 🎯 Топ-10 улучшений для платформы тестирования Ansible ролей
|
||||
|
||||
### 1. 🎨 Система шаблонов ролей
|
||||
**Что:** Предустановленные шаблоны для разных типов ролей (service, package, config, database, etc.)
|
||||
**Зачем:** Ускоряет создание новых ролей, стандартизирует структуру
|
||||
**Команда:** `make role create --template=service --name=nginx`
|
||||
|
||||
### 2. 🤖 Интерактивный мастер создания роли
|
||||
**Что:** Пошаговый мастер с вопросами о типе роли, ОС, зависимостях
|
||||
**Зачем:** Упрощает создание ролей для новичков
|
||||
**Команда:** `make role create-wizard`
|
||||
|
||||
### 3. ⚡ Параллельное тестирование
|
||||
**Что:** Запуск тестов на нескольких хостах одновременно
|
||||
**Зачем:** Ускоряет тестирование в 2-4 раза
|
||||
**Команда:** `make role test --parallel=4`
|
||||
|
||||
### 4. 📊 Dashboard для результатов
|
||||
**Что:** Web-интерфейс для визуализации результатов тестирования
|
||||
**Зачем:** Удобный просмотр истории и статистики
|
||||
**Команда:** `make dashboard start`
|
||||
|
||||
### 5. 🔄 Динамические preset'ы
|
||||
**Что:** Создание preset'ов на лету через CLI
|
||||
**Зачем:** Гибкость в выборе окружений для тестирования
|
||||
**Команда:** `make preset create --name=nginx-test --os=ubuntu22,debian12`
|
||||
|
||||
### 6. 📈 Отчеты в разных форматах
|
||||
**Что:** Генерация отчетов в HTML, JSON, XML, JUnit
|
||||
**Зачем:** Интеграция с CI/CD системами
|
||||
**Команда:** `make report generate --format=html,json`
|
||||
|
||||
### 7. 🔍 Автоматическое тестирование при коммите
|
||||
**Что:** Git hooks для автоматического запуска тестов
|
||||
**Зачем:** Раннее обнаружение проблем
|
||||
**Команда:** `make setup-git-hooks`
|
||||
|
||||
### 8. 🎯 Интерактивный режим
|
||||
**Что:** Меню с выбором действий
|
||||
**Зачем:** Упрощает работу для новичков
|
||||
**Команда:** `make interactive`
|
||||
|
||||
### 9. 🔐 Сканирование уязвимостей
|
||||
**Что:** Автоматическая проверка безопасности ролей
|
||||
**Зачем:** Обнаружение проблем безопасности до продакшна
|
||||
**Команда:** `make security scan --role=nginx`
|
||||
|
||||
### 10. 📦 Кеширование результатов
|
||||
**Что:** Кеширование установленных пакетов и результатов проверок
|
||||
**Зачем:** Ускорение повторных тестов
|
||||
**Команда:** `make cache enable`
|
||||
|
||||
---
|
||||
|
||||
## 📋 Быстрый старт улучшений
|
||||
|
||||
### Фаза 1: Быстрые победы (1-2 недели)
|
||||
- ✅ Интерактивный мастер создания роли
|
||||
- ✅ Параллельное тестирование
|
||||
- ✅ Отчеты в разных форматах
|
||||
- ✅ Git hooks для автоматического тестирования
|
||||
|
||||
### Фаза 2: Основной функционал (1 месяц)
|
||||
- ✅ Система шаблонов ролей
|
||||
- ✅ Динамические preset'ы
|
||||
- ✅ Dashboard для результатов
|
||||
- ✅ Интерактивный режим
|
||||
|
||||
### Фаза 3: Расширенный функционал (2-3 месяца)
|
||||
- ✅ Сканирование уязвимостей
|
||||
- ✅ Кеширование результатов
|
||||
- ✅ API для автоматизации
|
||||
- ✅ Интеграция с облаками
|
||||
|
||||
---
|
||||
|
||||
## 💡 Дополнительные идеи
|
||||
|
||||
- **Автодополнение команд** - bash/zsh completion
|
||||
- **История тестирования** - сравнение версий ролей
|
||||
- **Визуализация зависимостей** - граф зависимостей ролей
|
||||
- **Тестирование идемпотентности** - автоматическая проверка
|
||||
- **Семантическое версионирование** - автоматическое управление версиями
|
||||
|
||||
---
|
||||
|
||||
**Полная версия:** [IMPROVEMENTS.md](IMPROVEMENTS.md)
|
||||
89
docs/README.md
Normal file
89
docs/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Документация DevOpsLab
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 📚 Содержание
|
||||
|
||||
### 🚀 Быстрый старт
|
||||
|
||||
- **[getting-started.md](getting-started.md)** - Общий быстрый старт
|
||||
- **[web-interface-quickstart.md](web-interface-quickstart.md)** - Быстрый старт веб-интерфейса
|
||||
- **[web-interface-quickstart-docker.md](web-interface-quickstart-docker.md)** - Быстрый старт веб-интерфейса в Docker
|
||||
- **[web-interface-start-here.md](web-interface-start-here.md)** - Начните отсюда (веб-интерфейс)
|
||||
|
||||
### 🌐 Веб-интерфейс
|
||||
|
||||
- **[web-interface-readme.md](web-interface-readme.md)** - Общая документация веб-интерфейса
|
||||
- **[web-interface-docker.md](web-interface-docker.md)** - Запуск веб-интерфейса в Docker
|
||||
- **[WEB_INTERFACE_PROPOSAL.md](WEB_INTERFACE_PROPOSAL.md)** - Полное предложение по веб-интерфейсу
|
||||
- **[WEB_INTERFACE_DETAILS.md](WEB_INTERFACE_DETAILS.md)** - Детали работы веб-интерфейса
|
||||
- **[WEB_INTERFACE_DEPLOY_IMPORT_EXPORT.md](WEB_INTERFACE_DEPLOY_IMPORT_EXPORT.md)** - Деплой, импорт и экспорт через веб-интерфейс
|
||||
- **[WEB_INTERFACE_QUICKSTART.md](WEB_INTERFACE_QUICKSTART.md)** - Быстрый старт (старая версия)
|
||||
- **[web-interface-deployment-status.md](web-interface-deployment-status.md)** - Статус развертывания
|
||||
- **[web-interface-status.md](web-interface-status.md)** - Текущий статус веб-интерфейса
|
||||
|
||||
### 🔧 Ansible и Molecule
|
||||
|
||||
- **[molecule-guide.md](molecule-guide.md)** - Руководство по Molecule
|
||||
- **[creating-roles.md](creating-roles.md)** - Создание ролей
|
||||
- **[devops-role.md](devops-role.md)** - Универсальная роль devops
|
||||
- **[testing-vs-deployment.md](testing-vs-deployment.md)** - Различия между тестированием и развертыванием
|
||||
- **[universal-testing.md](universal-testing.md)** - Универсальное тестирование
|
||||
|
||||
### 🧪 Presets
|
||||
|
||||
- **[all-images-preset.md](all-images-preset.md)** - Пресет all-images для тестирования всех образов
|
||||
- **[cod-preset.md](cod-preset.md)** - COD preset для тестирования российских и зарубежных ОС (ARM64)
|
||||
- **[presets-by-os.md](presets-by-os.md)** - Presets по операционным системам
|
||||
|
||||
### 🚀 Развертывание
|
||||
|
||||
- **[deploy-yml-customization.md](deploy-yml-customization.md)** - Полное руководство по кастомизации deploy.yml
|
||||
- **[run-yml-guide.md](run-yml-guide.md)** - Руководство по run.yml
|
||||
- **[site-yml-guide.md](site-yml-guide.md)** - Руководство по site.yml
|
||||
|
||||
### 🔐 Безопасность
|
||||
|
||||
- **[vault-guide.md](vault-guide.md)** - Работа с Ansible Vault
|
||||
- **[linting-guide.md](linting-guide.md)** - Руководство по линтингу ролей
|
||||
|
||||
### 🐳 Docker
|
||||
|
||||
- **[dockerfiles.md](dockerfiles.md)** - Полная документация по Docker образам
|
||||
- **[arm64-support.md](arm64-support.md)** - Поддержка ARM64 архитектуры
|
||||
- **[buildx-fixes.md](buildx-fixes.md)** - Исправление проблем с Docker Buildx
|
||||
|
||||
### ☸️ Kubernetes
|
||||
|
||||
- **[kubernetes-kind.md](kubernetes-kind.md)** - Руководство по Kubernetes (Kind)
|
||||
- **[kubernetes-full-guide.md](kubernetes-full-guide.md)** - Полное руководство по Kubernetes
|
||||
- **[kubernetes-commands.md](kubernetes-commands.md)** - Команды Kubernetes
|
||||
- **[k8s-scripts.md](k8s-scripts.md)** - Описание K8s скриптов
|
||||
- **[k8s-ingress-fix.md](k8s-ingress-fix.md)** - Исправление Ingress
|
||||
|
||||
### 📊 Мониторинг и диагностика
|
||||
|
||||
- **[monitoring.md](monitoring.md)** - Мониторинг, диагностика и troubleshooting
|
||||
|
||||
### 🖥️ Платформы
|
||||
|
||||
- **[platform-support.md](platform-support.md)** - Поддержка платформ
|
||||
|
||||
### 📝 Примеры
|
||||
|
||||
- **[examples.md](examples.md)** - Примеры использования
|
||||
|
||||
### 🔄 CI/CD
|
||||
|
||||
- **[cicd-setup.md](cicd-setup.md)** - Настройка CI/CD
|
||||
|
||||
### 📈 Улучшения
|
||||
|
||||
- **[IMPROVEMENTS.md](IMPROVEMENTS.md)** - Предложения по улучшению
|
||||
- **[IMPROVEMENTS_SUMMARY.md](IMPROVEMENTS_SUMMARY.md)** - Краткое резюме улучшений
|
||||
|
||||
---
|
||||
|
||||
**Версия документации:** 3.0.0
|
||||
**Последнее обновление:** 2024-02-15
|
||||
985
docs/WEB_INTERFACE_DEPLOY_IMPORT_EXPORT.md
Normal file
985
docs/WEB_INTERFACE_DEPLOY_IMPORT_EXPORT.md
Normal file
@@ -0,0 +1,985 @@
|
||||
# Деплой, импорт и экспорт ролей в веб-интерфейсе
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 🎯 Обзор
|
||||
|
||||
Этот документ описывает функциональность деплоя на живые серверы, импорта и экспорта ролей через веб-интерфейс.
|
||||
|
||||
---
|
||||
|
||||
## 1. 🚀 Деплой на живые серверы
|
||||
|
||||
### 1.1. Страница деплоя роли
|
||||
|
||||
**URL:** `/roles/{role_name}/deploy`
|
||||
|
||||
**Интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Деплой роли: nginx на продакшн серверы │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ⚠️ ВНИМАНИЕ: Вы собираетесь изменить реальные серверы!│
|
||||
│ │
|
||||
│ 📋 Шаг 1: Выбор inventory │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ○ Использовать существующий inventory │ │
|
||||
│ │ [production ▼] [staging] [development] │ │
|
||||
│ │ │ │
|
||||
│ │ ● Создать/редактировать inventory │ │
|
||||
│ │ [Открыть редактор inventory] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📝 Шаг 2: Настройка переменных │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Переменные для продакшн: │ │
|
||||
│ │ │ │
|
||||
│ │ nginx_version: [1.25.0] │ │
|
||||
│ │ nginx_worker_processes: [4] │ │
|
||||
│ │ nginx_worker_connections: [2048] │ │
|
||||
│ │ nginx_sites: │ │
|
||||
│ │ - name: example.com │ │
|
||||
│ │ root: /var/www/html │ │
|
||||
│ │ ssl: ☑ │ │
|
||||
│ │ │ │
|
||||
│ │ [📥 Загрузить из шаблона] │ │
|
||||
│ │ [💾 Сохранить как шаблон] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ⚙️ Шаг 3: Параметры деплоя │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Режим: │ │
|
||||
│ │ ○ Dry-run (только проверка, без изменений) │ │
|
||||
│ │ ● Реальный деплой │ │
|
||||
│ │ │ │
|
||||
│ │ Опции: │ │
|
||||
│ │ ☑ Проверка подключения перед деплоем │ │
|
||||
│ │ ☑ Проверка синтаксиса │ │
|
||||
│ │ ☐ Только определенные теги │ │
|
||||
│ │ [web,config] │ │
|
||||
│ │ ☐ Только определенные хосты │ │
|
||||
│ │ [web1,web2] │ │
|
||||
│ │ ☐ Лимит хостов (для постепенного деплоя) │ │
|
||||
│ │ [2 из 5] │ │
|
||||
│ │ │ │
|
||||
│ │ Стратегия деплоя: │ │
|
||||
│ │ ○ Все хосты одновременно │ │
|
||||
│ │ ● Постепенно (по одному) │ │
|
||||
│ │ ○ По группам (сначала web, потом db) │ │
|
||||
│ │ │ │
|
||||
│ │ Rollback: │ │
|
||||
│ │ ☑ Создать backup перед деплоем │ │
|
||||
│ │ ☑ Включить автоматический rollback при ошибке │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🔐 Шаг 4: Безопасность │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ☑ Использовать Vault для секретов │ │
|
||||
│ │ ☑ Шифровать SSH ключи │ │
|
||||
│ │ ☑ Требовать подтверждение для критических операций│
|
||||
│ │ │ │
|
||||
│ │ Подтверждение: │ │
|
||||
│ │ [ ] Я понимаю, что это изменит продакшн серверы │ │
|
||||
│ │ [ ] Я проверил переменные │ │
|
||||
│ │ [ ] У меня есть backup │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [🔍 Dry-run] [🚀 Запустить деплой] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.2. Live мониторинг деплоя
|
||||
|
||||
**После запуска деплоя открывается страница с live логами:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Деплой роли: nginx | Статус: 🟢 Running │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📊 Прогресс: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ████████████████░░░░ 80% │ │
|
||||
│ │ Хостов обработано: 4 из 5 │ │
|
||||
│ │ Текущий хост: web3.example.com │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 🖥️ Статус хостов: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ✅ web1.example.com [Успешно] (2m 15s) │ │
|
||||
│ │ ✅ web2.example.com [Успешно] (2m 10s) │ │
|
||||
│ │ 🟢 web3.example.com [В процессе...] │ │
|
||||
│ │ ⏳ web4.example.com [Ожидание...] │ │
|
||||
│ │ ⏳ web5.example.com [Ожидание...] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📝 Live логи (WebSocket): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [10:30:15] PLAY [web_servers] ****************** │ │
|
||||
│ │ [10:30:16] TASK [nginx : Install packages] │ │
|
||||
│ │ [10:30:17] changed: [web1.example.com] │ │
|
||||
│ │ [10:30:18] TASK [nginx : Configure nginx] │ │
|
||||
│ │ [10:30:19] changed: [web1.example.com] │ │
|
||||
│ │ [10:30:20] TASK [nginx : Start nginx] │ │
|
||||
│ │ [10:30:21] changed: [web1.example.com] │ │
|
||||
│ │ [10:30:22] PLAY RECAP ************************** │ │
|
||||
│ │ [10:30:23] web1.example.com : ok=5 changed=3 │ │
|
||||
│ │ ... │ │
|
||||
│ │ │ │
|
||||
│ │ [Автоскролл: ☑] [Очистить] [📥 Скачать] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📈 Статистика: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Успешно: 2 │ │
|
||||
│ │ В процессе: 1 │ │
|
||||
│ │ Ожидание: 2 │ │
|
||||
│ │ Ошибок: 0 │ │
|
||||
│ │ Среднее время: 2m 12s │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [⏸️ Пауза] [⏹️ Остановить] [🔄 Retry failed] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.3. WebSocket реализация для live деплоя
|
||||
|
||||
```python
|
||||
# app/api/v1/endpoints/deploy.py
|
||||
from fastapi import WebSocket, APIRouter
|
||||
from app.core.make_executor import MakeExecutor
|
||||
from app.services.deploy_service import DeployService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.websocket("/ws/deploy/{deploy_id}")
|
||||
async def deploy_websocket(websocket: WebSocket, deploy_id: str):
|
||||
await websocket.accept()
|
||||
|
||||
# Получение параметров деплоя из БД
|
||||
deploy_config = await get_deploy_config(deploy_id)
|
||||
|
||||
# Запуск ansible-playbook с потоковым выводом
|
||||
executor = MakeExecutor()
|
||||
process = await executor.execute_stream(
|
||||
f"role deploy",
|
||||
args=[
|
||||
"--inventory", deploy_config["inventory"],
|
||||
"--extra-vars", json.dumps(deploy_config["vars"]),
|
||||
"--limit", deploy_config.get("limit", ""),
|
||||
"--tags", deploy_config.get("tags", "")
|
||||
]
|
||||
)
|
||||
|
||||
# Отправка логов в реальном времени
|
||||
current_host = None
|
||||
async for line in process.stdout:
|
||||
decoded_line = line.decode()
|
||||
|
||||
# Парсинг строки для определения хоста
|
||||
host_match = re.search(r'\[([^\]]+)\]', decoded_line)
|
||||
if host_match:
|
||||
current_host = host_match.group(1)
|
||||
|
||||
# Отправка с метаданными
|
||||
await websocket.send_json({
|
||||
"type": "log",
|
||||
"host": current_host,
|
||||
"data": decoded_line,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"level": detect_log_level(decoded_line) # info, warning, error
|
||||
})
|
||||
|
||||
# Отправка статуса хоста
|
||||
if "PLAY RECAP" in decoded_line or "ok=" in decoded_line:
|
||||
status = parse_play_recap(decoded_line)
|
||||
await websocket.send_json({
|
||||
"type": "host_status",
|
||||
"host": current_host,
|
||||
"status": status["status"], # success, failed, changed
|
||||
"changed": status.get("changed", 0),
|
||||
"ok": status.get("ok", 0),
|
||||
"failed": status.get("failed", 0)
|
||||
})
|
||||
|
||||
# Финальный статус
|
||||
await websocket.send_json({
|
||||
"type": "complete",
|
||||
"status": "success" if process.returncode == 0 else "failed",
|
||||
"summary": await generate_deploy_summary(deploy_id)
|
||||
})
|
||||
```
|
||||
|
||||
### 1.4. Сохранение истории деплоев
|
||||
|
||||
**Автоматическое сохранение в БД:**
|
||||
|
||||
```python
|
||||
# app/db/models.py
|
||||
class DeployHistory(Base):
|
||||
__tablename__ = "deploy_history"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
role_name = Column(String, nullable=False)
|
||||
inventory = Column(String, nullable=False)
|
||||
started_at = Column(DateTime, nullable=False)
|
||||
completed_at = Column(DateTime)
|
||||
status = Column(String) # success, failed, cancelled
|
||||
duration = Column(Integer) # секунды
|
||||
|
||||
# Параметры деплоя
|
||||
variables = Column(JSON) # Переменные роли
|
||||
limit = Column(String) # Ограничение хостов
|
||||
tags = Column(String) # Теги для выполнения
|
||||
|
||||
# Результаты
|
||||
total_hosts = Column(Integer)
|
||||
successful_hosts = Column(Integer)
|
||||
failed_hosts = Column(Integer)
|
||||
changed_hosts = Column(Integer)
|
||||
|
||||
# Логи
|
||||
logs = Column(Text) # Полные логи
|
||||
summary = Column(Text) # Краткое резюме
|
||||
|
||||
# Пользователь
|
||||
user = Column(String)
|
||||
dry_run = Column(Boolean, default=False)
|
||||
```
|
||||
|
||||
**Интерфейс истории:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ История деплоев │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Фильтры: │
|
||||
│ [Роль: nginx ▼] [Статус: Все ▼] [Дата: Последние 7 дней]│
|
||||
│ │
|
||||
│ 📊 Таблица деплоев: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Дата | Роль | Inventory | Статус | Действия│
|
||||
│ ├─────────────────────────────────────────────────┤ │
|
||||
│ │ 15.01 10:30| nginx | production| ✅ | [👁️][📥]│
|
||||
│ │ 15.01 09:15| nginx | staging | ✅ | [👁️][📥]│
|
||||
│ │ 14.01 16:45| docker| production| ❌ | [👁️][📥]│
|
||||
│ │ 14.01 14:20| python| production| ✅ | [👁️][📥]│
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [📥 Экспорт в CSV] [📥 Экспорт в JSON] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 📤 Экспорт ролей в отдельные Git репозитории
|
||||
|
||||
### 2.1. Страница экспорта роли
|
||||
|
||||
**URL:** `/roles/{role_name}/export`
|
||||
|
||||
**Интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Экспорт роли: nginx в отдельный репозиторий │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Шаг 1: Настройка репозитория │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Тип экспорта: │ │
|
||||
│ │ ○ Создать новый репозиторий │ │
|
||||
│ │ ● Использовать существующий │ │
|
||||
│ │ │ │
|
||||
│ │ URL репозитория: │ │
|
||||
│ │ [https://github.com/user/ansible-role-nginx] │ │
|
||||
│ │ │ │
|
||||
│ │ Ветка: [main ▼] [master] [develop] │ │
|
||||
│ │ │ │
|
||||
│ │ Аутентификация: │ │
|
||||
│ │ ○ SSH ключ (из настроек) │ │
|
||||
│ │ ● Personal Access Token │ │
|
||||
│ │ [token: ****************] │ │
|
||||
│ │ │ │
|
||||
│ │ [🔐 Тест подключения] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📦 Шаг 2: Выбор компонентов для экспорта │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ☑ Структура роли (tasks, handlers, etc.) │ │
|
||||
│ │ ☑ defaults/main.yml │ │
|
||||
│ │ ☑ vars/main.yml │ │
|
||||
│ │ ☑ templates/ │ │
|
||||
│ │ ☑ files/ │ │
|
||||
│ │ ☑ meta/main.yml │ │
|
||||
│ │ ☑ README.md │ │
|
||||
│ │ ☐ molecule/ (конфигурация тестирования) │ │
|
||||
│ │ ☐ tests/ (тестовые playbook'и) │ │
|
||||
│ │ ☐ .github/ (CI/CD workflows) │ │
|
||||
│ │ │ │
|
||||
│ │ ⚠️ Секреты (vars/main.yml): │ │
|
||||
│ │ ○ Экспортировать зашифрованными │ │
|
||||
│ │ ● Экспортировать без секретов (оставить пустыми)│
|
||||
│ │ ○ Не экспортировать │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📝 Шаг 3: Метаданные и версионирование │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Версия: [1.0.0] │ │
|
||||
│ │ Тег: [v1.0.0] (создать git tag) │ │
|
||||
│ │ │ │
|
||||
│ │ Описание изменений: │ │
|
||||
│ │ [Исправлена конфигурация nginx...] │ │
|
||||
│ │ │ │
|
||||
│ │ CHANGELOG.md: │ │
|
||||
│ │ ☑ Автоматически обновить │ │
|
||||
│ │ ☑ Создать release notes │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📋 Шаг 4: Предпросмотр │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Структура репозитория: │ │
|
||||
│ │ ansible-role-nginx/ │ │
|
||||
│ │ ├── tasks/ │ │
|
||||
│ │ ├── handlers/ │ │
|
||||
│ │ ├── defaults/ │ │
|
||||
│ │ ├── vars/ │ │
|
||||
│ │ ├── templates/ │ │
|
||||
│ │ ├── files/ │ │
|
||||
│ │ ├── meta/ │ │
|
||||
│ │ ├── README.md │ │
|
||||
│ │ └── .gitignore │ │
|
||||
│ │ │ │
|
||||
│ │ Файлов для экспорта: 47 │ │
|
||||
│ │ Размер: 2.3 MB │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [👁️ Предпросмотр файлов] [📤 Экспортировать] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2. Процесс экспорта с прогрессом
|
||||
|
||||
**После нажатия "Экспортировать":**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Экспорт роли: nginx │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📊 Прогресс: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ████████████████████░░ 90% │ │
|
||||
│ │ Этап: Загрузка в репозиторий │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📋 Этапы: │
|
||||
│ ✅ Подготовка файлов │ │
|
||||
│ ✅ Обработка секретов │ │
|
||||
│ ✅ Создание .gitignore │ │
|
||||
│ ✅ Клонирование репозитория │ │
|
||||
│ ✅ Копирование файлов │ │
|
||||
│ 🟢 Загрузка в репозиторий (git push) │ │
|
||||
│ ⏳ Создание тега │ │
|
||||
│ ⏳ Создание release │ │
|
||||
│ │
|
||||
│ 📝 Логи: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [10:35:15] Подготовка файлов... │ │
|
||||
│ │ [10:35:16] Обработка секретов... │ │
|
||||
│ │ [10:35:17] Клонирование репозитория... │ │
|
||||
│ │ [10:35:20] Копирование 47 файлов... │ │
|
||||
│ │ [10:35:22] git add . │ │
|
||||
│ │ [10:35:23] git commit -m "v1.0.0: ..." │ │
|
||||
│ │ [10:35:25] git push origin main... │ │
|
||||
│ │ ... │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [✅ Экспорт завершен] [🔗 Открыть репозиторий] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.3. Реализация экспорта
|
||||
|
||||
```python
|
||||
# app/services/export_service.py
|
||||
from git import Repo
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
class ExportService:
|
||||
async def export_role(
|
||||
self,
|
||||
role_name: str,
|
||||
repo_url: str,
|
||||
branch: str = "main",
|
||||
version: str = None,
|
||||
components: List[str] = None,
|
||||
include_secrets: bool = False
|
||||
) -> dict:
|
||||
"""Экспорт роли в Git репозиторий"""
|
||||
|
||||
# 1. Подготовка файлов
|
||||
role_path = Path(f"roles/{role_name}")
|
||||
temp_dir = Path(f"/tmp/export_{role_name}")
|
||||
temp_dir.mkdir(exist_ok=True)
|
||||
|
||||
# 2. Копирование выбранных компонентов
|
||||
components = components or ["tasks", "handlers", "defaults", "meta", "README.md"]
|
||||
for component in components:
|
||||
src = role_path / component
|
||||
if src.exists():
|
||||
if src.is_dir():
|
||||
shutil.copytree(src, temp_dir / component)
|
||||
else:
|
||||
shutil.copy2(src, temp_dir / component)
|
||||
|
||||
# 3. Обработка секретов
|
||||
if "vars" in components:
|
||||
vars_file = role_path / "vars" / "main.yml"
|
||||
if vars_file.exists():
|
||||
if include_secrets:
|
||||
# Копировать зашифрованным
|
||||
shutil.copy2(vars_file, temp_dir / "vars" / "main.yml")
|
||||
else:
|
||||
# Создать без секретов
|
||||
self.create_vars_without_secrets(vars_file, temp_dir / "vars" / "main.yml")
|
||||
|
||||
# 4. Создание .gitignore
|
||||
self.create_gitignore(temp_dir)
|
||||
|
||||
# 5. Клонирование/обновление репозитория
|
||||
repo_dir = Path(f"/tmp/repo_{role_name}")
|
||||
if repo_dir.exists():
|
||||
repo = Repo(repo_dir)
|
||||
repo.remote().pull()
|
||||
else:
|
||||
repo = Repo.clone_from(repo_url, repo_dir, branch=branch)
|
||||
|
||||
# 6. Копирование файлов в репозиторий
|
||||
for item in temp_dir.iterdir():
|
||||
dest = repo_dir / item.name
|
||||
if dest.exists():
|
||||
if dest.is_dir():
|
||||
shutil.rmtree(dest)
|
||||
else:
|
||||
dest.unlink()
|
||||
if item.is_dir():
|
||||
shutil.copytree(item, dest)
|
||||
else:
|
||||
shutil.copy2(item, dest)
|
||||
|
||||
# 7. Коммит и push
|
||||
repo.git.add(A=True)
|
||||
commit_message = f"{version}: {self.get_changelog_entry(role_name, version)}"
|
||||
repo.index.commit(commit_message)
|
||||
repo.remote().push()
|
||||
|
||||
# 8. Создание тега
|
||||
if version:
|
||||
repo.create_tag(f"v{version}")
|
||||
repo.remote().push(tags=True)
|
||||
|
||||
# 9. Очистка
|
||||
shutil.rmtree(temp_dir)
|
||||
shutil.rmtree(repo_dir)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"repo_url": repo_url,
|
||||
"version": version,
|
||||
"commit": repo.head.commit.hexsha
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 📥 Импорт ролей из других репозиториев
|
||||
|
||||
### 3.1. Страница импорта роли
|
||||
|
||||
**URL:** `/roles/import`
|
||||
|
||||
**Интерфейс:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Импорт роли из репозитория │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Шаг 1: Источник роли │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Тип источника: │ │
|
||||
│ │ ○ Git репозиторий │ │
|
||||
│ │ ● Ansible Galaxy │ │
|
||||
│ │ ○ Локальный архив (tar.gz, zip) │ │
|
||||
│ │ ○ URL (прямая ссылка на архив) │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─ Git репозиторий ─────────────────────────┐ │ │
|
||||
│ │ │ URL: │ │ │
|
||||
│ │ │ [https://github.com/user/ansible-role-nginx]│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Ветка/тег: [main ▼] [v1.0.0] [latest] │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Путь к роли (если не в корне): │ │ │
|
||||
│ │ │ [/roles/nginx] (оставить пустым если в корне)│ │ │
|
||||
│ │ └────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─ Ansible Galaxy ───────────────────────────┐ │ │
|
||||
│ │ │ Роль: [geerlingguy.nginx] │ │ │
|
||||
│ │ │ Версия: [latest ▼] [1.0.0] [0.9.0] │ │ │
|
||||
│ │ └────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ [🔍 Проверить доступность] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📝 Шаг 2: Настройка импорта │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Имя роли в проекте: │ │
|
||||
│ │ [nginx] (автоматически из источника) │ │
|
||||
│ │ │ │
|
||||
│ │ Действие при конфликте: │ │
|
||||
│ │ ○ Пропустить (не импортировать) │ │
|
||||
│ │ ● Перезаписать существующую роль │ │
|
||||
│ │ ○ Создать копию (nginx-imported) │ │
|
||||
│ │ │ │
|
||||
│ │ Импортировать: │ │
|
||||
│ │ ☑ Структуру роли │ │
|
||||
│ │ ☑ molecule конфигурацию (если есть) │ │
|
||||
│ │ ☑ tests/ (тестовые playbook'и) │ │
|
||||
│ │ ☐ .github/ (CI/CD workflows) │ │
|
||||
│ │ ☐ Документацию (если отличается) │ │
|
||||
│ │ │ │
|
||||
│ │ Обработка зависимостей: │ │
|
||||
│ │ ○ Импортировать зависимости автоматически │ │
|
||||
│ │ ● Показать список для подтверждения │ │
|
||||
│ │ ○ Пропустить зависимости │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📋 Шаг 3: Предпросмотр │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Информация о роли: │ │
|
||||
│ │ ├─ Название: nginx │ │
|
||||
│ │ ├─ Версия: 1.0.0 │ │
|
||||
│ │ ├─ Автор: geerlingguy │ │
|
||||
│ │ ├─ Описание: Install and configure nginx │ │
|
||||
│ │ ├─ Платформы: Ubuntu, Debian, CentOS, RHEL │ │
|
||||
│ │ └─ Зависимости: common (geerlingguy.common) │ │
|
||||
│ │ │ │
|
||||
│ │ Структура: │ │
|
||||
│ │ roles/nginx/ │ │
|
||||
│ │ ├── tasks/ (12 файлов) │ │
|
||||
│ │ ├── handlers/ (2 файла) │ │
|
||||
│ │ ├── defaults/ (1 файл) │ │
|
||||
│ │ ├── templates/ (5 файлов) │ │
|
||||
│ │ ├── meta/ (1 файл) │ │
|
||||
│ │ └── README.md │ │
|
||||
│ │ │ │
|
||||
│ │ Файлов: 23 │ │
|
||||
│ │ Размер: 1.8 MB │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [👁️ Предпросмотр файлов] [📥 Импортировать] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2. Процесс импорта
|
||||
|
||||
**После нажатия "Импортировать":**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Импорт роли: nginx │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📊 Прогресс: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ████████████████████░░ 95% │ │
|
||||
│ │ Этап: Интеграция в проект │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📋 Этапы: │
|
||||
│ ✅ Клонирование репозитория │ │
|
||||
│ ✅ Извлечение роли │ │
|
||||
│ ✅ Проверка структуры │ │
|
||||
│ ✅ Копирование файлов │ │
|
||||
│ 🟢 Интеграция в проект (обновление deploy.yml) │ │
|
||||
│ ⏳ Импорт зависимостей │ │
|
||||
│ │
|
||||
│ 📝 Логи: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [10:40:15] Клонирование репозитория... │ │
|
||||
│ │ [10:40:18] Извлечение роли nginx... │ │
|
||||
│ │ [10:40:19] Проверка структуры... │ │
|
||||
│ │ [10:40:20] Копирование 23 файлов... │ │
|
||||
│ │ [10:40:22] Обновление roles/deploy.yml... │ │
|
||||
│ │ [10:40:23] Импорт зависимости: common... │ │
|
||||
│ │ ... │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [✅ Импорт завершен] [👁️ Просмотреть роль] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.3. Реализация импорта
|
||||
|
||||
```python
|
||||
# app/services/import_service.py
|
||||
from git import Repo
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
import ansible_galaxy
|
||||
|
||||
class ImportService:
|
||||
async def import_role(
|
||||
self,
|
||||
source: str,
|
||||
source_type: str, # git, galaxy, archive, url
|
||||
role_name: str = None,
|
||||
version: str = None,
|
||||
conflict_action: str = "overwrite" # skip, overwrite, copy
|
||||
) -> dict:
|
||||
"""Импорт роли из внешнего источника"""
|
||||
|
||||
role_path = Path(f"roles/{role_name}")
|
||||
|
||||
# Проверка конфликтов
|
||||
if role_path.exists() and conflict_action == "skip":
|
||||
return {"success": False, "error": "Роль уже существует"}
|
||||
|
||||
# Импорт в зависимости от типа
|
||||
if source_type == "git":
|
||||
await self.import_from_git(source, role_name, version)
|
||||
elif source_type == "galaxy":
|
||||
await self.import_from_galaxy(source, role_name, version)
|
||||
elif source_type == "archive":
|
||||
await self.import_from_archive(source, role_name)
|
||||
elif source_type == "url":
|
||||
await self.import_from_url(source, role_name)
|
||||
|
||||
# Обработка конфликтов
|
||||
if conflict_action == "copy" and role_path.exists():
|
||||
role_path = Path(f"roles/{role_name}-imported")
|
||||
|
||||
# Интеграция в проект
|
||||
await self.integrate_role(role_name)
|
||||
|
||||
# Импорт зависимостей
|
||||
dependencies = await self.get_role_dependencies(role_name)
|
||||
if dependencies:
|
||||
await self.import_dependencies(dependencies)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"role_name": role_name,
|
||||
"path": str(role_path),
|
||||
"dependencies": dependencies
|
||||
}
|
||||
|
||||
async def import_from_git(self, repo_url: str, role_name: str, version: str = None):
|
||||
"""Импорт из Git репозитория"""
|
||||
temp_dir = Path(f"/tmp/import_{role_name}")
|
||||
temp_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Клонирование
|
||||
repo = Repo.clone_from(repo_url, temp_dir)
|
||||
if version:
|
||||
repo.git.checkout(version)
|
||||
|
||||
# Поиск роли в репозитории
|
||||
role_source = self.find_role_in_repo(temp_dir, role_name)
|
||||
|
||||
# Копирование
|
||||
role_path = Path(f"roles/{role_name}")
|
||||
if role_path.exists():
|
||||
shutil.rmtree(role_path)
|
||||
shutil.copytree(role_source, role_path)
|
||||
|
||||
# Очистка
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
async def import_from_galaxy(self, role_id: str, role_name: str, version: str = None):
|
||||
"""Импорт из Ansible Galaxy"""
|
||||
# Использование ansible-galaxy
|
||||
import subprocess
|
||||
cmd = ["ansible-galaxy", "install", role_id]
|
||||
if version:
|
||||
cmd.extend(["--version", version])
|
||||
subprocess.run(cmd, cwd="roles")
|
||||
|
||||
# Переименование если нужно
|
||||
installed_name = role_id.replace(".", "-")
|
||||
if installed_name != role_name:
|
||||
Path(f"roles/{installed_name}").rename(f"roles/{role_name}")
|
||||
|
||||
async def integrate_role(self, role_name: str):
|
||||
"""Интеграция роли в проект"""
|
||||
# Обновление roles/deploy.yml
|
||||
await self.update_deploy_yml(role_name)
|
||||
|
||||
# Создание molecule конфигурации если нужно
|
||||
await self.setup_molecule_config(role_name)
|
||||
|
||||
# Обновление документации
|
||||
await self.update_project_docs(role_name)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 📊 История команд и результатов
|
||||
|
||||
### 4.1. База данных для истории
|
||||
|
||||
```python
|
||||
# app/db/models.py
|
||||
class CommandHistory(Base):
|
||||
__tablename__ = "command_history"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
command = Column(String, nullable=False) # make role test nginx
|
||||
command_type = Column(String) # test, deploy, export, import
|
||||
role_name = Column(String)
|
||||
started_at = Column(DateTime, nullable=False)
|
||||
completed_at = Column(DateTime)
|
||||
status = Column(String) # success, failed, cancelled, running
|
||||
duration = Column(Integer) # секунды
|
||||
|
||||
# Параметры
|
||||
parameters = Column(JSON) # Все параметры команды
|
||||
|
||||
# Результаты
|
||||
stdout = Column(Text)
|
||||
stderr = Column(Text)
|
||||
return_code = Column(Integer)
|
||||
|
||||
# Пользователь
|
||||
user = Column(String)
|
||||
ip_address = Column(String)
|
||||
|
||||
# Связи
|
||||
test_result_id = Column(Integer, ForeignKey("test_results.id"))
|
||||
deploy_id = Column(Integer, ForeignKey("deploy_history.id"))
|
||||
```
|
||||
|
||||
### 4.2. Интерфейс истории команд
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ История команд │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Фильтры: │
|
||||
│ [Тип: Все ▼] [Роль: Все ▼] [Статус: Все ▼] │
|
||||
│ [Дата: Последние 7 дней ▼] │
|
||||
│ │
|
||||
│ 📊 Таблица команд: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Дата | Команда | Роль | Статус | Действия │ │
|
||||
│ ├─────────────────────────────────────────────────┤ │
|
||||
│ │ 15.01 10:30| test | nginx| ✅ | [👁️][📥]│
|
||||
│ │ 15.01 09:15| deploy | nginx| ✅ | [👁️][📥]│
|
||||
│ │ 15.01 08:45| export | nginx| ✅ | [👁️][📥]│
|
||||
│ │ 14.01 16:30| import | docker| ✅ | [👁️][📥]│
|
||||
│ │ 14.01 15:20| test | python| ❌ | [👁️][📥]│
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📈 Статистика: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Всего команд: 127 │ │
|
||||
│ │ Успешных: 115 (90.6%) │ │
|
||||
│ │ Ошибок: 12 (9.4%) │ │
|
||||
│ │ Среднее время: 2m 15s │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [📥 Экспорт в CSV] [📥 Экспорт в JSON] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.3. Детали команды
|
||||
|
||||
**При клике на команду:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Детали команды: make role test nginx default │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📋 Информация: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Команда: make role test nginx default │ │
|
||||
│ │ Тип: test │ │
|
||||
│ │ Роль: nginx │ │
|
||||
│ │ Preset: default │ │
|
||||
│ │ Статус: ✅ Успешно │ │
|
||||
│ │ Начало: 15.01.2024 10:30:15 │ │
|
||||
│ │ Завершение: 15.01.2024 10:32:30 │ │
|
||||
│ │ Длительность: 2m 15s │ │
|
||||
│ │ Пользователь: admin │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📝 Параметры: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ { │ │
|
||||
│ │ "role": "nginx", │ │
|
||||
│ │ "preset": "default", │ │
|
||||
│ │ "parallel": false, │ │
|
||||
│ │ "lint": true │ │
|
||||
│ │ } │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📄 Вывод (stdout): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ [Показать полный вывод] │ │
|
||||
│ │ ... │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ❌ Ошибки (stderr): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ (нет ошибок) │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [📥 Скачать логи] [🔄 Повторить команду] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 🔄 Автоматическое сохранение истории
|
||||
|
||||
### 5.1. Middleware для логирования команд
|
||||
|
||||
```python
|
||||
# app/core/command_logger.py
|
||||
from app.db.database import SessionLocal
|
||||
from app.db.models import CommandHistory
|
||||
from datetime import datetime
|
||||
|
||||
class CommandLogger:
|
||||
async def log_command(
|
||||
self,
|
||||
command: str,
|
||||
command_type: str,
|
||||
parameters: dict,
|
||||
user: str = None
|
||||
) -> int:
|
||||
"""Сохранение команды в историю"""
|
||||
db = SessionLocal()
|
||||
history = CommandHistory(
|
||||
command=command,
|
||||
command_type=command_type,
|
||||
role_name=parameters.get("role_name"),
|
||||
started_at=datetime.now(),
|
||||
status="running",
|
||||
parameters=parameters,
|
||||
user=user
|
||||
)
|
||||
db.add(history)
|
||||
db.commit()
|
||||
return history.id
|
||||
|
||||
async def update_command(
|
||||
self,
|
||||
history_id: int,
|
||||
status: str,
|
||||
stdout: str = None,
|
||||
stderr: str = None,
|
||||
return_code: int = None
|
||||
):
|
||||
"""Обновление результата команды"""
|
||||
db = SessionLocal()
|
||||
history = db.query(CommandHistory).filter_by(id=history_id).first()
|
||||
history.completed_at = datetime.now()
|
||||
history.status = status
|
||||
history.stdout = stdout
|
||||
history.stderr = stderr
|
||||
history.return_code = return_code
|
||||
history.duration = (history.completed_at - history.started_at).seconds
|
||||
db.commit()
|
||||
```
|
||||
|
||||
### 5.2. Интеграция с MakeExecutor
|
||||
|
||||
```python
|
||||
# app/core/make_executor.py
|
||||
class MakeExecutor:
|
||||
def __init__(self):
|
||||
self.logger = CommandLogger()
|
||||
|
||||
async def execute(
|
||||
self,
|
||||
command: str,
|
||||
args: List[str] = None,
|
||||
user: str = None
|
||||
) -> Dict:
|
||||
"""Выполнение команды с логированием"""
|
||||
# Сохранение в историю
|
||||
history_id = await self.logger.log_command(
|
||||
command=command,
|
||||
command_type=self.detect_command_type(command),
|
||||
parameters=self.parse_parameters(command, args),
|
||||
user=user
|
||||
)
|
||||
|
||||
# Выполнение команды
|
||||
cmd = ["make"] + command.split() + (args or [])
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=PROJECT_ROOT
|
||||
)
|
||||
|
||||
# Обновление истории
|
||||
await self.logger.update_command(
|
||||
history_id=history_id,
|
||||
status="success" if result.returncode == 0 else "failed",
|
||||
stdout=result.stdout,
|
||||
stderr=result.stderr,
|
||||
return_code=result.returncode
|
||||
)
|
||||
|
||||
return {
|
||||
"success": result.returncode == 0,
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr,
|
||||
"history_id": history_id
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Резюме
|
||||
|
||||
Все функции доступны через веб-интерфейс:
|
||||
|
||||
1. **Деплой на живые серверы:**
|
||||
- Выбор inventory
|
||||
- Настройка переменных
|
||||
- Live логи через WebSocket
|
||||
- Сохранение истории
|
||||
|
||||
2. **Экспорт ролей:**
|
||||
- В отдельные Git репозитории
|
||||
- С версионированием и тегами
|
||||
- С обработкой секретов
|
||||
|
||||
3. **Импорт ролей:**
|
||||
- Из Git репозиториев
|
||||
- Из Ansible Galaxy
|
||||
- С автоматической интеграцией
|
||||
|
||||
4. **История команд:**
|
||||
- Автоматическое сохранение всех команд
|
||||
- Детальные логи
|
||||
- Статистика и аналитика
|
||||
|
||||
Всё с live обновлениями, сохранением истории и удобным интерфейсом!
|
||||
|
||||
---
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
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
|
||||
702
docs/WEB_INTERFACE_PROPOSAL.md
Normal file
702
docs/WEB_INTERFACE_PROPOSAL.md
Normal file
@@ -0,0 +1,702 @@
|
||||
# Предложение по созданию веб-интерфейса для DevOpsLab
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
**Дата:** 2024
|
||||
|
||||
## 🎯 Цель
|
||||
|
||||
Создать современный веб-интерфейс на FastAPI + HTMX для управления всеми возможностями проекта DevOpsLab через браузер.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Архитектура решения
|
||||
|
||||
### Технологический стек
|
||||
|
||||
```
|
||||
Frontend:
|
||||
├── HTMX - динамическое обновление контента без перезагрузки
|
||||
├── Alpine.js - легковесная реактивность
|
||||
├── Tailwind CSS - современный UI
|
||||
├── Jinja2 Templates - серверный рендеринг
|
||||
└── Chart.js - визуализация данных
|
||||
|
||||
Backend:
|
||||
├── FastAPI - современный Python веб-фреймворк
|
||||
├── Pydantic - валидация данных
|
||||
├── Celery + Redis - фоновые задачи (тестирование)
|
||||
├── WebSocket - real-time обновления статуса
|
||||
└── SQLite/PostgreSQL - хранение истории и метрик
|
||||
|
||||
Интеграция:
|
||||
├── Вызов Makefile команд через subprocess
|
||||
├── Парсинг результатов тестов
|
||||
├── Управление Docker через API
|
||||
└── Работа с Git через GitPython
|
||||
```
|
||||
|
||||
### Структура проекта
|
||||
|
||||
```
|
||||
app/
|
||||
├── api/
|
||||
│ ├── v1/
|
||||
│ │ ├── endpoints/
|
||||
│ │ │ ├── roles.py # Управление ролями
|
||||
│ │ │ ├── presets.py # Управление preset'ами
|
||||
│ │ │ ├── tests.py # Запуск тестов
|
||||
│ │ │ ├── docker.py # Управление Docker
|
||||
│ │ │ ├── vault.py # Управление секретами
|
||||
│ │ │ ├── dashboard.py # Dashboard данные
|
||||
│ │ │ └── websocket.py # WebSocket для real-time
|
||||
│ │ └── router.py # Роутер API
|
||||
│ └── dependencies.py # Зависимости (auth, db)
|
||||
├── core/
|
||||
│ ├── config.py # Конфигурация
|
||||
│ ├── security.py # Безопасность
|
||||
│ ├── make_executor.py # Выполнение Makefile команд
|
||||
│ └── docker_client.py # Docker клиент
|
||||
├── models/
|
||||
│ ├── role.py # Модели ролей
|
||||
│ ├── test.py # Модели тестов
|
||||
│ └── preset.py # Модели preset'ов
|
||||
├── services/
|
||||
│ ├── role_service.py # Бизнес-логика ролей
|
||||
│ ├── test_service.py # Бизнес-логика тестов
|
||||
│ ├── preset_service.py # Бизнес-логика preset'ов
|
||||
│ └── docker_service.py # Бизнес-логика Docker
|
||||
├── templates/
|
||||
│ ├── base.html # Базовый шаблон
|
||||
│ ├── components/
|
||||
│ │ ├── navbar.html
|
||||
│ │ ├── sidebar.html
|
||||
│ │ ├── role_card.html
|
||||
│ │ ├── test_status.html
|
||||
│ │ └── preset_selector.html
|
||||
│ ├── pages/
|
||||
│ │ ├── dashboard.html # Главная страница
|
||||
│ │ ├── roles/
|
||||
│ │ │ ├── list.html # Список ролей
|
||||
│ │ │ ├── create.html # Создание роли
|
||||
│ │ │ ├── edit.html # Редактирование роли
|
||||
│ │ │ ├── detail.html # Детали роли
|
||||
│ │ │ └── test.html # Тестирование роли
|
||||
│ │ ├── presets/
|
||||
│ │ │ ├── list.html
|
||||
│ │ │ ├── create.html
|
||||
│ │ │ └── edit.html
|
||||
│ │ ├── tests/
|
||||
│ │ │ ├── history.html # История тестов
|
||||
│ │ │ ├── results.html # Результаты теста
|
||||
│ │ │ └── live.html # Live тестирование
|
||||
│ │ ├── docker/
|
||||
│ │ │ ├── images.html # Docker образы
|
||||
│ │ │ ├── containers.html # Контейнеры
|
||||
│ │ │ └── build.html # Сборка образов
|
||||
│ │ └── vault/
|
||||
│ │ ├── list.html
|
||||
│ │ └── edit.html
|
||||
│ └── partials/
|
||||
│ ├── role_form.html
|
||||
│ ├── preset_form.html
|
||||
│ └── test_logs.html
|
||||
├── static/
|
||||
│ ├── css/
|
||||
│ │ └── main.css # Tailwind + кастомные стили
|
||||
│ ├── js/
|
||||
│ │ ├── htmx.min.js
|
||||
│ │ ├── alpine.js
|
||||
│ │ └── app.js # Кастомный JS
|
||||
│ └── images/
|
||||
│ └── logo.svg
|
||||
├── tasks/
|
||||
│ └── celery_tasks.py # Фоновые задачи Celery
|
||||
├── db/
|
||||
│ ├── models.py # SQLAlchemy модели
|
||||
│ ├── database.py # Подключение к БД
|
||||
│ └── migrations/ # Миграции
|
||||
├── main.py # Точка входа FastAPI
|
||||
└── requirements.txt # Зависимости Python
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📱 Основные страницы и функциональность
|
||||
|
||||
### 1. Dashboard (Главная страница)
|
||||
|
||||
**URL:** `/`
|
||||
|
||||
**Функциональность:**
|
||||
- Статистика по ролям (всего, протестировано, успешно)
|
||||
- График успешности тестов за период
|
||||
- Последние тесты с результатами
|
||||
- Быстрые действия (создать роль, запустить тест)
|
||||
- Статус Docker (образы, контейнеры)
|
||||
- Активные задачи (Celery)
|
||||
|
||||
**HTMX фичи:**
|
||||
- Автообновление статистики каждые 5 секунд
|
||||
- Live статус тестов через WebSocket
|
||||
- Интерактивные графики
|
||||
|
||||
### 2. Управление ролями
|
||||
|
||||
#### 2.1. Список ролей (`/roles`)
|
||||
|
||||
**Функциональность:**
|
||||
- Карточки ролей с информацией:
|
||||
- Имя роли
|
||||
- Описание
|
||||
- Последний тест (статус, дата)
|
||||
- Количество переменных
|
||||
- Поддерживаемые ОС
|
||||
- Фильтры:
|
||||
- По статусу теста
|
||||
- По ОС
|
||||
- По тегам
|
||||
- Поиск по имени/описанию
|
||||
- Действия:
|
||||
- Создать новую роль
|
||||
- Редактировать
|
||||
- Удалить
|
||||
- Запустить тест
|
||||
- Просмотреть детали
|
||||
|
||||
**HTMX фичи:**
|
||||
- Фильтрация без перезагрузки
|
||||
- Модальные окна для действий
|
||||
- Inline редактирование
|
||||
|
||||
#### 2.2. Создание роли (`/roles/create`)
|
||||
|
||||
**Функциональность:**
|
||||
- Мастер создания роли (шаги):
|
||||
1. **Базовая информация:**
|
||||
- Имя роли
|
||||
- Описание
|
||||
- Тип роли (service, package, config, etc.)
|
||||
- Шаблон (выбор из доступных)
|
||||
|
||||
2. **Поддерживаемые ОС:**
|
||||
- Чекбоксы для каждой ОС
|
||||
- Версии ОС
|
||||
|
||||
3. **Переменные:**
|
||||
- Динамическое добавление переменных
|
||||
- Тип переменной (string, int, bool, list, dict)
|
||||
- Значение по умолчанию
|
||||
- Описание
|
||||
|
||||
4. **Зависимости:**
|
||||
- Выбор зависимых ролей
|
||||
- Версии зависимостей
|
||||
|
||||
5. **Тесты:**
|
||||
- Выбор preset'а для тестирования
|
||||
- Настройки тестирования
|
||||
|
||||
6. **Превью и создание:**
|
||||
- Превью структуры роли
|
||||
- Кнопка создания
|
||||
|
||||
**HTMX фичи:**
|
||||
- Прогресс-бар шагов
|
||||
- Валидация на лету
|
||||
- Сохранение черновика
|
||||
- Предпросмотр структуры
|
||||
|
||||
#### 2.3. Редактирование роли (`/roles/{role_name}/edit`)
|
||||
|
||||
**Функциональность:**
|
||||
- Редактирование tasks/main.yml (CodeMirror)
|
||||
- Редактирование defaults/main.yml (форма с переменными)
|
||||
- Редактирование handlers/main.yml
|
||||
- Управление templates и files
|
||||
- Редактирование meta/main.yml
|
||||
- Редактирование README.md (Markdown редактор)
|
||||
|
||||
**HTMX фичи:**
|
||||
- Автосохранение
|
||||
- Синтаксис-подсветка
|
||||
- Предпросмотр Markdown
|
||||
- Валидация YAML
|
||||
|
||||
#### 2.4. Детали роли (`/roles/{role_name}`)
|
||||
|
||||
**Функциональность:**
|
||||
- Вкладки:
|
||||
- **Обзор:** описание, метаданные, статистика
|
||||
- **Переменные:** таблица всех переменных с описаниями
|
||||
- **Задачи:** список задач с описаниями
|
||||
- **Тесты:** история тестирования
|
||||
- **Зависимости:** граф зависимостей
|
||||
- **Документация:** README.md
|
||||
|
||||
**HTMX фичи:**
|
||||
- Переключение вкладок без перезагрузки
|
||||
- Интерактивный граф зависимостей
|
||||
- Фильтрация истории тестов
|
||||
|
||||
#### 2.5. Тестирование роли (`/roles/{role_name}/test`)
|
||||
|
||||
**Функциональность:**
|
||||
- Выбор preset'а
|
||||
- Настройка переменных (форма)
|
||||
- Параметры теста:
|
||||
- Параллельность
|
||||
- Verbose режим
|
||||
- Только lint
|
||||
- Только синтаксис
|
||||
- Запуск теста
|
||||
- Live логи (WebSocket)
|
||||
- Прогресс выполнения
|
||||
- Результаты:
|
||||
- Статус (успех/ошибка)
|
||||
- Время выполнения
|
||||
- Детальные логи
|
||||
- Сравнение с предыдущим тестом
|
||||
|
||||
**HTMX фичи:**
|
||||
- Live обновление логов
|
||||
- Прогресс-бар
|
||||
- Автоматическое обновление статуса
|
||||
- Скачивание логов
|
||||
|
||||
### 3. Управление preset'ами (`/presets`)
|
||||
|
||||
**Функциональность:**
|
||||
- Список preset'ов
|
||||
- Создание preset'а:
|
||||
- Визуальный редактор хостов
|
||||
- Drag & drop для изменения порядка
|
||||
- Выбор образов
|
||||
- Настройка сети
|
||||
- Редактирование preset'а
|
||||
- Копирование preset'а
|
||||
- Удаление preset'а
|
||||
- Предпросмотр preset'а (YAML)
|
||||
|
||||
**HTMX фичи:**
|
||||
- Визуальный редактор
|
||||
- Предпросмотр YAML
|
||||
- Валидация
|
||||
|
||||
### 4. История тестов (`/tests`)
|
||||
|
||||
**Функциональность:**
|
||||
- Таблица всех тестов:
|
||||
- Роль
|
||||
- Preset
|
||||
- Статус
|
||||
- Дата/время
|
||||
- Длительность
|
||||
- Действия (просмотр, скачать логи)
|
||||
- Фильтры:
|
||||
- По роли
|
||||
- По статусу
|
||||
- По дате
|
||||
- По preset'у
|
||||
- Графики:
|
||||
- Успешность по времени
|
||||
- Время выполнения
|
||||
- Распределение по ОС
|
||||
|
||||
**HTMX фичи:**
|
||||
- Пагинация
|
||||
- Сортировка
|
||||
- Экспорт в CSV/JSON
|
||||
|
||||
### 5. Управление Docker (`/docker`)
|
||||
|
||||
**Функциональность:**
|
||||
- Список образов:
|
||||
- Статус (локально/в registry)
|
||||
- Размер
|
||||
- Дата создания
|
||||
- Архитектуры
|
||||
- Действия (pull, push, build, delete)
|
||||
- Список контейнеров:
|
||||
- Статус
|
||||
- Образ
|
||||
- Порты
|
||||
- Действия (start, stop, logs, exec)
|
||||
- Сборка образов:
|
||||
- Выбор образа
|
||||
- Параметры сборки
|
||||
- Прогресс сборки
|
||||
- Registry настройки
|
||||
|
||||
**HTMX фичи:**
|
||||
- Live обновление статуса
|
||||
- Прогресс сборки
|
||||
- Модальные окна для действий
|
||||
|
||||
### 6. Управление секретами (`/vault`)
|
||||
|
||||
**Функциональность:**
|
||||
- Список зашифрованных файлов
|
||||
- Редактирование секретов:
|
||||
- Форма с полями
|
||||
- Шифрование/расшифровка
|
||||
- Смена пароля
|
||||
- Поиск секретов в коде
|
||||
- Аудит безопасности
|
||||
|
||||
**HTMX фичи:**
|
||||
- Безопасное редактирование
|
||||
- Валидация перед шифрованием
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Технические детали
|
||||
|
||||
### FastAPI структура
|
||||
|
||||
```python
|
||||
# app/main.py
|
||||
from fastapi import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from app.api.v1.router import api_router
|
||||
|
||||
app = FastAPI(
|
||||
title="DevOpsLab Web Interface",
|
||||
description="Веб-интерфейс для управления Ansible ролями",
|
||||
version="1.0.0"
|
||||
)
|
||||
|
||||
# Статические файлы
|
||||
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
||||
|
||||
# Шаблоны
|
||||
templates = Jinja2Templates(directory="app/templates")
|
||||
|
||||
# API роуты
|
||||
app.include_router(api_router, prefix="/api/v1")
|
||||
|
||||
# Web роуты
|
||||
@app.get("/")
|
||||
async def dashboard(request: Request):
|
||||
return templates.TemplateResponse("pages/dashboard.html", {"request": request})
|
||||
```
|
||||
|
||||
### Выполнение Makefile команд
|
||||
|
||||
```python
|
||||
# app/core/make_executor.py
|
||||
import subprocess
|
||||
import asyncio
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
class MakeExecutor:
|
||||
"""Выполнение Makefile команд с отслеживанием прогресса"""
|
||||
|
||||
async def execute(
|
||||
self,
|
||||
command: str,
|
||||
args: List[str] = None,
|
||||
stream: bool = False
|
||||
) -> Dict:
|
||||
"""Выполнение команды make"""
|
||||
cmd = ["make"] + command.split() + (args or [])
|
||||
|
||||
if stream:
|
||||
# Для live логов через WebSocket
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE
|
||||
)
|
||||
return process
|
||||
else:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=PROJECT_ROOT
|
||||
)
|
||||
return {
|
||||
"success": result.returncode == 0,
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr,
|
||||
"returncode": result.returncode
|
||||
}
|
||||
```
|
||||
|
||||
### WebSocket для live обновлений
|
||||
|
||||
```python
|
||||
# app/api/v1/endpoints/websocket.py
|
||||
from fastapi import WebSocket
|
||||
from app.core.make_executor import MakeExecutor
|
||||
|
||||
@app.websocket("/ws/test/{test_id}")
|
||||
async def test_websocket(websocket: WebSocket, test_id: str):
|
||||
await websocket.accept()
|
||||
executor = MakeExecutor()
|
||||
|
||||
process = await executor.execute(
|
||||
f"role test {test_id}",
|
||||
stream=True
|
||||
)
|
||||
|
||||
async for line in process.stdout:
|
||||
await websocket.send_json({
|
||||
"type": "log",
|
||||
"data": line.decode()
|
||||
})
|
||||
|
||||
await websocket.send_json({
|
||||
"type": "complete",
|
||||
"status": "success"
|
||||
})
|
||||
```
|
||||
|
||||
### Celery для фоновых задач
|
||||
|
||||
```python
|
||||
# app/tasks/celery_tasks.py
|
||||
from celery import Celery
|
||||
from app.core.config import settings
|
||||
|
||||
celery_app = Celery(
|
||||
"devopslab",
|
||||
broker=settings.REDIS_URL,
|
||||
backend=settings.REDIS_URL
|
||||
)
|
||||
|
||||
@celery_app.task
|
||||
def run_role_test(role_name: str, preset: str):
|
||||
"""Запуск теста роли в фоне"""
|
||||
executor = MakeExecutor()
|
||||
result = executor.execute(f"role test {preset}")
|
||||
return result
|
||||
```
|
||||
|
||||
### База данных для истории
|
||||
|
||||
```python
|
||||
# app/db/models.py
|
||||
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text
|
||||
from app.db.database import Base
|
||||
|
||||
class TestResult(Base):
|
||||
__tablename__ = "test_results"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
role_name = Column(String, nullable=False)
|
||||
preset = Column(String, nullable=False)
|
||||
status = Column(String) # success, failed, running
|
||||
started_at = Column(DateTime)
|
||||
completed_at = Column(DateTime)
|
||||
duration = Column(Integer) # секунды
|
||||
logs = Column(Text)
|
||||
stdout = Column(Text)
|
||||
stderr = Column(Text)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI/UX дизайн
|
||||
|
||||
### Цветовая схема
|
||||
|
||||
```css
|
||||
/* Tailwind конфигурация */
|
||||
colors: {
|
||||
primary: '#3B82F6', // Синий
|
||||
secondary: '#10B981', // Зеленый
|
||||
danger: '#EF4444', // Красный
|
||||
warning: '#F59E0B', // Оранжевый
|
||||
dark: '#1F2937', // Темный
|
||||
light: '#F9FAFB' // Светлый
|
||||
}
|
||||
```
|
||||
|
||||
### Компоненты
|
||||
|
||||
1. **Navbar:**
|
||||
- Логотип
|
||||
- Навигация (Dashboard, Roles, Presets, Tests, Docker, Vault)
|
||||
- Уведомления
|
||||
- Профиль пользователя
|
||||
|
||||
2. **Sidebar:**
|
||||
- Быстрые действия
|
||||
- Последние тесты
|
||||
- Статистика
|
||||
|
||||
3. **Card компонент:**
|
||||
- Заголовок
|
||||
- Контент
|
||||
- Действия (кнопки)
|
||||
|
||||
4. **Modal компонент:**
|
||||
- HTMX для открытия/закрытия
|
||||
- Формы внутри
|
||||
|
||||
5. **Table компонент:**
|
||||
- Сортировка
|
||||
- Фильтрация
|
||||
- Пагинация
|
||||
|
||||
6. **Status badges:**
|
||||
- Успех (зеленый)
|
||||
- Ошибка (красный)
|
||||
- В процессе (синий)
|
||||
- Пропущен (серый)
|
||||
|
||||
---
|
||||
|
||||
## 📦 Зависимости
|
||||
|
||||
```txt
|
||||
# app/requirements.txt
|
||||
fastapi==0.104.1
|
||||
uvicorn[standard]==0.24.0
|
||||
jinja2==3.1.2
|
||||
python-multipart==0.0.6
|
||||
pydantic==2.5.0
|
||||
pydantic-settings==2.1.0
|
||||
|
||||
# HTMX и статика
|
||||
jinja2-partials==0.3.0
|
||||
|
||||
# База данных
|
||||
sqlalchemy==2.0.23
|
||||
alembic==1.12.1
|
||||
asyncpg==0.29.0 # Для PostgreSQL
|
||||
|
||||
# Фоновые задачи
|
||||
celery==5.3.4
|
||||
redis==5.0.1
|
||||
|
||||
# WebSocket
|
||||
websockets==12.0
|
||||
|
||||
# Docker
|
||||
docker==6.1.3
|
||||
|
||||
# Git
|
||||
GitPython==3.1.40
|
||||
|
||||
# Утилиты
|
||||
python-dotenv==1.0.0
|
||||
pyyaml==6.0.1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 План реализации
|
||||
|
||||
### Фаза 1: Базовая инфраструктура (1 неделя)
|
||||
- ✅ Настройка FastAPI проекта
|
||||
- ✅ Базовая структура папок
|
||||
- ✅ Интеграция с Makefile (MakeExecutor)
|
||||
- ✅ Базовые шаблоны (base.html, navbar, sidebar)
|
||||
- ✅ Dashboard страница (статичная)
|
||||
|
||||
### Фаза 2: Управление ролями (2 недели)
|
||||
- ✅ Список ролей
|
||||
- ✅ Создание роли (мастер)
|
||||
- ✅ Редактирование роли
|
||||
- ✅ Детали роли
|
||||
- ✅ Интеграция с Git
|
||||
|
||||
### Фаза 3: Тестирование (2 недели)
|
||||
- ✅ Запуск тестов через интерфейс
|
||||
- ✅ WebSocket для live логов
|
||||
- ✅ История тестов
|
||||
- ✅ Результаты тестов
|
||||
|
||||
### Фаза 4: Preset'ы и Docker (1 неделя)
|
||||
- ✅ Управление preset'ами
|
||||
- ✅ Управление Docker образами
|
||||
- ✅ Управление контейнерами
|
||||
|
||||
### Фаза 5: Полировка (1 неделя)
|
||||
- ✅ Улучшение UI/UX
|
||||
- ✅ Оптимизация производительности
|
||||
- ✅ Документация
|
||||
- ✅ Тестирование
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Безопасность
|
||||
|
||||
1. **Аутентификация:**
|
||||
- JWT токены
|
||||
- Сессии
|
||||
- OAuth2 (опционально)
|
||||
|
||||
2. **Авторизация:**
|
||||
- Роли пользователей
|
||||
- Права доступа
|
||||
|
||||
3. **Валидация:**
|
||||
- Pydantic схемы
|
||||
- Санитизация входных данных
|
||||
|
||||
4. **Защита от атак:**
|
||||
- CSRF токены
|
||||
- Rate limiting
|
||||
- SQL injection защита
|
||||
|
||||
---
|
||||
|
||||
## 📊 Метрики и мониторинг
|
||||
|
||||
1. **Производительность:**
|
||||
- Время ответа API
|
||||
- Использование памяти
|
||||
- CPU нагрузка
|
||||
|
||||
2. **Использование:**
|
||||
- Количество пользователей
|
||||
- Популярные роли
|
||||
- Частота тестирования
|
||||
|
||||
3. **Ошибки:**
|
||||
- Логирование ошибок
|
||||
- Sentry интеграция (опционально)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Преимущества решения
|
||||
|
||||
1. **Удобство:**
|
||||
- Не нужно знать команды make
|
||||
- Визуальный интерфейс
|
||||
- Интуитивная навигация
|
||||
|
||||
2. **Производительность:**
|
||||
- HTMX - минимальный JS
|
||||
- Серверный рендеринг
|
||||
- Быстрая загрузка
|
||||
|
||||
3. **Расширяемость:**
|
||||
- Модульная архитектура
|
||||
- Легко добавлять новые функции
|
||||
- API для интеграций
|
||||
|
||||
4. **Современность:**
|
||||
- FastAPI - быстрый и современный
|
||||
- HTMX - простота и мощность
|
||||
- Tailwind - красивый UI
|
||||
|
||||
---
|
||||
|
||||
## 📝 Следующие шаги
|
||||
|
||||
1. Создать git ветку: `git checkout -b feature/web-interface`
|
||||
2. Настроить структуру проекта
|
||||
3. Реализовать базовую инфраструктуру
|
||||
4. Постепенно добавлять функциональность
|
||||
5. Тестировать и улучшать
|
||||
|
||||
---
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
306
docs/WEB_INTERFACE_QUICKSTART.md
Normal file
306
docs/WEB_INTERFACE_QUICKSTART.md
Normal file
@@ -0,0 +1,306 @@
|
||||
# Быстрый старт веб-интерфейса DevOpsLab
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
### 1. Создание git ветки
|
||||
|
||||
```bash
|
||||
git checkout -b feature/web-interface
|
||||
git push -u origin feature/web-interface
|
||||
```
|
||||
|
||||
### 2. Структура проекта
|
||||
|
||||
```
|
||||
app/
|
||||
├── main.py # FastAPI приложение
|
||||
├── api/v1/endpoints/ # API endpoints
|
||||
├── templates/ # HTMX шаблоны
|
||||
├── static/ # CSS, JS
|
||||
└── core/ # Ядро (MakeExecutor, DockerClient)
|
||||
```
|
||||
|
||||
### 3. Основные компоненты
|
||||
|
||||
#### MakeExecutor - выполнение Makefile команд
|
||||
|
||||
```python
|
||||
# app/core/make_executor.py
|
||||
import subprocess
|
||||
from typing import Dict, List
|
||||
|
||||
class MakeExecutor:
|
||||
def execute(self, command: str, args: List[str] = None) -> Dict:
|
||||
cmd = ["make"] + command.split() + (args or [])
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return {
|
||||
"success": result.returncode == 0,
|
||||
"stdout": result.stdout,
|
||||
"stderr": result.stderr
|
||||
}
|
||||
```
|
||||
|
||||
#### FastAPI роуты
|
||||
|
||||
```python
|
||||
# app/api/v1/endpoints/roles.py
|
||||
from fastapi import APIRouter, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from app.core.make_executor import MakeExecutor
|
||||
|
||||
router = APIRouter()
|
||||
templates = Jinja2Templates(directory="app/templates")
|
||||
executor = MakeExecutor()
|
||||
|
||||
@router.get("/roles", response_class=HTMLResponse)
|
||||
async def list_roles(request: Request):
|
||||
# Получаем список ролей через make
|
||||
result = executor.execute("role list")
|
||||
roles = parse_roles(result["stdout"])
|
||||
return templates.TemplateResponse(
|
||||
"pages/roles/list.html",
|
||||
{"request": request, "roles": roles}
|
||||
)
|
||||
|
||||
@router.post("/roles/{role_name}/test")
|
||||
async def test_role(role_name: str, preset: str = "default"):
|
||||
# Запуск теста
|
||||
result = executor.execute(f"role test {preset}")
|
||||
return {"status": "success" if result["success"] else "failed"}
|
||||
```
|
||||
|
||||
#### HTMX шаблон
|
||||
|
||||
```html
|
||||
<!-- app/templates/pages/roles/list.html -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{% for role in roles %}
|
||||
<div class="card">
|
||||
<h3>{{ role.name }}</h3>
|
||||
<p>{{ role.description }}</p>
|
||||
<button
|
||||
hx-post="/api/v1/roles/{{ role.name }}/test"
|
||||
hx-target="#test-results"
|
||||
class="btn-primary">
|
||||
Запустить тест
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
### 4. Примеры страниц
|
||||
|
||||
#### Dashboard
|
||||
|
||||
```html
|
||||
<!-- app/templates/pages/dashboard.html -->
|
||||
<div class="dashboard">
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<h3>Всего ролей</h3>
|
||||
<p hx-get="/api/v1/stats/roles" hx-trigger="every 5s">
|
||||
{{ total_roles }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recent-tests">
|
||||
<h2>Последние тесты</h2>
|
||||
<div id="test-list"
|
||||
hx-get="/api/v1/tests/recent"
|
||||
hx-trigger="every 10s">
|
||||
<!-- Загружается через HTMX -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Создание роли
|
||||
|
||||
```html
|
||||
<!-- app/templates/pages/roles/create.html -->
|
||||
<form hx-post="/api/v1/roles/create" hx-target="#result">
|
||||
<div class="step" id="step-1">
|
||||
<h3>Шаг 1: Базовая информация</h3>
|
||||
<input name="name" placeholder="Имя роли" required>
|
||||
<textarea name="description" placeholder="Описание"></textarea>
|
||||
<select name="template">
|
||||
<option value="service">Service</option>
|
||||
<option value="package">Package</option>
|
||||
<option value="config">Config</option>
|
||||
</select>
|
||||
<button type="button" hx-get="/api/v1/roles/create/step/2">
|
||||
Далее
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="step" id="step-2" style="display:none;">
|
||||
<h3>Шаг 2: Переменные</h3>
|
||||
<div id="variables">
|
||||
<div class="variable-row">
|
||||
<input name="var_name" placeholder="Имя переменной">
|
||||
<input name="var_value" placeholder="Значение">
|
||||
<select name="var_type">
|
||||
<option value="string">String</option>
|
||||
<option value="int">Integer</option>
|
||||
<option value="bool">Boolean</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" hx-post="/api/v1/roles/create/add-variable">
|
||||
Добавить переменную
|
||||
</button>
|
||||
<button type="submit">Создать роль</button>
|
||||
</div>
|
||||
</form>
|
||||
```
|
||||
|
||||
### 5. WebSocket для live логов
|
||||
|
||||
```python
|
||||
# app/api/v1/endpoints/websocket.py
|
||||
from fastapi import WebSocket
|
||||
from app.core.make_executor import MakeExecutor
|
||||
|
||||
@router.websocket("/ws/test/{test_id}")
|
||||
async def test_websocket(websocket: WebSocket, test_id: str):
|
||||
await websocket.accept()
|
||||
executor = MakeExecutor()
|
||||
|
||||
# Запуск теста с потоковым выводом
|
||||
process = await executor.execute_stream(f"role test {test_id}")
|
||||
|
||||
async for line in process.stdout:
|
||||
await websocket.send_json({
|
||||
"type": "log",
|
||||
"data": line.decode()
|
||||
})
|
||||
|
||||
await websocket.send_json({"type": "complete"})
|
||||
```
|
||||
|
||||
```javascript
|
||||
// app/static/js/test-live.js
|
||||
const ws = new WebSocket('ws://localhost:8000/ws/test/nginx');
|
||||
const logContainer = document.getElementById('test-logs');
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.type === 'log') {
|
||||
logContainer.innerHTML += `<div>${data.data}</div>`;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 6. Запуск приложения
|
||||
|
||||
```python
|
||||
# app/main.py
|
||||
from fastapi import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from app.api.v1.endpoints import roles, presets, tests
|
||||
|
||||
app = FastAPI(title="DevOpsLab Web Interface")
|
||||
|
||||
# Статика
|
||||
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
||||
|
||||
# Шаблоны
|
||||
templates = Jinja2Templates(directory="app/templates")
|
||||
|
||||
# Роуты
|
||||
app.include_router(roles.router, prefix="/api/v1")
|
||||
app.include_router(presets.router, prefix="/api/v1")
|
||||
app.include_router(tests.router, prefix="/api/v1")
|
||||
|
||||
@app.get("/")
|
||||
async def dashboard(request: Request):
|
||||
return templates.TemplateResponse("pages/dashboard.html", {"request": request})
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
```
|
||||
|
||||
### 7. Docker Compose для разработки
|
||||
|
||||
```yaml
|
||||
# docker-compose.dev.yml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build: ./app
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./app:/app
|
||||
- .:/workspace
|
||||
environment:
|
||||
- PROJECT_ROOT=/workspace
|
||||
command: uvicorn main:app --reload --host 0.0.0.0
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
celery:
|
||||
build: ./app
|
||||
command: celery -A tasks.celery_tasks worker --loglevel=info
|
||||
volumes:
|
||||
- ./app:/app
|
||||
- .:/workspace
|
||||
depends_on:
|
||||
- redis
|
||||
```
|
||||
|
||||
### 8. Команды для разработки
|
||||
|
||||
```bash
|
||||
# Установка зависимостей
|
||||
cd app
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Запуск в режиме разработки
|
||||
uvicorn main:app --reload
|
||||
|
||||
# Запуск через Docker
|
||||
docker-compose -f docker-compose.dev.yml up
|
||||
|
||||
# Запуск Celery worker
|
||||
celery -A tasks.celery_tasks worker --loglevel=info
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Чек-лист реализации
|
||||
|
||||
- [ ] Создать git ветку
|
||||
- [ ] Настроить структуру проекта
|
||||
- [ ] Реализовать MakeExecutor
|
||||
- [ ] Создать базовые шаблоны
|
||||
- [ ] Реализовать Dashboard
|
||||
- [ ] Реализовать список ролей
|
||||
- [ ] Реализовать создание роли
|
||||
- [ ] Реализовать тестирование роли
|
||||
- [ ] Добавить WebSocket для live логов
|
||||
- [ ] Настроить Celery для фоновых задач
|
||||
- [ ] Добавить базу данных для истории
|
||||
- [ ] Улучшить UI/UX
|
||||
- [ ] Добавить аутентификацию
|
||||
- [ ] Написать документацию
|
||||
|
||||
---
|
||||
|
||||
**Полная версия:** [WEB_INTERFACE_PROPOSAL.md](WEB_INTERFACE_PROPOSAL.md)
|
||||
133
docs/web-interface-deployment-status.md
Normal file
133
docs/web-interface-deployment-status.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Статус развертывания веб-интерфейса
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
**Дата:** 2024-02-15
|
||||
|
||||
## ✅ Статус: РАБОТАЕТ
|
||||
|
||||
### Проверка работоспособности
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl http://localhost:8000/health
|
||||
# Ответ: {"status":"ok","version":"1.0.0"}
|
||||
|
||||
# Главная страница
|
||||
curl http://localhost:8000/
|
||||
# Ответ: HTML страница Dashboard
|
||||
|
||||
# API статистики
|
||||
curl http://localhost:8000/api/v1/stats/roles
|
||||
# Ответ: {"count":4}
|
||||
```
|
||||
|
||||
### Запущенные контейнеры
|
||||
|
||||
```bash
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
Все контейнеры должны быть в статусе `Up`:
|
||||
- ✅ `devopslab-web` - Веб-интерфейс (порт 8000)
|
||||
- ✅ `devopslab-redis` - Redis (порт 6379)
|
||||
- ✅ `devopslab-celery-worker` - Celery worker
|
||||
- ✅ `devopslab-celery-beat` - Celery beat
|
||||
|
||||
## 🔧 Исправленные проблемы
|
||||
|
||||
### 1. Конфликт зависимостей Redis
|
||||
**Проблема:** `celery[redis] 5.3.4` требует `redis <5.0.0`, но был указан `redis==5.0.1`
|
||||
|
||||
**Решение:** Изменена версия на `redis==4.6.0`
|
||||
|
||||
### 2. Ошибка импорта модулей
|
||||
**Проблема:** `ModuleNotFoundError: No module named 'app'`
|
||||
|
||||
**Решение:**
|
||||
- Изменена структура в Dockerfile: файлы копируются в `/app/app/`
|
||||
- Добавлен `PYTHONPATH=/app` в переменные окружения
|
||||
- Изменена команда запуска на `python -m uvicorn app.main:app`
|
||||
- Создан `app/app/__init__.py` для правильного пакета
|
||||
|
||||
### 3. Команды Celery
|
||||
**Проблема:** Celery не мог найти модуль tasks
|
||||
|
||||
**Решение:** Изменены команды на `celery -A app.tasks.celery_tasks`
|
||||
|
||||
## 📋 Структура в контейнере
|
||||
|
||||
```
|
||||
/app/ # Рабочая директория
|
||||
├── app/ # Пакет приложения
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py # Точка входа (было в корне)
|
||||
│ ├── api/
|
||||
│ ├── core/
|
||||
│ ├── models/
|
||||
│ ├── services/
|
||||
│ ├── templates/
|
||||
│ ├── static/
|
||||
│ ├── tasks/
|
||||
│ └── db/
|
||||
├── logs/ # Логи
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
## 🚀 Команды для работы
|
||||
|
||||
```bash
|
||||
# Запуск
|
||||
cd app
|
||||
make up
|
||||
# или
|
||||
docker-compose up -d
|
||||
|
||||
# Остановка
|
||||
make down
|
||||
# или
|
||||
docker-compose down
|
||||
|
||||
# Логи
|
||||
make logs
|
||||
# или
|
||||
docker-compose logs -f web
|
||||
|
||||
# Shell в контейнере
|
||||
make shell
|
||||
# или
|
||||
docker-compose exec web bash
|
||||
|
||||
# Статус
|
||||
make status
|
||||
# или
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
## 🌐 Доступ
|
||||
|
||||
- **Веб-интерфейс:** http://localhost:8000
|
||||
- **API документация:** http://localhost:8000/api/docs
|
||||
- **ReDoc:** http://localhost:8000/api/redoc
|
||||
- **Health check:** http://localhost:8000/health
|
||||
|
||||
## ✅ Проверка работоспособности
|
||||
|
||||
1. ✅ Контейнеры запускаются
|
||||
2. ✅ Веб-интерфейс отвечает на запросы
|
||||
3. ✅ API endpoints работают
|
||||
4. ✅ Redis подключен
|
||||
5. ✅ Celery worker запущен
|
||||
6. ✅ Доступ к Docker socket работает
|
||||
7. ✅ Монтирование проекта работает
|
||||
|
||||
## 📝 Следующие шаги
|
||||
|
||||
1. Реализовать список ролей
|
||||
2. Реализовать создание роли
|
||||
3. Реализовать тестирование с live логами
|
||||
4. Добавить базу данных для истории
|
||||
|
||||
---
|
||||
|
||||
**Статус:** ✅ Готово к разработке
|
||||
219
docs/web-interface-docker.md
Normal file
219
docs/web-interface-docker.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# Запуск веб-интерфейса в Docker
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 🐳 Быстрый старт
|
||||
|
||||
### 1. Запуск через docker-compose
|
||||
|
||||
```bash
|
||||
cd app
|
||||
make up
|
||||
# или
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 2. Проверка статуса
|
||||
|
||||
```bash
|
||||
make status
|
||||
# или
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### 3. Просмотр логов
|
||||
|
||||
```bash
|
||||
make logs
|
||||
# или
|
||||
docker-compose logs -f web
|
||||
```
|
||||
|
||||
### 4. Открыть в браузере
|
||||
|
||||
- Веб-интерфейс: http://localhost:8000
|
||||
- API документация: http://localhost:8000/api/docs
|
||||
|
||||
## 📋 Доступные команды
|
||||
|
||||
```bash
|
||||
make build # Собрать образы
|
||||
make up # Запустить контейнеры
|
||||
make down # Остановить контейнеры
|
||||
make restart # Перезапустить контейнеры
|
||||
make logs # Показать логи веб-интерфейса
|
||||
make logs-all # Показать логи всех сервисов
|
||||
make shell # Открыть shell в контейнере web
|
||||
make shell-celery # Открыть shell в контейнере celery-worker
|
||||
make rebuild # Пересобрать и перезапустить
|
||||
make clean # Очистить контейнеры и volumes
|
||||
make status # Показать статус контейнеров
|
||||
```
|
||||
|
||||
## 🏗️ Архитектура
|
||||
|
||||
### Сервисы
|
||||
|
||||
1. **web** - Веб-интерфейс FastAPI
|
||||
- Порт: 8000
|
||||
- Доступ к Docker socket для управления контейнерами
|
||||
- Монтирование проекта для доступа к roles, molecule
|
||||
|
||||
2. **redis** - Redis для Celery
|
||||
- Порт: 6379
|
||||
- Хранение задач и результатов
|
||||
|
||||
3. **celery-worker** - Celery worker для фоновых задач
|
||||
- Выполнение тестов, деплоев в фоне
|
||||
- Доступ к Docker socket
|
||||
|
||||
4. **celery-beat** - Celery beat для периодических задач
|
||||
- Опционально, для планирования задач
|
||||
|
||||
### Volumes
|
||||
|
||||
- `/workspace` - Весь проект DevOpsLab (монтируется из родительской директории)
|
||||
- `/app` - Код веб-интерфейса (для hot reload)
|
||||
- `/var/run/docker.sock` - Docker socket для управления контейнерами
|
||||
|
||||
### Networks
|
||||
|
||||
- `devopslab-network` - Внутренняя сеть для связи между сервисами
|
||||
|
||||
## 🔧 Настройка
|
||||
|
||||
### Переменные окружения
|
||||
|
||||
Все настройки через переменные окружения в `docker-compose.yml`:
|
||||
|
||||
- `PROJECT_ROOT=/workspace` - Корень проекта
|
||||
- `DOCKER_HOST=unix:///var/run/docker.sock` - Docker socket
|
||||
- `REDIS_URL=redis://redis:6379/0` - Redis для Celery
|
||||
|
||||
### Переопределение для разработки
|
||||
|
||||
Создайте `docker-compose.override.yml` для локальных настроек:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
```
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Ошибка: Cannot connect to Docker daemon
|
||||
|
||||
Убедитесь, что Docker socket доступен:
|
||||
```bash
|
||||
ls -la /var/run/docker.sock
|
||||
```
|
||||
|
||||
### Ошибка: Permission denied
|
||||
|
||||
Добавьте пользователя в группу docker:
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
Или запустите с sudo (не рекомендуется):
|
||||
```bash
|
||||
sudo docker-compose up -d
|
||||
```
|
||||
|
||||
### Ошибка: Port already in use
|
||||
|
||||
Измените порт в `docker-compose.yml`:
|
||||
```yaml
|
||||
ports:
|
||||
- "8001:8000" # Внешний порт:внутренний порт
|
||||
```
|
||||
|
||||
### Просмотр логов всех сервисов
|
||||
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### Перезапуск конкретного сервиса
|
||||
|
||||
```bash
|
||||
docker-compose restart web
|
||||
docker-compose restart celery-worker
|
||||
```
|
||||
|
||||
## 📊 Мониторинг
|
||||
|
||||
### Статус контейнеров
|
||||
|
||||
```bash
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### Использование ресурсов
|
||||
|
||||
```bash
|
||||
docker stats devopslab-web devopslab-redis devopslab-celery-worker
|
||||
```
|
||||
|
||||
### Логи Redis
|
||||
|
||||
```bash
|
||||
docker-compose logs redis
|
||||
```
|
||||
|
||||
## 🔄 Обновление
|
||||
|
||||
### Обновление кода
|
||||
|
||||
```bash
|
||||
# Остановить
|
||||
make down
|
||||
|
||||
# Обновить код (git pull, etc.)
|
||||
|
||||
# Пересобрать и запустить
|
||||
make rebuild
|
||||
```
|
||||
|
||||
### Обновление зависимостей
|
||||
|
||||
```bash
|
||||
# Отредактировать requirements.txt
|
||||
# Пересобрать образ
|
||||
make rebuild
|
||||
```
|
||||
|
||||
## 🧹 Очистка
|
||||
|
||||
### Очистка контейнеров и volumes
|
||||
|
||||
```bash
|
||||
make clean
|
||||
```
|
||||
|
||||
### Очистка образов
|
||||
|
||||
```bash
|
||||
docker-compose down --rmi all
|
||||
```
|
||||
|
||||
### Полная очистка
|
||||
|
||||
```bash
|
||||
make clean
|
||||
docker system prune -a
|
||||
```
|
||||
|
||||
## 📝 Примечания
|
||||
|
||||
- Веб-интерфейс имеет доступ к Docker socket для управления контейнерами тестирования
|
||||
- Весь проект монтируется в `/workspace` для доступа к roles, molecule, etc.
|
||||
- Redis данные сохраняются в volume `redis-data`
|
||||
- Для разработки используйте `docker-compose.override.yml`
|
||||
80
docs/web-interface-quickstart-docker.md
Normal file
80
docs/web-interface-quickstart-docker.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Быстрый старт веб-интерфейса в Docker
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 🚀 Запуск за 3 шага
|
||||
|
||||
### 1. Перейти в директорию app
|
||||
|
||||
```bash
|
||||
cd app
|
||||
```
|
||||
|
||||
### 2. Запустить docker-compose
|
||||
|
||||
```bash
|
||||
make up
|
||||
# или
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 3. Открыть в браузере
|
||||
|
||||
http://localhost:8000
|
||||
|
||||
## ✅ Готово!
|
||||
|
||||
Веб-интерфейс запущен и готов к работе. Ничего не нужно устанавливать на локальную машину - всё работает в Docker!
|
||||
|
||||
## 📋 Что запускается
|
||||
|
||||
- **web** - Веб-интерфейс на порту 8000
|
||||
- **redis** - Redis для Celery на порту 6379
|
||||
- **celery-worker** - Worker для фоновых задач
|
||||
- **celery-beat** - Планировщик задач (опционально)
|
||||
|
||||
## 🔧 Полезные команды
|
||||
|
||||
```bash
|
||||
# Просмотр логов
|
||||
make logs
|
||||
|
||||
# Остановка
|
||||
make down
|
||||
|
||||
# Перезапуск
|
||||
make restart
|
||||
|
||||
# Shell в контейнере
|
||||
make shell
|
||||
|
||||
# Статус
|
||||
make status
|
||||
```
|
||||
|
||||
## 🐛 Если что-то не работает
|
||||
|
||||
### Проверьте Docker
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### Проверьте логи
|
||||
|
||||
```bash
|
||||
docker-compose logs web
|
||||
docker-compose logs redis
|
||||
```
|
||||
|
||||
### Пересоберите
|
||||
|
||||
```bash
|
||||
make rebuild
|
||||
```
|
||||
|
||||
## 📚 Подробная документация
|
||||
|
||||
См. `README_DOCKER.md` для полной документации.
|
||||
153
docs/web-interface-quickstart.md
Normal file
153
docs/web-interface-quickstart.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Быстрый старт веб-интерфейса DevOpsLab
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## ✅ Что уже сделано
|
||||
|
||||
1. ✅ Создана git ветка `feature/web-interface`
|
||||
2. ✅ Создана базовая структура проекта
|
||||
3. ✅ Настроен FastAPI с базовыми шаблонами
|
||||
4. ✅ Реализован MakeExecutor для выполнения команд
|
||||
5. ✅ Создан Dashboard с базовой статистикой
|
||||
6. ✅ Настроены HTMX шаблоны
|
||||
|
||||
## 🚀 Запуск
|
||||
|
||||
### 1. Установка зависимостей
|
||||
|
||||
```bash
|
||||
cd app
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 2. Настройка окружения
|
||||
|
||||
```bash
|
||||
# Скопируйте пример конфигурации
|
||||
cp env.example .env
|
||||
|
||||
# Отредактируйте .env (особенно PROJECT_ROOT)
|
||||
# PROJECT_ROOT должен указывать на корень проекта DevOpsLab
|
||||
```
|
||||
|
||||
### 3. Запуск приложения
|
||||
|
||||
```bash
|
||||
# Из директории app/
|
||||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||
|
||||
# Или через Python
|
||||
python main.py
|
||||
```
|
||||
|
||||
### 4. Открыть в браузере
|
||||
|
||||
- Веб-интерфейс: http://localhost:8000
|
||||
- API документация: http://localhost:8000/api/docs
|
||||
|
||||
## 📁 Структура проекта
|
||||
|
||||
```
|
||||
app/
|
||||
├── api/v1/endpoints/ # API endpoints
|
||||
│ └── stats.py # ✅ Статистика (реализовано)
|
||||
├── core/ # Ядро
|
||||
│ ├── config.py # ✅ Конфигурация
|
||||
│ └── make_executor.py # ✅ Выполнение Makefile команд
|
||||
├── templates/ # HTMX шаблоны
|
||||
│ ├── base.html # ✅ Базовый шаблон
|
||||
│ ├── components/ # ✅ Компоненты (navbar, sidebar)
|
||||
│ └── pages/ # Страницы
|
||||
│ └── dashboard.html # ✅ Dashboard
|
||||
├── static/ # Статические файлы
|
||||
│ ├── css/main.css # ✅ Стили
|
||||
│ └── js/app.js # ✅ JavaScript
|
||||
└── main.py # ✅ Точка входа FastAPI
|
||||
```
|
||||
|
||||
## 📋 Следующие шаги
|
||||
|
||||
### Приоритет 1: Базовый функционал
|
||||
- [ ] Реализовать список ролей (`/roles`)
|
||||
- [ ] Реализовать создание роли (`/roles/create`)
|
||||
- [ ] Реализовать тестирование роли (`/roles/{name}/test`)
|
||||
|
||||
### Приоритет 2: Preset'ы и тестирование
|
||||
- [ ] Управление preset'ами (`/presets`)
|
||||
- [ ] WebSocket для live логов тестирования
|
||||
- [ ] История тестов (`/tests`)
|
||||
|
||||
### Приоритет 3: Деплой и импорт/экспорт
|
||||
- [ ] Деплой на живые серверы (`/roles/{name}/deploy`)
|
||||
- [ ] Экспорт ролей (`/roles/{name}/export`)
|
||||
- [ ] Импорт ролей (`/roles/import`)
|
||||
|
||||
### Приоритет 4: Дополнительно
|
||||
- [ ] База данных для истории
|
||||
- [ ] Celery для фоновых задач
|
||||
- [ ] Аутентификация
|
||||
|
||||
## 🔧 Разработка
|
||||
|
||||
### Добавление нового endpoint
|
||||
|
||||
1. Создайте файл в `app/api/v1/endpoints/`
|
||||
2. Создайте роутер:
|
||||
```python
|
||||
from fastapi import APIRouter
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/example")
|
||||
async def example():
|
||||
return {"message": "Hello"}
|
||||
```
|
||||
|
||||
3. Подключите в `app/api/v1/router.py`:
|
||||
```python
|
||||
from app.api.v1.endpoints import example
|
||||
api_router.include_router(example.router, prefix="/example")
|
||||
```
|
||||
|
||||
### Добавление новой страницы
|
||||
|
||||
1. Создайте шаблон в `app/templates/pages/`
|
||||
2. Добавьте роут в `app/main.py`:
|
||||
```python
|
||||
@app.get("/example", response_class=HTMLResponse)
|
||||
async def example_page(request: Request):
|
||||
return templates.TemplateResponse("pages/example.html", {"request": request})
|
||||
```
|
||||
|
||||
## 📚 Документация
|
||||
|
||||
- `docs/WEB_INTERFACE_PROPOSAL.md` - Полное предложение
|
||||
- `docs/WEB_INTERFACE_DETAILS.md` - Детали работы
|
||||
- `docs/WEB_INTERFACE_DEPLOY_IMPORT_EXPORT.md` - Деплой, импорт, экспорт
|
||||
- `docs/WEB_INTERFACE_QUICKSTART.md` - Быстрый старт
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Ошибка: ModuleNotFoundError
|
||||
|
||||
Убедитесь, что вы установили зависимости:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Ошибка: PROJECT_ROOT не найден
|
||||
|
||||
Проверьте `.env` файл и убедитесь, что `PROJECT_ROOT` указывает на правильный путь.
|
||||
|
||||
### Ошибка: Порт уже занят
|
||||
|
||||
Измените порт в `.env` или убейте процесс:
|
||||
```bash
|
||||
lsof -ti:8000 | xargs kill
|
||||
```
|
||||
|
||||
## 📝 Примечания
|
||||
|
||||
- Проект находится в ветке `feature/web-interface`
|
||||
- Все изменения должны быть в директории `app/`
|
||||
- Не изменяйте существующий код проекта (roles/, molecule/, etc.)
|
||||
74
docs/web-interface-readme.md
Normal file
74
docs/web-interface-readme.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# DevOpsLab Web Interface
|
||||
|
||||
Веб-интерфейс для управления Ansible ролями в проекте DevOpsLab.
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
### Установка зависимостей
|
||||
|
||||
```bash
|
||||
cd app
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Настройка окружения
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Отредактируйте .env файл
|
||||
```
|
||||
|
||||
### Запуск приложения
|
||||
|
||||
```bash
|
||||
# Режим разработки
|
||||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||
|
||||
# Или через Python
|
||||
python main.py
|
||||
```
|
||||
|
||||
### Доступ к приложению
|
||||
|
||||
- Веб-интерфейс: http://localhost:8000
|
||||
- API документация: http://localhost:8000/api/docs
|
||||
- ReDoc: http://localhost:8000/api/redoc
|
||||
|
||||
## 📁 Структура проекта
|
||||
|
||||
```
|
||||
app/
|
||||
├── api/v1/endpoints/ # API endpoints
|
||||
├── core/ # Ядро (config, make_executor)
|
||||
├── models/ # Модели данных
|
||||
├── services/ # Бизнес-логика
|
||||
├── templates/ # HTMX шаблоны
|
||||
├── static/ # Статические файлы
|
||||
├── tasks/ # Celery задачи
|
||||
├── db/ # База данных
|
||||
└── main.py # Точка входа
|
||||
```
|
||||
|
||||
## 🔧 Разработка
|
||||
|
||||
### Добавление нового endpoint
|
||||
|
||||
1. Создайте файл в `api/v1/endpoints/`
|
||||
2. Создайте роутер с endpoints
|
||||
3. Подключите роутер в `api/v1/router.py`
|
||||
|
||||
### Добавление новой страницы
|
||||
|
||||
1. Создайте шаблон в `templates/pages/`
|
||||
2. Добавьте роут в `main.py`
|
||||
3. Используйте `base.html` как базовый шаблон
|
||||
|
||||
## 📚 Документация
|
||||
|
||||
Полная документация находится в `docs/`:
|
||||
- `WEB_INTERFACE_PROPOSAL.md` - Полное предложение
|
||||
- `WEB_INTERFACE_DETAILS.md` - Детали работы
|
||||
- `WEB_INTERFACE_DEPLOY_IMPORT_EXPORT.md` - Деплой, импорт, экспорт
|
||||
96
docs/web-interface-start-here.md
Normal file
96
docs/web-interface-start-here.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# 🚀 Начните отсюда!
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
|
||||
## Быстрый запуск веб-интерфейса в Docker
|
||||
|
||||
### Шаг 1: Перейти в директорию app
|
||||
|
||||
```bash
|
||||
cd app
|
||||
```
|
||||
|
||||
### Шаг 2: Запустить docker-compose
|
||||
|
||||
```bash
|
||||
make up
|
||||
```
|
||||
|
||||
Или напрямую:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Шаг 3: Открыть в браузере
|
||||
|
||||
http://localhost:8000
|
||||
|
||||
## ✅ Готово!
|
||||
|
||||
Веб-интерфейс запущен! Ничего не нужно устанавливать на локальную машину.
|
||||
|
||||
## 📋 Что запускается
|
||||
|
||||
- **web** (порт 8000) - Веб-интерфейс FastAPI
|
||||
- **redis** (порт 6379) - Redis для Celery
|
||||
- **celery-worker** - Worker для фоновых задач
|
||||
- **celery-beat** - Планировщик задач
|
||||
|
||||
## 🔧 Полезные команды
|
||||
|
||||
```bash
|
||||
# Просмотр логов
|
||||
make logs
|
||||
|
||||
# Остановка
|
||||
make down
|
||||
|
||||
# Перезапуск
|
||||
make restart
|
||||
|
||||
# Shell в контейнере
|
||||
make shell
|
||||
|
||||
# Статус контейнеров
|
||||
make status
|
||||
|
||||
# Пересборка
|
||||
make rebuild
|
||||
```
|
||||
|
||||
## 📚 Документация
|
||||
|
||||
- `README_DOCKER.md` - Полная документация по Docker
|
||||
- `QUICKSTART_DOCKER.md` - Быстрый старт
|
||||
- `README.md` - Общая документация
|
||||
|
||||
## 🐛 Проблемы?
|
||||
|
||||
### Проверьте Docker
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### Проверьте логи
|
||||
|
||||
```bash
|
||||
docker-compose logs web
|
||||
```
|
||||
|
||||
### Пересоберите
|
||||
|
||||
```bash
|
||||
make rebuild
|
||||
```
|
||||
|
||||
## 💡 Особенности
|
||||
|
||||
- ✅ Всё работает в Docker - ничего не нужно устанавливать локально
|
||||
- ✅ Доступ к Docker socket для управления контейнерами тестирования
|
||||
- ✅ Весь проект монтируется в контейнер
|
||||
- ✅ Hot reload для разработки
|
||||
- ✅ Celery для фоновых задач
|
||||
116
docs/web-interface-status.md
Normal file
116
docs/web-interface-status.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# ✅ Статус развертывания веб-интерфейса DevOpsLab
|
||||
|
||||
**Автор:** Сергей Антропов
|
||||
**Сайт:** https://devops.org.ru
|
||||
**Дата проверки:** 2024-02-15
|
||||
|
||||
## 🎉 УСПЕШНО ЗАПУЩЕНО!
|
||||
|
||||
### Проверка работоспособности
|
||||
|
||||
```bash
|
||||
# ✅ Health check
|
||||
$ curl http://localhost:8000/health
|
||||
{"status":"ok","version":"1.0.0"}
|
||||
|
||||
# ✅ Главная страница
|
||||
$ curl http://localhost:8000/
|
||||
<!DOCTYPE html>... (HTML загружается)
|
||||
|
||||
# ✅ API статистики
|
||||
$ curl http://localhost:8000/api/v1/stats/roles
|
||||
{"count":4}
|
||||
```
|
||||
|
||||
### Статус контейнеров
|
||||
|
||||
```
|
||||
✅ devopslab-web Up - порт 8000
|
||||
✅ devopslab-redis Up - порт 6379
|
||||
✅ devopslab-celery-worker Up - готов к работе
|
||||
✅ devopslab-celery-beat Up - готов к работе
|
||||
```
|
||||
|
||||
## 🔧 Исправленные проблемы
|
||||
|
||||
### 1. Конфликт зависимостей Redis
|
||||
- **Было:** `redis==5.0.1` (несовместимо с celery[redis] 5.3.4)
|
||||
- **Стало:** `redis==4.6.0` ✅
|
||||
|
||||
### 2. Ошибка импорта модулей
|
||||
- **Было:** `ModuleNotFoundError: No module named 'app'`
|
||||
- **Исправлено:**
|
||||
- Структура: файлы в `/app/app/`
|
||||
- `PYTHONPATH=/app`
|
||||
- Команда: `python -m uvicorn app.main:app`
|
||||
- Создан `app/app/__init__.py` ✅
|
||||
|
||||
### 3. Команды Celery
|
||||
- **Было:** `celery -A tasks.celery_tasks`
|
||||
- **Стало:** `celery -A app.tasks.celery_tasks` ✅
|
||||
|
||||
## 📁 Структура проекта
|
||||
|
||||
```
|
||||
app/
|
||||
├── Dockerfile ✅ Готов
|
||||
├── docker-compose.yml ✅ Готов
|
||||
├── requirements.txt ✅ Исправлен (redis 4.6.0)
|
||||
├── main.py ✅ Работает
|
||||
├── app/ ✅ Пакет Python
|
||||
│ ├── __init__.py ✅ Создан
|
||||
│ ├── main.py
|
||||
│ ├── api/
|
||||
│ ├── core/
|
||||
│ ├── templates/
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
## 🌐 Доступные endpoints
|
||||
|
||||
- ✅ `GET /` - Главная страница (Dashboard)
|
||||
- ✅ `GET /health` - Health check
|
||||
- ✅ `GET /api/v1/stats/roles` - Количество ролей
|
||||
- ✅ `GET /api/docs` - Swagger документация
|
||||
- ✅ `GET /api/redoc` - ReDoc документация
|
||||
|
||||
## 🚀 Команды для работы
|
||||
|
||||
```bash
|
||||
# Запуск
|
||||
cd app && make up
|
||||
|
||||
# Остановка
|
||||
make down
|
||||
|
||||
# Логи
|
||||
make logs
|
||||
|
||||
# Shell
|
||||
make shell
|
||||
|
||||
# Статус
|
||||
make status
|
||||
```
|
||||
|
||||
## ✅ Что работает
|
||||
|
||||
1. ✅ Docker сборка проходит успешно
|
||||
2. ✅ Контейнеры запускаются
|
||||
3. ✅ Веб-интерфейс отвечает на запросы
|
||||
4. ✅ API endpoints работают
|
||||
5. ✅ Redis подключен
|
||||
6. ✅ Celery worker запущен и готов
|
||||
7. ✅ Доступ к Docker socket работает
|
||||
8. ✅ Монтирование проекта работает
|
||||
9. ✅ HTMX шаблоны загружаются
|
||||
10. ✅ Статистика ролей работает
|
||||
|
||||
## 📝 Готово к разработке!
|
||||
|
||||
Веб-интерфейс полностью настроен и готов к дальнейшей разработке функционала.
|
||||
|
||||
---
|
||||
|
||||
**Статус:** ✅ **РАБОТАЕТ**
|
||||
Reference in New Issue
Block a user